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
This commit is contained in:
parent
75bf5e44d2
commit
5bb6a8399d
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user