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:
parent
8bfbe2c0aa
commit
be8762564e
@ -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.
|
||||
|
@ -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.
|
||||
// -------------------------------------------
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
37
src/frames.h
37
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<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.
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user