Commit 7a51f8c8 authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

X87: [runtime] Unify and simplify how frames are marked.

  port 9dcd0857 (r34571)

  original commit message:
  Before this CL, various code stubs used different techniques
  for marking their frames to enable stack-crawling and other
  access to data in the frame. All of them were based on a abuse
  of the "standard" frame representation, e.g. storing the a
  context pointer immediately below the frame's fp, and a
  function pointer after that. Although functional, this approach
  tends to make stubs and builtins do an awkward, unnecessary
  dance to appear like standard frames, even if they have
  nothing to do with JavaScript execution.

  This CL attempts to improve this by:

  * Ensuring that there are only two fundamentally different
    types of frames, a "standard" frame and a "typed" frame.
    Standard frames, as before, contain both a context and
    function pointer. Typed frames contain only a minimum
    of a smi marker in the position immediately below the fp
    where the context is in standard frames.
  * Only interpreted, full codegen, and optimized Crankshaft and
    TurboFan JavaScript frames use the "standard" format. All
    other frames use the type frame format with an explicit
    marker.
  * Typed frames can contain one or more values below the
    type marker. There is new magic macro machinery in
    frames.h that simplifies defining the offsets of these fields
    in typed frames.
  * A new flag in the CallDescriptor enables specifying whether
    a frame is a standard frame or a typed frame. Secondary
    register location spilling is now only enabled for standard
    frames.
  * A zillion places in the code have been updated to deal with
    the fact that most code stubs and internal frames use the
    typed frame format. This includes changes in the
    deoptimizer, debugger, and liveedit.
  * StandardFrameConstants::kMarkerOffset is deprecated,
    (CommonFrameConstants::kContextOrFrameTypeOffset
    and StandardFrameConstants::kFrameOffset are now used
    in its stead).

BUG=

Review URL: https://codereview.chromium.org/1774353002

Cr-Commit-Position: refs/heads/master@{#34648}
parent 43adcd3c
......@@ -2006,16 +2006,15 @@ void CodeGenerator::AssembleDeoptimizerCall(
void CodeGenerator::AssemblePrologue() {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
if (descriptor->IsCFunctionCall()) {
// Assemble a prologue similar the to cdecl calling convention.
__ push(ebp);
__ mov(ebp, esp);
} else if (descriptor->IsJSFunctionCall()) {
// TODO(turbofan): this prologue is redundant with OSR, but needed for
// code aging.
__ Prologue(this->info()->GeneratePreagedPrologue());
} else if (frame()->needs_frame()) {
__ StubPrologue();
if (frame()->needs_frame()) {
if (descriptor->IsCFunctionCall()) {
__ push(ebp);
__ mov(ebp, esp);
} else if (descriptor->IsJSFunctionCall()) {
__ Prologue(this->info()->GeneratePreagedPrologue());
} else {
__ StubPrologue(info()->GetOutputStackFrameType());
}
} else {
frame()->SetElidedFrameSizeInSlots(kPCOnStackSize / kPointerSize);
}
......
......@@ -98,7 +98,7 @@ bool LCodeGen::GeneratePrologue() {
DCHECK(!frame_is_built_);
frame_is_built_ = true;
if (info()->IsStub()) {
__ StubPrologue();
__ StubPrologue(StackFrame::STUB);
} else {
__ Prologue(info()->GeneratePreagedPrologue());
}
......@@ -273,32 +273,24 @@ bool LCodeGen::GenerateJumpTable() {
}
if (needs_frame.is_linked()) {
__ bind(&needs_frame);
/* stack layout
4: entry address
3: return address <-- esp
2: garbage
3: entry address
2: return address <-- esp
1: garbage
0: garbage
*/
__ sub(esp, Immediate(kPointerSize)); // Reserve space for stub marker.
__ push(MemOperand(esp, kPointerSize)); // Copy return address.
__ push(MemOperand(esp, 3 * kPointerSize)); // Copy entry address.
__ push(MemOperand(esp, 0)); // Copy return address.
__ push(MemOperand(esp, 2 * kPointerSize)); // Copy entry address.
/* stack layout
4: entry address
3: return address
2: garbage
1: return address
0: entry address <-- esp
*/
__ mov(MemOperand(esp, 4 * kPointerSize), ebp); // Save ebp.
// Copy context.
__ mov(ebp, MemOperand(ebp, StandardFrameConstants::kContextOffset));
__ mov(MemOperand(esp, 3 * kPointerSize), ebp);
__ mov(MemOperand(esp, 3 * kPointerSize), ebp); // Save ebp.
// Fill ebp with the right stack frame address.
__ lea(ebp, MemOperand(esp, 4 * kPointerSize));
__ lea(ebp, MemOperand(esp, 3 * kPointerSize));
// This variant of deopt can only be used with stubs. Since we don't
// have a function pointer to install in the stack frame that we're
......@@ -308,8 +300,7 @@ bool LCodeGen::GenerateJumpTable() {
Immediate(Smi::FromInt(StackFrame::STUB)));
/* stack layout
4: old ebp
3: context pointer
3: old ebp
2: stub marker
1: return address
0: entry address <-- esp
......@@ -346,9 +337,8 @@ bool LCodeGen::GenerateDeferredCode() {
frame_is_built_ = true;
// Build the frame in such a way that esi isn't trashed.
__ push(ebp); // Caller's frame pointer.
__ push(Operand(ebp, StandardFrameConstants::kContextOffset));
__ push(Immediate(Smi::FromInt(StackFrame::STUB)));
__ lea(ebp, Operand(esp, 2 * kPointerSize));
__ lea(ebp, Operand(esp, TypedFrameConstants::kFixedFrameSizeFromFp));
Comment(";;; Deferred code");
}
code->Generate();
......@@ -3088,7 +3078,8 @@ void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
// Check for arguments adapter frame.
Label done, adapted;
__ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
__ mov(result,
Operand(result, CommonFrameConstants::kContextOrFrameTypeOffset));
__ cmp(Operand(result),
Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(equal, &adapted, Label::kNear);
......
......@@ -110,9 +110,12 @@ void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
// We do not know our frame height, but set esp based on ebp.
__ lea(esp, Operand(ebp, -1 * kPointerSize));
__ lea(esp, Operand(ebp, FrameDropperFrameConstants::kFunctionOffset));
__ pop(edi); // Function.
__ add(esp, Immediate(-FrameDropperFrameConstants::kCodeOffset)); // INTERNAL
// frame
// marker
// and code
__ pop(ebp);
ParameterCount dummy(0);
......
......@@ -23,6 +23,9 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
{
FrameScope scope(masm, StackFrame::INTERNAL);
// Save context register
__ push(esi);
if (accessor_index >= 0) {
DCHECK(!holder.is(scratch));
DCHECK(!receiver.is(scratch));
......@@ -46,7 +49,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
}
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ pop(esi);
}
__ ret(0);
}
......@@ -252,6 +255,8 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
{
FrameScope scope(masm, StackFrame::INTERNAL);
// Save context register
__ push(esi);
// Save value register, so we can restore it later.
__ push(value());
......@@ -280,9 +285,8 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
// We have to return the passed value, not the return value of the setter.
__ pop(eax);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ pop(esi);
}
__ ret(0);
}
......
......@@ -123,6 +123,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool check_derived_construct) {
// ----------- S t a t e -------------
// -- eax: number of arguments
// -- esi: context
// -- edi: constructor function
// -- ebx: allocation site or undefined
// -- edx: new target
......@@ -134,6 +135,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// Preserve the incoming parameters on the stack.
__ AssertUndefinedOrAllocationSite(ebx);
__ push(esi);
__ push(ebx);
__ SmiTag(eax);
__ push(eax);
......@@ -201,7 +203,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
}
// Restore context from the frame.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset));
if (create_implicit_receiver) {
// If the result is an object (in the ECMA sense), we should get rid
......@@ -325,9 +327,6 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
bool is_construct) {
ProfileEntryHookStub::MaybeCallEntryHook(masm);
// Clear the context before we push it when entering the internal frame.
__ Move(esi, Immediate(0));
{
FrameScope scope(masm, StackFrame::INTERNAL);
......@@ -1899,7 +1898,7 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
// Drop possible interpreter handler/stub frame.
{
Label no_interpreter_frame;
__ cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
__ cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
Immediate(Smi::FromInt(StackFrame::STUB)));
__ j(not_equal, &no_interpreter_frame, Label::kNear);
__ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
......@@ -1910,7 +1909,7 @@ void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
Register caller_args_count_reg = scratch1;
Label no_arguments_adaptor, formal_parameter_count_loaded;
__ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ cmp(Operand(scratch2, StandardFrameConstants::kContextOffset),
__ cmp(Operand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset),
Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(not_equal, &no_arguments_adaptor, Label::kNear);
......@@ -2457,7 +2456,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// Call the entry point.
__ bind(&invoke);
// Restore function pointer.
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ mov(edi, Operand(ebp, ArgumentsAdaptorFrameConstants::kFunctionOffset));
// eax : expected number of arguments
// edx : new target (passed through to callee)
// edi : function (passed through to callee)
......
......@@ -1720,8 +1720,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
// Push marker in two places.
int marker = type();
__ push(Immediate(Smi::FromInt(marker))); // context slot
__ push(Immediate(Smi::FromInt(marker))); // function slot
__ push(Immediate(Smi::FromInt(marker))); // marker
ExternalReference context_address(Isolate::kContextAddress, isolate());
__ push(Operand::StaticVariable(context_address)); // context
// Save callee-saved registers (C calling conventions).
__ push(edi);
__ push(esi);
......@@ -3385,7 +3386,7 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
CEntryStub ces(isolate(), 1, kSaveFPRegs);
__ call(ces.GetCode(), RelocInfo::CODE_TARGET);
int parameter_count_offset =
StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
StubFailureTrampolineFrameConstants::kArgumentsLengthOffset;
__ mov(ebx, MemOperand(ebp, parameter_count_offset));
masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
__ pop(ecx);
......@@ -4531,7 +4532,7 @@ void FastNewRestParameterStub::Generate(MacroAssembler* masm) {
__ bind(&loop);
__ mov(edx, Operand(edx, StandardFrameConstants::kCallerFPOffset));
__ bind(&loop_entry);
__ cmp(edi, Operand(edx, StandardFrameConstants::kMarkerOffset));
__ cmp(edi, Operand(edx, StandardFrameConstants::kFunctionOffset));
__ j(not_equal, &loop);
}
......@@ -4539,7 +4540,7 @@ void FastNewRestParameterStub::Generate(MacroAssembler* masm) {
// arguments adaptor frame below the function frame).
Label no_rest_parameters;
__ mov(ebx, Operand(edx, StandardFrameConstants::kCallerFPOffset));
__ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
__ cmp(Operand(ebx, CommonFrameConstants::kContextOrFrameTypeOffset),
Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(not_equal, &no_rest_parameters, Label::kNear);
......@@ -4681,7 +4682,7 @@ void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) {
// Check if the calling frame is an arguments adaptor frame.
Label adaptor_frame, try_allocate, runtime;
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ mov(eax, Operand(ebx, StandardFrameConstants::kContextOffset));
__ mov(eax, Operand(ebx, CommonFrameConstants::kContextOrFrameTypeOffset));
__ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(equal, &adaptor_frame, Label::kNear);
......@@ -4917,14 +4918,14 @@ void FastNewStrictArgumentsStub::Generate(MacroAssembler* masm) {
__ bind(&loop);
__ mov(edx, Operand(edx, StandardFrameConstants::kCallerFPOffset));
__ bind(&loop_entry);
__ cmp(edi, Operand(edx, StandardFrameConstants::kMarkerOffset));
__ cmp(edi, Operand(edx, StandardFrameConstants::kFunctionOffset));
__ j(not_equal, &loop);
}
// Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done;
__ mov(ebx, Operand(edx, StandardFrameConstants::kCallerFPOffset));
__ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
__ cmp(Operand(ebx, CommonFrameConstants::kContextOrFrameTypeOffset),
Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(equal, &arguments_adaptor, Label::kNear);
{
......
......@@ -246,7 +246,12 @@ void Deoptimizer::TableEntryGenerator::Generate() {
__ push(edi);
// Allocate a new deoptimizer object.
__ PrepareCallCFunction(6, eax);
__ mov(eax, Immediate(0));
Label context_check;
__ mov(edi, Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset));
__ JumpIfSmi(edi, &context_check);
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ bind(&context_check);
__ mov(Operand(esp, 0 * kPointerSize), eax); // Function.
__ mov(Operand(esp, 1 * kPointerSize), Immediate(type())); // Bailout type.
__ mov(Operand(esp, 2 * kPointerSize), ebx); // Bailout id.
......
......@@ -42,13 +42,11 @@ class EntryFrameConstants : public AllStatic {
static const int kArgvOffset = +6 * kPointerSize;
};
class ExitFrameConstants : public AllStatic {
class ExitFrameConstants : public TypedFrameConstants {
public:
static const int kFrameSize = 2 * kPointerSize;
static const int kCodeOffset = -2 * kPointerSize;
static const int kSPOffset = -1 * kPointerSize;
static const int kSPOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
static const int kCodeOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
DEFINE_TYPED_FRAME_SIZES(2);
static const int kCallerFPOffset = 0 * kPointerSize;
static const int kCallerPCOffset = +1 * kPointerSize;
......@@ -66,7 +64,7 @@ class JavaScriptFrameConstants : public AllStatic {
// FP-relative.
static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
static const int kLastParameterOffset = +2 * kPointerSize;
static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
static const int kFunctionOffset = StandardFrameConstants::kFunctionOffset;
// Caller SP-relative.
static const int kParam0Offset = -2 * kPointerSize;
......
......@@ -954,12 +954,10 @@ void MacroAssembler::AssertNotSmi(Register object) {
}
}
void MacroAssembler::StubPrologue() {
void MacroAssembler::StubPrologue(StackFrame::Type type) {
push(ebp); // Caller's frame pointer.
mov(ebp, esp);
push(esi); // Callee's context.
push(Immediate(Smi::FromInt(StackFrame::STUB)));
push(Immediate(Smi::FromInt(type)));
}
......@@ -997,9 +995,10 @@ void MacroAssembler::EnterFrame(StackFrame::Type type,
void MacroAssembler::EnterFrame(StackFrame::Type type) {
push(ebp);
mov(ebp, esp);
push(esi);
push(Immediate(Smi::FromInt(type)));
push(Immediate(CodeObject()));
if (type == StackFrame::INTERNAL) {
push(Immediate(CodeObject()));
}
if (emit_debug_code()) {
cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value()));
Check(not_equal, kCodeObjectNotProperlyPatched);
......@@ -1009,7 +1008,7 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) {
void MacroAssembler::LeaveFrame(StackFrame::Type type) {
if (emit_debug_code()) {
cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
Immediate(Smi::FromInt(type)));
Check(equal, kStackFrameTypesMustMatch);
}
......@@ -1019,15 +1018,17 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
void MacroAssembler::EnterExitFramePrologue() {
// Set up the frame structure on the stack.
DCHECK(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
DCHECK(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
DCHECK(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize);
DCHECK_EQ(+2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
DCHECK_EQ(+1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
push(ebp);
mov(ebp, esp);
// Reserve room for entry stack pointer and push the code object.
DCHECK(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
push(Immediate(Smi::FromInt(StackFrame::EXIT)));
DCHECK_EQ(-2 * kPointerSize, ExitFrameConstants::kSPOffset);
push(Immediate(0)); // Saved entry sp, patched before call.
DCHECK_EQ(-3 * kPointerSize, ExitFrameConstants::kCodeOffset);
push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot.
// Save the frame pointer and the context in top.
......@@ -1046,7 +1047,7 @@ void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
// Store FPU state to m108byte.
int space = 108 + argc * kPointerSize;
sub(esp, Immediate(space));
const int offset = -2 * kPointerSize; // entry fp + code object.
const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
fnsave(MemOperand(ebp, offset - 108));
} else {
sub(esp, Immediate(argc * kPointerSize));
......@@ -1086,7 +1087,7 @@ void MacroAssembler::EnterApiExitFrame(int argc) {
void MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) {
// Optionally restore FPU state.
if (save_doubles) {
const int offset = -2 * kPointerSize;
const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
frstor(MemOperand(ebp, offset - 108));
}
......@@ -1166,8 +1167,18 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
DCHECK(!holder_reg.is(scratch2));
DCHECK(!scratch1.is(scratch2));
// Load current lexical context from the stack frame.
mov(scratch1, Operand(ebp, StandardFrameConstants::kContextOffset));
// Load current lexical context from the active StandardFrame, which
// may require crawling past STUB frames.
Label load_context;
Label has_context;
mov(scratch2, ebp);
bind(&load_context);
mov(scratch1,
MemOperand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset));
JumpIfNotSmi(scratch1, &has_context);
mov(scratch2, MemOperand(scratch2, CommonFrameConstants::kCallerFPOffset));
jmp(&load_context);
bind(&has_context);
// When generating debug code, make sure the lexical context is set.
if (emit_debug_code()) {
......
......@@ -236,7 +236,7 @@ class MacroAssembler: public Assembler {
void DebugBreak();
// Generates function and stub prologue code.
void StubPrologue();
void StubPrologue(StackFrame::Type type);
void Prologue(bool code_pre_aging);
// Enter specific kind of exit frame. Expects the number of
......
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