Chromium Code Reviews| Index: src/compiler/ast-graph-builder.cc |
| diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc |
| index 9778c79b1e714473d0d974001f70422b3ab0b545..d9ef647f31bc0cc75634776b5885312fddedccf0 100644 |
| --- a/src/compiler/ast-graph-builder.cc |
| +++ b/src/compiler/ast-graph-builder.cc |
| @@ -1712,8 +1712,8 @@ void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) { |
| DCHECK_NOT_NULL(expr->class_variable_proxy()); |
| Variable* var = expr->class_variable_proxy()->var(); |
| FrameStateBeforeAndAfter states(this, BailoutId::None()); |
| - BuildVariableAssignment(states, var, literal, Token::INIT_CONST, |
| - BailoutId::None()); |
| + BuildVariableAssignment(var, literal, Token::INIT_CONST, BailoutId::None(), |
| + states); |
| } |
| ast_context()->ProduceValue(literal); |
| @@ -1742,7 +1742,7 @@ void AstGraphBuilder::VisitConditional(Conditional* expr) { |
| void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot()); |
| FrameStateBeforeAndAfter states(this, BeforeId(expr)); |
| - Node* value = BuildVariableLoad(states, expr->var(), expr->id(), pair, |
| + Node* value = BuildVariableLoad(expr->var(), expr->id(), states, pair, |
| ast_context()->GetStateCombine()); |
| ast_context()->ProduceValue(value); |
| } |
| @@ -2054,7 +2054,7 @@ void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value, |
| case VARIABLE: { |
| Variable* var = expr->AsVariableProxy()->var(); |
| FrameStateBeforeAndAfter states(this, BailoutId::None()); |
| - BuildVariableAssignment(states, var, value, Token::ASSIGN, bailout_id); |
| + BuildVariableAssignment(var, value, Token::ASSIGN, bailout_id, states); |
| break; |
| } |
| case NAMED_PROPERTY: { |
| @@ -2126,7 +2126,7 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { |
| CreateVectorSlotPair(proxy->VariableFeedbackSlot()); |
| FrameStateBeforeAndAfter states(this, BeforeId(proxy)); |
| old_value = |
| - BuildVariableLoad(states, proxy->var(), expr->target()->id(), pair, |
| + BuildVariableLoad(proxy->var(), expr->target()->id(), states, pair, |
| OutputFrameStateCombine::Push()); |
| break; |
| } |
| @@ -2181,8 +2181,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { |
| switch (assign_type) { |
| case VARIABLE: { |
| Variable* variable = expr->target()->AsVariableProxy()->var(); |
| - BuildVariableAssignment(store_states, variable, value, expr->op(), |
| - expr->id(), ast_context()->GetStateCombine()); |
| + BuildVariableAssignment(variable, value, expr->op(), expr->id(), |
| + store_states, ast_context()->GetStateCombine()); |
| break; |
| } |
| case NAMED_PROPERTY: { |
| @@ -2270,7 +2270,7 @@ void AstGraphBuilder::VisitCall(Call* expr) { |
| VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot()); |
| FrameStateBeforeAndAfter states(this, BeforeId(proxy)); |
| callee_value = |
| - BuildVariableLoad(states, proxy->var(), expr->expression()->id(), |
| + BuildVariableLoad(proxy->var(), expr->expression()->id(), states, |
| pair, OutputFrameStateCombine::Push()); |
| receiver_value = jsgraph()->UndefinedConstant(); |
| break; |
| @@ -2498,7 +2498,7 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot()); |
| FrameStateBeforeAndAfter states(this, BeforeId(proxy)); |
| old_value = |
| - BuildVariableLoad(states, proxy->var(), expr->expression()->id(), |
| + BuildVariableLoad(proxy->var(), expr->expression()->id(), states, |
| pair, OutputFrameStateCombine::Push()); |
| stack_depth = 0; |
| break; |
| @@ -2562,8 +2562,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| case VARIABLE: { |
| Variable* variable = expr->expression()->AsVariableProxy()->var(); |
| environment()->Push(value); |
| - BuildVariableAssignment(store_states, variable, value, expr->op(), |
| - expr->AssignmentId()); |
| + BuildVariableAssignment(variable, value, expr->op(), expr->AssignmentId(), |
| + store_states); |
| environment()->Pop(); |
| break; |
| } |
| @@ -2766,7 +2766,7 @@ void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) { |
| VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot()); |
| FrameStateBeforeAndAfter states(this, BeforeId(proxy)); |
| operand = |
| - BuildVariableLoad(states, proxy->var(), expr->expression()->id(), pair, |
| + BuildVariableLoad(proxy->var(), expr->expression()->id(), states, pair, |
| OutputFrameStateCombine::Push(), NOT_CONTEXTUAL); |
| } else { |
| VisitForValue(expr->expression()); |
| @@ -2942,8 +2942,8 @@ Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) { |
| DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated()); |
| // This should never lazy deopt, so it is fine to send invalid bailout id. |
| FrameStateBeforeAndAfter states(this, BailoutId::None()); |
| - BuildVariableAssignment(states, arguments, object, Token::ASSIGN, |
| - BailoutId::None()); |
| + BuildVariableAssignment(arguments, object, Token::ASSIGN, BailoutId::None(), |
| + states); |
| return object; |
| } |
| @@ -2960,8 +2960,8 @@ Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest, int index) { |
| DCHECK(rest->IsContextSlot() || rest->IsStackAllocated()); |
| // This should never lazy deopt, so it is fine to send invalid bailout id. |
| FrameStateBeforeAndAfter states(this, BailoutId::None()); |
| - BuildVariableAssignment(states, rest, object, Token::ASSIGN, |
| - BailoutId::None()); |
| + BuildVariableAssignment(rest, object, Token::ASSIGN, BailoutId::None(), |
| + states); |
| return object; |
| } |
| @@ -3010,9 +3010,9 @@ Node* AstGraphBuilder::BuildThrowIfStaticPrototype(Node* name, |
| } |
| -Node* AstGraphBuilder::BuildVariableLoad(FrameStateBeforeAndAfter& states, |
| - Variable* variable, |
| +Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, |
| BailoutId bailout_id, |
| + FrameStateBeforeAndAfter& states, |
| const VectorSlotPair& feedback, |
| OutputFrameStateCombine combine, |
| ContextualMode contextual_mode) { |
| @@ -3071,15 +3071,18 @@ Node* AstGraphBuilder::BuildVariableLoad(FrameStateBeforeAndAfter& states, |
| } |
| case Variable::LOOKUP: { |
| // Dynamic lookup of context variable (anywhere in the chain). |
| - Node* name = jsgraph()->Constant(variable->name()); |
| - Runtime::FunctionId function_id = |
| - (contextual_mode == CONTEXTUAL) |
| - ? Runtime::kLoadLookupSlot |
| - : Runtime::kLoadLookupSlotNoReferenceError; |
| - const Operator* op = javascript()->CallRuntime(function_id, 2); |
| - Node* pair = NewNode(op, current_context(), name); |
| - PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1)); |
| - return NewNode(common()->Projection(0), pair); |
| + if (mode == DYNAMIC_GLOBAL) { |
| + // Try to optimize known global when not shadowed. |
| + if (Node* fast_value = TryVariableLoadDynamicGlobal( |
| + variable, bailout_id, states, feedback, combine, |
| + contextual_mode)) { |
| + return fast_value; |
| + } |
| + } else if (mode == DYNAMIC_LOCAL) { |
| + // Try to optimize known local when not shadowed. |
| + // TODO(mstarzinger): Implement TryVariableLoadDynamicLocal(). |
| + } |
| + return BuildDynamicVariableLoad(variable, bailout_id, contextual_mode); |
| } |
| } |
| UNREACHABLE(); |
| @@ -3121,8 +3124,8 @@ Node* AstGraphBuilder::BuildVariableDelete(Variable* variable, |
| Node* AstGraphBuilder::BuildVariableAssignment( |
| - FrameStateBeforeAndAfter& states, Variable* variable, Node* value, |
| - Token::Value op, BailoutId bailout_id, OutputFrameStateCombine combine) { |
| + Variable* variable, Node* value, Token::Value op, BailoutId bailout_id, |
| + FrameStateBeforeAndAfter& states, OutputFrameStateCombine combine) { |
| Node* the_hole = jsgraph()->TheHoleConstant(); |
| VariableMode mode = variable->mode(); |
| switch (variable->location()) { |
| @@ -3227,6 +3230,89 @@ Node* AstGraphBuilder::BuildVariableAssignment( |
| } |
| +Node* AstGraphBuilder::TryVariableLoadDynamicGlobal( |
|
titzer
2015/05/27 14:06:21
The ordering of the words is kind of mixed up here
Michael Starzinger
2015/05/27 14:10:28
Done. True, the name is confusing, changed it to T
|
| + Variable* variable, BailoutId bailout_id, FrameStateBeforeAndAfter& states, |
| + const VectorSlotPair& feedback, OutputFrameStateCombine combine, |
| + ContextualMode contextual_mode) { |
| + DCHECK_EQ(DYNAMIC_GLOBAL, variable->mode()); |
| + |
| + // Determine which contexts need to be checked for extension objects that |
| + // might shadow the optimistic declaration. |
| + int current_depth = 0; |
| + ZoneVector<int> check_depths(local_zone()); |
| + for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) { |
| + if (s->num_heap_slots() <= 0) continue; |
| + check_depths.push_back(current_depth++); |
| + } |
| + |
| + // Impose artificial upper bound on the number of checks. |
| + const int kMaxContextExtensionObjectChecks = 6; |
| + if (check_depths.size() > kMaxContextExtensionObjectChecks) return nullptr; |
| + |
| + // We are using two blocks to model fast and slow cases. |
| + BlockBuilder fast_block(this); |
| + BlockBuilder slow_block(this); |
| + environment()->Push(jsgraph()->TheHoleConstant()); |
| + slow_block.BeginBlock(); |
| + environment()->Pop(); |
| + fast_block.BeginBlock(); |
| + |
| + // Perform checks whether the fast mode applies, by looking whether for any |
| + // extension object which might shadow the optimistic declaration. |
| + for (int depth : check_depths) { |
| + Node* load = NewNode( |
| + javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false), |
| + current_context()); |
| + Node* check = |
| + NewNode(javascript()->CallRuntime(Runtime::kInlineIsSmi, 1), load); |
| + fast_block.BreakUnless(check, BranchHint::kTrue); |
| + } |
| + |
| + // Fast case, because variable is not shadowed. Perform global object load. |
| + Node* fast = BuildGlobalVariableLoad(variable, bailout_id, states, feedback, |
| + combine, contextual_mode); |
| + environment()->Push(fast); |
| + slow_block.Break(); |
| + environment()->Pop(); |
| + fast_block.EndBlock(); |
| + |
| + // Slow case, because variable potentially shadowed. Perform dynamic lookup. |
| + Node* slow = BuildDynamicVariableLoad(variable, bailout_id, contextual_mode); |
| + environment()->Push(slow); |
| + slow_block.EndBlock(); |
| + |
| + return environment()->Pop(); |
| +} |
| + |
| + |
| +Node* AstGraphBuilder::BuildGlobalVariableLoad(Variable* variable, |
| + BailoutId bailout_id, |
| + FrameStateBeforeAndAfter& states, |
| + const VectorSlotPair& feedback, |
| + OutputFrameStateCombine combine, |
| + ContextualMode contextual_mode) { |
| + Node* global = BuildLoadGlobalObject(); |
| + Handle<Name> name = variable->name(); |
| + Node* node = BuildNamedLoad(global, name, feedback, contextual_mode); |
| + states.AddToNode(node, bailout_id, combine); |
| + return node; |
| +} |
| + |
| + |
| +Node* AstGraphBuilder::BuildDynamicVariableLoad( |
| + Variable* variable, BailoutId bailout_id, ContextualMode contextual_mode) { |
| + Node* name = jsgraph()->Constant(variable->name()); |
| + Runtime::FunctionId function_id = |
| + (contextual_mode == CONTEXTUAL) |
| + ? Runtime::kLoadLookupSlot |
| + : Runtime::kLoadLookupSlotNoReferenceError; |
| + const Operator* op = javascript()->CallRuntime(function_id, 2); |
| + Node* pair = NewNode(op, current_context(), name); |
| + PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1)); |
| + return NewNode(common()->Projection(0), pair); |
| +} |
| + |
| + |
| static inline Node* Record(JSTypeFeedbackTable* js_type_feedback, Node* node, |
| FeedbackVectorICSlot slot) { |
| if (js_type_feedback) { |