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

Side by Side Diff: src/compiler/ast-graph-builder.cc

Issue 2201193004: Use Variable::binding_needs_init() to determine hole initialization (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Remove one more comment Created 4 years, 4 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 unified diff | Download patch
« no previous file with comments | « no previous file | src/crankshaft/hydrogen.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/ast-graph-builder.h" 5 #include "src/compiler/ast-graph-builder.h"
6 6
7 #include "src/ast/scopes.h" 7 #include "src/ast/scopes.h"
8 #include "src/compiler.h" 8 #include "src/compiler.h"
9 #include "src/compiler/ast-loop-assignment-analyzer.h" 9 #include "src/compiler/ast-loop-assignment-analyzer.h"
10 #include "src/compiler/control-builders.h" 10 #include "src/compiler/control-builders.h"
(...skipping 1068 matching lines...) Expand 10 before | Expand all | Expand 10 after
1079 if (!CheckStackOverflow()) { 1079 if (!CheckStackOverflow()) {
1080 AstVisitor<AstGraphBuilder>::Visit(expr); 1080 AstVisitor<AstGraphBuilder>::Visit(expr);
1081 } else { 1081 } else {
1082 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); 1082 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant());
1083 } 1083 }
1084 } 1084 }
1085 1085
1086 1086
1087 void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) { 1087 void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) {
1088 Variable* variable = decl->proxy()->var(); 1088 Variable* variable = decl->proxy()->var();
1089 VariableMode mode = decl->mode();
1090 bool hole_init = mode == CONST || mode == LET;
1091 switch (variable->location()) { 1089 switch (variable->location()) {
1092 case VariableLocation::GLOBAL: 1090 case VariableLocation::GLOBAL:
1093 case VariableLocation::UNALLOCATED: { 1091 case VariableLocation::UNALLOCATED: {
1094 DCHECK(!variable->binding_needs_init()); 1092 DCHECK(!variable->binding_needs_init());
1095 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot(); 1093 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot();
1096 DCHECK(!slot.IsInvalid()); 1094 DCHECK(!slot.IsInvalid());
1097 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate())); 1095 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate()));
1098 globals()->push_back(isolate()->factory()->undefined_value()); 1096 globals()->push_back(isolate()->factory()->undefined_value());
1099 break; 1097 break;
1100 } 1098 }
1101 case VariableLocation::PARAMETER: 1099 case VariableLocation::PARAMETER:
1102 case VariableLocation::LOCAL: 1100 case VariableLocation::LOCAL:
1103 if (hole_init) { 1101 if (variable->binding_needs_init()) {
1104 Node* value = jsgraph()->TheHoleConstant(); 1102 Node* value = jsgraph()->TheHoleConstant();
1105 environment()->Bind(variable, value); 1103 environment()->Bind(variable, value);
1106 } 1104 }
1107 break; 1105 break;
1108 case VariableLocation::CONTEXT: 1106 case VariableLocation::CONTEXT:
1109 if (hole_init) { 1107 if (variable->binding_needs_init()) {
1110 Node* value = jsgraph()->TheHoleConstant(); 1108 Node* value = jsgraph()->TheHoleConstant();
1111 const Operator* op = javascript()->StoreContext(0, variable->index()); 1109 const Operator* op = javascript()->StoreContext(0, variable->index());
1112 NewNode(op, current_context(), value); 1110 NewNode(op, current_context(), value);
1113 } 1111 }
1114 break; 1112 break;
1115 case VariableLocation::LOOKUP: { 1113 case VariableLocation::LOOKUP: {
1116 DCHECK(!hole_init); 1114 DCHECK(!variable->binding_needs_init());
1117 Node* name = jsgraph()->Constant(variable->name()); 1115 Node* name = jsgraph()->Constant(variable->name());
1118 const Operator* op = javascript()->CallRuntime(Runtime::kDeclareEvalVar); 1116 const Operator* op = javascript()->CallRuntime(Runtime::kDeclareEvalVar);
1119 Node* store = NewNode(op, name); 1117 Node* store = NewNode(op, name);
1120 PrepareFrameState(store, decl->proxy()->id()); 1118 PrepareFrameState(store, decl->proxy()->id());
1121 break; 1119 break;
1122 } 1120 }
1123 } 1121 }
1124 } 1122 }
1125 1123
1126 1124
(...skipping 2189 matching lines...) Expand 10 before | Expand all | Expand 10 after
3316 return environment()->Pop(); 3314 return environment()->Pop();
3317 } 3315 }
3318 3316
3319 3317
3320 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, 3318 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
3321 BailoutId bailout_id, 3319 BailoutId bailout_id,
3322 const VectorSlotPair& feedback, 3320 const VectorSlotPair& feedback,
3323 OutputFrameStateCombine combine, 3321 OutputFrameStateCombine combine,
3324 TypeofMode typeof_mode) { 3322 TypeofMode typeof_mode) {
3325 Node* the_hole = jsgraph()->TheHoleConstant(); 3323 Node* the_hole = jsgraph()->TheHoleConstant();
3326 VariableMode mode = variable->mode();
3327 switch (variable->location()) { 3324 switch (variable->location()) {
3328 case VariableLocation::GLOBAL: 3325 case VariableLocation::GLOBAL:
3329 case VariableLocation::UNALLOCATED: { 3326 case VariableLocation::UNALLOCATED: {
3330 // Global var, const, or let variable. 3327 // Global var, const, or let variable.
3331 Handle<Name> name = variable->name(); 3328 Handle<Name> name = variable->name();
3332 if (Node* node = TryLoadGlobalConstant(name)) return node; 3329 if (Node* node = TryLoadGlobalConstant(name)) return node;
3333 Node* value = BuildGlobalLoad(name, feedback, typeof_mode); 3330 Node* value = BuildGlobalLoad(name, feedback, typeof_mode);
3334 PrepareFrameState(value, bailout_id, combine); 3331 PrepareFrameState(value, bailout_id, combine);
3335 return value; 3332 return value;
3336 } 3333 }
3337 case VariableLocation::PARAMETER: 3334 case VariableLocation::PARAMETER:
3338 case VariableLocation::LOCAL: { 3335 case VariableLocation::LOCAL: {
3339 // Local var, const, or let variable. 3336 // Local var, const, or let variable.
3340 Node* value = environment()->Lookup(variable); 3337 Node* value = environment()->Lookup(variable);
3341 if (mode == LET || mode == CONST) { 3338 if (variable->binding_needs_init()) {
3342 // Perform check for uninitialized let/const variables. 3339 // Perform check for uninitialized let/const variables.
3343 if (value->op() == the_hole->op()) { 3340 if (value->op() == the_hole->op()) {
3344 value = BuildThrowReferenceError(variable, bailout_id); 3341 value = BuildThrowReferenceError(variable, bailout_id);
3345 } else if (value->opcode() == IrOpcode::kPhi) { 3342 } else if (value->opcode() == IrOpcode::kPhi) {
3346 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id); 3343 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id);
3347 } 3344 }
3348 } 3345 }
3349 return value; 3346 return value;
3350 } 3347 }
3351 case VariableLocation::CONTEXT: { 3348 case VariableLocation::CONTEXT: {
3352 // Context variable (potentially up the context chain). 3349 // Context variable (potentially up the context chain).
3353 int depth = current_scope()->ContextChainLength(variable->scope()); 3350 int depth = current_scope()->ContextChainLength(variable->scope());
3354 bool immutable = variable->maybe_assigned() == kNotAssigned; 3351 bool immutable = variable->maybe_assigned() == kNotAssigned;
3355 const Operator* op = 3352 const Operator* op =
3356 javascript()->LoadContext(depth, variable->index(), immutable); 3353 javascript()->LoadContext(depth, variable->index(), immutable);
3357 Node* value = NewNode(op, current_context()); 3354 Node* value = NewNode(op, current_context());
3358 // TODO(titzer): initialization checks are redundant for already 3355 // TODO(titzer): initialization checks are redundant for already
3359 // initialized immutable context loads, but only specialization knows. 3356 // initialized immutable context loads, but only specialization knows.
3360 // Maybe specializer should be a parameter to the graph builder? 3357 // Maybe specializer should be a parameter to the graph builder?
3361 if (mode == LET || mode == CONST) { 3358 if (variable->binding_needs_init()) {
3362 // Perform check for uninitialized let/const variables. 3359 // Perform check for uninitialized let/const variables.
3363 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id); 3360 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id);
3364 } 3361 }
3365 return value; 3362 return value;
3366 } 3363 }
3367 case VariableLocation::LOOKUP: { 3364 case VariableLocation::LOOKUP: {
3368 // Dynamic lookup of context variable (anywhere in the chain). 3365 // Dynamic lookup of context variable (anywhere in the chain).
3369 Handle<String> name = variable->name(); 3366 Handle<String> name = variable->name();
3370 if (Node* node = TryLoadDynamicVariable(variable, name, bailout_id, 3367 if (Node* node = TryLoadDynamicVariable(variable, name, bailout_id,
3371 feedback, combine, typeof_mode)) { 3368 feedback, combine, typeof_mode)) {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
3440 if (is_strict(language_mode())) { 3437 if (is_strict(language_mode())) {
3441 return BuildThrowConstAssignError(bailout_id); 3438 return BuildThrowConstAssignError(bailout_id);
3442 } 3439 }
3443 return value; 3440 return value;
3444 } else if (mode == LET && op == Token::INIT) { 3441 } else if (mode == LET && op == Token::INIT) {
3445 // No initialization check needed because scoping guarantees it. Note 3442 // No initialization check needed because scoping guarantees it. Note
3446 // that we still perform a lookup to keep the variable live, because 3443 // that we still perform a lookup to keep the variable live, because
3447 // baseline code might contain debug code that inspects the variable. 3444 // baseline code might contain debug code that inspects the variable.
3448 Node* current = environment()->Lookup(variable); 3445 Node* current = environment()->Lookup(variable);
3449 CHECK_NOT_NULL(current); 3446 CHECK_NOT_NULL(current);
3450 } else if (mode == LET && op != Token::INIT) {
3451 // Perform an initialization check for let declared variables.
3452 Node* current = environment()->Lookup(variable);
3453 if (current->op() == the_hole->op()) {
3454 return BuildThrowReferenceError(variable, bailout_id);
3455 } else if (current->opcode() == IrOpcode::kPhi) {
3456 BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3457 }
3458 } else if (mode == CONST && op == Token::INIT) { 3447 } else if (mode == CONST && op == Token::INIT) {
3459 // Perform an initialization check for const {this} variables. 3448 // Perform an initialization check for const {this} variables.
3460 // Note that the {this} variable is the only const variable being able 3449 // Note that the {this} variable is the only const variable being able
3461 // to trigger bind operations outside the TDZ, via {super} calls. 3450 // to trigger bind operations outside the TDZ, via {super} calls.
3462 Node* current = environment()->Lookup(variable); 3451 Node* current = environment()->Lookup(variable);
3463 if (current->op() != the_hole->op() && variable->is_this()) { 3452 if (current->op() != the_hole->op() && variable->is_this()) {
3464 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); 3453 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id);
3465 } 3454 }
3466 } else if (mode == CONST && op != Token::INIT) { 3455 } else if (IsLexicalVariableMode(mode) && op != Token::INIT) {
3467 // Assignment to const is exception in all modes. 3456 // Perform an initialization check for lexically declared variables.
3468 Node* current = environment()->Lookup(variable); 3457 Node* current = environment()->Lookup(variable);
3469 if (current->op() == the_hole->op()) { 3458 if (variable->binding_needs_init()) {
3470 return BuildThrowReferenceError(variable, bailout_id); 3459 if (current->op() == the_hole->op()) {
3471 } else if (current->opcode() == IrOpcode::kPhi) { 3460 return BuildThrowReferenceError(variable, bailout_id);
3472 BuildHoleCheckThenThrow(current, variable, value, bailout_id); 3461 } else if (current->opcode() == IrOpcode::kPhi) {
3462 BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3463 }
3473 } 3464 }
3474 return BuildThrowConstAssignError(bailout_id); 3465 if (mode == CONST) {
3466 return BuildThrowConstAssignError(bailout_id);
3467 }
3475 } 3468 }
3476 environment()->Bind(variable, value); 3469 environment()->Bind(variable, value);
3477 return value; 3470 return value;
3478 case VariableLocation::CONTEXT: { 3471 case VariableLocation::CONTEXT: {
3479 // Context variable (potentially up the context chain). 3472 // Context variable (potentially up the context chain).
3480 int depth = current_scope()->ContextChainLength(variable->scope()); 3473 int depth = current_scope()->ContextChainLength(variable->scope());
3481 if (mode == CONST_LEGACY && op != Token::INIT) { 3474 if (mode == CONST_LEGACY && op != Token::INIT) {
3482 // Non-initializing assignment to legacy const is 3475 // Non-initializing assignment to legacy const is
3483 // - exception in strict mode. 3476 // - exception in strict mode.
3484 // - ignored in sloppy mode. 3477 // - ignored in sloppy mode.
3485 if (is_strict(language_mode())) { 3478 if (is_strict(language_mode())) {
3486 return BuildThrowConstAssignError(bailout_id); 3479 return BuildThrowConstAssignError(bailout_id);
3487 } 3480 }
3488 return value; 3481 return value;
3489 } else if (mode == LET && op != Token::INIT) {
3490 // Perform an initialization check for let declared variables.
3491 const Operator* op =
3492 javascript()->LoadContext(depth, variable->index(), false);
3493 Node* current = NewNode(op, current_context());
3494 value = BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3495 } else if (mode == CONST && op == Token::INIT) { 3482 } else if (mode == CONST && op == Token::INIT) {
3496 // Perform an initialization check for const {this} variables. 3483 // Perform an initialization check for const {this} variables.
3497 // Note that the {this} variable is the only const variable being able 3484 // Note that the {this} variable is the only const variable being able
3498 // to trigger bind operations outside the TDZ, via {super} calls. 3485 // to trigger bind operations outside the TDZ, via {super} calls.
3499 if (variable->is_this()) { 3486 if (variable->is_this()) {
3500 const Operator* op = 3487 const Operator* op =
3501 javascript()->LoadContext(depth, variable->index(), false); 3488 javascript()->LoadContext(depth, variable->index(), false);
3502 Node* current = NewNode(op, current_context()); 3489 Node* current = NewNode(op, current_context());
3503 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); 3490 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id);
3504 } 3491 }
3505 } else if (mode == CONST && op != Token::INIT) { 3492 } else if (IsLexicalVariableMode(mode) && op != Token::INIT) {
3506 // Assignment to const is exception in all modes. 3493 // Perform an initialization check for lexically declared variables.
3507 const Operator* op = 3494 if (variable->binding_needs_init()) {
3508 javascript()->LoadContext(depth, variable->index(), false); 3495 const Operator* op =
3509 Node* current = NewNode(op, current_context()); 3496 javascript()->LoadContext(depth, variable->index(), false);
3510 BuildHoleCheckThenThrow(current, variable, value, bailout_id); 3497 Node* current = NewNode(op, current_context());
3511 return BuildThrowConstAssignError(bailout_id); 3498 value = BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3499 }
3500 if (mode == CONST) {
3501 // Assignment to const is exception in all modes.
3502 return BuildThrowConstAssignError(bailout_id);
3503 }
3512 } 3504 }
3513 const Operator* op = javascript()->StoreContext(depth, variable->index()); 3505 const Operator* op = javascript()->StoreContext(depth, variable->index());
3514 return NewNode(op, current_context(), value); 3506 return NewNode(op, current_context(), value);
3515 } 3507 }
3516 case VariableLocation::LOOKUP: { 3508 case VariableLocation::LOOKUP: {
3517 // Dynamic lookup of context variable (anywhere in the chain). 3509 // Dynamic lookup of context variable (anywhere in the chain).
3518 Handle<Name> name = variable->name(); 3510 Handle<Name> name = variable->name();
3519 Node* store = BuildDynamicStore(name, value); 3511 Node* store = BuildDynamicStore(name, value);
3520 PrepareFrameState(store, bailout_id, combine); 3512 PrepareFrameState(store, bailout_id, combine);
3521 return store; 3513 return store;
(...skipping 795 matching lines...) Expand 10 before | Expand all | Expand 10 after
4317 // Phi does not exist yet, introduce one. 4309 // Phi does not exist yet, introduce one.
4318 value = NewPhi(inputs, value, control); 4310 value = NewPhi(inputs, value, control);
4319 value->ReplaceInput(inputs - 1, other); 4311 value->ReplaceInput(inputs - 1, other);
4320 } 4312 }
4321 return value; 4313 return value;
4322 } 4314 }
4323 4315
4324 } // namespace compiler 4316 } // namespace compiler
4325 } // namespace internal 4317 } // namespace internal
4326 } // namespace v8 4318 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | src/crankshaft/hydrogen.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698