Fix lazy deopt after tagged binary ops

Also add policing code to ensure that optimized frames can in fact lazily deopt
at their respective current PC when we patch them for lazy bailout.

BUG=chromium:350434
LOG=y
R=jarin@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19834 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
jkummerow@chromium.org 2014-03-12 09:59:36 +00:00
parent 25468478e3
commit 8a1812f252
25 changed files with 209 additions and 151 deletions

View File

@ -506,15 +506,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
instr->MarkAsCall();
instr = AssignPointerMap(instr);
if (hinstr->HasObservableSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
ASSERT(instruction_pending_deoptimization_environment_ == NULL);
ASSERT(pending_deoptimization_ast_id_.IsNone());
instruction_pending_deoptimization_environment_ = instr;
pending_deoptimization_ast_id_ = sim->ast_id();
}
// If instruction does not have side-effects lazy deoptimization
// after the call will try to deoptimize to the point before the call.
// Thus we still need to attach environment to this call even if
@ -736,6 +727,26 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
instr = AssignEnvironment(instr);
}
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HValue* hydrogen_value_for_lazy_bailout = current;
LInstruction* instruction_needing_environment = NULL;
if (current->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(current->next());
instruction_needing_environment = instr;
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
if (instruction_needing_environment != NULL) {
// Store the lazy deopt environment with the instruction if needed.
// Right now it is only used for LInstanceOfKnownGlobal.
instruction_needing_environment->
SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
}
}
}
current_instruction_ = old_current;
}
@ -2106,21 +2117,6 @@ LInstruction* LChunkBuilder::DoShr(HShr* instr) {
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
instr->ReplayEnvironment(current_block_->last_environment());
// If there is an instruction pending deoptimization environment create a
// lazy bailout instruction to capture the environment.
if (pending_deoptimization_ast_id_ == instr->ast_id()) {
LInstruction* result = new(zone()) LLazyBailout;
result = AssignEnvironment(result);
// Store the lazy deopt environment with the instruction if needed. Right
// now it is only used for LInstanceOfKnownGlobal.
instruction_pending_deoptimization_environment_->
SetDeferredLazyDeoptimizationEnvironment(result->environment());
instruction_pending_deoptimization_environment_ = NULL;
pending_deoptimization_ast_id_ = BailoutId::None();
return result;
}
return NULL;
}

View File

@ -2976,9 +2976,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
status_(UNUSED),
current_instruction_(NULL),
current_block_(NULL),
allocator_(allocator),
instruction_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(BailoutId::None()) { }
allocator_(allocator) { }
// Build the sequence for the graph.
LPlatformChunk* Build();
@ -3115,8 +3113,6 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
HInstruction* current_instruction_;
HBasicBlock* current_block_;
LAllocator* allocator_;
LInstruction* instruction_pending_deoptimization_environment_;
BailoutId pending_deoptimization_ast_id_;
DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
};

View File

@ -771,6 +771,13 @@ void LCodeGen::GenerateOsrPrologue() {
}
void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
if (!instr->IsLazyBailout() && !instr->IsGap()) {
safepoints_.BumpLastLazySafepointIndex();
}
}
bool LCodeGen::GenerateDeferredCode() {
ASSERT(is_generating());
if (deferred_.length() > 0) {

View File

@ -276,6 +276,7 @@ class LCodeGen: public LCodeGenBase {
void RestoreCallerDoubles();
// Code generation steps. Returns true if code generation should continue.
void GenerateBodyInstructionPre(LInstruction* instr) V8_OVERRIDE;
bool GeneratePrologue();
bool GenerateDeferredCode();
bool GenerateDeoptJumpTable();

View File

@ -614,15 +614,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
instr->MarkAsCall();
instr = AssignPointerMap(instr);
if (hinstr->HasObservableSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
ASSERT(instruction_pending_deoptimization_environment_ == NULL);
ASSERT(pending_deoptimization_ast_id_.IsNone());
instruction_pending_deoptimization_environment_ = instr;
pending_deoptimization_ast_id_ = sim->ast_id();
}
// If instruction does not have side-effects lazy deoptimization
// after the call will try to deoptimize to the point before the call.
// Thus we still need to attach environment to this call even if
@ -905,6 +896,26 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
instr = AssignEnvironment(instr);
}
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HValue* hydrogen_value_for_lazy_bailout = current;
LInstruction* instruction_needing_environment = NULL;
if (current->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(current->next());
instruction_needing_environment = instr;
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
if (instruction_needing_environment != NULL) {
// Store the lazy deopt environment with the instruction if needed.
// Right now it is only used for LInstanceOfKnownGlobal.
instruction_needing_environment->
SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
}
}
}
current_instruction_ = old_current;
}
@ -2445,21 +2456,6 @@ LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
instr->ReplayEnvironment(current_block_->last_environment());
// If there is an instruction pending deoptimization environment create a
// lazy bailout instruction to capture the environment.
if (pending_deoptimization_ast_id_ == instr->ast_id()) {
LInstruction* result = new(zone()) LLazyBailout;
result = AssignEnvironment(result);
// Store the lazy deopt environment with the instruction if needed. Right
// now it is only used for LInstanceOfKnownGlobal.
instruction_pending_deoptimization_environment_->
SetDeferredLazyDeoptimizationEnvironment(result->environment());
instruction_pending_deoptimization_environment_ = NULL;
pending_deoptimization_ast_id_ = BailoutId::None();
return result;
}
return NULL;
}

View File

@ -2720,9 +2720,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
current_instruction_(NULL),
current_block_(NULL),
next_block_(NULL),
allocator_(allocator),
instruction_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(BailoutId::None()) { }
allocator_(allocator) { }
// Build the sequence for the graph.
LPlatformChunk* Build();
@ -2866,8 +2864,6 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
HBasicBlock* current_block_;
HBasicBlock* next_block_;
LAllocator* allocator_;
LInstruction* instruction_pending_deoptimization_environment_;
BailoutId pending_deoptimization_ast_id_;
DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
};

View File

@ -269,6 +269,13 @@ void LCodeGen::GenerateOsrPrologue() {
}
void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
if (!instr->IsLazyBailout() && !instr->IsGap()) {
safepoints_.BumpLastLazySafepointIndex();
}
}
bool LCodeGen::GenerateDeferredCode() {
ASSERT(is_generating());
if (deferred_.length() > 0) {
@ -2066,7 +2073,6 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
// is in the correct position.
Assembler::BlockConstPoolScope block_const_pool(masm());
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
__ nop(); // Signals no inlined code.
}

View File

@ -191,6 +191,7 @@ class LCodeGen: public LCodeGenBase {
// Code generation passes. Returns true if code generation should
// continue.
void GenerateBodyInstructionPre(LInstruction* instr) V8_OVERRIDE;
bool GeneratePrologue();
bool GenerateDeferredCode();
bool GenerateDeoptJumpTable();

View File

@ -392,9 +392,33 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
element = next;
}
#ifdef DEBUG
// Make sure all activations of optimized code can deopt at their current PC.
for (StackFrameIterator it(isolate, isolate->thread_local_top());
!it.done(); it.Advance()) {
StackFrame::Type type = it.frame()->type();
if (type == StackFrame::OPTIMIZED) {
Code* code = it.frame()->LookupCode();
if (FLAG_trace_deopt) {
JSFunction* function =
static_cast<OptimizedFrame*>(it.frame())->function();
CodeTracer::Scope scope(isolate->GetCodeTracer());
PrintF(scope.file(), "[deoptimizer patches for lazy deopt: ");
function->PrintName(scope.file());
PrintF(scope.file(),
" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
}
SafepointEntry safepoint = code->GetSafepointEntry(it.frame()->pc());
int deopt_index = safepoint.deoptimization_index();
CHECK(deopt_index != Safepoint::kNoDeoptimizationIndex);
}
}
#endif
// TODO(titzer): we need a handle scope only because of the macro assembler,
// which is only used in EnsureCodeForDeoptimizationEntry.
HandleScope scope(isolate);
// Now patch all the codes for deoptimization.
for (int i = 0; i < codes.length(); i++) {
// It is finally time to die, code object.

View File

@ -614,6 +614,9 @@ void Heap::GarbageCollectionEpilogue() {
if (FLAG_code_stats) ReportCodeStatistics("After GC");
#endif
if (FLAG_deopt_every_n_garbage_collections > 0) {
// TODO(jkummerow/ulan/jarin): This is not safe! We can't assume that
// the topmost optimized frame can be deoptimized safely, because it
// might not have a lazy bailout point right after its current PC.
if (++gcs_since_last_deopt_ == FLAG_deopt_every_n_garbage_collections) {
Deoptimizer::DeoptimizeAll(isolate());
gcs_since_last_deopt_ = 0;

View File

@ -2470,6 +2470,7 @@ void HSimulate::PrintDataTo(StringStream* stream) {
void HSimulate::ReplayEnvironment(HEnvironment* env) {
if (done_with_replay_) return;
ASSERT(env != NULL);
env->set_ast_id(ast_id());
env->Drop(pop_count());
@ -2481,6 +2482,7 @@ void HSimulate::ReplayEnvironment(HEnvironment* env) {
env->Push(value);
}
}
done_with_replay_ = true;
}

View File

@ -1877,7 +1877,8 @@ class HSimulate V8_FINAL : public HInstruction {
values_(2, zone),
assigned_indexes_(2, zone),
zone_(zone),
removable_(removable) {}
removable_(removable),
done_with_replay_(false) {}
~HSimulate() {}
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
@ -1960,7 +1961,8 @@ class HSimulate V8_FINAL : public HInstruction {
ZoneList<HValue*> values_;
ZoneList<int> assigned_indexes_;
Zone* zone_;
RemovableSimulate removable_;
RemovableSimulate removable_ : 2;
bool done_with_replay_ : 1;
#ifdef DEBUG
Handle<JSFunction> closure_;

View File

@ -390,6 +390,9 @@ void LCodeGen::GenerateOsrPrologue() {
void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
if (!instr->IsLazyBailout() && !instr->IsGap()) {
safepoints_.BumpLastLazySafepointIndex();
}
if (!CpuFeatures::IsSupported(SSE2)) FlushX87StackIfNecessary(instr);
}
@ -2285,7 +2288,6 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
__ nop(); // Signals no inlined code.
}

View File

@ -679,15 +679,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
instr->MarkAsCall();
instr = AssignPointerMap(instr);
if (hinstr->HasObservableSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
ASSERT(instruction_pending_deoptimization_environment_ == NULL);
ASSERT(pending_deoptimization_ast_id_.IsNone());
instruction_pending_deoptimization_environment_ = instr;
pending_deoptimization_ast_id_ = sim->ast_id();
}
// If instruction does not have side-effects lazy deoptimization
// after the call will try to deoptimize to the point before the call.
// Thus we still need to attach environment to this call even if
@ -980,6 +971,26 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
chunk_->AddInstruction(clobber, current_block_);
}
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HValue* hydrogen_value_for_lazy_bailout = current;
LInstruction* instruction_needing_environment = NULL;
if (current->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(current->next());
instruction_needing_environment = instr;
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
if (instruction_needing_environment != NULL) {
// Store the lazy deopt environment with the instruction if needed.
// Right now it is only used for LInstanceOfKnownGlobal.
instruction_needing_environment->
SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
}
}
}
current_instruction_ = old_current;
}
@ -2585,22 +2596,6 @@ LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
instr->ReplayEnvironment(current_block_->last_environment());
// If there is an instruction pending deoptimization environment create a
// lazy bailout instruction to capture the environment.
if (!pending_deoptimization_ast_id_.IsNone()) {
ASSERT(pending_deoptimization_ast_id_ == instr->ast_id());
LLazyBailout* lazy_bailout = new(zone()) LLazyBailout;
LInstruction* result = AssignEnvironment(lazy_bailout);
// Store the lazy deopt environment with the instruction if needed. Right
// now it is only used for LInstanceOfKnownGlobal.
instruction_pending_deoptimization_environment_->
SetDeferredLazyDeoptimizationEnvironment(result->environment());
instruction_pending_deoptimization_environment_ = NULL;
pending_deoptimization_ast_id_ = BailoutId::None();
return result;
}
return NULL;
}

View File

@ -2752,9 +2752,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
current_instruction_(NULL),
current_block_(NULL),
next_block_(NULL),
allocator_(allocator),
instruction_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(BailoutId::None()) { }
allocator_(allocator) { }
// Build the sequence for the graph.
LPlatformChunk* Build();
@ -2906,8 +2904,6 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
HBasicBlock* current_block_;
HBasicBlock* next_block_;
LAllocator* allocator_;
LInstruction* instruction_pending_deoptimization_environment_;
BailoutId pending_deoptimization_ast_id_;
DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
};

View File

@ -259,6 +259,13 @@ void LCodeGen::GenerateOsrPrologue() {
}
void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
if (!instr->IsLazyBailout() && !instr->IsGap()) {
safepoints_.BumpLastLazySafepointIndex();
}
}
bool LCodeGen::GenerateDeferredCode() {
ASSERT(is_generating());
if (deferred_.length() > 0) {

View File

@ -191,6 +191,7 @@ class LCodeGen: public LCodeGenBase {
// Code generation passes. Returns true if code generation should
// continue.
void GenerateBodyInstructionPre(LInstruction* instr) V8_OVERRIDE;
bool GeneratePrologue();
bool GenerateDeferredCode();
bool GenerateDeoptJumpTable();

View File

@ -619,15 +619,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
instr->MarkAsCall();
instr = AssignPointerMap(instr);
if (hinstr->HasObservableSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
ASSERT(instruction_pending_deoptimization_environment_ == NULL);
ASSERT(pending_deoptimization_ast_id_.IsNone());
instruction_pending_deoptimization_environment_ = instr;
pending_deoptimization_ast_id_ = sim->ast_id();
}
// If instruction does not have side-effects lazy deoptimization
// after the call will try to deoptimize to the point before the call.
// Thus we still need to attach environment to this call even if
@ -913,6 +904,26 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
instr = AssignEnvironment(instr);
}
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HValue* hydrogen_value_for_lazy_bailout = current;
LInstruction* instruction_needing_environment = NULL;
if (current->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(current->next());
instruction_needing_environment = instr;
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
if (instruction_needing_environment != NULL) {
// Store the lazy deopt environment with the instruction if needed.
// Right now it is only used for LInstanceOfKnownGlobal.
instruction_needing_environment->
SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
}
}
}
current_instruction_ = old_current;
}
@ -2347,21 +2358,6 @@ LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
instr->ReplayEnvironment(current_block_->last_environment());
// If there is an instruction pending deoptimization environment create a
// lazy bailout instruction to capture the environment.
if (pending_deoptimization_ast_id_ == instr->ast_id()) {
LInstruction* result = new(zone()) LLazyBailout;
result = AssignEnvironment(result);
// Store the lazy deopt environment with the instruction if needed. Right
// now it is only used for LInstanceOfKnownGlobal.
instruction_pending_deoptimization_environment_->
SetDeferredLazyDeoptimizationEnvironment(result->environment());
instruction_pending_deoptimization_environment_ = NULL;
pending_deoptimization_ast_id_ = BailoutId::None();
return result;
}
return NULL;
}

View File

@ -2642,9 +2642,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
current_instruction_(NULL),
current_block_(NULL),
next_block_(NULL),
allocator_(allocator),
instruction_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(BailoutId::None()) { }
allocator_(allocator) { }
// Build the sequence for the graph.
LPlatformChunk* Build();
@ -2784,8 +2782,6 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
HBasicBlock* current_block_;
HBasicBlock* next_block_;
LAllocator* allocator_;
LInstruction* instruction_pending_deoptimization_environment_;
BailoutId pending_deoptimization_ast_id_;
DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
};

View File

@ -219,6 +219,9 @@ class SafepointTableBuilder BASE_EMBEDDED {
// Record deoptimization index for lazy deoptimization for the last
// outstanding safepoints.
void RecordLazyDeoptimizationIndex(int index);
void BumpLastLazySafepointIndex() {
last_lazy_safepoint_ = deopt_index_list_.length();
}
// Emit the safepoint table after the body. The number of bits per
// entry must be enough to hold all the pointer indexes.

View File

@ -273,6 +273,13 @@ void LCodeGen::GenerateOsrPrologue() {
}
void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
if (!instr->IsLazyBailout() && !instr->IsGap()) {
safepoints_.BumpLastLazySafepointIndex();
}
}
bool LCodeGen::GenerateJumpTable() {
Label needs_frame;
if (jump_table_.length() > 0) {
@ -1900,7 +1907,6 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
__ nop(); // Signals no inlined code.
}

View File

@ -157,6 +157,7 @@ class LCodeGen: public LCodeGenBase {
// Code generation passes. Returns true if code generation should
// continue.
void GenerateBodyInstructionPre(LInstruction* instr) V8_OVERRIDE;
bool GeneratePrologue();
bool GenerateDeferredCode();
bool GenerateJumpTable();

View File

@ -630,15 +630,6 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
instr->MarkAsCall();
instr = AssignPointerMap(instr);
if (hinstr->HasObservableSideEffects()) {
ASSERT(hinstr->next()->IsSimulate());
HSimulate* sim = HSimulate::cast(hinstr->next());
ASSERT(instruction_pending_deoptimization_environment_ == NULL);
ASSERT(pending_deoptimization_ast_id_.IsNone());
instruction_pending_deoptimization_environment_ = instr;
pending_deoptimization_ast_id_ = sim->ast_id();
}
// If instruction does not have side-effects lazy deoptimization
// after the call will try to deoptimize to the point before the call.
// Thus we still need to attach environment to this call even if
@ -916,6 +907,26 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
instr = AssignEnvironment(instr);
}
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HValue* hydrogen_value_for_lazy_bailout = current;
LInstruction* instruction_needing_environment = NULL;
if (current->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(current->next());
instruction_needing_environment = instr;
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
if (instruction_needing_environment != NULL) {
// Store the lazy deopt environment with the instruction if needed.
// Right now it is only used for LInstanceOfKnownGlobal.
instruction_needing_environment->
SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
}
}
}
current_instruction_ = old_current;
}
@ -2435,21 +2446,6 @@ LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
instr->ReplayEnvironment(current_block_->last_environment());
// If there is an instruction pending deoptimization environment create a
// lazy bailout instruction to capture the environment.
if (pending_deoptimization_ast_id_ == instr->ast_id()) {
LLazyBailout* lazy_bailout = new(zone()) LLazyBailout;
LInstruction* result = AssignEnvironment(lazy_bailout);
// Store the lazy deopt environment with the instruction if needed. Right
// now it is only used for LInstanceOfKnownGlobal.
instruction_pending_deoptimization_environment_->
SetDeferredLazyDeoptimizationEnvironment(result->environment());
instruction_pending_deoptimization_environment_ = NULL;
pending_deoptimization_ast_id_ = BailoutId::None();
return result;
}
return NULL;
}

View File

@ -2666,9 +2666,7 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
current_instruction_(NULL),
current_block_(NULL),
next_block_(NULL),
allocator_(allocator),
instruction_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(BailoutId::None()) { }
allocator_(allocator) { }
// Build the sequence for the graph.
LPlatformChunk* Build();
@ -2813,8 +2811,6 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
HBasicBlock* current_block_;
HBasicBlock* next_block_;
LAllocator* allocator_;
LInstruction* instruction_pending_deoptimization_environment_;
BailoutId pending_deoptimization_ast_id_;
DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
};

View File

@ -0,0 +1,33 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --gc-global --noincremental-marking --allow-natives-syntax
function Ctor() {
this.foo = 1;
}
var o = new Ctor();
var p = new Ctor();
function crash(o, timeout) {
var s = "4000111222"; // Outside Smi range.
%SetAllocationTimeout(100000, timeout);
// This allocates a heap number, causing a GC, triggering lazy deopt.
var end = s >>> 0;
s = s.substring(0, end);
// This creates a map dependency, which gives the GC a reason to trigger
// a lazy deopt when that map dies.
o.bar = 2;
}
crash(o, 100000);
crash(o, 100000);
crash(p, 100000);
%OptimizeFunctionOnNextCall(crash);
crash(o, 100000);
o = null;
p = null;
crash({}, 0);