Revision: 10796
Author: vego...@chromium.org
Date: Wed Feb 22 08:45:35 2012
Log: 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=fschnei...@chromium.org
TEST=test/mjsunit/compiler/optimized-for-in.js
Review URL: https://chromiumcodereview.appspot.com/9431030
http://code.google.com/p/v8/source/detail?r=10796
Modified:
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/src/runtime-profiler.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/runtime.h
/branches/bleeding_edge/test/mjsunit/compiler/optimized-for-in.js
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Wed Feb 22 04:47:42 2012
+++ /branches/bleeding_edge/src/hydrogen.cc Wed Feb 22 08:45:35 2012
@@ -3058,15 +3058,24 @@
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 @@
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 @@
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::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();
}
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Wed Feb 22 04:47:42 2012
+++ /branches/bleeding_edge/src/hydrogen.h Wed Feb 22 08:45:35 2012
@@ -398,6 +398,10 @@
bool is_special_index(int i) const {
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);
=======================================
--- /branches/bleeding_edge/src/runtime-profiler.h Thu Feb 9 05:30:01 2012
+++ /branches/bleeding_edge/src/runtime-profiler.h Wed Feb 22 08:45:35 2012
@@ -101,6 +101,8 @@
void RemoveDeadSamples();
void UpdateSamplesAfterCompact(ObjectVisitor* visitor);
+ void AttemptOnStackReplacement(JSFunction* function);
+
private:
static const int kSamplerWindowSize = 16;
@@ -108,8 +110,6 @@
void Optimize(JSFunction* function, const char* reason);
- void AttemptOnStackReplacement(JSFunction* function);
-
void ClearSampleBuffer();
void ClearSampleBufferNewSpaceEntries();
=======================================
--- /branches/bleeding_edge/src/runtime.cc Tue Feb 21 04:47:27 2012
+++ /branches/bleeding_edge/src/runtime.cc Wed Feb 22 08:45:35 2012
@@ -8590,10 +8590,22 @@
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();
}
=======================================
--- /branches/bleeding_edge/src/runtime.h Tue Feb 21 04:47:27 2012
+++ /branches/bleeding_edge/src/runtime.h Wed Feb 22 08:45:35 2012
@@ -91,7 +91,7 @@
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) \
=======================================
--- /branches/bleeding_edge/test/mjsunit/compiler/optimized-for-in.js Wed
Feb 22 04:47:42 2012
+++ /branches/bleeding_edge/test/mjsunit/compiler/optimized-for-in.js Wed
Feb 22 08:45:35 2012
@@ -242,3 +242,57 @@
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();
--
v8-dev mailing list
v8-dev@googlegroups.com
http://groups.google.com/group/v8-dev