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:
titzer@chromium.org 2013-08-22 13:03:40 +00:00
parent 6d137c3f50
commit 6f3169e571
3 changed files with 102 additions and 46 deletions

View File

@ -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_; }

View File

@ -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

View 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();