Fix deoptimization bug, where recursive call can frighten and confuse the unwitting, simple, poor caveman that is Runtime_NotifyDeoptimized.
BUG=274164 R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/23201016 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16273 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
6d137c3f50
commit
6f3169e571
@ -166,7 +166,9 @@ class Deoptimizer : public Malloced {
|
|||||||
|
|
||||||
int output_count() const { return output_count_; }
|
int output_count() const { return output_count_; }
|
||||||
|
|
||||||
Code::Kind compiled_code_kind() const { return compiled_code_->kind(); }
|
Handle<JSFunction> function() const { return Handle<JSFunction>(function_); }
|
||||||
|
Handle<Code> compiled_code() const { return Handle<Code>(compiled_code_); }
|
||||||
|
BailoutType bailout_type() const { return bailout_type_; }
|
||||||
|
|
||||||
// Number of created JS frames. Not all created frames are necessarily JS.
|
// Number of created JS frames. Not all created frames are necessarily JS.
|
||||||
int jsframe_count() const { return jsframe_count_; }
|
int jsframe_count() const { return jsframe_count_; }
|
||||||
|
@ -8292,26 +8292,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InstallRecompiledCode) {
|
|||||||
|
|
||||||
class ActivationsFinder : public ThreadVisitor {
|
class ActivationsFinder : public ThreadVisitor {
|
||||||
public:
|
public:
|
||||||
explicit ActivationsFinder(JSFunction* function)
|
Code* code_;
|
||||||
: function_(function), has_activations_(false) {}
|
bool has_code_activations_;
|
||||||
|
|
||||||
|
explicit ActivationsFinder(Code* code)
|
||||||
|
: code_(code),
|
||||||
|
has_code_activations_(false) { }
|
||||||
|
|
||||||
void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
|
void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
|
||||||
if (has_activations_) return;
|
JavaScriptFrameIterator it(isolate, top);
|
||||||
|
VisitFrames(&it);
|
||||||
for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
|
|
||||||
JavaScriptFrame* frame = it.frame();
|
|
||||||
if (frame->is_optimized() && frame->function() == function_) {
|
|
||||||
has_activations_ = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_activations() { return has_activations_; }
|
void VisitFrames(JavaScriptFrameIterator* it) {
|
||||||
|
for (; !it->done(); it->Advance()) {
|
||||||
private:
|
JavaScriptFrame* frame = it->frame();
|
||||||
JSFunction* function_;
|
if (code_->contains(frame->pc())) has_code_activations_ = true;
|
||||||
bool has_activations_;
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -8334,7 +8332,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
|
|||||||
Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
|
Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
|
||||||
ASSERT(AllowHeapAllocation::IsAllowed());
|
ASSERT(AllowHeapAllocation::IsAllowed());
|
||||||
|
|
||||||
ASSERT(deoptimizer->compiled_code_kind() == Code::OPTIMIZED_FUNCTION);
|
Handle<JSFunction> function = deoptimizer->function();
|
||||||
|
Handle<Code> optimized_code = deoptimizer->compiled_code();
|
||||||
|
|
||||||
|
ASSERT(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
|
||||||
|
ASSERT(type == deoptimizer->bailout_type());
|
||||||
|
|
||||||
// Make sure to materialize objects before causing any allocation.
|
// Make sure to materialize objects before causing any allocation.
|
||||||
JavaScriptFrameIterator it(isolate);
|
JavaScriptFrameIterator it(isolate);
|
||||||
@ -8343,10 +8345,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
|
|||||||
|
|
||||||
JavaScriptFrame* frame = it.frame();
|
JavaScriptFrame* frame = it.frame();
|
||||||
RUNTIME_ASSERT(frame->function()->IsJSFunction());
|
RUNTIME_ASSERT(frame->function()->IsJSFunction());
|
||||||
Handle<JSFunction> function(frame->function(), isolate);
|
|
||||||
Handle<Code> optimized_code(function->code());
|
|
||||||
RUNTIME_ASSERT((type != Deoptimizer::EAGER &&
|
|
||||||
type != Deoptimizer::SOFT) || function->IsOptimized());
|
|
||||||
|
|
||||||
// Avoid doing too much work when running with --always-opt and keep
|
// Avoid doing too much work when running with --always-opt and keep
|
||||||
// the optimized code around.
|
// the optimized code around.
|
||||||
@ -8354,33 +8352,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
|
|||||||
return isolate->heap()->undefined_value();
|
return isolate->heap()->undefined_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find other optimized activations of the function or functions that
|
// Search for other activations of the same function and code.
|
||||||
// share the same optimized code.
|
ActivationsFinder activations_finder(*optimized_code);
|
||||||
bool has_other_activations = false;
|
activations_finder.VisitFrames(&it);
|
||||||
while (!it.done()) {
|
isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
|
||||||
JavaScriptFrame* frame = it.frame();
|
|
||||||
JSFunction* other_function = frame->function();
|
|
||||||
if (frame->is_optimized() && other_function->code() == function->code()) {
|
|
||||||
has_other_activations = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
it.Advance();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!has_other_activations) {
|
if (!activations_finder.has_code_activations_) {
|
||||||
ActivationsFinder activations_finder(*function);
|
if (function->code() == *optimized_code) {
|
||||||
isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
|
if (FLAG_trace_deopt) {
|
||||||
has_other_activations = activations_finder.has_activations();
|
PrintF("[removing optimized code for: ");
|
||||||
}
|
function->PrintName();
|
||||||
|
PrintF("]\n");
|
||||||
if (!has_other_activations) {
|
}
|
||||||
if (FLAG_trace_deopt) {
|
function->ReplaceCode(function->shared()->code());
|
||||||
PrintF("[removing optimized code for: ");
|
|
||||||
function->PrintName();
|
|
||||||
PrintF("]\n");
|
|
||||||
}
|
}
|
||||||
function->ReplaceCode(function->shared()->code());
|
|
||||||
} else {
|
} else {
|
||||||
|
// TODO(titzer): we should probably do DeoptimizeCodeList(code)
|
||||||
|
// unconditionally if the code is not already marked for deoptimization.
|
||||||
|
// If there is an index by shared function info, all the better.
|
||||||
Deoptimizer::DeoptimizeFunction(*function);
|
Deoptimizer::DeoptimizeFunction(*function);
|
||||||
}
|
}
|
||||||
// Evict optimized code for this function from the cache so that it doesn't
|
// Evict optimized code for this function from the cache so that it doesn't
|
||||||
|
65
test/mjsunit/compiler/regress-shared-deopt.js
Normal file
65
test/mjsunit/compiler/regress-shared-deopt.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// Flags: --allow-natives-syntax
|
||||||
|
|
||||||
|
var soft = false;
|
||||||
|
|
||||||
|
// disable optimization of this global
|
||||||
|
soft = true;
|
||||||
|
soft = false;
|
||||||
|
soft = true;
|
||||||
|
soft = false;
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
var f4 = makeF(4);
|
||||||
|
var f5 = makeF(5);
|
||||||
|
|
||||||
|
function makeF(i) {
|
||||||
|
return function f(x) {
|
||||||
|
if (x == 0) return i;
|
||||||
|
if (i == 4) if (soft) print("wahoo" + i);
|
||||||
|
return f4(x - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f4(9);
|
||||||
|
f4(11);
|
||||||
|
%OptimizeFunctionOnNextCall(f4);
|
||||||
|
f4(12);
|
||||||
|
|
||||||
|
f5(9);
|
||||||
|
f5(11);
|
||||||
|
%OptimizeFunctionOnNextCall(f5);
|
||||||
|
f5(12);
|
||||||
|
|
||||||
|
soft = true;
|
||||||
|
f4(1);
|
||||||
|
f5(9);
|
||||||
|
}
|
||||||
|
|
||||||
|
test();
|
Loading…
Reference in New Issue
Block a user