| Index: src/compiler/ast-graph-builder.cc
|
| diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc
|
| index fb848c9142f31ace157cb93f0860f7fdf95fd1ad..78a0906780e9a6df95e2a808529a7b60078786b4 100644
|
| --- a/src/compiler/ast-graph-builder.cc
|
| +++ b/src/compiler/ast-graph-builder.cc
|
| @@ -1292,148 +1292,80 @@ void AstGraphBuilder::VisitForStatement(ForStatement* stmt) {
|
| }
|
|
|
|
|
| -// TODO(dcarney): this is a big function. Try to clean up some.
|
| void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
|
| VisitForValue(stmt->subject());
|
| - Node* obj = environment()->Pop();
|
| - // Check for undefined or null before entering loop.
|
| - IfBuilder is_undefined(this);
|
| - Node* is_undefined_cond =
|
| - NewNode(javascript()->StrictEqual(), obj, jsgraph()->UndefinedConstant());
|
| - is_undefined.If(is_undefined_cond);
|
| - is_undefined.Then();
|
| - is_undefined.Else();
|
| + Node* object = environment()->Pop();
|
| + BlockBuilder for_block(this);
|
| + for_block.BeginBlock();
|
| + // Check for null or undefined before entering loop.
|
| + Node* is_null_cond =
|
| + NewNode(javascript()->StrictEqual(), object, jsgraph()->NullConstant());
|
| + for_block.BreakWhen(is_null_cond, BranchHint::kFalse);
|
| + Node* is_undefined_cond = NewNode(javascript()->StrictEqual(), object,
|
| + jsgraph()->UndefinedConstant());
|
| + for_block.BreakWhen(is_undefined_cond, BranchHint::kFalse);
|
| {
|
| - IfBuilder is_null(this);
|
| - Node* is_null_cond =
|
| - NewNode(javascript()->StrictEqual(), obj, jsgraph()->NullConstant());
|
| - is_null.If(is_null_cond);
|
| - is_null.Then();
|
| - is_null.Else();
|
| // Convert object to jsobject.
|
| - // PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
|
| - obj = NewNode(javascript()->ToObject(), obj);
|
| - PrepareFrameState(obj, stmt->ToObjectId(), OutputFrameStateCombine::Push());
|
| - environment()->Push(obj);
|
| - // TODO(dcarney): should do a fast enum cache check here to skip runtime.
|
| - Node* cache_type = NewNode(
|
| - javascript()->CallRuntime(Runtime::kGetPropertyNamesFast, 1), obj);
|
| - PrepareFrameState(cache_type, stmt->EnumId(),
|
| - OutputFrameStateCombine::Push());
|
| - // TODO(dcarney): these next runtime calls should be removed in favour of
|
| - // a few simplified instructions.
|
| - Node* cache_pair = NewNode(
|
| - javascript()->CallRuntime(Runtime::kForInInit, 2), obj, cache_type);
|
| - // cache_type may have been replaced.
|
| - Node* cache_array = NewNode(common()->Projection(0), cache_pair);
|
| - cache_type = NewNode(common()->Projection(1), cache_pair);
|
| - Node* cache_length =
|
| - NewNode(javascript()->CallRuntime(Runtime::kForInCacheArrayLength, 2),
|
| - cache_type, cache_array);
|
| + object = BuildToObject(object, stmt->ToObjectId());
|
| + environment()->Push(object);
|
| +
|
| + // Prepare for-in cache.
|
| + Node* prepare = NewNode(javascript()->ForInPrepare(), object);
|
| + PrepareFrameState(prepare, stmt->EnumId(), OutputFrameStateCombine::Push());
|
| + Node* cache_type = NewNode(common()->Projection(0), prepare);
|
| + Node* cache_array = NewNode(common()->Projection(1), prepare);
|
| + Node* cache_length = NewNode(common()->Projection(2), prepare);
|
| +
|
| + // Construct the rest of the environment.
|
| + environment()->Push(cache_type);
|
| + environment()->Push(cache_array);
|
| + environment()->Push(cache_length);
|
| + environment()->Push(jsgraph()->ZeroConstant());
|
| +
|
| + // Build the actual loop body.
|
| + LoopBuilder for_loop(this);
|
| + for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
|
| {
|
| - // Construct the rest of the environment.
|
| - environment()->Push(cache_type);
|
| - environment()->Push(cache_array);
|
| - environment()->Push(cache_length);
|
| - environment()->Push(jsgraph()->ZeroConstant());
|
| -
|
| - // Build the actual loop body.
|
| - VisitForInBody(stmt);
|
| - }
|
| - is_null.End();
|
| - }
|
| - is_undefined.End();
|
| -}
|
| -
|
| -
|
| -// TODO(dcarney): this is a big function. Try to clean up some.
|
| -void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) {
|
| - LoopBuilder for_loop(this);
|
| - for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
|
| -
|
| - // These stack values are renamed in the case of OSR, so reload them
|
| - // from the environment.
|
| - Node* index = environment()->Peek(0);
|
| - Node* cache_length = environment()->Peek(1);
|
| - Node* cache_array = environment()->Peek(2);
|
| - Node* cache_type = environment()->Peek(3);
|
| - Node* obj = environment()->Peek(4);
|
| -
|
| - // Check loop termination condition (cannot deoptimize).
|
| - {
|
| - FrameStateBeforeAndAfter states(this, BailoutId::None());
|
| - Node* exit_cond = NewNode(javascript()->LessThan(LanguageMode::SLOPPY),
|
| - index, cache_length);
|
| - states.AddToNode(exit_cond, BailoutId::None(),
|
| - OutputFrameStateCombine::Ignore());
|
| - for_loop.BreakUnless(exit_cond);
|
| - }
|
| - Node* pair = NewNode(javascript()->CallRuntime(Runtime::kForInNext, 4), obj,
|
| - cache_array, cache_type, index);
|
| - Node* value = NewNode(common()->Projection(0), pair);
|
| - Node* should_filter = NewNode(common()->Projection(1), pair);
|
| - environment()->Push(value);
|
| - {
|
| - // Test if FILTER_KEY needs to be called.
|
| - IfBuilder test_should_filter(this);
|
| - Node* should_filter_cond = NewNode(
|
| - javascript()->StrictEqual(), should_filter, jsgraph()->TrueConstant());
|
| - test_should_filter.If(should_filter_cond);
|
| - test_should_filter.Then();
|
| - value = environment()->Pop();
|
| - Node* builtins = BuildLoadBuiltinsObject();
|
| - Node* function = BuildLoadObjectField(
|
| - builtins,
|
| - JSBuiltinsObject::OffsetOfFunctionWithId(Builtins::FILTER_KEY));
|
| - // result is either the string key or Smi(0) indicating the property
|
| - // is gone.
|
| - Node* res = NewNode(
|
| - javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS, language_mode()),
|
| - function, obj, value);
|
| - PrepareFrameState(res, stmt->FilterId(), OutputFrameStateCombine::Push());
|
| - Node* property_missing =
|
| - NewNode(javascript()->StrictEqual(), res, jsgraph()->ZeroConstant());
|
| - {
|
| - IfBuilder is_property_missing(this);
|
| - is_property_missing.If(property_missing);
|
| - is_property_missing.Then();
|
| - // Inc counter and continue (cannot deoptimize).
|
| + // These stack values are renamed in the case of OSR, so reload them
|
| + // from the environment.
|
| + Node* index = environment()->Peek(0);
|
| + Node* cache_length = environment()->Peek(1);
|
| + Node* cache_array = environment()->Peek(2);
|
| + Node* cache_type = environment()->Peek(3);
|
| + Node* object = environment()->Peek(4);
|
| +
|
| + // Check loop termination condition.
|
| + Node* exit_cond = NewNode(javascript()->ForInDone(), index, cache_length);
|
| + for_loop.BreakWhen(exit_cond);
|
| +
|
| + // Compute the next enumerated value.
|
| + Node* value = NewNode(javascript()->ForInNext(), object, cache_array,
|
| + cache_type, index);
|
| + PrepareFrameState(value, stmt->FilterId(),
|
| + OutputFrameStateCombine::Push());
|
| + IfBuilder test_value(this);
|
| + Node* test_value_cond = NewNode(javascript()->StrictEqual(), value,
|
| + jsgraph()->UndefinedConstant());
|
| + test_value.If(test_value_cond, BranchHint::kFalse);
|
| + test_value.Then();
|
| + test_value.Else();
|
| {
|
| - FrameStateBeforeAndAfter states(this, BailoutId::None());
|
| - Node* index_inc = NewNode(javascript()->Add(LanguageMode::SLOPPY),
|
| - index, jsgraph()->OneConstant());
|
| - states.AddToNode(index_inc, BailoutId::None(),
|
| - OutputFrameStateCombine::Ignore());
|
| - environment()->Poke(0, index_inc);
|
| + // Bind value and do loop body.
|
| + VisitForInAssignment(stmt->each(), value, stmt->AssignmentId());
|
| + VisitIterationBody(stmt, &for_loop);
|
| }
|
| - for_loop.Continue();
|
| - is_property_missing.Else();
|
| - is_property_missing.End();
|
| - }
|
| - // Replace 'value' in environment.
|
| - environment()->Push(res);
|
| - test_should_filter.Else();
|
| - test_should_filter.End();
|
| - }
|
| - value = environment()->Pop();
|
| - // Bind value and do loop body.
|
| - VisitForInAssignment(stmt->each(), value, stmt->AssignmentId());
|
| - VisitIterationBody(stmt, &for_loop);
|
| - index = environment()->Peek(0);
|
| - for_loop.EndBody();
|
| + test_value.End();
|
| + index = environment()->Peek(0);
|
| + for_loop.EndBody();
|
|
|
| - // Inc counter and continue (cannot deoptimize).
|
| - {
|
| - FrameStateBeforeAndAfter states(this, BailoutId::None());
|
| - Node* index_inc = NewNode(javascript()->Add(LanguageMode::SLOPPY), index,
|
| - jsgraph()->OneConstant());
|
| - states.AddToNode(index_inc, BailoutId::None(),
|
| - OutputFrameStateCombine::Ignore());
|
| - environment()->Poke(0, index_inc);
|
| + // Increment counter and continue.
|
| + index = NewNode(javascript()->ForInStep(), index);
|
| + environment()->Poke(0, index);
|
| + }
|
| + for_loop.EndLoop();
|
| + environment()->Drop(5);
|
| }
|
| - for_loop.EndLoop();
|
| - environment()->Drop(5);
|
| - // PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
| + for_block.EndBlock();
|
| }
|
|
|
|
|
| @@ -3339,6 +3271,13 @@ Node* AstGraphBuilder::BuildToName(Node* input, BailoutId bailout_id) {
|
| }
|
|
|
|
|
| +Node* AstGraphBuilder::BuildToObject(Node* input, BailoutId bailout_id) {
|
| + Node* object = NewNode(javascript()->ToObject(), input);
|
| + PrepareFrameState(object, bailout_id, OutputFrameStateCombine::Push());
|
| + return object;
|
| +}
|
| +
|
| +
|
| Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object,
|
| Expression* expr) {
|
| if (!FunctionLiteral::NeedsHomeObject(expr)) return value;
|
|
|