Crankshaft is now able to compile top level code even if there is a ScriptContext.
authorishell <ishell@chromium.org>
Tue, 1 Sep 2015 07:06:49 +0000 (00:06 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 1 Sep 2015 07:07:05 +0000 (07:07 +0000)
This CL introduces HPrologue instruction which does the context allocation work and supports deoptimization.

Review URL: https://codereview.chromium.org/1317383002

Cr-Commit-Position: refs/heads/master@{#30496}

33 files changed:
src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/arm64/lithium-arm64.cc
src/arm64/lithium-arm64.h
src/arm64/lithium-codegen-arm64.cc
src/bootstrapper.cc
src/compiler/ast-graph-builder.cc
src/contexts.cc
src/contexts.h
src/full-codegen/arm/full-codegen-arm.cc
src/full-codegen/arm64/full-codegen-arm64.cc
src/full-codegen/ia32/full-codegen-ia32.cc
src/full-codegen/mips/full-codegen-mips.cc
src/full-codegen/mips64/full-codegen-mips64.cc
src/full-codegen/x64/full-codegen-x64.cc
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/hydrogen.h
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/mips/lithium-codegen-mips.cc
src/mips/lithium-mips.cc
src/mips/lithium-mips.h
src/mips64/lithium-codegen-mips64.cc
src/mips64/lithium-mips64.cc
src/mips64/lithium-mips64.h
src/utils.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h

index ec58f8d670c9432d57f89d57af486723782aea0e..0504fa13fd1a1373d1a1ceb4c42bae2b6c3e4981 100644 (file)
@@ -914,7 +914,7 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
   }
   chunk_->AddInstruction(instr, current_block_);
 
-  if (instr->IsCall()) {
+  if (instr->IsCall() || instr->IsPrologue()) {
     HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
     if (hydrogen_val->HasObservableSideEffects()) {
       HSimulate* sim = HSimulate::cast(hydrogen_val->next());
@@ -928,6 +928,11 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
 }
 
 
+LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
+  return new (zone()) LPrologue();
+}
+
+
 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
   return new(zone()) LGoto(instr->FirstSuccessor());
 }
index b6fc2e6ca0511aa607f4aae5973f6c4802013fc1..acd5c207ec6e1b6327fc368109e606727887839e 100644 (file)
@@ -131,6 +131,7 @@ class LCodeGen;
   V(OsrEntry)                                \
   V(Parameter)                               \
   V(Power)                                   \
+  V(Prologue)                                \
   V(PushArgument)                            \
   V(RegExpLiteral)                           \
   V(Return)                                  \
@@ -389,6 +390,12 @@ class LGoto final : public LTemplateInstruction<0, 0, 0> {
 };
 
 
+class LPrologue final : public LTemplateInstruction<0, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(Prologue, "prologue")
+};
+
+
 class LLazyBailout final : public LTemplateInstruction<0, 0, 0> {
  public:
   LLazyBailout() : gap_instructions_size_(0) { }
index f26f0ce99bce8a467e5af7ffb479c99019755a1a..fb1d84a166d0f1eb3988b1809da24ac95851fa8d 100644 (file)
@@ -170,16 +170,27 @@ bool LCodeGen::GeneratePrologue() {
   if (info()->saves_caller_doubles()) {
     SaveCallerDoubles();
   }
+  return !is_aborted();
+}
+
+
+void LCodeGen::DoPrologue(LPrologue* instr) {
+  Comment(";;; Prologue begin");
 
   // Possibly allocate a local context.
-  int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
-  if (heap_slots > 0) {
+  if (info()->scope()->num_heap_slots() > 0) {
     Comment(";;; Allocate local context");
     bool need_write_barrier = true;
     // Argument to NewContext is the function, which is in r1.
-    DCHECK(!info()->scope()->is_script_scope());
-    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
-      FastNewContextStub stub(isolate(), heap_slots);
+    int slots = info()->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+    Safepoint::DeoptMode deopt_mode = Safepoint::kNoLazyDeopt;
+    if (info()->scope()->is_script_scope()) {
+      __ push(r1);
+      __ Push(info()->scope()->GetScopeInfo(info()->isolate()));
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
+      deopt_mode = Safepoint::kLazyDeopt;
+    } else if (slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(isolate(), slots);
       __ CallStub(&stub);
       // Result of FastNewContextStub is always in new space.
       need_write_barrier = false;
@@ -187,7 +198,8 @@ bool LCodeGen::GeneratePrologue() {
       __ push(r1);
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    RecordSafepoint(Safepoint::kNoLazyDeopt);
+    RecordSafepoint(deopt_mode);
+
     // Context is returned in both r0 and cp.  It replaces the context
     // passed to us.  It's saved in the stack and kept live in cp.
     __ mov(cp, r0);
@@ -225,13 +237,7 @@ bool LCodeGen::GeneratePrologue() {
     Comment(";;; End allocate local context");
   }
 
-  // Trace the call.
-  if (FLAG_trace && info()->IsOptimizing()) {
-    // We have not executed any compiled code yet, so cp still holds the
-    // incoming context.
-    __ CallRuntime(Runtime::kTraceEnter, 0);
-  }
-  return !is_aborted();
+  Comment(";;; Prologue end");
 }
 
 
index 1db7d6b4b2383d1e4482bb76bebdfa8595be0811..bdf49bfff009e94a0c66c33bd7c30ac5d940fb6b 100644 (file)
@@ -756,7 +756,7 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
   }
   chunk_->AddInstruction(instr, current_block_);
 
-  if (instr->IsCall()) {
+  if (instr->IsCall() || instr->IsPrologue()) {
     HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
     if (hydrogen_val->HasObservableSideEffects()) {
       HSimulate* sim = HSimulate::cast(hydrogen_val->next());
@@ -781,6 +781,11 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
 }
 
 
+LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
+  return new (zone()) LPrologue();
+}
+
+
 LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
   // The control instruction marking the end of a block that completed
   // abruptly (e.g., threw an exception). There is nothing specific to do.
index bdc622c4e3759460d8e02c783cc3fecf7fd93600..159e60cc542644a4bd6c36997af18d92e2914134 100644 (file)
@@ -138,6 +138,7 @@ class LCodeGen;
   V(OsrEntry)                                \
   V(Parameter)                               \
   V(Power)                                   \
+  V(Prologue)                                \
   V(PreparePushArguments)                    \
   V(PushArguments)                           \
   V(RegExpLiteral)                           \
@@ -473,6 +474,12 @@ class LGoto final : public LTemplateInstruction<0, 0, 0> {
 };
 
 
+class LPrologue final : public LTemplateInstruction<0, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(Prologue, "prologue")
+};
+
+
 class LLazyBailout final : public LTemplateInstruction<0, 0, 0> {
  public:
   LLazyBailout() : gap_instructions_size_(0) { }
index 7ed95ed9abe8db06fbd158813f963cdbd4329b3f..b317900a79e059c3538335d592f28cb745628757 100644 (file)
@@ -665,16 +665,27 @@ bool LCodeGen::GeneratePrologue() {
   if (info()->saves_caller_doubles()) {
     SaveCallerDoubles();
   }
+  return !is_aborted();
+}
+
+
+void LCodeGen::DoPrologue(LPrologue* instr) {
+  Comment(";;; Prologue begin");
 
   // Allocate a local context if needed.
-  int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
-  if (heap_slots > 0) {
+  if (info()->num_heap_slots() > 0) {
     Comment(";;; Allocate local context");
     bool need_write_barrier = true;
     // Argument to NewContext is the function, which is in x1.
-    DCHECK(!info()->scope()->is_script_scope());
-    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
-      FastNewContextStub stub(isolate(), heap_slots);
+    int slots = info()->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+    Safepoint::DeoptMode deopt_mode = Safepoint::kNoLazyDeopt;
+    if (info()->scope()->is_script_scope()) {
+      __ Mov(x10, Operand(info()->scope()->GetScopeInfo(info()->isolate())));
+      __ Push(x1, x10);
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
+      deopt_mode = Safepoint::kLazyDeopt;
+    } else if (slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(isolate(), slots);
       __ CallStub(&stub);
       // Result of FastNewContextStub is always in new space.
       need_write_barrier = false;
@@ -682,7 +693,7 @@ bool LCodeGen::GeneratePrologue() {
       __ Push(x1);
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    RecordSafepoint(Safepoint::kNoLazyDeopt);
+    RecordSafepoint(deopt_mode);
     // Context is returned in x0. It replaces the context passed to us. It's
     // saved in the stack and kept live in cp.
     __ Mov(cp, x0);
@@ -719,14 +730,7 @@ bool LCodeGen::GeneratePrologue() {
     Comment(";;; End allocate local context");
   }
 
-  // Trace the call.
-  if (FLAG_trace && info()->IsOptimizing()) {
-    // We have not executed any compiled code yet, so cp still holds the
-    // incoming context.
-    __ CallRuntime(Runtime::kTraceEnter, 0);
-  }
-
-  return !is_aborted();
+  Comment(";;; Prologue end");
 }
 
 
index 06bd125127a11fdb6dcde79bb14f48cf5aacd356..0cd277987780699391008ed5947a2526a915a464 100644 (file)
@@ -3161,7 +3161,9 @@ Genesis::Genesis(Isolate* isolate,
 
   // Check that the script context table is empty except for the 'this' binding.
   // We do not need script contexts for native scripts.
-  DCHECK_EQ(1, native_context()->script_context_table()->used());
+  if (!FLAG_global_var_shortcuts) {
+    DCHECK_EQ(1, native_context()->script_context_table()->used());
+  }
 
   result_ = native_context();
 }
index b383786e6891674cdb829e74ed8853cd1bd53dea..10abec7b8824741217a09e39e69e8e35b4a9224c 100644 (file)
@@ -3156,7 +3156,7 @@ Node* AstGraphBuilder::BuildLocalScriptContext(Scope* scope) {
   const Operator* op = javascript()->CreateScriptContext();
   Node* scope_info = jsgraph()->Constant(scope->GetScopeInfo(isolate()));
   Node* local_context = NewNode(op, GetFunctionClosure(), scope_info);
-  PrepareFrameState(local_context, BailoutId::FunctionEntry());
+  PrepareFrameState(local_context, BailoutId::Prologue());
 
   return local_context;
 }
index 37021ac7f67f789e33bdf6f91d876fc99eb4c551..d66a33043424c6cb13fc15214e3a97c4f3f36243 100644 (file)
@@ -18,7 +18,7 @@ Handle<ScriptContextTable> ScriptContextTable::Extend(
   int used = table->used();
   int length = table->length();
   CHECK(used >= 0 && length > 0 && used < length);
-  if (used + 1 == length) {
+  if (used + kFirstContextSlot == length) {
     CHECK(length < Smi::kMaxValue / 2);
     Isolate* isolate = table->GetIsolate();
     Handle<FixedArray> copy =
@@ -31,7 +31,7 @@ Handle<ScriptContextTable> ScriptContextTable::Extend(
   result->set_used(used + 1);
 
   DCHECK(script_context->IsScriptContext());
-  result->set(used + 1, *script_context);
+  result->set(used + kFirstContextSlot, *script_context);
   return result;
 }
 
index 05bc3b55ec872f65ce3b934b0639fcb98beb0e2b..4e4dd2c8e72c2d5efb56684c87f30b3924a88c9f 100644 (file)
@@ -314,12 +314,11 @@ class ScriptContextTable : public FixedArray {
   };
 
   int used() const { return Smi::cast(get(kUsedSlot))->value(); }
-
   void set_used(int used) { set(kUsedSlot, Smi::FromInt(used)); }
 
   static Handle<Context> GetContext(Handle<ScriptContextTable> table, int i) {
     DCHECK(i < table->used());
-    return Handle<Context>::cast(FixedArray::get(table, i + 1));
+    return Handle<Context>::cast(FixedArray::get(table, i + kFirstContextSlot));
   }
 
   // Lookup a variable `name` in a ScriptContextTable.
@@ -340,8 +339,9 @@ class ScriptContextTable : public FixedArray {
 
  private:
   static const int kUsedSlot = 0;
+  static const int kFirstContextSlot = kUsedSlot + 1;
   static const int kFirstContextOffset =
-      FixedArray::kHeaderSize + (kUsedSlot + 1) * kPointerSize;
+      FixedArray::kHeaderSize + kFirstContextSlot * kPointerSize;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(ScriptContextTable);
 };
index c238860d0d2868f22fd90bc1d0538f5d455eaa31..8840ee57d45786a05eacc03fe5cb7065e1b4edf7 100644 (file)
@@ -181,7 +181,7 @@ void FullCodeGenerator::Generate() {
     }
   }
 
-  bool function_in_register = true;
+  bool function_in_register_r1 = true;
 
   // Possibly allocate a local context.
   if (info->scope()->num_heap_slots() > 0) {
@@ -202,7 +202,7 @@ void FullCodeGenerator::Generate() {
       __ push(r1);
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    function_in_register = false;
+    function_in_register_r1 = false;
     // Context is returned in r0.  It replaces the context passed to us.
     // It's saved in the stack and kept live in cp.
     __ mov(cp, r0);
@@ -235,14 +235,19 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  PrepareForBailoutForId(BailoutId::Prologue(), NO_REGISTERS);
+  // Function register is trashed in case we bailout here. But since that
+  // could happen only when we allocate a context the value of
+  // |function_in_register_r1| is correct.
+
   // Possibly set up a local binding to the this function which is used in
   // derived constructors with super calls.
   Variable* this_function_var = scope()->this_function_var();
   if (this_function_var != nullptr) {
     Comment cmnt(masm_, "[ This function");
-    if (!function_in_register) {
+    if (!function_in_register_r1) {
       __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
-      // The write barrier clobbers register again, keep is marked as such.
+      // The write barrier clobbers register again, keep it marked as such.
     }
     SetVar(this_function_var, r1, r0, r2);
   }
@@ -258,6 +263,7 @@ void FullCodeGenerator::Generate() {
     __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset));
     __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
     Label non_construct_frame, done;
+    function_in_register_r1 = false;
 
     __ b(ne, &non_construct_frame);
     __ ldr(r0,
@@ -285,6 +291,7 @@ void FullCodeGenerator::Generate() {
     __ mov(r1, Operand(Smi::FromInt(rest_index)));
     __ mov(r0, Operand(Smi::FromInt(language_mode())));
     __ Push(r3, r2, r1, r0);
+    function_in_register_r1 = false;
 
     RestParamAccessStub stub(isolate());
     __ CallStub(&stub);
@@ -296,7 +303,7 @@ void FullCodeGenerator::Generate() {
   if (arguments != NULL) {
     // Function uses arguments object.
     Comment cmnt(masm_, "[ Allocate arguments object");
-    if (!function_in_register) {
+    if (!function_in_register_r1) {
       // Load this again, if it's used by the local context below.
       __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
     } else {
@@ -328,7 +335,6 @@ void FullCodeGenerator::Generate() {
     SetVar(arguments, r0, r1, r2);
   }
 
-
   if (FLAG_trace) {
     __ CallRuntime(Runtime::kTraceEnter, 0);
   }
index ea560b411da2c1fb32092ac5196a15bbda2e9a03..5a2834d9b4d17110e8118fb35dbf4c59aea46e1e 100644 (file)
@@ -237,6 +237,11 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  PrepareForBailoutForId(BailoutId::Prologue(), NO_REGISTERS);
+  // Function register is trashed in case we bailout here. But since that
+  // could happen only when we allocate a context the value of
+  // |function_in_register_x1| is correct.
+
   // Possibly set up a local binding to the this function which is used in
   // derived constructors with super calls.
   Variable* this_function_var = scope()->this_function_var();
@@ -244,7 +249,7 @@ void FullCodeGenerator::Generate() {
     Comment cmnt(masm_, "[ This function");
     if (!function_in_register_x1) {
       __ Ldr(x1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
-      // The write barrier clobbers register again, keep is marked as such.
+      // The write barrier clobbers register again, keep it marked as such.
     }
     SetVar(this_function_var, x1, x0, x2);
   }
@@ -263,6 +268,7 @@ void FullCodeGenerator::Generate() {
     __ Bind(&check_frame_marker);
     __ Ldr(x1, MemOperand(x2, StandardFrameConstants::kMarkerOffset));
     __ Cmp(x1, Smi::FromInt(StackFrame::CONSTRUCT));
+    function_in_register_x1 = false;
 
     Label non_construct_frame, done;
 
@@ -293,6 +299,7 @@ void FullCodeGenerator::Generate() {
     __ Mov(x1, Smi::FromInt(rest_index));
     __ Mov(x0, Smi::FromInt(language_mode()));
     __ Push(x3, x2, x1, x0);
+    function_in_register_x1 = false;
 
     RestParamAccessStub stub(isolate());
     __ CallStub(&stub);
index 30351539fce77567ddb7126adad7195241c8a0db..3440868624158fbf25005efc04646f83d9909e54 100644 (file)
@@ -232,6 +232,11 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  PrepareForBailoutForId(BailoutId::Prologue(), NO_REGISTERS);
+  // Function register is trashed in case we bailout here. But since that
+  // could happen only when we allocate a context the value of
+  // |function_in_register| is correct.
+
   // Possibly set up a local binding to the this function which is used in
   // derived constructors with super calls.
   Variable* this_function_var = scope()->this_function_var();
@@ -239,7 +244,7 @@ void FullCodeGenerator::Generate() {
     Comment cmnt(masm_, "[ This function");
     if (!function_in_register) {
       __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
-      // The write barrier clobbers register again, keep is marked as such.
+      // The write barrier clobbers register again, keep it marked as such.
     }
     SetVar(this_function_var, edi, ebx, edx);
   }
index d272e67ba514d599b44749f49d51dfac206b0e36..3a296a521c9930a99cd7f3904a6570be03612c52 100644 (file)
@@ -190,7 +190,7 @@ void FullCodeGenerator::Generate() {
     }
   }
 
-  bool function_in_register = true;
+  bool function_in_register_a1 = true;
 
   // Possibly allocate a local context.
   if (info->scope()->num_heap_slots() > 0) {
@@ -211,7 +211,7 @@ void FullCodeGenerator::Generate() {
       __ push(a1);
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    function_in_register = false;
+    function_in_register_a1 = false;
     // Context is returned in v0. It replaces the context passed to us.
     // It's saved in the stack and kept live in cp.
     __ mov(cp, v0);
@@ -244,14 +244,19 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  PrepareForBailoutForId(BailoutId::Prologue(), NO_REGISTERS);
+  // Function register is trashed in case we bailout here. But since that
+  // could happen only when we allocate a context the value of
+  // |function_in_register_a1| is correct.
+
   // Possibly set up a local binding to the this function which is used in
   // derived constructors with super calls.
   Variable* this_function_var = scope()->this_function_var();
   if (this_function_var != nullptr) {
     Comment cmnt(masm_, "[ This function");
-    if (!function_in_register) {
+    if (!function_in_register_a1) {
       __ lw(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
-      // The write barrier clobbers register again, keep is marked as such.
+      // The write barrier clobbers register again, keep it marked as such.
     }
     SetVar(this_function_var, a1, a2, a3);
   }
@@ -273,6 +278,7 @@ void FullCodeGenerator::Generate() {
     // Check the marker in the calling frame.
     __ bind(&check_frame_marker);
     __ lw(a1, MemOperand(a2, StandardFrameConstants::kMarkerOffset));
+    function_in_register_a1 = false;
 
     Label non_construct_frame, done;
     __ Branch(&non_construct_frame, ne, a1,
@@ -304,6 +310,7 @@ void FullCodeGenerator::Generate() {
     __ li(a1, Operand(Smi::FromInt(rest_index)));
     __ li(a0, Operand(Smi::FromInt(language_mode())));
     __ Push(a3, a2, a1, a0);
+    function_in_register_a1 = false;
 
     RestParamAccessStub stub(isolate());
     __ CallStub(&stub);
@@ -315,7 +322,7 @@ void FullCodeGenerator::Generate() {
   if (arguments != NULL) {
     // Function uses arguments object.
     Comment cmnt(masm_, "[ Allocate arguments object");
-    if (!function_in_register) {
+    if (!function_in_register_a1) {
       // Load this again, if it's used by the local context below.
       __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
     } else {
index 9cd5117485db78308eae83fb40a0673ea6fff417..93f0735827e07bca00966ed7bc7a776da5295324 100644 (file)
@@ -187,7 +187,7 @@ void FullCodeGenerator::Generate() {
     }
   }
 
-  bool function_in_register = true;
+  bool function_in_register_a1 = true;
 
   // Possibly allocate a local context.
   if (info->scope()->num_heap_slots() > 0) {
@@ -208,7 +208,7 @@ void FullCodeGenerator::Generate() {
       __ push(a1);
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    function_in_register = false;
+    function_in_register_a1 = false;
     // Context is returned in v0. It replaces the context passed to us.
     // It's saved in the stack and kept live in cp.
     __ mov(cp, v0);
@@ -241,14 +241,19 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  PrepareForBailoutForId(BailoutId::Prologue(), NO_REGISTERS);
+  // Function register is trashed in case we bailout here. But since that
+  // could happen only when we allocate a context the value of
+  // |function_in_register_a1| is correct.
+
   // Possibly set up a local binding to the this function which is used in
   // derived constructors with super calls.
   Variable* this_function_var = scope()->this_function_var();
   if (this_function_var != nullptr) {
     Comment cmnt(masm_, "[ This function");
-    if (!function_in_register) {
+    if (!function_in_register_a1) {
       __ ld(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
-      // The write barrier clobbers register again, keep is marked as such.
+      // The write barrier clobbers register again, keep it marked as such.
     }
     SetVar(this_function_var, a1, a2, a3);
   }
@@ -269,6 +274,7 @@ void FullCodeGenerator::Generate() {
     // Check the marker in the calling frame.
     __ bind(&check_frame_marker);
     __ ld(a1, MemOperand(a2, StandardFrameConstants::kMarkerOffset));
+    function_in_register_a1 = false;
 
     Label non_construct_frame, done;
     __ Branch(&non_construct_frame, ne, a1,
@@ -300,6 +306,7 @@ void FullCodeGenerator::Generate() {
     __ li(a1, Operand(Smi::FromInt(rest_index)));
     __ li(a0, Operand(Smi::FromInt(language_mode())));
     __ Push(a3, a2, a1, a0);
+    function_in_register_a1 = false;
 
     RestParamAccessStub stub(isolate());
     __ CallStub(&stub);
@@ -311,7 +318,7 @@ void FullCodeGenerator::Generate() {
   if (arguments != NULL) {
     // Function uses arguments object.
     Comment cmnt(masm_, "[ Allocate arguments object");
-    if (!function_in_register) {
+    if (!function_in_register_a1) {
       // Load this again, if it's used by the local context below.
       __ ld(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
     } else {
@@ -346,6 +353,7 @@ void FullCodeGenerator::Generate() {
   if (FLAG_trace) {
     __ CallRuntime(Runtime::kTraceEnter, 0);
   }
+
   // Visit the declarations and body unless there is an illegal
   // redeclaration.
   if (scope()->HasIllegalRedeclaration()) {
index 0eaf7412f5967acca9b541bafe2689d0bd3504d1..4022378d41c77ca8fae568e950963c3ac3ff2ccc 100644 (file)
@@ -227,6 +227,11 @@ void FullCodeGenerator::Generate() {
     }
   }
 
+  PrepareForBailoutForId(BailoutId::Prologue(), NO_REGISTERS);
+  // Function register is trashed in case we bailout here. But since that
+  // could happen only when we allocate a context the value of
+  // |function_in_register| is correct.
+
   // Possibly set up a local binding to the this function which is used in
   // derived constructors with super calls.
   Variable* this_function_var = scope()->this_function_var();
@@ -234,7 +239,7 @@ void FullCodeGenerator::Generate() {
     Comment cmnt(masm_, "[ This function");
     if (!function_in_register) {
       __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
-      // The write barrier clobbers register again, keep is marked as such.
+      // The write barrier clobbers register again, keep it marked as such.
     }
     SetVar(this_function_var, rdi, rbx, rdx);
   }
index 1f04a15103599e6803ae054ffacc56c4c88bdd46..09f20b93f0b375597d52acb1fcc22f78c07210ba 100644 (file)
@@ -880,6 +880,7 @@ bool HInstruction::CanDeoptimize() {
     case HValue::kMul:
     case HValue::kOsrEntry:
     case HValue::kPower:
+    case HValue::kPrologue:
     case HValue::kRor:
     case HValue::kSar:
     case HValue::kSeqStringSetChar:
index b524cfb2666383f454ca8dd42aadd51f07c1e0e8..191d86b47a44e24d920036d378cf81dd4e4fba4a 100644 (file)
@@ -131,6 +131,7 @@ class LChunkBuilder;
   V(OsrEntry)                                 \
   V(Parameter)                                \
   V(Power)                                    \
+  V(Prologue)                                 \
   V(PushArguments)                            \
   V(RegExpLiteral)                            \
   V(Return)                                   \
@@ -1284,6 +1285,18 @@ class HDebugBreak final : public HTemplateInstruction<0> {
 };
 
 
+class HPrologue final : public HTemplateInstruction<0> {
+ public:
+  static HPrologue* New(Zone* zone) { return new (zone) HPrologue(); }
+
+  Representation RequiredInputRepresentation(int index) override {
+    return Representation::None();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(Prologue)
+};
+
+
 class HGoto final : public HTemplateControlInstruction<1, 0> {
  public:
   explicit HGoto(HBasicBlock* target) {
index b5c4eabf7a95010a9d94948abe36b1a1e0cb603c..9cc715c07bff81e3ba906fda6c02c221ed6d41f4 100644 (file)
@@ -3646,7 +3646,7 @@ HGraph::HGraph(CompilationInfo* info)
     start_environment_ =
         new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
   }
-  start_environment_->set_ast_id(BailoutId::FunctionEntry());
+  start_environment_->set_ast_id(BailoutId::Prologue());
   entry_block_ = CreateBasicBlock();
   entry_block_->SetInitialEnvironment(start_environment_);
 }
@@ -4408,12 +4408,6 @@ bool HOptimizedGraphBuilder::BuildGraph() {
     return false;
   }
 
-  int slots = current_info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
-  if (current_info()->scope()->is_script_scope() && slots > 0) {
-    Bailout(kScriptContext);
-    return false;
-  }
-
   Scope* scope = current_info()->scope();
   SetUpScope(scope);
 
@@ -4617,36 +4611,50 @@ HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
 
 
 void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
+  HEnvironment* prolog_env = environment();
+  int parameter_count = environment()->parameter_count();
+  ZoneList<HValue*> parameters(parameter_count, zone());
+  for (int i = 0; i < parameter_count; ++i) {
+    HInstruction* parameter = Add<HParameter>(static_cast<unsigned>(i));
+    parameters.Add(parameter, zone());
+    environment()->Bind(i, parameter);
+  }
+
+  HConstant* undefined_constant = graph()->GetConstantUndefined();
+  // Initialize specials and locals to undefined.
+  for (int i = parameter_count + 1; i < environment()->length(); ++i) {
+    environment()->Bind(i, undefined_constant);
+  }
+  Add<HPrologue>();
+
+  HEnvironment* initial_env = environment()->CopyWithoutHistory();
+  HBasicBlock* body_entry = CreateBasicBlock(initial_env);
+  GotoNoSimulate(body_entry);
+  set_current_block(body_entry);
+
+  // Initialize context of prolog environment to undefined.
+  prolog_env->BindContext(undefined_constant);
+
   // First special is HContext.
   HInstruction* context = Add<HContext>();
   environment()->BindContext(context);
 
   // Create an arguments object containing the initial parameters.  Set the
   // initial values of parameters including "this" having parameter index 0.
-  DCHECK_EQ(scope->num_parameters() + 1, environment()->parameter_count());
-  HArgumentsObject* arguments_object =
-      New<HArgumentsObject>(environment()->parameter_count());
-  for (int i = 0; i < environment()->parameter_count(); ++i) {
-    HInstruction* parameter = Add<HParameter>(i);
+  DCHECK_EQ(scope->num_parameters() + 1, parameter_count);
+  HArgumentsObject* arguments_object = New<HArgumentsObject>(parameter_count);
+  for (int i = 0; i < parameter_count; ++i) {
+    HValue* parameter = parameters.at(i);
     arguments_object->AddArgument(parameter, zone());
-    environment()->Bind(i, parameter);
   }
+
   AddInstruction(arguments_object);
   graph()->SetArgumentsObject(arguments_object);
 
-  HConstant* undefined_constant = graph()->GetConstantUndefined();
-  // Initialize specials and locals to undefined.
-  for (int i = environment()->parameter_count() + 1;
-       i < environment()->length();
-       ++i) {
-    environment()->Bind(i, undefined_constant);
-  }
-
   // Handle the arguments and arguments shadow variables specially (they do
   // not have declarations).
   if (scope->arguments() != NULL) {
-    environment()->Bind(scope->arguments(),
-                        graph()->GetArgumentsObject());
+    environment()->Bind(scope->arguments(), graph()->GetArgumentsObject());
   }
 
   int rest_index;
@@ -4659,6 +4667,11 @@ void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
       scope->new_target_var() != nullptr) {
     return Bailout(kSuperReference);
   }
+
+  // Trace the call.
+  if (FLAG_trace && top_info()->IsOptimizing()) {
+    Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kTraceEnter), 0);
+  }
 }
 
 
@@ -12996,6 +13009,12 @@ void HEnvironment::Drop(int count) {
 }
 
 
+void HEnvironment::Print() const {
+  OFStream os(stdout);
+  os << *this << "\n";
+}
+
+
 HEnvironment* HEnvironment::Copy() const {
   return new(zone()) HEnvironment(this, zone());
 }
index 4d51fd36a225c65eb402a0243c439267c88193ea..c5f35a32b6c8562bd1ecc7b62176127ea83bf0c3 100644 (file)
@@ -613,6 +613,8 @@ class HEnvironment final : public ZoneObject {
   void SetExpressionStackAt(int index_from_top, HValue* value);
   HValue* RemoveExpressionStackAt(int index_from_top);
 
+  void Print() const;
+
   HEnvironment* Copy() const;
   HEnvironment* CopyWithoutHistory() const;
   HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
@@ -2026,17 +2028,38 @@ inline HInstruction* HGraphBuilder::AddUncasted<HCallRuntime>(
 }
 
 
-template<>
-inline HContext* HGraphBuilder::New<HContext>() {
-  return HContext::New(zone());
+template <>
+inline HParameter* HGraphBuilder::New<HParameter>(unsigned index) {
+  return HParameter::New(isolate(), zone(), nullptr, index);
 }
 
 
-template<>
-inline HInstruction* HGraphBuilder::NewUncasted<HContext>() {
-  return New<HContext>();
+template <>
+inline HParameter* HGraphBuilder::New<HParameter>(
+    unsigned index, HParameter::ParameterKind kind) {
+  return HParameter::New(isolate(), zone(), nullptr, index, kind);
+}
+
+
+template <>
+inline HParameter* HGraphBuilder::New<HParameter>(
+    unsigned index, HParameter::ParameterKind kind, Representation r) {
+  return HParameter::New(isolate(), zone(), nullptr, index, kind, r);
 }
 
+
+template <>
+inline HPrologue* HGraphBuilder::New<HPrologue>() {
+  return HPrologue::New(zone());
+}
+
+
+template <>
+inline HContext* HGraphBuilder::New<HContext>() {
+  return HContext::New(zone());
+}
+
+
 class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
  public:
   // A class encapsulating (lazily-allocated) break and continue blocks for
index a74501082cffb1ea1adc406ce1093208fff1258b..e8cf3452b8b56e87a88a6159a8905f05a77a18a4 100644 (file)
@@ -248,16 +248,27 @@ bool LCodeGen::GeneratePrologue() {
 
     if (info()->saves_caller_doubles()) SaveCallerDoubles();
   }
+  return !is_aborted();
+}
+
+
+void LCodeGen::DoPrologue(LPrologue* instr) {
+  Comment(";;; Prologue begin");
 
   // Possibly allocate a local context.
-  int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
-  if (heap_slots > 0) {
+  if (info_->num_heap_slots() > 0) {
     Comment(";;; Allocate local context");
     bool need_write_barrier = true;
     // Argument to NewContext is the function, which is still in edi.
-    DCHECK(!info()->scope()->is_script_scope());
-    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
-      FastNewContextStub stub(isolate(), heap_slots);
+    int slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+    Safepoint::DeoptMode deopt_mode = Safepoint::kNoLazyDeopt;
+    if (info()->scope()->is_script_scope()) {
+      __ push(edi);
+      __ Push(info()->scope()->GetScopeInfo(info()->isolate()));
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
+      deopt_mode = Safepoint::kLazyDeopt;
+    } else if (slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(isolate(), slots);
       __ CallStub(&stub);
       // Result of FastNewContextStub is always in new space.
       need_write_barrier = false;
@@ -265,7 +276,8 @@ bool LCodeGen::GeneratePrologue() {
       __ push(edi);
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    RecordSafepoint(Safepoint::kNoLazyDeopt);
+    RecordSafepoint(deopt_mode);
+
     // Context is returned in eax.  It replaces the context passed to us.
     // It's saved in the stack and kept live in esi.
     __ mov(esi, eax);
@@ -302,13 +314,7 @@ bool LCodeGen::GeneratePrologue() {
     Comment(";;; End allocate local context");
   }
 
-  // Trace the call.
-  if (FLAG_trace && info()->IsOptimizing()) {
-    // We have not executed any compiled code yet, so esi still holds the
-    // incoming context.
-    __ CallRuntime(Runtime::kTraceEnter, 0);
-  }
-  return !is_aborted();
+  Comment(";;; Prologue end");
 }
 
 
index 598170c3e528a03e16f2cef43a3a58b82f96fd29..cc4300592c0dd9b895656d3ad3929bc40226dfcd 100644 (file)
@@ -955,7 +955,7 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
   }
   chunk_->AddInstruction(instr, current_block_);
 
-  if (instr->IsCall()) {
+  if (instr->IsCall() || instr->IsPrologue()) {
     HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
     if (hydrogen_val->HasObservableSideEffects()) {
       HSimulate* sim = HSimulate::cast(hydrogen_val->next());
@@ -969,6 +969,11 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
 }
 
 
+LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
+  return new (zone()) LPrologue();
+}
+
+
 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
   return new(zone()) LGoto(instr->FirstSuccessor());
 }
index 04634a3236c9a8b98b5b7206899c6bf80b91fe09..8c7e28c2d2b3bd1db3433874b68547e1ba27dfda 100644 (file)
@@ -133,6 +133,7 @@ class LCodeGen;
   V(OsrEntry)                                \
   V(Parameter)                               \
   V(Power)                                   \
+  V(Prologue)                                \
   V(PushArgument)                            \
   V(RegExpLiteral)                           \
   V(Return)                                  \
@@ -394,6 +395,12 @@ class LGoto final : public LTemplateInstruction<0, 0, 0> {
 };
 
 
+class LPrologue final : public LTemplateInstruction<0, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(Prologue, "prologue")
+};
+
+
 class LLazyBailout final : public LTemplateInstruction<0, 0, 0> {
  public:
   DECLARE_CONCRETE_INSTRUCTION(LazyBailout, "lazy-bailout")
index 2c25c34e0c756eddc8c3091e65f7adcf136aaf28..01ccdf7216374a7b3bbf7f06e2a4afcce13001bb 100644 (file)
@@ -190,16 +190,27 @@ bool LCodeGen::GeneratePrologue() {
   if (info()->saves_caller_doubles()) {
     SaveCallerDoubles();
   }
+  return !is_aborted();
+}
+
+
+void LCodeGen::DoPrologue(LPrologue* instr) {
+  Comment(";;; Prologue begin");
 
   // Possibly allocate a local context.
-  int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
-  if (heap_slots > 0) {
+  if (info()->scope()->num_heap_slots() > 0) {
     Comment(";;; Allocate local context");
     bool need_write_barrier = true;
     // Argument to NewContext is the function, which is in a1.
-    DCHECK(!info()->scope()->is_script_scope());
-    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
-      FastNewContextStub stub(isolate(), heap_slots);
+    int slots = info()->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+    Safepoint::DeoptMode deopt_mode = Safepoint::kNoLazyDeopt;
+    if (info()->scope()->is_script_scope()) {
+      __ push(a1);
+      __ Push(info()->scope()->GetScopeInfo(info()->isolate()));
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
+      deopt_mode = Safepoint::kLazyDeopt;
+    } else if (slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(isolate(), slots);
       __ CallStub(&stub);
       // Result of FastNewContextStub is always in new space.
       need_write_barrier = false;
@@ -207,7 +218,8 @@ bool LCodeGen::GeneratePrologue() {
       __ push(a1);
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    RecordSafepoint(Safepoint::kNoLazyDeopt);
+    RecordSafepoint(deopt_mode);
+
     // Context is returned in both v0. It replaces the context passed to us.
     // It's saved in the stack and kept live in cp.
     __ mov(cp, v0);
@@ -240,13 +252,7 @@ bool LCodeGen::GeneratePrologue() {
     Comment(";;; End allocate local context");
   }
 
-  // Trace the call.
-  if (FLAG_trace && info()->IsOptimizing()) {
-    // We have not executed any compiled code yet, so cp still holds the
-    // incoming context.
-    __ CallRuntime(Runtime::kTraceEnter, 0);
-  }
-  return !is_aborted();
+  Comment(";;; Prologue end");
 }
 
 
index 806ce3c98d191567dad4f74686776c1818a27be6..8ff2206068a205f1ffac208932bd9f87389148e3 100644 (file)
@@ -924,7 +924,7 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
   }
   chunk_->AddInstruction(instr, current_block_);
 
-  if (instr->IsCall()) {
+  if (instr->IsCall() || instr->IsPrologue()) {
     HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
     if (hydrogen_val->HasObservableSideEffects()) {
       HSimulate* sim = HSimulate::cast(hydrogen_val->next());
@@ -938,6 +938,11 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
 }
 
 
+LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
+  return new (zone()) LPrologue();
+}
+
+
 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
   return new(zone()) LGoto(instr->FirstSuccessor());
 }
index 93dd2c898d1adb33f9defdf0b507bf652ad49764..8c45ab922b8c260c07c19abc341da7ce928e997d 100644 (file)
@@ -130,6 +130,7 @@ class LCodeGen;
   V(OsrEntry)                                \
   V(Parameter)                               \
   V(Power)                                   \
+  V(Prologue)                                \
   V(PushArgument)                            \
   V(RegExpLiteral)                           \
   V(Return)                                  \
@@ -386,6 +387,12 @@ class LGoto final : public LTemplateInstruction<0, 0, 0> {
 };
 
 
+class LPrologue final : public LTemplateInstruction<0, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(Prologue, "prologue")
+};
+
+
 class LLazyBailout final : public LTemplateInstruction<0, 0, 0> {
  public:
   LLazyBailout() : gap_instructions_size_(0) { }
index 9a68b608943b699c69ae4e8db77360c9346fec13..8168d7041ba89fec13e54b38a912625ba2a2e2a7 100644 (file)
@@ -165,16 +165,27 @@ bool LCodeGen::GeneratePrologue() {
   if (info()->saves_caller_doubles()) {
     SaveCallerDoubles();
   }
+  return !is_aborted();
+}
+
+
+void LCodeGen::DoPrologue(LPrologue* instr) {
+  Comment(";;; Prologue begin");
 
   // Possibly allocate a local context.
-  int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
-  if (heap_slots > 0) {
+  if (info()->scope()->num_heap_slots() > 0) {
     Comment(";;; Allocate local context");
     bool need_write_barrier = true;
     // Argument to NewContext is the function, which is in a1.
-    DCHECK(!info()->scope()->is_script_scope());
-    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
-      FastNewContextStub stub(isolate(), heap_slots);
+    int slots = info()->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+    Safepoint::DeoptMode deopt_mode = Safepoint::kNoLazyDeopt;
+    if (info()->scope()->is_script_scope()) {
+      __ push(a1);
+      __ Push(info()->scope()->GetScopeInfo(info()->isolate()));
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
+      deopt_mode = Safepoint::kLazyDeopt;
+    } else if (slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(isolate(), slots);
       __ CallStub(&stub);
       // Result of FastNewContextStub is always in new space.
       need_write_barrier = false;
@@ -182,7 +193,8 @@ bool LCodeGen::GeneratePrologue() {
       __ push(a1);
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    RecordSafepoint(Safepoint::kNoLazyDeopt);
+    RecordSafepoint(deopt_mode);
+
     // Context is returned in both v0. It replaces the context passed to us.
     // It's saved in the stack and kept live in cp.
     __ mov(cp, v0);
@@ -215,13 +227,7 @@ bool LCodeGen::GeneratePrologue() {
     Comment(";;; End allocate local context");
   }
 
-  // Trace the call.
-  if (FLAG_trace && info()->IsOptimizing()) {
-    // We have not executed any compiled code yet, so cp still holds the
-    // incoming context.
-    __ CallRuntime(Runtime::kTraceEnter, 0);
-  }
-  return !is_aborted();
+  Comment(";;; Prologue end");
 }
 
 
index 2c7fbdff8a6617a7feacd915d7d3c01bb688393c..b00bb6240f7ab6338854043e0f6b7c0c8f573631 100644 (file)
@@ -924,7 +924,7 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
   }
   chunk_->AddInstruction(instr, current_block_);
 
-  if (instr->IsCall()) {
+  if (instr->IsCall() || instr->IsPrologue()) {
     HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
     if (hydrogen_val->HasObservableSideEffects()) {
       HSimulate* sim = HSimulate::cast(hydrogen_val->next());
@@ -938,6 +938,11 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
 }
 
 
+LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
+  return new (zone()) LPrologue();
+}
+
+
 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
   return new(zone()) LGoto(instr->FirstSuccessor());
 }
index 79beb7691712c2fdf44f1abb1e39cd0ad8aadbaf..8dae5e9dfb750e8afd179d6a77e02b819506f3ba 100644 (file)
@@ -132,6 +132,7 @@ class LCodeGen;
   V(OsrEntry)                                \
   V(Parameter)                               \
   V(Power)                                   \
+  V(Prologue)                                \
   V(PushArgument)                            \
   V(RegExpLiteral)                           \
   V(Return)                                  \
@@ -389,6 +390,12 @@ class LGoto final : public LTemplateInstruction<0, 0, 0> {
 };
 
 
+class LPrologue final : public LTemplateInstruction<0, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(Prologue, "prologue")
+};
+
+
 class LLazyBailout final : public LTemplateInstruction<0, 0, 0> {
  public:
   LLazyBailout() : gap_instructions_size_(0) { }
index 822b4b2e1edfea7c79a2d3566ab3f7b98de9e082..ef35f9696489678a74a7dcc33793343f00193eb4 100644 (file)
@@ -1084,6 +1084,7 @@ class BailoutId {
   int ToInt() const { return id_; }
 
   static BailoutId None() { return BailoutId(kNoneId); }
+  static BailoutId Prologue() { return BailoutId(kPrologueId); }
   static BailoutId FunctionEntry() { return BailoutId(kFunctionEntryId); }
   static BailoutId Declarations() { return BailoutId(kDeclarationsId); }
   static BailoutId FirstUsable() { return BailoutId(kFirstUsableId); }
@@ -1099,6 +1100,7 @@ class BailoutId {
   static const int kNoneId = -1;
 
   // Using 0 could disguise errors.
+  static const int kPrologueId = 1;
   static const int kFunctionEntryId = 2;
 
   // This AST id identifies the point after the declarations have been visited.
index c085fa058883c13ec81a9718b4a7bc08f30a6c58..4e1ac86aefcd18b8d754458b060eeea17812a23c 100644 (file)
@@ -185,16 +185,27 @@ bool LCodeGen::GeneratePrologue() {
       SaveCallerDoubles();
     }
   }
+  return !is_aborted();
+}
+
+
+void LCodeGen::DoPrologue(LPrologue* instr) {
+  Comment(";;; Prologue begin");
 
   // Possibly allocate a local context.
-  int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
-  if (heap_slots > 0) {
+  if (info_->num_heap_slots() > 0) {
     Comment(";;; Allocate local context");
     bool need_write_barrier = true;
     // Argument to NewContext is the function, which is still in rdi.
-    DCHECK(!info()->scope()->is_script_scope());
-    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
-      FastNewContextStub stub(isolate(), heap_slots);
+    int slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+    Safepoint::DeoptMode deopt_mode = Safepoint::kNoLazyDeopt;
+    if (info()->scope()->is_script_scope()) {
+      __ Push(rdi);
+      __ Push(info()->scope()->GetScopeInfo(info()->isolate()));
+      __ CallRuntime(Runtime::kNewScriptContext, 2);
+      deopt_mode = Safepoint::kLazyDeopt;
+    } else if (slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(isolate(), slots);
       __ CallStub(&stub);
       // Result of FastNewContextStub is always in new space.
       need_write_barrier = false;
@@ -202,7 +213,8 @@ bool LCodeGen::GeneratePrologue() {
       __ Push(rdi);
       __ CallRuntime(Runtime::kNewFunctionContext, 1);
     }
-    RecordSafepoint(Safepoint::kNoLazyDeopt);
+    RecordSafepoint(deopt_mode);
+
     // Context is returned in rax.  It replaces the context passed to us.
     // It's saved in the stack and kept live in rsi.
     __ movp(rsi, rax);
@@ -235,11 +247,7 @@ bool LCodeGen::GeneratePrologue() {
     Comment(";;; End allocate local context");
   }
 
-  // Trace the call.
-  if (FLAG_trace && info()->IsOptimizing()) {
-    __ CallRuntime(Runtime::kTraceEnter, 0);
-  }
-  return !is_aborted();
+  Comment(";;; Prologue end");
 }
 
 
index 382c11ce8626d43817b539c7a20418b46104c83f..c8954ba2c68db6863539237c7f51815a36f8cfcf 100644 (file)
@@ -938,7 +938,7 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
   }
   chunk_->AddInstruction(instr, current_block_);
 
-  if (instr->IsCall()) {
+  if (instr->IsCall() || instr->IsPrologue()) {
     HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
     if (hydrogen_val->HasObservableSideEffects()) {
       HSimulate* sim = HSimulate::cast(hydrogen_val->next());
@@ -957,6 +957,11 @@ LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
 }
 
 
+LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
+  return new (zone()) LPrologue();
+}
+
+
 LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
   return new(zone()) LDebugBreak();
 }
index e66acc0b647c93562a56a9264f287419bdffc199..c46f5ac703224207cb2e0b8fd0edeceaf96abc0c 100644 (file)
@@ -129,6 +129,7 @@ class LCodeGen;
   V(OsrEntry)                                \
   V(Parameter)                               \
   V(Power)                                   \
+  V(Prologue)                                \
   V(PushArgument)                            \
   V(RegExpLiteral)                           \
   V(Return)                                  \
@@ -393,6 +394,12 @@ class LGoto final : public LTemplateInstruction<0, 0, 0> {
 };
 
 
+class LPrologue final : public LTemplateInstruction<0, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(Prologue, "prologue")
+};
+
+
 class LLazyBailout final : public LTemplateInstruction<0, 0, 0> {
  public:
   LLazyBailout() : gap_instructions_size_(0) { }