Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Unified Diff: src/compiler/ast-graph-builder.cc

Issue 1158183002: [turbofan] Optimize variable loads in DYNAMIC_GLOBAL mode. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Addressed comments and small cleanup. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/ast-graph-builder.h ('k') | src/compiler/control-builders.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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) {
« no previous file with comments | « src/compiler/ast-graph-builder.h ('k') | src/compiler/control-builders.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698