From: vegorov@chromium.org Date: Wed, 22 Feb 2012 16:45:35 +0000 (+0000) Subject: Support OSR in for-in loops. X-Git-Tag: upstream/4.7.83~17295 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5bb6a8399d74f7d59c3051f8e7b784b289f3d86e;p=platform%2Fupstream%2Fv8.git Support OSR in for-in loops. Modify PreProcessOsrEntry to work with OSR entries that have non-empty expression stack. Modify graph builder to take for-in state from environment instead of directly referencing emitted instructions. Extend %OptimizeFunctionOnNextCall with an argument to force OSR to make writing OSR tests easier: %OptimizeFunctionOnNextCall(f, "osr"). R=fschneider@chromium.org TEST=test/mjsunit/compiler/optimized-for-in.js Review URL: https://chromiumcodereview.appspot.com/9431030 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10796 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/hydrogen.cc b/src/hydrogen.cc index dd8b402..9918e85 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -3058,15 +3058,24 @@ void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { set_current_block(osr_entry); int osr_entry_id = statement->OsrEntryId(); - // We want the correct environment at the OsrEntry instruction. Build - // it explicitly. The expression stack should be empty. - ASSERT(environment()->ExpressionStackIsEmpty()); - for (int i = 0; i < environment()->length(); ++i) { + int first_expression_index = environment()->first_expression_index(); + int length = environment()->length(); + for (int i = 0; i < first_expression_index; ++i) { HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue; AddInstruction(osr_value); environment()->Bind(i, osr_value); } + if (first_expression_index != length) { + environment()->Drop(length - first_expression_index); + for (int i = first_expression_index; i < length; ++i) { + HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue; + AddInstruction(osr_value); + environment()->Push(osr_value); + } + } + + AddSimulate(osr_entry_id); AddInstruction(new(zone()) HOsrEntry(osr_entry_id)); HContext* context = new(zone()) HContext; @@ -3274,15 +3283,17 @@ void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) { HForInCacheArray::cast(array)->set_index_cache( HForInCacheArray::cast(index_cache)); + PreProcessOsrEntry(stmt); HBasicBlock* loop_entry = CreateLoopHeaderBlock(); current_block()->Goto(loop_entry); set_current_block(loop_entry); - HValue* index = Top(); + HValue* index = environment()->ExpressionStackAt(0); + HValue* limit = environment()->ExpressionStackAt(1); // Check that we still have more keys. HCompareIDAndBranch* compare_index = - new(zone()) HCompareIDAndBranch(index, array_length, Token::LT); + new(zone()) HCompareIDAndBranch(index, limit, Token::LT); compare_index->SetInputRepresentation(Representation::Integer32()); HBasicBlock* loop_body = graph()->CreateBasicBlock(); @@ -3299,11 +3310,15 @@ void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) { HValue* key = AddInstruction( new(zone()) HLoadKeyedFastElement( - array, index, HLoadKeyedFastElement::OMIT_HOLE_CHECK)); + environment()->ExpressionStackAt(2), // Enum cache. + environment()->ExpressionStackAt(0), // Iteration index. + HLoadKeyedFastElement::OMIT_HOLE_CHECK)); // Check if the expected map still matches that of the enumerable. // If not just deoptimize. - AddInstruction(new(zone()) HCheckMapValue(enumerable, map)); + AddInstruction(new(zone()) HCheckMapValue( + environment()->ExpressionStackAt(4), + environment()->ExpressionStackAt(3))); Bind(each_var, key); @@ -7440,9 +7455,8 @@ bool HEnvironment::HasExpressionAt(int index) const { bool HEnvironment::ExpressionStackIsEmpty() const { - int first_expression = parameter_count() + specials_count() + local_count(); - ASSERT(length() >= first_expression); - return length() == first_expression; + ASSERT(length() >= first_expression_index()); + return length() == first_expression_index(); } diff --git a/src/hydrogen.h b/src/hydrogen.h index 1226656..65aa346 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -399,6 +399,10 @@ class HEnvironment: public ZoneObject { return i >= parameter_count() && i < parameter_count() + specials_count(); } + int first_expression_index() const { + return parameter_count() + specials_count() + local_count(); + } + void Bind(Variable* variable, HValue* value) { Bind(IndexFor(variable), value); } diff --git a/src/runtime-profiler.h b/src/runtime-profiler.h index f374566..f7ca3f0 100644 --- a/src/runtime-profiler.h +++ b/src/runtime-profiler.h @@ -101,6 +101,8 @@ class RuntimeProfiler { void RemoveDeadSamples(); void UpdateSamplesAfterCompact(ObjectVisitor* visitor); + void AttemptOnStackReplacement(JSFunction* function); + private: static const int kSamplerWindowSize = 16; @@ -108,8 +110,6 @@ class RuntimeProfiler { void Optimize(JSFunction* function, const char* reason); - void AttemptOnStackReplacement(JSFunction* function); - void ClearSampleBuffer(); void ClearSampleBufferNewSpaceEntries(); diff --git a/src/runtime.cc b/src/runtime.cc index 1115542..9597681 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -8590,10 +8590,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) { RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) { HandleScope scope(isolate); - ASSERT(args.length() == 1); + RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); + if (!function->IsOptimizable()) return isolate->heap()->undefined_value(); function->MarkForLazyRecompilation(); + + Code* unoptimized = function->shared()->code(); + if (args.length() == 2 && + unoptimized->kind() == Code::FUNCTION) { + CONVERT_ARG_HANDLE_CHECKED(String, type, 1); + CHECK(type->IsEqualTo(CStrVector("osr"))); + isolate->runtime_profiler()->AttemptOnStackReplacement(*function); + unoptimized->set_allow_osr_at_loop_nesting_level( + Code::kMaxLoopNestingMarker); + } + return isolate->heap()->undefined_value(); } diff --git a/src/runtime.h b/src/runtime.h index 73f82b2..bd6568f 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -91,7 +91,7 @@ namespace internal { F(NotifyOSR, 0, 1) \ F(DeoptimizeFunction, 1, 1) \ F(RunningInSimulator, 0, 1) \ - F(OptimizeFunctionOnNextCall, 1, 1) \ + F(OptimizeFunctionOnNextCall, -1, 1) \ F(GetOptimizationStatus, 1, 1) \ F(GetOptimizationCount, 1, 1) \ F(CompileForOnStackReplacement, 1, 1) \ diff --git a/test/mjsunit/compiler/optimized-for-in.js b/test/mjsunit/compiler/optimized-for-in.js index c8076ac..8b16101 100644 --- a/test/mjsunit/compiler/optimized-for-in.js +++ b/test/mjsunit/compiler/optimized-for-in.js @@ -242,3 +242,57 @@ tryFunction("a1b2c3d4e5f6", function () { for (var i in t) r.push(i + t[i]); return r.join(''); }); + +// Test OSR inside for-in. +function osr_inner(t, limit) { + var r = 1; + for (var x in t) { + for (var i = 0; i < t[x].length; i++) { + r += t[x][i]; + if (i === limit) { + %OptimizeFunctionOnNextCall(osr_inner, "osr"); + } + } + r += x; + } + return r; +} + +function osr_outer(t, osr_after) { + var r = 1; + for (var x in t) { + for (var i = 0; i < t[x].length; i++) { + r += t[x][i]; + } + if (x === osr_after) { + %OptimizeFunctionOnNextCall(osr_outer, "osr"); + } + r += x; + } + return r; +} + +function osr_outer_and_deopt(t, osr_after) { + var r = 1; + for (var x in t) { + r += x; + if (x == osr_after) { + %OptimizeFunctionOnNextCall(osr_outer_and_deopt, "osr"); + } + } + return r; +} + +function test_osr() { + with ({}) {} // Disable optimizations of this function. + var arr = new Array(20); + for (var i = 0; i < arr.length; i++) { + arr[i] = i + 1; + } + arr.push(":"); // Force deopt at the end of the loop. + assertEquals("211:x", osr_inner({x: arr}, (arr.length / 2) | 0)); + assertEquals("7x456y", osr_outer({x: [1,2,3], y: [4,5,6]}, "x")); + assertEquals("101234567", osr_outer_and_deopt([1,2,3,4,5,6,7,8], "5")); +} + +test_osr();