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
This commit is contained in:
kasperl@chromium.org 2008-10-10 09:09:38 +00:00
parent 8bfbe2c0aa
commit be8762564e
12 changed files with 75 additions and 113 deletions

View File

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

View File

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

View File

@ -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<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
Code* code = Builtins::builtin(Builtins::Illegal);
*resolved = false;

View File

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

View File

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

View File

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

View File

@ -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<ConstructFrame*>(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.

View File

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

View File

@ -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<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
// Activation support.
void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type);
};

View File

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

View File

@ -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<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
// Activation support.
void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type);
};

View File

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