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:
Jakob Linke 2022-12-15 12:16:00 +01:00 committed by V8 LUCI CQ
parent 20d32a7042
commit c505f9b37c
17 changed files with 58 additions and 40 deletions

View File

@ -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});

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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));

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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
};