OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |