Commit 0c63aa9e authored by Shu-yu Guo's avatar Shu-yu Guo Committed by Commit Bot

[ptr-cage] Reserve base registers on x64 (r14) and arm64 (x28)

Also add a V8_COMPRESS_POINTERS_IN_SHARED_CAGE define when pointer
compression is enabled.

This CL is to get performance numbers for reserving an extra register.
There is no actual pointer cage yet, and the base register will always
have the same value as the root register. The pointer decompression code
is switched to using the base register instead of the root register.

Bug: v8:11460
Change-Id: I40bae556c2098608fb6fc193a52694e3f54754bd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2716075Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73204}
parent f458cade
......@@ -108,6 +108,7 @@ declare_args() {
# Enable pointer compression (sets -dV8_COMPRESS_POINTERS).
v8_enable_pointer_compression = ""
v8_enable_pointer_compression_shared_cage = ""
v8_enable_31bit_smis_on_64bit_arch = false
# Sets -dOBJECT_PRINT.
......@@ -324,6 +325,9 @@ if (v8_enable_pointer_compression == "") {
v8_enable_pointer_compression =
v8_current_cpu == "arm64" || v8_current_cpu == "x64"
}
if (v8_enable_pointer_compression_shared_cage == "") {
v8_enable_pointer_compression_shared_cage = v8_enable_pointer_compression
}
if (v8_enable_fast_torque == "") {
v8_enable_fast_torque = v8_enable_fast_mksnapshot
}
......@@ -388,6 +392,10 @@ assert(!v8_use_multi_snapshots || !v8_control_flow_integrity,
assert(!v8_enable_heap_sandbox || v8_enable_pointer_compression,
"V8 Heap Sandbox requires pointer compression")
assert(
!v8_enable_pointer_compression_shared_cage || v8_enable_pointer_compression,
"Can't share a pointer compression cage if pointers aren't compressed")
assert(!v8_enable_unconditional_write_barriers || !v8_disable_write_barriers,
"Write barriers can't be both enabled and disabled")
......@@ -527,6 +535,7 @@ config("external_startup_data") {
external_v8_defines = [
"V8_ENABLE_CHECKS",
"V8_COMPRESS_POINTERS",
"V8_COMPRESS_POINTERS_IN_SHARED_CAGE",
"V8_31BIT_SMIS_ON_64BIT_ARCH",
"V8_COMPRESS_ZONES",
"V8_HEAP_SANDBOX",
......@@ -544,6 +553,9 @@ if (v8_enable_v8_checks) {
if (v8_enable_pointer_compression) {
enabled_external_v8_defines += [ "V8_COMPRESS_POINTERS" ]
}
if (v8_enable_pointer_compression_shared_cage) {
enabled_external_v8_defines += [ "V8_COMPRESS_POINTERS_IN_SHARED_CAGE" ]
}
if (v8_enable_pointer_compression || v8_enable_31bit_smis_on_64bit_arch) {
enabled_external_v8_defines += [ "V8_31BIT_SMIS_ON_64BIT_ARCH" ]
}
......
......@@ -17,7 +17,7 @@ namespace detail {
// Avoid using kScratchRegister(==r10) since the macro-assembler doesn't use
// this scope and will conflict.
static constexpr Register kScratchRegisters[] = {r8, r9, r11, r12, r14, r15};
static constexpr Register kScratchRegisters[] = {r8, r9, r11, r12, r15};
static constexpr int kNumScratchRegisters = arraysize(kScratchRegisters);
} // namespace detail
......
......@@ -632,6 +632,11 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
// Initialize the root register.
// C calling convention. The first argument is passed in x0.
__ Mov(kRootRegister, x0);
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
// Initialize the pointer cage base register.
__ Mov(kPointerCageBaseRegister, x0);
#endif
}
// Set up fp. It points to the {fp, lr} pair pushed as the last step in
......@@ -910,10 +915,13 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
__ Mov(x23, x19);
__ Mov(x24, x19);
__ Mov(x25, x19);
#ifndef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
__ Mov(x28, x19);
#endif
// Don't initialize the reserved registers.
// x26 : root register (kRootRegister).
// x27 : context pointer (cp).
// x28 : pointer cage base register (kPointerCageBaseRegister).
// x29 : frame pointer (fp).
Handle<Code> builtin = is_construct
......
......@@ -377,6 +377,12 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
// Initialize the root register.
// C calling convention. The first argument is passed in arg_reg_1.
__ movq(kRootRegister, arg_reg_1);
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
// Initialize the pointer cage base register.
// TODO(syg): Actually make a cage.
__ movq(kPointerCageBaseRegister, arg_reg_1);
#endif
}
// Save copies of the top frame descriptor on the stack.
......@@ -1633,7 +1639,7 @@ void Builtins::Generate_BaselineOutOfLinePrologue(MacroAssembler* masm) {
__ incl(
FieldOperand(feedback_vector, FeedbackVector::kInvocationCountOffset));
Register return_address = r12;
Register return_address = r15;
__ RecordComment("[ Frame Setup");
// Save the return address, so that we can push it to the end of the newly
......@@ -2810,8 +2816,8 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
DCHECK(save_doubles == kDontSaveFPRegs);
DCHECK(!builtin_exit_frame);
__ EnterApiExitFrame(arg_stack_space);
// Move argc into r14 (argv is already in r15).
__ movq(r14, rax);
// Move argc into r12 (argv is already in r15).
__ movq(r12, rax);
} else {
__ EnterExitFrame(
arg_stack_space, save_doubles == kSaveFPRegs,
......@@ -2821,7 +2827,7 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
// rbx: pointer to builtin function (C callee-saved).
// rbp: frame pointer of exit frame (restored after C call).
// rsp: stack pointer (restored after C call).
// r14: number of arguments including receiver (C callee-saved).
// r12: number of arguments including receiver (C callee-saved).
// r15: argv pointer (C callee-saved).
// Check stack alignment.
......@@ -2834,7 +2840,7 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
if (result_size <= kMaxRegisterResultSize) {
// Pass a pointer to the Arguments object as the first argument.
// Return result in single register (rax), or a register pair (rax, rdx).
__ movq(kCCallArg0, r14); // argc.
__ movq(kCCallArg0, r12); // argc.
__ movq(kCCallArg1, r15); // argv.
__ Move(kCCallArg2, ExternalReference::isolate_address(masm->isolate()));
} else {
......@@ -2842,7 +2848,7 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
// Pass a pointer to the result location as the first argument.
__ leaq(kCCallArg0, StackSpaceOperand(kArgExtraStackSpace));
// Pass a pointer to the Arguments object as the second argument.
__ movq(kCCallArg1, r14); // argc.
__ movq(kCCallArg1, r12); // argc.
__ movq(kCCallArg2, r15); // argv.
__ Move(kCCallArg3, ExternalReference::isolate_address(masm->isolate()));
}
......@@ -2866,12 +2872,12 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
// should have returned the exception sentinel.
if (FLAG_debug_code) {
Label okay;
__ LoadRoot(r14, RootIndex::kTheHoleValue);
__ LoadRoot(kScratchRegister, RootIndex::kTheHoleValue);
ExternalReference pending_exception_address = ExternalReference::Create(
IsolateAddressId::kPendingExceptionAddress, masm->isolate());
Operand pending_exception_operand =
masm->ExternalReferenceAsOperand(pending_exception_address);
__ cmp_tagged(r14, pending_exception_operand);
__ cmp_tagged(kScratchRegister, pending_exception_operand);
__ j(equal, &okay, Label::kNear);
__ int3();
__ bind(&okay);
......@@ -3212,7 +3218,7 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
kLastSpillOffset - kSystemPointerSize;
// For Integer section.
// Set the current_int_param_slot to point to the start of the section.
Register current_int_param_slot = r14;
Register current_int_param_slot = r10;
__ leaq(current_int_param_slot, MemOperand(rsp, -kSystemPointerSize));
Register params_size = param_count;
param_count = no_reg;
......@@ -3326,7 +3332,7 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r8 : start_int_section
// -- rdi : start_float_section
// -- r14 : current_int_param_slot
// -- r10 : current_int_param_slot
// -- r15 : current_float_param_slot
// -- r11 : valuetypes_array_ptr
// -- r12 : valuetype
......@@ -3758,7 +3764,7 @@ int Offset(ExternalReference ref0, ExternalReference ref1) {
}
// Calls an API function. Allocates HandleScope, extracts returned value
// from handle and propagates exceptions. Clobbers r14, r15, rbx and
// from handle and propagates exceptions. Clobbers r12, r15, rbx and
// caller-save registers. Restores context. On return removes
// stack_space * kSystemPointerSize (GCed).
void CallApiFunctionAndReturn(MacroAssembler* masm, Register function_address,
......@@ -3785,7 +3791,7 @@ void CallApiFunctionAndReturn(MacroAssembler* masm, Register function_address,
DCHECK(rdx == function_address || r8 == function_address);
// Allocate HandleScope in callee-save registers.
Register prev_next_address_reg = r14;
Register prev_next_address_reg = r12;
Register prev_limit_reg = rbx;
Register base_reg = r15;
__ Move(base_reg, next_address);
......
......@@ -1036,6 +1036,9 @@ void TurboAssembler::Uxtw(const Register& rd, const Register& rn) {
void TurboAssembler::InitializeRootRegister() {
ExternalReference isolate_root = ExternalReference::isolate_root(isolate());
Mov(kRootRegister, Operand(isolate_root));
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
Mov(kPointerCageBaseRegister, Operand(isolate_root));
#endif
}
void MacroAssembler::SmiTag(Register dst, Register src) {
......
......@@ -2816,14 +2816,14 @@ void TurboAssembler::DecompressTaggedPointer(const Register& destination,
const MemOperand& field_operand) {
RecordComment("[ DecompressTaggedPointer");
Ldr(destination.W(), field_operand);
Add(destination, kRootRegister, destination);
Add(destination, kPointerCageBaseRegister, destination);
RecordComment("]");
}
void TurboAssembler::DecompressTaggedPointer(const Register& destination,
const Register& source) {
RecordComment("[ DecompressTaggedPointer");
Add(destination, kRootRegister, Operand(source, UXTW));
Add(destination, kPointerCageBaseRegister, Operand(source, UXTW));
RecordComment("]");
}
......@@ -2831,7 +2831,7 @@ void TurboAssembler::DecompressAnyTagged(const Register& destination,
const MemOperand& field_operand) {
RecordComment("[ DecompressAnyTagged");
Ldr(destination.W(), field_operand);
Add(destination, kRootRegister, destination);
Add(destination, kPointerCageBaseRegister, destination);
RecordComment("]");
}
......
......@@ -30,11 +30,21 @@ namespace internal {
// x18 is the platform register and is reserved for the use of platform ABIs.
// It is known to be reserved by the OS at least on Windows and iOS.
#define ALLOCATABLE_GENERAL_REGISTERS(R) \
#define ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(R) \
R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \
R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \
R(x19) R(x20) R(x21) R(x22) R(x23) R(x24) R(x25) \
R(x27) R(x28)
R(x27)
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
#define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(R)
#else
#define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(R) R(x28)
#endif
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(V) \
MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V)
#define FLOAT_REGISTERS(V) \
V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) \
......@@ -458,6 +468,12 @@ ALIAS_REGISTER(Register, wip1, w17);
// Root register.
ALIAS_REGISTER(Register, kRootRegister, x26);
ALIAS_REGISTER(Register, rr, x26);
// Pointer cage base register.
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
ALIAS_REGISTER(Register, kPointerCageBaseRegister, x28);
#else
ALIAS_REGISTER(Register, kPointerCageBaseRegister, kRootRegister);
#endif
// Context pointer register.
ALIAS_REGISTER(Register, cp, x27);
ALIAS_REGISTER(Register, fp, x29);
......
......@@ -25,6 +25,9 @@ void CallInterfaceDescriptorData::InitializePlatformSpecific(
// within the calling convention are disallowed.
#ifdef DEBUG
CHECK_NE(registers[i], kRootRegister);
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
CHECK_NE(registers[i], kPointerCageBaseRegister);
#endif
// Check for duplicated registers.
for (int j = i + 1; j < register_parameter_count; j++) {
CHECK_NE(registers[i], registers[j]);
......
......@@ -288,7 +288,7 @@ void TurboAssembler::DecompressTaggedPointer(Register destination,
Operand field_operand) {
RecordComment("[ DecompressTaggedPointer");
movl(destination, field_operand);
addq(destination, kRootRegister);
addq(destination, kPointerCageBaseRegister);
RecordComment("]");
}
......@@ -296,7 +296,7 @@ void TurboAssembler::DecompressTaggedPointer(Register destination,
Register source) {
RecordComment("[ DecompressTaggedPointer");
movl(destination, source);
addq(destination, kRootRegister);
addq(destination, kPointerCageBaseRegister);
RecordComment("]");
}
......@@ -304,7 +304,7 @@ void TurboAssembler::DecompressAnyTagged(Register destination,
Operand field_operand) {
RecordComment("[ DecompressAnyTagged");
movl(destination, field_operand);
addq(destination, kRootRegister);
addq(destination, kPointerCageBaseRegister);
RecordComment("]");
}
......@@ -3379,7 +3379,7 @@ void TurboAssembler::AllocateStackSpace(int bytes) {
}
#endif
void MacroAssembler::EnterExitFramePrologue(bool save_rax,
void MacroAssembler::EnterExitFramePrologue(Register saved_rax_reg,
StackFrame::Type frame_type) {
DCHECK(frame_type == StackFrame::EXIT ||
frame_type == StackFrame::BUILTIN_EXIT);
......@@ -3399,8 +3399,8 @@ void MacroAssembler::EnterExitFramePrologue(bool save_rax,
Push(Immediate(0)); // Saved entry sp, patched before call.
// Save the frame pointer and the context in top.
if (save_rax) {
movq(r14, rax); // Backup rax in callee-save register.
if (saved_rax_reg != no_reg) {
movq(saved_rax_reg, rax); // Backup rax in callee-save register.
}
Store(
......@@ -3449,18 +3449,19 @@ void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space,
void MacroAssembler::EnterExitFrame(int arg_stack_space, bool save_doubles,
StackFrame::Type frame_type) {
EnterExitFramePrologue(true, frame_type);
Register saved_rax_reg = r12;
EnterExitFramePrologue(saved_rax_reg, frame_type);
// Set up argv in callee-saved register r15. It is reused in LeaveExitFrame,
// so it must be retained across the C-call.
int offset = StandardFrameConstants::kCallerSPOffset - kSystemPointerSize;
leaq(r15, Operand(rbp, r14, times_system_pointer_size, offset));
leaq(r15, Operand(rbp, saved_rax_reg, times_system_pointer_size, offset));
EnterExitFrameEpilogue(arg_stack_space, save_doubles);
}
void MacroAssembler::EnterApiExitFrame(int arg_stack_space) {
EnterExitFramePrologue(false, StackFrame::EXIT);
EnterExitFramePrologue(no_reg, StackFrame::EXIT);
EnterExitFrameEpilogue(arg_stack_space, false);
}
......
......@@ -704,6 +704,9 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void InitializeRootRegister() {
ExternalReference isolate_root = ExternalReference::isolate_root(isolate());
Move(kRootRegister, isolate_root);
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
Move(kPointerCageBaseRegister, isolate_root);
#endif
}
void SaveRegisters(RegList registers);
......@@ -1146,7 +1149,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
Register actual_parameter_count, Label* done,
InvokeFlag flag);
void EnterExitFramePrologue(bool save_rax, StackFrame::Type frame_type);
void EnterExitFramePrologue(Register saved_rax_reg,
StackFrame::Type frame_type);
// Allocates arg_stack_space * kSystemPointerSize memory (not GCed) on the
// stack accessible via StackSpaceOperand.
......
......@@ -29,20 +29,29 @@ namespace internal {
V(r14) \
V(r15)
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
V(rax) \
V(rbx) \
V(rdx) \
V(rcx) \
V(rsi) \
V(rdi) \
V(r8) \
V(r9) \
V(r11) \
V(r12) \
V(r14) \
#define ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(V) \
V(rax) \
V(rbx) \
V(rdx) \
V(rcx) \
V(rsi) \
V(rdi) \
V(r8) \
V(r9) \
V(r11) \
V(r12) \
V(r15)
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
#define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V)
#else
#define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V) V(r14)
#endif
#define ALLOCATABLE_GENERAL_REGISTERS(V) \
ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(V) \
MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V)
enum RegisterCode {
#define REGISTER_CODE(R) kRegCode_##R,
GENERAL_REGISTERS(REGISTER_CODE)
......@@ -201,7 +210,7 @@ constexpr Register kAllocateSizeRegister = rdx;
constexpr Register kSpeculationPoisonRegister = r12;
constexpr Register kInterpreterAccumulatorRegister = rax;
constexpr Register kInterpreterBytecodeOffsetRegister = r9;
constexpr Register kInterpreterBytecodeArrayRegister = r14;
constexpr Register kInterpreterBytecodeArrayRegister = r12;
constexpr Register kInterpreterDispatchTableRegister = r15;
constexpr Register kJavaScriptCallArgCountRegister = rax;
......@@ -221,6 +230,11 @@ constexpr Register kWasmInstanceRegister = rsi;
constexpr Register kScratchRegister = r10;
constexpr XMMRegister kScratchDoubleReg = xmm15;
constexpr Register kRootRegister = r13; // callee save
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
constexpr Register kPointerCageBaseRegister = r14; // callee save
#else
constexpr Register kPointerCageBaseRegister = kRootRegister;
#endif
constexpr Register kOffHeapTrampolineRegister = kScratchRegister;
......
......@@ -962,6 +962,10 @@ void Deoptimizer::DoComputeOutputFrames() {
FrameDescription* topmost = output_[count - 1];
topmost->GetRegisterValues()->SetRegister(kRootRegister.code(),
isolate()->isolate_root());
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
topmost->GetRegisterValues()->SetRegister(kPointerCageBaseRegister.code(),
isolate()->isolate_root());
#endif
// Print some helpful diagnostic information.
if (verbose_tracing_enabled()) {
......
......@@ -58,11 +58,15 @@ constexpr RegList kLiftoffAssemblerFpCacheRegs = LowDwVfpRegister::ListOf(
#elif V8_TARGET_ARCH_ARM64
// x16: ip0, x17: ip1, x18: platform register, x26: root, x27: cp, x29: fp,
// x30: lr, x31: xzr.
// x16: ip0, x17: ip1, x18: platform register, x26: root, x27: cp, x8: base,
// x29: fp, x30: lr, x31: xzr.
constexpr RegList kLiftoffAssemblerGpCacheRegs =
CPURegister::ListOf(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12,
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
x13, x14, x15, x19, x20, x21, x22, x23, x24, x25);
#else
x13, x14, x15, x19, x20, x21, x22, x23, x24, x25, x28);
#endif
// d15: fp_zero, d30-d31: macro-assembler scratch V Registers.
constexpr RegList kLiftoffAssemblerFpCacheRegs = CPURegister::ListOf(
......
......@@ -60,10 +60,18 @@ using F0 = int();
static void EntryCode(MacroAssembler* masm) {
// Smi constant register is callee save.
__ pushq(kRootRegister);
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
__ pushq(kPointerCageBaseRegister);
#endif
__ InitializeRootRegister();
}
static void ExitCode(MacroAssembler* masm) { __ popq(kRootRegister); }
static void ExitCode(MacroAssembler* masm) {
#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
__ popq(kPointerCageBaseRegister);
#endif
__ popq(kRootRegister);
}
TEST(Smi) {
// Check that C++ Smi operations work as expected.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment