Introduce a special kind of frames for construct frames, e.g.
authorkasperl@chromium.org <kasperl@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 10 Oct 2008 09:09:38 +0000 (09:09 +0000)
committerkasperl@chromium.org <kasperl@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 10 Oct 2008 09:09:38 +0000 (09:09 +0000)
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

12 files changed:
src/builtins-arm.cc
src/builtins-ia32.cc
src/builtins.cc
src/builtins.h
src/frames-inl.h
src/frames.cc
src/frames.h
src/macro-assembler-arm.cc
src/macro-assembler-arm.h
src/macro-assembler-ia32.cc
src/macro-assembler-ia32.h
src/runtime.cc

index c030cde0c3d8e1d6867fb0be0acb6800d4fa5bb8..68b5f1d86304356a70ac080b1fc5b6ff0fb41402 100644 (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.
index e049fbefb02ae62f4cc6dc7b434c7a0f2613dcc2..32533064a2b13dc920ab5919d0cd0e47677c5dad 100644 (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.
   // -------------------------------------------
index 616941187542c0c1b377a6e5d2f94ab1a21741b3..c8c428bf303cd534f2dde3f27edd944940395f53 100644 (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;
index 14d4ee66e6f61bb6a1a71d006b91dd506cfc52ee..80a897d6540bc31c590d6ed0c90ea2cd52e8753f 100644 (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);
index fac14184d679d334c43e95f6a3e864895b907c2e..2b50d55bd6e89361ad8e0d0d87b90c797fa2fd1a 100644 (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
index f5a72ec60aa6f7925c99498d5361bc1ff0f63d04..09c6a02e75a8b5a26ee33845050dab01ee9e6f34 100644 (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);
 }
 
 
index 44e9a9161c09d39119030f145ffe17dc8439aa1a..662d2373f51e87dadb9943277727b8bd0fb40a36 100644 (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.
index a6c336fe646da282846e2e36ce05c3108762f465..c7139f4b2a5d758a44c709e5e91234011fbc7256 100644 (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());
 }
index 7930e4cfc8e7e097dd48efc733b1db261cc79dce..d1a4a445269d0c05f3910fb61fe8a3c047698a9d 100644 (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);
 };
 
 
index 5c048f048c119deb189230c71e9bffa808753f41..e72eeb2329bd4e78dc23e19b2e64eae49cf58461 100644 (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");
index c62c61db9f4e5a0562a7f3d3a2315e64c83f51b4..e126c3cf6566d38699aaf496ff8282191eeaab49 100644 (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);
 };
 
 
index a10e3300ba191835010df2d6ecea974ea5e5dd74..77ec25cd1f4d8086bf23baa10a883adc861c6958 100644 (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;