Support pass-through of stub caller arguments
authordanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Feb 2013 08:09:32 +0000 (08:09 +0000)
committerdanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Feb 2013 08:09:32 +0000 (08:09 +0000)
Review URL: https://codereview.chromium.org/12093089

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13593 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

22 files changed:
src/arm/code-stubs-arm.cc
src/arm/deoptimizer-arm.cc
src/arm/frames-arm.h
src/arm/lithium-arm.cc
src/code-stubs-hydrogen.cc
src/code-stubs.cc
src/code-stubs.h
src/deoptimizer.cc
src/frames-inl.h
src/frames.cc
src/frames.h
src/hydrogen-instructions.h
src/ia32/code-stubs-ia32.cc
src/ia32/deoptimizer-ia32.cc
src/ia32/frames-ia32.h
src/ia32/lithium-ia32.cc
src/isolate.cc
src/runtime.cc
src/x64/code-stubs-x64.cc
src/x64/deoptimizer-x64.cc
src/x64/frames-x64.h
src/x64/lithium-x64.cc

index 3aa76e7c82c72d832f9edb798a168c7b01831129..62fcc9a981ccd5946ed7946d006d7e6d5224d4d1 100644 (file)
@@ -7879,7 +7879,12 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
   bool save_fp_regs = CpuFeatures::IsSupported(VFP2);
   CEntryStub ces(1, save_fp_regs ? kSaveFPRegs : kDontSaveFPRegs);
   __ Call(ces.GetCode(), RelocInfo::CODE_TARGET);
+  int parameter_count_offset =
+      StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
+  __ ldr(r1, MemOperand(fp, parameter_count_offset));
   masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
+  __ mov(r1, Operand(r1, LSL, kPointerSizeLog2));
+  __ add(sp, sp, r1);
   __ Ret();
 }
 
index 85b62da9e611ddd23bcf8e3f44d77d549dff99d0..6a7c1466a8c3bdd2e09d3b7df6d0dfaef1f3dd88 100644 (file)
@@ -466,13 +466,19 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
   // v  +-------------------------+          +-------------------------|
   //    |   COMPILED_STUB marker  |          |   STUB_FAILURE marker   |
   //    +-------------------------+          +-------------------------+
-  //    |                         |          |     stub parameter 1    |
+  //    |                         |          |   caller args.length_   |
   //    | ...                     |          +-------------------------+
-  //    |                         |          |            ...          |
+  //    |                         |          |  caller args.arguments_ |
   //    |-------------------------|<-sp      +-------------------------+
-  //                                         |     stub parameter n    |
-  //      parameters in registers            +-------------------------+<-sp
-  //       and spilled to stack              r0 = number of parameters
+  //                                         |  caller args pointer    |
+  //                                         +-------------------------+
+  //                                         |  caller stack param 1   |
+  //      parameters in registers            +-------------------------+
+  //       and spilled to stack              |           ....          |
+  //                                         +-------------------------+
+  //                                         |  caller stack param n   |
+  //                                         +-------------------------+<-sp
+  //                                         r0 = number of parameters
   //                                         r1 = failure handler address
   //                                         fp = saved frame
   //                                         cp = JSFunction context
@@ -483,9 +489,15 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
   CodeStubInterfaceDescriptor* descriptor =
       isolate_->code_stub_interface_descriptor(major_key);
 
+  // The output frame must have room for all pushed register parameters
+  // and the standard stack frame slots.
   int output_frame_size = StandardFrameConstants::kFixedFrameSize +
       kPointerSize * descriptor->register_param_count_;
 
+  // Include space for an argument object to the callee and optionally
+  // the space to pass the argument object to the stub failure handler.
+  output_frame_size += sizeof(Arguments) + kPointerSize;
+
   FrameDescription* output_frame =
       new(output_frame_size) FrameDescription(output_frame_size, 0);
   ASSERT(frame_index == 0);
@@ -497,12 +509,15 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
       reinterpret_cast<intptr_t>(notify_failure->entry()));
 
   Code* trampoline = NULL;
-  StubFailureTrampolineStub().FindCodeInCache(&trampoline, isolate_);
+  int extra = descriptor->extra_expression_stack_count_;
+  StubFailureTrampolineStub(extra).FindCodeInCache(&trampoline, isolate_);
   ASSERT(trampoline != NULL);
   output_frame->SetPc(reinterpret_cast<intptr_t>(
       trampoline->instruction_start()));
   unsigned input_frame_size = input_->GetFrameSize();
 
+  intptr_t frame_ptr = input_->GetRegister(fp.code());
+
   // JSFunction continuation
   intptr_t input_frame_offset = input_frame_size - kPointerSize;
   intptr_t output_frame_offset = output_frame_size - kPointerSize;
@@ -528,6 +543,28 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
       Smi::FromInt(StackFrame::STUB_FAILURE_TRAMPOLINE));
   output_frame->SetFrameSlot(output_frame_offset, value);
 
+  int caller_arg_count = 0;
+  if (descriptor->stack_parameter_count_ != NULL) {
+    caller_arg_count =
+        input_->GetRegister(descriptor->stack_parameter_count_->code());
+  }
+
+  // Build the Arguments object for the caller's parameters and a pointer to it.
+  output_frame_offset -= kPointerSize;
+  value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
+      (caller_arg_count - 1) * kPointerSize;
+  output_frame->SetFrameSlot(output_frame_offset, value);
+
+  output_frame->SetFrameSlot(output_frame_offset, value);
+  output_frame_offset -= kPointerSize;
+  output_frame->SetFrameSlot(output_frame_offset, caller_arg_count);
+
+  value = frame_ptr - (output_frame_size - output_frame_offset) -
+      StandardFrameConstants::kMarkerOffset;
+  output_frame_offset -= kPointerSize;
+  output_frame->SetFrameSlot(output_frame_offset, value);
+
+  // Copy the register parameters to the failure frame.
   for (int i = 0; i < descriptor->register_param_count_; ++i) {
     output_frame_offset -= kPointerSize;
     DoTranslateCommand(iterator, 0, output_frame_offset);
@@ -538,14 +575,17 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
     output_frame->SetDoubleRegister(i, double_value);
   }
 
-  value = input_->GetRegister(fp.code());
-  output_frame->SetRegister(fp.code(), value);
-  output_frame->SetFp(value);
+  output_frame->SetRegister(fp.code(), frame_ptr);
+  output_frame->SetFp(frame_ptr);
 
   ApiFunction function(descriptor->deoptimization_handler_);
   ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
   intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
-  output_frame->SetRegister(r0.code(), descriptor->register_param_count_);
+  int params = descriptor->register_param_count_;
+  if (descriptor->stack_parameter_count_ != NULL) {
+    params++;
+  }
+  output_frame->SetRegister(r0.code(), params);
   output_frame->SetRegister(r1.code(), handler);
 }
 
index a10acd06871cf992efdcc23245190a15ae92f193..ee9fc0e44e86f0c7522d92deefc3fc979475cfe3 100644 (file)
@@ -134,20 +134,6 @@ class ExitFrameConstants : public AllStatic {
 };
 
 
-class StandardFrameConstants : public AllStatic {
- public:
-  // Fixed part of the frame consists of return address, caller fp,
-  // context and function.
-  static const int kFixedFrameSize    =  4 * kPointerSize;
-  static const int kExpressionsOffset = -3 * kPointerSize;
-  static const int kMarkerOffset      = -2 * kPointerSize;
-  static const int kContextOffset     = -1 * kPointerSize;
-  static const int kCallerFPOffset    =  0 * kPointerSize;
-  static const int kCallerPCOffset    =  1 * kPointerSize;
-  static const int kCallerSPOffset    =  2 * kPointerSize;
-};
-
-
 class JavaScriptFrameConstants : public AllStatic {
  public:
   // FP-relative.
index 04ab3810726f3cfd012ea150b71c170ddee1bf0b..dacdd5a02e7f7acbddd66d17ecf5d31045e74cac 100644 (file)
@@ -2257,7 +2257,7 @@ LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
 
 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
   LParameter* result = new(zone()) LParameter;
-  if (info()->IsOptimizing()) {
+  if (instr->kind() == HParameter::STACK_PARAMETER) {
     int spill_index = chunk()->GetParameterStackSlot(instr->index());
     return DefineAsSpilled(result, spill_index);
   } else {
index b638c40673eb9a1449feb175f56717995c83a153..f837045eed037a9235d5cdac317dd84dde883421 100644 (file)
@@ -102,7 +102,8 @@ bool CodeStubGraphBuilderBase::BuildGraph() {
   HGraph* graph = this->graph();
   Zone* zone = this->zone();
   for (int i = 0; i < descriptor->register_param_count_; ++i) {
-    HParameter* param = new(zone) HParameter(i);
+    HParameter* param =
+        new(zone) HParameter(i, HParameter::REGISTER_PARAMETER);
     AddInstruction(param);
     graph->start_environment()->Push(param);
     parameters_[i] = param;
index 2d23ddb7da40fd32c7df88bf3e79d2dfa5dfd6fa..5e3795ce69386d7ca7d3689d082a3e7cff16de93 100644 (file)
@@ -606,6 +606,14 @@ void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
 }
 
 
+void StubFailureTrampolineStub::GenerateAheadOfTime() {
+  int i = 0;
+  for (; i <= StubFailureTrampolineStub::kMaxExtraExpressionStackCount; ++i) {
+    StubFailureTrampolineStub(i).GetCode();
+  }
+}
+
+
 FunctionEntryHook ProfileEntryHookStub::entry_hook_ = NULL;
 
 
index 1b160c40fa0495af5119e7b7eeaa77379d4cb213..5eea0a4fe0e4eed8695246e018d2b7c052856cf2 100644 (file)
@@ -253,8 +253,12 @@ class PlatformCodeStub : public CodeStub {
 struct CodeStubInterfaceDescriptor {
   CodeStubInterfaceDescriptor()
       : register_param_count_(-1),
+        stack_parameter_count_(NULL),
+        extra_expression_stack_count_(0),
         register_params_(NULL) { }
   int register_param_count_;
+  const Register* stack_parameter_count_;
+  int extra_expression_stack_count_;
   Register* register_params_;
   Address deoptimization_handler_;
 };
@@ -1420,14 +1424,23 @@ class StoreArrayLiteralElementStub : public PlatformCodeStub {
 
 class StubFailureTrampolineStub : public PlatformCodeStub {
  public:
-  StubFailureTrampolineStub() {}
+  static const int kMaxExtraExpressionStackCount = 1;
+
+  explicit StubFailureTrampolineStub(int extra_expression_stack_count)
+      : extra_expression_stack_count_(extra_expression_stack_count) {}
+
+  virtual bool IsPregenerated() { return true; }
+
+  static void GenerateAheadOfTime();
 
  private:
   Major MajorKey() { return StubFailureTrampoline; }
-  int MinorKey() { return 0; }
+  int MinorKey() { return extra_expression_stack_count_; }
 
   void Generate(MacroAssembler* masm);
 
+  int extra_expression_stack_count_;
+
   DISALLOW_COPY_AND_ASSIGN(StubFailureTrampolineStub);
 };
 
index 8015baf6e9dd02531d4e69b9950f5a5a4c441270..a82fda90f653d83776f2b4d861be59a48b93b48a 100644 (file)
@@ -1497,10 +1497,9 @@ unsigned Deoptimizer::ComputeInputFrameSize() const {
     // size matches with the stack height we can compute based on the
     // environment at the OSR entry. The code for that his built into
     // the DoComputeOsrOutputFrame function for now.
-  } else {
+  } else if (compiled_code_->kind() != Code::COMPILED_STUB) {
     unsigned stack_slots = compiled_code_->stack_slots();
-    unsigned outgoing_size = compiled_code_->kind() == Code::COMPILED_STUB
-        ? 0 : ComputeOutgoingArgumentSize();
+    unsigned outgoing_size = ComputeOutgoingArgumentSize();
     ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size);
   }
 #endif
index e0c934f46c80368086e18a35a037ab33e9166da3..83b37a5fe53a81f294d411e9381b8b9d555e6250 100644 (file)
@@ -256,7 +256,7 @@ inline InternalFrame::InternalFrame(StackFrameIterator* iterator)
 
 
 inline StubFailureTrampolineFrame::StubFailureTrampolineFrame(
-    StackFrameIterator* iterator) : InternalFrame(iterator) {
+    StackFrameIterator* iterator) : StandardFrame(iterator) {
 }
 
 
index 98b3d65f955ed9eac36b52fc1f4dc365447bbfa7..40abf640363e5ab0322ce39c5cabd3fafdeed485 100644 (file)
@@ -1304,14 +1304,41 @@ void InternalFrame::Iterate(ObjectVisitor* v) const {
 
 
 void StubFailureTrampolineFrame::Iterate(ObjectVisitor* v) const {
-  const int offset = StandardFrameConstants::kContextOffset;
   Object** base = &Memory::Object_at(sp());
-  Object** limit = &Memory::Object_at(fp() + offset) + 1;
+  Object** limit = &Memory::Object_at(fp() +
+                                      kFirstRegisterParameterFrameOffset);
+  v->VisitPointers(base, limit);
+  base = &Memory::Object_at(fp() + StandardFrameConstants::kMarkerOffset);
+  const int offset = StandardFrameConstants::kContextOffset;
+  limit = &Memory::Object_at(fp() + offset) + 1;
   v->VisitPointers(base, limit);
   IteratePc(v, pc_address(), LookupCode());
 }
 
 
+Address StubFailureTrampolineFrame::GetCallerStackPointer() const {
+  return fp() + StandardFrameConstants::kCallerSPOffset;
+}
+
+
+Code* StubFailureTrampolineFrame::unchecked_code() const {
+  int i = 0;
+  for (; i <= StubFailureTrampolineStub::kMaxExtraExpressionStackCount; ++i) {
+    Code* trampoline;
+    StubFailureTrampolineStub(i).FindCodeInCache(&trampoline, isolate());
+    ASSERT(trampoline != NULL);
+    Address current_pc = pc();
+    Address code_start = trampoline->instruction_start();
+    Address code_end = code_start + trampoline->instruction_size();
+    if (code_start <= current_pc && current_pc < code_end) {
+      return trampoline;
+    }
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
 // -------------------------------------------------------------------------
 
 
index 26bf434ac91cb22cd9afef83aba12d5aacd12f2c..a60e535947f033a9e5083e44da4e1aea831d0dab 100644 (file)
@@ -143,6 +143,22 @@ class StackHandler BASE_EMBEDDED {
   V(ARGUMENTS_ADAPTOR,       ArgumentsAdaptorFrame)
 
 
+class StandardFrameConstants : public AllStatic {
+ public:
+  // Fixed part of the frame consists of return address, caller fp,
+  // context and function.
+  // StandardFrame::IterateExpressions assumes that kContextOffset is the last
+  // object pointer.
+  static const int kFixedFrameSize    =  4 * kPointerSize;
+  static const int kExpressionsOffset = -3 * kPointerSize;
+  static const int kMarkerOffset      = -2 * kPointerSize;
+  static const int kContextOffset     = -1 * kPointerSize;
+  static const int kCallerFPOffset    =  0 * kPointerSize;
+  static const int kCallerPCOffset    = +1 * kPointerSize;
+  static const int kCallerSPOffset    = +2 * kPointerSize;
+};
+
+
 // Abstract base class for all stack frames.
 class StackFrame BASE_EMBEDDED {
  public:
@@ -672,16 +688,30 @@ class InternalFrame: public StandardFrame {
 };
 
 
-class StubFailureTrampolineFrame: public InternalFrame {
+class StubFailureTrampolineFrame: public StandardFrame {
  public:
+  // sizeof(Arguments) - sizeof(Arguments*) is 3 * kPointerSize), but the
+  // presubmit script complains about using sizeof() on a type.
+  static const int kFirstRegisterParameterFrameOffset =
+      StandardFrameConstants::kMarkerOffset - 3 * kPointerSize;
+
+  static const int kCallerStackParameterCountFrameOffset =
+      StandardFrameConstants::kMarkerOffset - 2 * kPointerSize;
+
   virtual Type type() const { return STUB_FAILURE_TRAMPOLINE; }
 
+  // Get the code associated with this frame.
+  // This method could be called during marking phase of GC.
+  virtual Code* unchecked_code() const;
+
   virtual void Iterate(ObjectVisitor* v) const;
 
  protected:
   inline explicit StubFailureTrampolineFrame(
       StackFrameIterator* iterator);
 
+  virtual Address GetCallerStackPointer() const;
+
  private:
   friend class StackFrameIterator;
 };
index eea429e6f2b11ea2d506d448e7bf39871886d472..53f1b65755beaa3cbaa3ada0086830d60529bc27 100644 (file)
@@ -4010,11 +4010,20 @@ class HOsrEntry: public HTemplateInstruction<0> {
 
 class HParameter: public HTemplateInstruction<0> {
  public:
-  explicit HParameter(unsigned index) : index_(index) {
+  enum ParameterKind {
+    STACK_PARAMETER,
+    REGISTER_PARAMETER
+  };
+
+  explicit HParameter(unsigned index,
+                      ParameterKind kind = STACK_PARAMETER)
+      : index_(index),
+        kind_(kind) {
     set_representation(Representation::Tagged());
   }
 
   unsigned index() const { return index_; }
+  ParameterKind kind() const { return kind_; }
 
   virtual void PrintDataTo(StringStream* stream);
 
@@ -4026,6 +4035,7 @@ class HParameter: public HTemplateInstruction<0> {
 
  private:
   unsigned index_;
+  ParameterKind kind_;
 };
 
 
index 95463123b32aa3d6a1ef9519e87fb48dc44fb295..d9cd90d64f17868726d25f06ad2826b4934945f6 100644 (file)
@@ -48,6 +48,7 @@ void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
   static Register registers[] = { edx, ecx };
   descriptor->register_param_count_ = 2;
   descriptor->register_params_ = registers;
+  descriptor->stack_parameter_count_ = NULL;
   descriptor->deoptimization_handler_ =
       FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
 }
@@ -7646,8 +7647,14 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
   bool save_fp_regs = CpuFeatures::IsSupported(SSE2);
   CEntryStub ces(1, save_fp_regs ? kSaveFPRegs : kDontSaveFPRegs);
   __ call(ces.GetCode(), RelocInfo::CODE_TARGET);
+  int parameter_count_offset =
+      StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
+  __ mov(ebx, MemOperand(ebp, parameter_count_offset));
   masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
-  __ ret(0);  // Return to IC Miss stub, continuation still on stack.
+  __ pop(ecx);
+  __ lea(esp, MemOperand(esp, ebx, times_pointer_size,
+                         extra_expression_stack_count_ * kPointerSize));
+  __ jmp(ecx);  // Return to IC Miss stub, continuation still on stack.
 }
 
 
index 8d9c6b25f73a439dc50629a82f5c0a3a4de48f7f..e4377ce6c7fd81ff2fc99549626ee43dcff92496 100644 (file)
@@ -573,13 +573,19 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
   // v  +-------------------------+          +-------------------------|
   //    |   COMPILED_STUB marker  |          |   STUB_FAILURE marker   |
   //    +-------------------------+          +-------------------------+
-  //    |                         |          |     stub parameter 1    |
+  //    |                         |          |   caller args.length_   |
   //    | ...                     |          +-------------------------+
-  //    |                         |          |            ...          |
+  //    |                         |          |  caller args.arguments_ |
   //    |-------------------------|<-esp     +-------------------------+
-  //                                         |     stub parameter n    |
-  //      parameters in registers            +-------------------------+<-esp
-  //       and spilled to stack              eax = number of parameters
+  //                                         |  caller args pointer    |
+  //                                         +-------------------------+
+  //                                         |  caller stack param 1   |
+  //      parameters in registers            +-------------------------+
+  //       and spilled to stack              |           ....          |
+  //                                         +-------------------------+
+  //                                         |  caller stack param n   |
+  //                                         +-------------------------+<-esp
+  //                                         eax = number of parameters
   //                                         ebx = failure handler address
   //                                         ebp = saved frame
   //                                         esi = JSFunction context
@@ -590,9 +596,15 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
   CodeStubInterfaceDescriptor* descriptor =
       isolate_->code_stub_interface_descriptor(major_key);
 
+  // The output frame must have room for all pushed register parameters
+  // and the standard stack frame slots.
   int output_frame_size = StandardFrameConstants::kFixedFrameSize +
       kPointerSize * descriptor->register_param_count_;
 
+  // Include space for an argument object to the callee and optionally
+  // the space to pass the argument object to the stub failure handler.
+  output_frame_size += sizeof(Arguments) + kPointerSize;
+
   FrameDescription* output_frame =
       new(output_frame_size) FrameDescription(output_frame_size, 0);
   ASSERT(frame_index == 0);
@@ -604,12 +616,15 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
       reinterpret_cast<intptr_t>(notify_failure->entry()));
 
   Code* trampoline = NULL;
-  StubFailureTrampolineStub().FindCodeInCache(&trampoline, isolate_);
+  int extra = descriptor->extra_expression_stack_count_;
+  StubFailureTrampolineStub(extra).FindCodeInCache(&trampoline, isolate_);
   ASSERT(trampoline != NULL);
   output_frame->SetPc(reinterpret_cast<intptr_t>(
       trampoline->instruction_start()));
   unsigned input_frame_size = input_->GetFrameSize();
 
+  intptr_t frame_ptr = input_->GetRegister(ebp.code());
+
   // JSFunction continuation
   intptr_t input_frame_offset = input_frame_size - kPointerSize;
   intptr_t output_frame_offset = output_frame_size - kPointerSize;
@@ -635,14 +650,35 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
       Smi::FromInt(StackFrame::STUB_FAILURE_TRAMPOLINE));
   output_frame->SetFrameSlot(output_frame_offset, value);
 
+  int caller_arg_count = 0;
+  if (descriptor->stack_parameter_count_ != NULL) {
+    caller_arg_count =
+        input_->GetRegister(descriptor->stack_parameter_count_->code());
+  }
+
+  // Build the Arguments object for the caller's parameters and a pointer to it.
+  output_frame_offset -= kPointerSize;
+  value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
+      (caller_arg_count - 1) * kPointerSize;
+  output_frame->SetFrameSlot(output_frame_offset, value);
+
+  output_frame->SetFrameSlot(output_frame_offset, value);
+  output_frame_offset -= kPointerSize;
+  output_frame->SetFrameSlot(output_frame_offset, caller_arg_count);
+
+  value = frame_ptr - (output_frame_size - output_frame_offset) -
+      StandardFrameConstants::kMarkerOffset;
+  output_frame_offset -= kPointerSize;
+  output_frame->SetFrameSlot(output_frame_offset, value);
+
+  // Copy the register parameters to the failure frame.
   for (int i = 0; i < descriptor->register_param_count_; ++i) {
     output_frame_offset -= kPointerSize;
     DoTranslateCommand(iterator, 0, output_frame_offset);
   }
 
-  value = input_->GetRegister(ebp.code());
-  output_frame->SetRegister(ebp.code(), value);
-  output_frame->SetFp(value);
+  output_frame->SetRegister(ebp.code(), frame_ptr);
+  output_frame->SetFp(frame_ptr);
 
   for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; ++i) {
     double double_value = input_->GetDoubleRegister(i);
@@ -651,7 +687,11 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
 
   intptr_t handler =
       reinterpret_cast<intptr_t>(descriptor->deoptimization_handler_);
-  output_frame->SetRegister(eax.code(), descriptor->register_param_count_);
+  int params = descriptor->register_param_count_;
+  if (descriptor->stack_parameter_count_ != NULL) {
+    params++;
+  }
+  output_frame->SetRegister(eax.code(), params);
   output_frame->SetRegister(ebx.code(), handler);
 }
 
index 18915e2e3cdb80f34a43e21877ad85f2ba1395c7..5bd102a6a23d3dc965c647ede8eca4faa6ed1771 100644 (file)
@@ -97,22 +97,6 @@ class ExitFrameConstants : public AllStatic {
 };
 
 
-class StandardFrameConstants : public AllStatic {
- public:
-  // Fixed part of the frame consists of return address, caller fp,
-  // context and function.
-  // StandardFrame::IterateExpressions assumes that kContextOffset is the last
-  // object pointer.
-  static const int kFixedFrameSize    =  4 * kPointerSize;
-  static const int kExpressionsOffset = -3 * kPointerSize;
-  static const int kMarkerOffset      = -2 * kPointerSize;
-  static const int kContextOffset     = -1 * kPointerSize;
-  static const int kCallerFPOffset    =  0 * kPointerSize;
-  static const int kCallerPCOffset    = +1 * kPointerSize;
-  static const int kCallerSPOffset    = +2 * kPointerSize;
-};
-
-
 class JavaScriptFrameConstants : public AllStatic {
  public:
   // FP-relative.
index 42ae13f898175768d9fbc183d15cb31744889e7e..37d83909a011afd4d859c1413275696fbebeca4e 100644 (file)
@@ -2346,7 +2346,7 @@ LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
 
 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
   LParameter* result = new(zone()) LParameter;
-  if (info()->IsOptimizing()) {
+  if (instr->kind() == HParameter::STACK_PARAMETER) {
     int spill_index = chunk()->GetParameterStackSlot(instr->index());
     return DefineAsSpilled(result, spill_index);
   } else {
index d70e19e0ebcdfab65ceb688334da39f7255f901a..c8d9c3a4f6ce573c7f67ffa2c2dce20513841e0f 100644 (file)
@@ -2120,7 +2120,7 @@ bool Isolate::Init(Deserializer* des) {
     // Ensure that the stub failure trampoline has been generated.
     HandleScope scope(this);
     CodeStub::GenerateFPStubs();
-    StubFailureTrampolineStub().GetCode();
+    StubFailureTrampolineStub::GenerateAheadOfTime();
   }
 
   if (FLAG_parallel_recompilation) optimizing_compiler_thread_.Start();
index 4df7af9902ca7ab4dc7d242c1703d565c2f29fc4..d8623f8ce9b5376ba082bd0da79ff3ddcd3a3403 100644 (file)
@@ -78,6 +78,9 @@ namespace internal {
   RUNTIME_ASSERT(args[index]->Is##Type());                           \
   Handle<Type> name = args.at<Type>(index);
 
+#define CONVERT_ARG_STUB_CALLER_ARGS(name)                           \
+  Arguments* name = reinterpret_cast<Arguments*>(args[0]);
+
 // Cast the given object to a boolean and store it in a variable with
 // the given name.  If the object is not a boolean call IllegalOperation
 // and return.
index e4d401f6fd449b43850ded0d5659639d00b6a65a..095113c40da56f397fbecbdc8f8b6d261ee38295 100644 (file)
@@ -45,6 +45,7 @@ void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
   static Register registers[] = { rdx, rax };
   descriptor->register_param_count_ = 2;
   descriptor->register_params_ = registers;
+  descriptor->stack_parameter_count_ = NULL;
   descriptor->deoptimization_handler_ =
       FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
 }
@@ -6635,8 +6636,14 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
   ASSERT(!Serializer::enabled());
   CEntryStub ces(1, kSaveFPRegs);
   __ Call(ces.GetCode(), RelocInfo::CODE_TARGET);
+  int parameter_count_offset =
+      StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
+  __ movq(rbx, MemOperand(rbp, parameter_count_offset));
   masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
-  __ ret(0);  // Return to IC Miss stub, continuation still on stack.
+  __ pop(rcx);
+  __ lea(rsp, MemOperand(rsp, rbx, times_pointer_size,
+                         extra_expression_stack_count_ * kPointerSize));
+  __ jmp(rcx);  // Return to IC Miss stub, continuation still on stack.
 }
 
 
index 5d1a6d2fd0d7ea99b3145994f1013b71c86bc733..388168b28903506d5d192a0eae11f43fe36343d6 100644 (file)
@@ -462,13 +462,19 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
   // v  +-------------------------+          +-------------------------|
   //    |   COMPILED_STUB marker  |          |   STUB_FAILURE marker   |
   //    +-------------------------+          +-------------------------+
-  //    |                         |          |     stub parameter 1    |
+  //    |                         |          |   caller args.length_   |
   //    | ...                     |          +-------------------------+
-  //    |                         |          |            ...          |
+  //    |                         |          |  caller args.arguments_ |
   //    |-------------------------|<-rsp     +-------------------------+
-  //                                         |     stub parameter n    |
-  //      parameters in registers            +-------------------------+<-rsp
-  //       and spilled to stack              rax = number of parameters
+  //                                         |  caller args pointer    |
+  //                                         +-------------------------+
+  //                                         |  caller stack param 1   |
+  //      parameters in registers            +-------------------------+
+  //       and spilled to stack              |           ....          |
+  //                                         +-------------------------+
+  //                                         |  caller stack param n   |
+  //                                         +-------------------------+<-rsp
+  //                                         rax = number of parameters
   //                                         rbx = failure handler address
   //                                         rbp = saved frame
   //                                         rsi = JSFunction context
@@ -479,9 +485,15 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
   CodeStubInterfaceDescriptor* descriptor =
       isolate_->code_stub_interface_descriptor(major_key);
 
+  // The output frame must have room for all pushed register parameters
+  // and the standard stack frame slots.
   int output_frame_size = StandardFrameConstants::kFixedFrameSize +
       kPointerSize * descriptor->register_param_count_;
 
+  // Include space for an argument object to the callee and optionally
+  // the space to pass the argument object to the stub failure handler.
+  output_frame_size += sizeof(Arguments) + kPointerSize;
+
   FrameDescription* output_frame =
       new(output_frame_size) FrameDescription(output_frame_size, 0);
   ASSERT(frame_index == 0);
@@ -493,12 +505,15 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
       reinterpret_cast<intptr_t>(notify_failure->entry()));
 
   Code* trampoline = NULL;
-  StubFailureTrampolineStub().FindCodeInCache(&trampoline, isolate_);
+  int extra = descriptor->extra_expression_stack_count_;
+  StubFailureTrampolineStub(extra).FindCodeInCache(&trampoline, isolate_);
   ASSERT(trampoline != NULL);
   output_frame->SetPc(reinterpret_cast<intptr_t>(
       trampoline->instruction_start()));
   unsigned input_frame_size = input_->GetFrameSize();
 
+  intptr_t frame_ptr = input_->GetRegister(rbp.code());
+
   // JSFunction continuation
   unsigned input_frame_offset = input_frame_size - kPointerSize;
   unsigned output_frame_offset = output_frame_size - kPointerSize;
@@ -524,14 +539,35 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
       Smi::FromInt(StackFrame::STUB_FAILURE_TRAMPOLINE));
   output_frame->SetFrameSlot(output_frame_offset, value);
 
+  int caller_arg_count = 0;
+  if (descriptor->stack_parameter_count_ != NULL) {
+    caller_arg_count =
+        input_->GetRegister(descriptor->stack_parameter_count_->code());
+  }
+
+  // Build the Arguments object for the caller's parameters and a pointer to it.
+  output_frame_offset -= kPointerSize;
+  value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
+      (caller_arg_count - 1) * kPointerSize;
+  output_frame->SetFrameSlot(output_frame_offset, value);
+
+  output_frame->SetFrameSlot(output_frame_offset, value);
+  output_frame_offset -= kPointerSize;
+  output_frame->SetFrameSlot(output_frame_offset, caller_arg_count);
+
+  value = frame_ptr - (output_frame_size - output_frame_offset) -
+      StandardFrameConstants::kMarkerOffset;
+  output_frame_offset -= kPointerSize;
+  output_frame->SetFrameSlot(output_frame_offset, value);
+
+  // Copy the register parameters to the failure frame.
   for (int i = 0; i < descriptor->register_param_count_; ++i) {
     output_frame_offset -= kPointerSize;
     DoTranslateCommand(iterator, 0, output_frame_offset);
   }
 
-  value = input_->GetRegister(rbp.code());
-  output_frame->SetRegister(rbp.code(), value);
-  output_frame->SetFp(value);
+  output_frame->SetRegister(rbp.code(), frame_ptr);
+  output_frame->SetFp(frame_ptr);
 
   for (int i = 0; i < XMMRegister::NumAllocatableRegisters(); ++i) {
     double double_value = input_->GetDoubleRegister(i);
@@ -540,7 +576,11 @@ void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
 
   intptr_t handler =
       reinterpret_cast<intptr_t>(descriptor->deoptimization_handler_);
-  output_frame->SetRegister(rax.code(), descriptor->register_param_count_);
+  int params = descriptor->register_param_count_;
+  if (descriptor->stack_parameter_count_ != NULL) {
+    params++;
+  }
+  output_frame->SetRegister(rax.code(), params);
   output_frame->SetRegister(rbx.code(), handler);
 }
 
index 3e3d63d62b917f4c2547dd353cbeec6b7128ef9e..c9092afa39ca25ff79be232d37acbfe0d77582fb 100644 (file)
@@ -85,20 +85,6 @@ class ExitFrameConstants : public AllStatic {
 };
 
 
-class StandardFrameConstants : public AllStatic {
- public:
-  // Fixed part of the frame consists of return address, caller fp,
-  // context and function.
-  static const int kFixedFrameSize    =  4 * kPointerSize;
-  static const int kExpressionsOffset = -3 * kPointerSize;
-  static const int kMarkerOffset      = -2 * kPointerSize;
-  static const int kContextOffset     = -1 * kPointerSize;
-  static const int kCallerFPOffset    =  0 * kPointerSize;
-  static const int kCallerPCOffset    = +1 * kPointerSize;
-  static const int kCallerSPOffset    = +2 * kPointerSize;
-};
-
-
 class JavaScriptFrameConstants : public AllStatic {
  public:
   // FP-relative.
index a7efa760a721ac67ce2f67473138df6f76d1975c..e35a381faacd932d223a4a64d1d45a317e491007 100644 (file)
@@ -2200,7 +2200,7 @@ LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
 
 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
   LParameter* result = new(zone()) LParameter;
-  if (info()->IsOptimizing()) {
+  if (instr->kind() == HParameter::STACK_PARAMETER) {
     int spill_index = chunk()->GetParameterStackSlot(instr->index());
     return DefineAsSpilled(result, spill_index);
   } else {