| 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 |