Clarify how entry frames link the to the next exit frame
Entry frames use a dedicated (and nonstandard) slot to link to the next exit frame's frame pointer. This slot is initialized using the Isolate's `c_entry_fp_` field (1. we can't use rbp since it may contain arbitrary values with -fomit-frame-pointer, and 2. V8 stack walks skip over all C++ frames between exit- and entry frames). This CL clarifies all this by: - renaming EntryFrameConstants::kCallerFPOffset to kNextExitFrameFPOffset to avoid confusion with the StandardFrame::kCallerFPOffset constant. - extending comments in JSEntry codegen. - adding a static_assert as a link between the constant and related code. Change-Id: I38ed6d2f6f8249e0befabff5d3f3a8f95426e04c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3936278 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Commit-Queue: Jakob Linke <jgruber@chromium.org> Auto-Submit: Jakob Linke <jgruber@chromium.org> Cr-Commit-Position: refs/heads/main@{#84867}
This commit is contained in:
parent
20d32a7042
commit
c505f9b37c
@ -494,12 +494,13 @@ constexpr int kPushedStackSpace = kNumCalleeSaved * kPointerSize -
|
||||
kPointerSize /* FP */ +
|
||||
kNumDoubleCalleeSaved * kDoubleSize +
|
||||
5 * kPointerSize /* r5, r6, r7, fp, lr */ +
|
||||
EntryFrameConstants::kCallerFPOffset;
|
||||
EntryFrameConstants::kNextExitFrameFPOffset;
|
||||
|
||||
// Assert that the EntryFrameConstants are in sync with the builtin.
|
||||
static_assert(kPushedStackSpace == EntryFrameConstants::kDirectCallerSPOffset +
|
||||
3 * kPointerSize /* r5, r6, r7*/ +
|
||||
EntryFrameConstants::kCallerFPOffset,
|
||||
static_assert(kPushedStackSpace ==
|
||||
EntryFrameConstants::kDirectCallerSPOffset +
|
||||
3 * kPointerSize /* r5, r6, r7*/ +
|
||||
EntryFrameConstants::kNextExitFrameFPOffset,
|
||||
"Pushed stack space and frame constants do not match. See "
|
||||
"frame-constants-arm.h");
|
||||
|
||||
@ -529,7 +530,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
const RegList kCalleeSavedWithoutFp = kCalleeSaved - fp;
|
||||
|
||||
// Update |pushed_stack_space| when we manipulate the stack.
|
||||
int pushed_stack_space = EntryFrameConstants::kCallerFPOffset;
|
||||
int pushed_stack_space = EntryFrameConstants::kNextExitFrameFPOffset;
|
||||
{
|
||||
NoRootArrayScope no_root_array(masm);
|
||||
|
||||
@ -573,7 +574,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
Register scratch = r6;
|
||||
|
||||
// Set up frame pointer for the frame to be pushed.
|
||||
__ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
|
||||
__ add(fp, sp, Operand(-EntryFrameConstants::kNextExitFrameFPOffset));
|
||||
|
||||
// If this is the outermost JS call, set js_entry_sp value.
|
||||
Label non_outermost_js;
|
||||
@ -658,7 +659,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
|
||||
// Reset the stack to the callee saved registers.
|
||||
__ add(sp, sp,
|
||||
Operand(-EntryFrameConstants::kCallerFPOffset -
|
||||
Operand(-EntryFrameConstants::kNextExitFrameFPOffset -
|
||||
kSystemPointerSize /* already popped one */));
|
||||
|
||||
__ ldm(ia_w, sp, {fp, lr});
|
||||
|
@ -559,7 +559,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
__ St_d(zero_reg, MemOperand(s5, 0));
|
||||
|
||||
// Set up frame pointer for the frame to be pushed.
|
||||
__ addi_d(fp, sp, -EntryFrameConstants::kCallerFPOffset);
|
||||
__ addi_d(fp, sp, -EntryFrameConstants::kNextExitFrameFPOffset);
|
||||
|
||||
// Registers:
|
||||
// either
|
||||
@ -672,7 +672,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
__ St_d(a5, MemOperand(a4, 0));
|
||||
|
||||
// Reset the stack to the callee saved registers.
|
||||
__ addi_d(sp, sp, -EntryFrameConstants::kCallerFPOffset);
|
||||
__ addi_d(sp, sp, -EntryFrameConstants::kNextExitFrameFPOffset);
|
||||
|
||||
// Restore callee-saved fpu registers.
|
||||
__ MultiPopFPU(kCalleeSavedFPU);
|
||||
|
@ -562,7 +562,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
__ Sd(zero_reg, MemOperand(s5));
|
||||
|
||||
// Set up frame pointer for the frame to be pushed.
|
||||
__ daddiu(fp, sp, -EntryFrameConstants::kCallerFPOffset);
|
||||
__ daddiu(fp, sp, -EntryFrameConstants::kNextExitFrameFPOffset);
|
||||
|
||||
// Registers:
|
||||
// either
|
||||
@ -674,7 +674,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
__ Sd(a5, MemOperand(a4));
|
||||
|
||||
// Reset the stack to the callee saved registers.
|
||||
__ daddiu(sp, sp, -EntryFrameConstants::kCallerFPOffset);
|
||||
__ daddiu(sp, sp, -EntryFrameConstants::kNextExitFrameFPOffset);
|
||||
|
||||
// Restore callee-saved fpu registers.
|
||||
__ MultiPopFPU(kCalleeSavedFPU);
|
||||
|
@ -868,7 +868,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
|
||||
Register scratch = r9;
|
||||
// Set up frame pointer for the frame to be pushed.
|
||||
__ addi(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
|
||||
__ addi(fp, sp, Operand(-EntryFrameConstants::kNextExitFrameFPOffset));
|
||||
|
||||
// If this is the outermost JS call, set js_entry_sp value.
|
||||
Label non_outermost_js;
|
||||
@ -956,7 +956,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
__ StoreU64(r6, MemOperand(scratch));
|
||||
|
||||
// Reset the stack to the callee saved registers.
|
||||
__ addi(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
|
||||
__ addi(sp, sp, Operand(-EntryFrameConstants::kNextExitFrameFPOffset));
|
||||
|
||||
// Restore callee-saved double registers.
|
||||
__ MultiPopDoubles(kCalleeSavedDoubles);
|
||||
|
@ -596,7 +596,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
// frames on top.
|
||||
__ StoreWord(zero_reg, MemOperand(s5));
|
||||
// Set up frame pointer for the frame to be pushed.
|
||||
__ AddWord(fp, sp, -EntryFrameConstants::kCallerFPOffset);
|
||||
__ AddWord(fp, sp, -EntryFrameConstants::kNextExitFrameFPOffset);
|
||||
// Registers:
|
||||
// either
|
||||
// a1: entry address
|
||||
@ -708,7 +708,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
__ StoreWord(a5, MemOperand(a4));
|
||||
|
||||
// Reset the stack to the callee saved registers.
|
||||
__ AddWord(sp, sp, -EntryFrameConstants::kCallerFPOffset);
|
||||
__ AddWord(sp, sp, -EntryFrameConstants::kNextExitFrameFPOffset);
|
||||
|
||||
// Restore callee-saved fpu registers.
|
||||
__ MultiPopFPU(kCalleeSavedFPU);
|
||||
|
@ -772,7 +772,7 @@ namespace {
|
||||
constexpr int kPushedStackSpace =
|
||||
(kNumCalleeSaved + 2) * kSystemPointerSize +
|
||||
kNumCalleeSavedDoubles * kDoubleSize + 5 * kSystemPointerSize +
|
||||
EntryFrameConstants::kCallerFPOffset - kSystemPointerSize;
|
||||
EntryFrameConstants::kNextExitFrameFPOffset - kSystemPointerSize;
|
||||
|
||||
// Called with the native C calling convention. The corresponding function
|
||||
// signature is either:
|
||||
@ -871,10 +871,10 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
// Set up frame pointer for the frame to be pushed.
|
||||
// Need to add kSystemPointerSize, because sp has one extra
|
||||
// frame already for the frame type being pushed later.
|
||||
__ lay(fp, MemOperand(sp, -EntryFrameConstants::kCallerFPOffset +
|
||||
__ lay(fp, MemOperand(sp, -EntryFrameConstants::kNextExitFrameFPOffset +
|
||||
kSystemPointerSize));
|
||||
pushed_stack_space +=
|
||||
EntryFrameConstants::kCallerFPOffset - kSystemPointerSize;
|
||||
EntryFrameConstants::kNextExitFrameFPOffset - kSystemPointerSize;
|
||||
|
||||
// restore r6
|
||||
__ mov(r6, r0);
|
||||
@ -961,7 +961,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
__ StoreU64(r5, MemOperand(scrach));
|
||||
|
||||
// Reset the stack to the callee saved registers.
|
||||
__ lay(sp, MemOperand(sp, -EntryFrameConstants::kCallerFPOffset));
|
||||
__ lay(sp, MemOperand(sp, -EntryFrameConstants::kNextExitFrameFPOffset));
|
||||
|
||||
// Reload callee-saved preserved regs, return address reg (r14) and sp
|
||||
__ LoadMultipleP(r6, sp, MemOperand(sp, 0));
|
||||
|
@ -338,7 +338,14 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
|
||||
{
|
||||
NoRootArrayScope uninitialized_root_register(masm);
|
||||
// Set up frame.
|
||||
|
||||
// Set up the frame.
|
||||
//
|
||||
// Note: at this point we are entering V8-generated code from C++ and thus
|
||||
// rbp can be an arbitrary value (-fomit-frame-pointer). Since V8 still
|
||||
// needs to know where the next interesting frame is for the purpose of
|
||||
// stack walks, we instead push the stored EXIT frame fp
|
||||
// (IsolateAddressId::kCEntryFPAddress) below to a dedicated slot.
|
||||
__ pushq(rbp);
|
||||
__ movq(rbp, rsp);
|
||||
|
||||
@ -392,6 +399,16 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
|
||||
ExternalReference c_entry_fp = ExternalReference::Create(
|
||||
IsolateAddressId::kCEntryFPAddress, masm->isolate());
|
||||
{
|
||||
// Keep this static_assert to preserve a link between the offset constant
|
||||
// and the code location it refers to.
|
||||
#ifdef V8_TARGET_OS_WIN
|
||||
static_assert(EntryFrameConstants::kNextExitFrameFPOffset ==
|
||||
-3 * kSystemPointerSize + -7 * kSystemPointerSize -
|
||||
EntryFrameConstants::kXMMRegistersBlockSize);
|
||||
#else
|
||||
static_assert(EntryFrameConstants::kNextExitFrameFPOffset ==
|
||||
-3 * kSystemPointerSize + -5 * kSystemPointerSize);
|
||||
#endif // V8_TARGET_OS_WIN
|
||||
Operand c_entry_fp_operand = masm->ExternalReferenceAsOperand(c_entry_fp);
|
||||
__ Push(c_entry_fp_operand);
|
||||
|
||||
|
@ -33,7 +33,7 @@ class EntryFrameConstants : public AllStatic {
|
||||
public:
|
||||
// This is the offset to where JSEntry pushes the current value of
|
||||
// Isolate::c_entry_fp onto the stack.
|
||||
static constexpr int kCallerFPOffset = -3 * kSystemPointerSize;
|
||||
static constexpr int kNextExitFrameFPOffset = -3 * kSystemPointerSize;
|
||||
|
||||
// Stack offsets for arguments passed to JSEntry.
|
||||
static constexpr int kArgcOffset = +0 * kSystemPointerSize;
|
||||
|
@ -49,7 +49,7 @@ class EntryFrameConstants : public AllStatic {
|
||||
public:
|
||||
// This is the offset to where JSEntry pushes the current value of
|
||||
// Isolate::c_entry_fp onto the stack.
|
||||
static constexpr int kCallerFPOffset = -3 * kSystemPointerSize;
|
||||
static constexpr int kNextExitFrameFPOffset = -3 * kSystemPointerSize;
|
||||
static constexpr int kFixedFrameSize = 4 * kSystemPointerSize;
|
||||
|
||||
// The following constants are defined so we can static-assert their values
|
||||
|
@ -502,9 +502,9 @@ bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
|
||||
// See EntryFrame::GetCallerState. It computes the caller FP address
|
||||
// and calls ExitFrame::GetStateForFramePointer on it. We need to be
|
||||
// sure that caller FP address is valid.
|
||||
Address caller_fp =
|
||||
Memory<Address>(frame->fp() + EntryFrameConstants::kCallerFPOffset);
|
||||
if (!IsValidExitFrame(caller_fp)) return false;
|
||||
Address next_exit_frame_fp = Memory<Address>(
|
||||
frame->fp() + EntryFrameConstants::kNextExitFrameFPOffset);
|
||||
if (!IsValidExitFrame(next_exit_frame_fp)) return false;
|
||||
}
|
||||
frame->ComputeCallerState(&state);
|
||||
return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
|
||||
@ -818,9 +818,9 @@ void EntryFrame::ComputeCallerState(State* state) const {
|
||||
}
|
||||
|
||||
StackFrame::Type EntryFrame::GetCallerState(State* state) const {
|
||||
const int offset = EntryFrameConstants::kCallerFPOffset;
|
||||
Address fp = Memory<Address>(this->fp() + offset);
|
||||
return ExitFrame::GetStateForFramePointer(fp, state);
|
||||
Address next_exit_frame_fp =
|
||||
Memory<Address>(fp() + EntryFrameConstants::kNextExitFrameFPOffset);
|
||||
return ExitFrame::GetStateForFramePointer(next_exit_frame_fp, state);
|
||||
}
|
||||
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
|
@ -17,7 +17,7 @@ class EntryFrameConstants : public AllStatic {
|
||||
public:
|
||||
// This is the offset to where JSEntry pushes the current value of
|
||||
// Isolate::c_entry_fp onto the stack.
|
||||
static constexpr int kCallerFPOffset = -6 * kSystemPointerSize;
|
||||
static constexpr int kNextExitFrameFPOffset = -6 * kSystemPointerSize;
|
||||
|
||||
// EntryFrame is used by JSEntry, JSConstructEntry and JSRunMicrotasksEntry.
|
||||
// All of them take |root_register_value| as the first parameter.
|
||||
|
@ -17,7 +17,7 @@ class EntryFrameConstants : public AllStatic {
|
||||
public:
|
||||
// This is the offset to where JSEntry pushes the current value of
|
||||
// Isolate::c_entry_fp onto the stack.
|
||||
static constexpr int kCallerFPOffset = -3 * kSystemPointerSize;
|
||||
static constexpr int kNextExitFrameFPOffset = -3 * kSystemPointerSize;
|
||||
};
|
||||
|
||||
class WasmLiftoffSetupFrameConstants : public TypedFrameConstants {
|
||||
|
@ -17,7 +17,7 @@ class EntryFrameConstants : public AllStatic {
|
||||
public:
|
||||
// This is the offset to where JSEntry pushes the current value of
|
||||
// Isolate::c_entry_fp onto the stack.
|
||||
static constexpr int kCallerFPOffset = -3 * kSystemPointerSize;
|
||||
static constexpr int kNextExitFrameFPOffset = -3 * kSystemPointerSize;
|
||||
};
|
||||
|
||||
class WasmLiftoffSetupFrameConstants : public TypedFrameConstants {
|
||||
|
@ -16,9 +16,9 @@ namespace internal {
|
||||
class EntryFrameConstants : public AllStatic {
|
||||
public:
|
||||
// Need to take constant pool into account.
|
||||
static constexpr int kCallerFPOffset = V8_EMBEDDED_CONSTANT_POOL_BOOL
|
||||
? -4 * kSystemPointerSize
|
||||
: -3 * kSystemPointerSize;
|
||||
static constexpr int kNextExitFrameFPOffset = V8_EMBEDDED_CONSTANT_POOL_BOOL
|
||||
? -4 * kSystemPointerSize
|
||||
: -3 * kSystemPointerSize;
|
||||
};
|
||||
|
||||
class WasmLiftoffSetupFrameConstants : public TypedFrameConstants {
|
||||
|
@ -18,7 +18,7 @@ class EntryFrameConstants : public AllStatic {
|
||||
public:
|
||||
// This is the offset to where JSEntry pushes the current value of
|
||||
// Isolate::c_entry_fp onto the stack.
|
||||
static constexpr int kCallerFPOffset = -3 * kSystemPointerSize;
|
||||
static constexpr int kNextExitFrameFPOffset = -3 * kSystemPointerSize;
|
||||
};
|
||||
|
||||
class WasmLiftoffSetupFrameConstants : public TypedFrameConstants {
|
||||
|
@ -15,7 +15,7 @@ namespace internal {
|
||||
|
||||
class EntryFrameConstants : public AllStatic {
|
||||
public:
|
||||
static constexpr int kCallerFPOffset = -3 * kSystemPointerSize;
|
||||
static constexpr int kNextExitFrameFPOffset = -3 * kSystemPointerSize;
|
||||
|
||||
// Stack offsets for arguments passed to JSEntry.
|
||||
static constexpr int kArgvOffset = 20 * kSystemPointerSize;
|
||||
|
@ -26,9 +26,9 @@ class EntryFrameConstants : public AllStatic {
|
||||
// On x64, there are 7 pushq() and 3 Push() calls between setting up rbp and
|
||||
// pushing the c_entry_fp, plus we manually allocate kXMMRegistersBlockSize
|
||||
// bytes on the stack.
|
||||
static constexpr int kCallerFPOffset = -3 * kSystemPointerSize +
|
||||
-7 * kSystemPointerSize -
|
||||
kXMMRegistersBlockSize;
|
||||
static constexpr int kNextExitFrameFPOffset = -3 * kSystemPointerSize +
|
||||
-7 * kSystemPointerSize -
|
||||
kXMMRegistersBlockSize;
|
||||
|
||||
// Stack offsets for arguments passed to JSEntry.
|
||||
static constexpr int kArgcOffset = 6 * kSystemPointerSize;
|
||||
@ -38,7 +38,7 @@ class EntryFrameConstants : public AllStatic {
|
||||
// Isolate::c_entry_fp onto the stack.
|
||||
// On x64, there are 5 pushq() and 3 Push() calls between setting up rbp and
|
||||
// pushing the c_entry_fp.
|
||||
static constexpr int kCallerFPOffset =
|
||||
static constexpr int kNextExitFrameFPOffset =
|
||||
-3 * kSystemPointerSize + -5 * kSystemPointerSize;
|
||||
#endif
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user