| 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..3aa5f0eeae9500b64c2926c1c4bfc1c9edc3cd31 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) {
|
| @@ -3021,11 +3021,8 @@ Node* AstGraphBuilder::BuildVariableLoad(FrameStateBeforeAndAfter& states,
|
| switch (variable->location()) {
|
| case Variable::UNALLOCATED: {
|
| // Global var, const, or let variable.
|
| - Node* global = BuildLoadGlobalObject();
|
| - Handle<Name> name = variable->name();
|
| - Node* node = BuildNamedLoad(global, name, feedback, contextual_mode);
|
| - states.AddToNode(node, bailout_id, combine);
|
| - return node;
|
| + return BuildGlobalVariableLoad(variable, bailout_id, states, feedback,
|
| + combine, contextual_mode);
|
| }
|
| case Variable::PARAMETER:
|
| case Variable::LOCAL: {
|
| @@ -3071,15 +3068,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 = TryDynamicGlobalVariableLoad(
|
| + 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 +3121,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 +3227,89 @@ Node* AstGraphBuilder::BuildVariableAssignment(
|
| }
|
|
|
|
|
| +Node* AstGraphBuilder::TryDynamicGlobalVariableLoad(
|
| + 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 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) {
|
|
|