// -- sp[...]: constructor arguments
// -----------------------------------
- // Enter an internal frame.
- __ EnterInternalFrame();
+ // Enter a construct frame.
+ __ EnterConstructFrame();
// Preserve the two incoming parameters
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
// 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
// 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;
}
}
-static void ExitArgumentsAdaptorFrame(MacroAssembler* masm) {
+static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : result being passed through
// -----------------------------------
}
// 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.
// -- 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);
__ 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));
__ 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);
__ 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;
}
}
-static void ExitArgumentsAdaptorFrame(MacroAssembler* masm) {
+static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
// Retrieve the number of arguments from the stack.
__ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
}
// 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.
// -------------------------------------------
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;
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.
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);
}
-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);
}
}
-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
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);
}
V(EXIT_DEBUG, ExitDebugFrame) \
V(JAVA_SCRIPT, JavaScriptFrame) \
V(INTERNAL, InternalFrame) \
+ V(CONSTRUCT, ConstructFrame) \
V(ARGUMENTS_ADAPTOR, ArgumentsAdaptorFrame)
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.
// 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;
// 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
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;
};
+// 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.
}
-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);
}
-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());
}
// ---------------------------------------------------------------------------
// 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
// 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);
};
}
-void MacroAssembler::EnterInternalFrame() {
- int type = StackFrame::INTERNAL;
-
+void MacroAssembler::EnterFrame(StackFrame::Type type) {
push(ebp);
mov(ebp, Operand(esp));
push(esi);
}
-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");
// ---------------------------------------------------------------------------
// 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
// 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);
};
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;