From: kasperl@chromium.org Date: Fri, 10 Oct 2008 09:09:38 +0000 (+0000) Subject: Introduce a special kind of frames for construct frames, e.g. X-Git-Tag: upstream/4.7.83~25210 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=be8762564e3455b793044ffbd64f3cfd2f2acf1f;p=platform%2Fupstream%2Fv8.git Introduce a special kind of frames for construct frames, e.g. the trampoline frames introduced for invoking functions through the new keyword. Review URL: http://codereview.chromium.org/7223 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@485 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/builtins-arm.cc b/src/builtins-arm.cc index c030cde0c..68b5f1d86 100644 --- a/src/builtins-arm.cc +++ b/src/builtins-arm.cc @@ -58,8 +58,8 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // -- sp[...]: constructor arguments // ----------------------------------- - // Enter an internal frame. - __ EnterInternalFrame(); + // Enter a construct frame. + __ EnterConstructFrame(); // Preserve the two incoming parameters __ mov(r0, Operand(r0, LSL, kSmiTagSize)); @@ -116,10 +116,8 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // Call the function. // r0: number of arguments // r1: constructor function - Label return_site; ParameterCount actual(r0); __ InvokeFunction(r1, actual, CALL_FUNCTION); - __ bind(&return_site); // Pop the function from the stack. // sp[0]: constructor function @@ -168,15 +166,10 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // sp[1]: constructor function // sp[2]: number of arguments (smi-tagged) __ ldr(r1, MemOperand(sp, 2 * kPointerSize)); - __ LeaveInternalFrame(); + __ LeaveConstructFrame(); __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1)); __ add(sp, sp, Operand(kPointerSize)); __ mov(pc, Operand(lr)); - - // Compute the offset from the beginning of the JSConstructCall - // builtin code object to the return address after the call. - ASSERT(return_site.is_bound()); - construct_call_pc_offset_ = return_site.pos() + Code::kHeaderSize; } @@ -539,7 +532,7 @@ static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { } -static void ExitArgumentsAdaptorFrame(MacroAssembler* masm) { +static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : result being passed through // ----------------------------------- @@ -641,20 +634,13 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { } // Call the entry point. - Label return_site; __ bind(&invoke); - __ Call(r3); - __ bind(&return_site); - ExitArgumentsAdaptorFrame(masm); + // Exit frame and return. + LeaveArgumentsAdaptorFrame(masm); __ mov(pc, lr); - // Compute the offset from the beginning of the ArgumentsAdaptorTrampoline - // builtin code object to the return address after the call. - ASSERT(return_site.is_bound()); - arguments_adaptor_call_pc_offset_ = return_site.pos() + Code::kHeaderSize; - // ------------------------------------------- // Dont adapt arguments. diff --git a/src/builtins-ia32.cc b/src/builtins-ia32.cc index e049fbefb..32533064a 100644 --- a/src/builtins-ia32.cc +++ b/src/builtins-ia32.cc @@ -56,8 +56,8 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // -- edi: constructor function // ----------------------------------- - // Enter an internal frame. - __ EnterInternalFrame(); + // Enter a construct frame. + __ EnterConstructFrame(); // Store a smi-tagged arguments count on the stack. __ shl(eax, kSmiTagSize); @@ -265,10 +265,8 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { __ j(greater_equal, &loop); // Call the function. - Label return_site; ParameterCount actual(eax); __ InvokeFunction(edi, actual, CALL_FUNCTION); - __ bind(&return_site); // Restore context from the frame. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); @@ -294,10 +292,10 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { __ bind(&use_receiver); __ mov(eax, Operand(esp, 0)); - // Restore the arguments count and exit the internal frame. + // Restore the arguments count and leave the construct frame. __ bind(&exit); __ mov(ebx, Operand(esp, kPointerSize)); // get arguments count - __ LeaveInternalFrame(); + __ LeaveConstructFrame(); // Remove caller arguments from the stack and return. ASSERT(kSmiTagSize == 1 && kSmiTag == 0); @@ -305,11 +303,6 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver __ push(ecx); __ ret(0); - - // Compute the offset from the beginning of the JSConstructCall - // builtin code object to the return address after the call. - ASSERT(return_site.is_bound()); - construct_call_pc_offset_ = return_site.pos() + Code::kHeaderSize; } @@ -662,7 +655,7 @@ static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { } -static void ExitArgumentsAdaptorFrame(MacroAssembler* masm) { +static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { // Retrieve the number of arguments from the stack. __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset)); @@ -742,20 +735,13 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { } // Call the entry point. - Label return_site; __ bind(&invoke); __ call(Operand(edx)); - __ bind(&return_site); - ExitArgumentsAdaptorFrame(masm); + // Leave frame and return. + LeaveArgumentsAdaptorFrame(masm); __ ret(0); - // Compute the offset from the beginning of the ArgumentsAdaptorTrampoline - // builtin code object to the return address after the call. - ASSERT(return_site.is_bound()); - arguments_adaptor_call_pc_offset_ = return_site.pos() + Code::kHeaderSize; - - // ------------------------------------------- // Dont adapt arguments. // ------------------------------------------- diff --git a/src/builtins.cc b/src/builtins.cc index 616941187..c8c428bf3 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -94,33 +94,13 @@ static inline bool CalledAsConstructor() { ASSERT(it.frame()->is_exit()); it.Advance(); StackFrame* frame = it.frame(); - return frame->is_internal() && - InternalFrame::cast(frame)->is_construct_trampoline(); + return frame->is_construct(); } // ---------------------------------------------------------------------------- -int Builtins::construct_call_pc_offset_ = 0; -int Builtins::arguments_adaptor_call_pc_offset_ = 0; - - -// Check if the builtin was called in a 'new' call. -bool Builtins::IsConstructCall(Address pc) { - ASSERT(construct_call_pc_offset_ > 0); - int offset = pc - builtin(JSConstructCall)->address(); - return offset == construct_call_pc_offset_; -} - - -bool Builtins::IsArgumentsAdaptorCall(Address pc) { - ASSERT(arguments_adaptor_call_pc_offset_ > 0); - int offset = pc - builtin(ArgumentsAdaptorTrampoline)->address(); - return offset == arguments_adaptor_call_pc_offset_; -} - - Handle Builtins::GetCode(JavaScript id, bool* resolved) { Code* code = Builtins::builtin(Builtins::Illegal); *resolved = false; diff --git a/src/builtins.h b/src/builtins.h index 14d4ee66e..80a897d65 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -167,9 +167,6 @@ class Builtins : public AllStatic { id_count }; - static bool IsConstructCall(Address pc); - static bool IsArgumentsAdaptorCall(Address pc); - static Code* builtin(Name name) { // Code::cast cannot be used here since we access builtins // during the marking phase of mark sweep. See IC::Clear. @@ -206,12 +203,6 @@ class Builtins : public AllStatic { static const char* javascript_names_[id_count]; static int javascript_argc_[id_count]; - // The offset from the beginning of the JSConstructCall builtin code - // object to the return address after the call. Used for determining - // if a call is a constructor invocation. - static int construct_call_pc_offset_; - static int arguments_adaptor_call_pc_offset_; - static void Generate_Adaptor(MacroAssembler* masm, CFunctionId id); static void Generate_JSConstructCall(MacroAssembler* masm); static void Generate_JSEntryTrampoline(MacroAssembler* masm); diff --git a/src/frames-inl.h b/src/frames-inl.h index fac14184d..2b50d55bd 100644 --- a/src/frames-inl.h +++ b/src/frames-inl.h @@ -145,8 +145,10 @@ inline bool StandardFrame::IsArgumentsAdaptorFrame(Address fp) { } -inline bool StandardFrame::IsConstructTrampolineFrame(Address pc) { - return Builtins::builtin(Builtins::JSConstructCall)->contains(pc); +inline bool StandardFrame::IsConstructFrame(Address fp) { + Object* marker = + Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset); + return marker == Smi::FromInt(CONSTRUCT); } @@ -167,15 +169,6 @@ inline bool JavaScriptFrame::has_adapted_arguments() const { } -inline bool InternalFrame::is_construct_trampoline() const { - // TODO(1233795): This doesn't work when the stack frames have been - // cooked. We need to find another way of identifying construct - // trampoline frames possibly by manipulating the context field like - // we do for argument adaptor frames. - return IsConstructTrampolineFrame(pc()); -} - - inline JavaScriptFrame* JavaScriptFrameIterator::frame() const { // TODO(1233797): The frame hierarchy needs to change. It's // problematic that we can't use the safe-cast operator to cast to diff --git a/src/frames.cc b/src/frames.cc index f5a72ec60..09c6a02e7 100644 --- a/src/frames.cc +++ b/src/frames.cc @@ -311,10 +311,12 @@ int JavaScriptFrame::ComputeParametersCount() const { bool JavaScriptFrame::IsConstructor() const { - Address pc = has_adapted_arguments() - ? Memory::Address_at(ComputePCAddress(caller_fp())) - : caller_pc(); - return IsConstructTrampolineFrame(pc); + Address fp = caller_fp(); + if (has_adapted_arguments()) { + // Skip the arguments adaptor frame and look at the real caller. + fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); + } + return IsConstructFrame(fp); } diff --git a/src/frames.h b/src/frames.h index 44e9a9161..662d2373f 100644 --- a/src/frames.h +++ b/src/frames.h @@ -98,6 +98,7 @@ class StackHandler BASE_EMBEDDED { V(EXIT_DEBUG, ExitDebugFrame) \ V(JAVA_SCRIPT, JavaScriptFrame) \ V(INTERNAL, InternalFrame) \ + V(CONSTRUCT, ConstructFrame) \ V(ARGUMENTS_ADAPTOR, ArgumentsAdaptorFrame) @@ -124,6 +125,7 @@ class StackFrame BASE_EMBEDDED { bool is_java_script() const { return type() == JAVA_SCRIPT; } bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; } bool is_internal() const { return type() == INTERNAL; } + bool is_construct() const { return type() == CONSTRUCT; } virtual bool is_standard() const { return false; } // Accessors. @@ -352,9 +354,9 @@ class StandardFrame: public StackFrame { // an arguments adaptor frame. static inline bool IsArgumentsAdaptorFrame(Address fp); - // Determines if the standard frame for the given program counter is - // a construct trampoline. - static inline bool IsConstructTrampolineFrame(Address pc); + // Determines if the standard frame for the given frame pointer is a + // construct frame. + static inline bool IsConstructFrame(Address fp); private: friend class StackFrame; @@ -380,9 +382,7 @@ class JavaScriptFrame: public StandardFrame { // computed parameters count. int GetProvidedParametersCount() const; - // Check if this frame is a constructor frame invoked through - // 'new'. The operation may involve digging through a few stack - // frames to account for arguments adaptors. + // Check if this frame is a constructor frame invoked through 'new'. bool IsConstructor() const; // Check if this frame has "adapted" arguments in the sense that the @@ -459,11 +459,6 @@ class InternalFrame: public StandardFrame { public: virtual Type type() const { return INTERNAL; } - // Returns if this frame is a special trampoline frame introduced by - // the construct trampoline. NOTE: We should consider introducing a - // special stack frame type for this. - inline bool is_construct_trampoline() const; - // Garbage colletion support. virtual void Iterate(ObjectVisitor* v) const; @@ -486,6 +481,26 @@ class InternalFrame: public StandardFrame { }; +// Construct frames are special trampoline frames introduced to handle +// function invocations through 'new'. +class ConstructFrame: public InternalFrame { + public: + virtual Type type() const { return CONSTRUCT; } + + static ConstructFrame* cast(StackFrame* frame) { + ASSERT(frame->is_construct()); + return static_cast(frame); + } + + protected: + explicit ConstructFrame(StackFrameIterator* iterator) + : InternalFrame(iterator) { } + + private: + friend class StackFrameIterator; +}; + + class StackFrameIterator BASE_EMBEDDED { public: // An iterator that iterates over the current thread's stack. diff --git a/src/macro-assembler-arm.cc b/src/macro-assembler-arm.cc index a6c336fe6..c7139f4b2 100644 --- a/src/macro-assembler-arm.cc +++ b/src/macro-assembler-arm.cc @@ -251,10 +251,8 @@ void MacroAssembler::RecordWrite(Register object, Register offset, } -void MacroAssembler::EnterInternalFrame() { +void MacroAssembler::EnterFrame(StackFrame::Type type) { // r0-r3: preserved - int type = StackFrame::INTERNAL; - stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); mov(ip, Operand(Smi::FromInt(type))); push(ip); @@ -264,13 +262,13 @@ void MacroAssembler::EnterInternalFrame() { } -void MacroAssembler::LeaveInternalFrame() { +void MacroAssembler::LeaveFrame(StackFrame::Type type) { // r0: preserved // r1: preserved // r2: preserved - // Drop the execution stack down to the frame pointer and restore the caller - // frame pointer and return address. + // Drop the execution stack down to the frame pointer and restore + // the caller frame pointer and return address. mov(sp, fp); ldm(ia_w, sp, fp.bit() | lr.bit()); } diff --git a/src/macro-assembler-arm.h b/src/macro-assembler-arm.h index 7930e4cfc..d1a4a4452 100644 --- a/src/macro-assembler-arm.h +++ b/src/macro-assembler-arm.h @@ -99,8 +99,11 @@ class MacroAssembler: public Assembler { // --------------------------------------------------------------------------- // Activation frames - void EnterInternalFrame(); - void LeaveInternalFrame(); + void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); } + void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); } + + void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); } + void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); } // Enter specific kind of exit frame; either EXIT or // EXIT_DEBUG. Expects the number of arguments in register r0 and @@ -260,6 +263,10 @@ class MacroAssembler: public Assembler { // Get the code for the given builtin. Returns if able to resolve // the function in the 'resolved' flag. Handle ResolveBuiltin(Builtins::JavaScript id, bool* resolved); + + // Activation support. + void EnterFrame(StackFrame::Type type); + void LeaveFrame(StackFrame::Type type); }; diff --git a/src/macro-assembler-ia32.cc b/src/macro-assembler-ia32.cc index 5c048f048..e72eeb232 100644 --- a/src/macro-assembler-ia32.cc +++ b/src/macro-assembler-ia32.cc @@ -312,9 +312,7 @@ void MacroAssembler::FCmp() { } -void MacroAssembler::EnterInternalFrame() { - int type = StackFrame::INTERNAL; - +void MacroAssembler::EnterFrame(StackFrame::Type type) { push(ebp); mov(ebp, Operand(esp)); push(esi); @@ -323,9 +321,8 @@ void MacroAssembler::EnterInternalFrame() { } -void MacroAssembler::LeaveInternalFrame() { +void MacroAssembler::LeaveFrame(StackFrame::Type type) { if (FLAG_debug_code) { - StackFrame::Type type = StackFrame::INTERNAL; cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset), Immediate(Smi::FromInt(type))); Check(equal, "stack frame types must match"); diff --git a/src/macro-assembler-ia32.h b/src/macro-assembler-ia32.h index c62c61db9..e126c3cf6 100644 --- a/src/macro-assembler-ia32.h +++ b/src/macro-assembler-ia32.h @@ -86,8 +86,11 @@ class MacroAssembler: public Assembler { // --------------------------------------------------------------------------- // Activation frames - void EnterInternalFrame(); - void LeaveInternalFrame(); + void EnterInternalFrame() { EnterFrame(StackFrame::INTERNAL); } + void LeaveInternalFrame() { LeaveFrame(StackFrame::INTERNAL); } + + void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); } + void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); } // Enter specific kind of exit frame; either EXIT or // EXIT_DEBUG. Expects the number of arguments in register eax and @@ -274,6 +277,10 @@ class MacroAssembler: public Assembler { // Get the code for the given builtin. Returns if able to resolve // the function in the 'resolved' flag. Handle ResolveBuiltin(Builtins::JavaScript id, bool* resolved); + + // Activation support. + void EnterFrame(StackFrame::Type type); + void LeaveFrame(StackFrame::Type type); }; diff --git a/src/runtime.cc b/src/runtime.cc index a10e3300b..77ec25cd1 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -2917,7 +2917,7 @@ static Object* Runtime_NewObject(Arguments args) { if (Debug::StepInActive()) { StackFrameIterator it; it.Advance(); - ASSERT(InternalFrame::cast(it.frame())->is_construct_trampoline()); + ASSERT(it.frame()->is_construct()); it.Advance(); if (it.frame()->fp() == Debug::step_in_fp()) { HandleScope scope;