From 29ebcc32052d486cbc1933ac4738aa5cb68aa851 Mon Sep 17 00:00:00 2001 From: ishell Date: Tue, 1 Sep 2015 00:06:49 -0700 Subject: [PATCH] Crankshaft is now able to compile top level code even if there is a ScriptContext. 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} --- src/arm/lithium-arm.cc | 7 +- src/arm/lithium-arm.h | 7 ++ src/arm/lithium-codegen-arm.cc | 32 +++++---- src/arm64/lithium-arm64.cc | 7 +- src/arm64/lithium-arm64.h | 7 ++ src/arm64/lithium-codegen-arm64.cc | 32 +++++---- src/bootstrapper.cc | 4 +- src/compiler/ast-graph-builder.cc | 2 +- src/contexts.cc | 4 +- src/contexts.h | 6 +- src/full-codegen/arm/full-codegen-arm.cc | 18 +++-- src/full-codegen/arm64/full-codegen-arm64.cc | 9 ++- src/full-codegen/ia32/full-codegen-ia32.cc | 7 +- src/full-codegen/mips/full-codegen-mips.cc | 17 +++-- .../mips64/full-codegen-mips64.cc | 18 +++-- src/full-codegen/x64/full-codegen-x64.cc | 7 +- src/hydrogen-instructions.cc | 1 + src/hydrogen-instructions.h | 13 ++++ src/hydrogen.cc | 65 ++++++++++++------- src/hydrogen.h | 35 ++++++++-- src/ia32/lithium-codegen-ia32.cc | 32 +++++---- src/ia32/lithium-ia32.cc | 7 +- src/ia32/lithium-ia32.h | 7 ++ src/mips/lithium-codegen-mips.cc | 32 +++++---- src/mips/lithium-mips.cc | 7 +- src/mips/lithium-mips.h | 7 ++ src/mips64/lithium-codegen-mips64.cc | 32 +++++---- src/mips64/lithium-mips64.cc | 7 +- src/mips64/lithium-mips64.h | 7 ++ src/utils.h | 2 + src/x64/lithium-codegen-x64.cc | 30 +++++---- src/x64/lithium-x64.cc | 7 +- src/x64/lithium-x64.h | 7 ++ 33 files changed, 344 insertions(+), 138 deletions(-) diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index ec58f8d67..0504fa13f 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -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()); } diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index b6fc2e6ca..acd5c207e 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -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) { } diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index f26f0ce99..fb1d84a16 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -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"); } diff --git a/src/arm64/lithium-arm64.cc b/src/arm64/lithium-arm64.cc index 1db7d6b4b..bdf49bfff 100644 --- a/src/arm64/lithium-arm64.cc +++ b/src/arm64/lithium-arm64.cc @@ -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. diff --git a/src/arm64/lithium-arm64.h b/src/arm64/lithium-arm64.h index bdc622c4e..159e60cc5 100644 --- a/src/arm64/lithium-arm64.h +++ b/src/arm64/lithium-arm64.h @@ -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) { } diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index 7ed95ed9a..b317900a7 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -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"); } diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 06bd12512..0cd277987 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -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(); } diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index b383786e6..10abec7b8 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -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; } diff --git a/src/contexts.cc b/src/contexts.cc index 37021ac7f..d66a33043 100644 --- a/src/contexts.cc +++ b/src/contexts.cc @@ -18,7 +18,7 @@ Handle 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 copy = @@ -31,7 +31,7 @@ Handle 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; } diff --git a/src/contexts.h b/src/contexts.h index 05bc3b55e..4e4dd2c8e 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -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 GetContext(Handle table, int i) { DCHECK(i < table->used()); - return Handle::cast(FixedArray::get(table, i + 1)); + return Handle::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); }; diff --git a/src/full-codegen/arm/full-codegen-arm.cc b/src/full-codegen/arm/full-codegen-arm.cc index c238860d0..8840ee57d 100644 --- a/src/full-codegen/arm/full-codegen-arm.cc +++ b/src/full-codegen/arm/full-codegen-arm.cc @@ -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); } diff --git a/src/full-codegen/arm64/full-codegen-arm64.cc b/src/full-codegen/arm64/full-codegen-arm64.cc index ea560b411..5a2834d9b 100644 --- a/src/full-codegen/arm64/full-codegen-arm64.cc +++ b/src/full-codegen/arm64/full-codegen-arm64.cc @@ -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); diff --git a/src/full-codegen/ia32/full-codegen-ia32.cc b/src/full-codegen/ia32/full-codegen-ia32.cc index 30351539f..344086862 100644 --- a/src/full-codegen/ia32/full-codegen-ia32.cc +++ b/src/full-codegen/ia32/full-codegen-ia32.cc @@ -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); } diff --git a/src/full-codegen/mips/full-codegen-mips.cc b/src/full-codegen/mips/full-codegen-mips.cc index d272e67ba..3a296a521 100644 --- a/src/full-codegen/mips/full-codegen-mips.cc +++ b/src/full-codegen/mips/full-codegen-mips.cc @@ -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 { diff --git a/src/full-codegen/mips64/full-codegen-mips64.cc b/src/full-codegen/mips64/full-codegen-mips64.cc index 9cd511748..93f073582 100644 --- a/src/full-codegen/mips64/full-codegen-mips64.cc +++ b/src/full-codegen/mips64/full-codegen-mips64.cc @@ -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()) { diff --git a/src/full-codegen/x64/full-codegen-x64.cc b/src/full-codegen/x64/full-codegen-x64.cc index 0eaf7412f..4022378d4 100644 --- a/src/full-codegen/x64/full-codegen-x64.cc +++ b/src/full-codegen/x64/full-codegen-x64.cc @@ -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); } diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index 1f04a1510..09f20b93f 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -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: diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index b524cfb26..191d86b47 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -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) { diff --git a/src/hydrogen.cc b/src/hydrogen.cc index b5c4eabf7..9cc715c07 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -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 parameters(parameter_count, zone()); + for (int i = 0; i < parameter_count; ++i) { + HInstruction* parameter = Add(static_cast(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(); + + 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(); 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(environment()->parameter_count()); - for (int i = 0; i < environment()->parameter_count(); ++i) { - HInstruction* parameter = Add(i); + DCHECK_EQ(scope->num_parameters() + 1, parameter_count); + HArgumentsObject* arguments_object = New(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(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()); } diff --git a/src/hydrogen.h b/src/hydrogen.h index 4d51fd36a..c5f35a32b 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -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( } -template<> -inline HContext* HGraphBuilder::New() { - return HContext::New(zone()); +template <> +inline HParameter* HGraphBuilder::New(unsigned index) { + return HParameter::New(isolate(), zone(), nullptr, index); } -template<> -inline HInstruction* HGraphBuilder::NewUncasted() { - return New(); +template <> +inline HParameter* HGraphBuilder::New( + unsigned index, HParameter::ParameterKind kind) { + return HParameter::New(isolate(), zone(), nullptr, index, kind); +} + + +template <> +inline HParameter* HGraphBuilder::New( + unsigned index, HParameter::ParameterKind kind, Representation r) { + return HParameter::New(isolate(), zone(), nullptr, index, kind, r); } + +template <> +inline HPrologue* HGraphBuilder::New() { + return HPrologue::New(zone()); +} + + +template <> +inline HContext* HGraphBuilder::New() { + return HContext::New(zone()); +} + + class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { public: // A class encapsulating (lazily-allocated) break and continue blocks for diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index a74501082..e8cf3452b 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -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"); } diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 598170c3e..cc4300592 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -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()); } diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 04634a323..8c7e28c2d 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -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") diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 2c25c34e0..01ccdf721 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -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"); } diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index 806ce3c98..8ff220606 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -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()); } diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h index 93dd2c898..8c45ab922 100644 --- a/src/mips/lithium-mips.h +++ b/src/mips/lithium-mips.h @@ -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) { } diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc index 9a68b6089..8168d7041 100644 --- a/src/mips64/lithium-codegen-mips64.cc +++ b/src/mips64/lithium-codegen-mips64.cc @@ -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"); } diff --git a/src/mips64/lithium-mips64.cc b/src/mips64/lithium-mips64.cc index 2c7fbdff8..b00bb6240 100644 --- a/src/mips64/lithium-mips64.cc +++ b/src/mips64/lithium-mips64.cc @@ -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()); } diff --git a/src/mips64/lithium-mips64.h b/src/mips64/lithium-mips64.h index 79beb7691..8dae5e9df 100644 --- a/src/mips64/lithium-mips64.h +++ b/src/mips64/lithium-mips64.h @@ -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) { } diff --git a/src/utils.h b/src/utils.h index 822b4b2e1..ef35f9696 100644 --- a/src/utils.h +++ b/src/utils.h @@ -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. diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index c085fa058..4e1ac86ae 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -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"); } diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index 382c11ce8..c8954ba2c 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -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(); } diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index e66acc0b6..c46f5ac70 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -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) { } -- 2.34.1