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/compiler.h" | 7 #include "src/compiler.h" |
8 #include "src/compiler/ast-loop-assignment-analyzer.h" | 8 #include "src/compiler/ast-loop-assignment-analyzer.h" |
9 #include "src/compiler/control-builders.h" | 9 #include "src/compiler/control-builders.h" |
10 #include "src/compiler/linkage.h" | 10 #include "src/compiler/linkage.h" |
(...skipping 1614 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1625 javascript()->CallRuntime(Runtime::kFinalizeClassDefinition, 2); | 1625 javascript()->CallRuntime(Runtime::kFinalizeClassDefinition, 2); |
1626 literal = NewNode(op, literal, proto); | 1626 literal = NewNode(op, literal, proto); |
1627 | 1627 |
1628 // Assign to class variable. | 1628 // Assign to class variable. |
1629 if (expr->class_variable_proxy() != nullptr) { | 1629 if (expr->class_variable_proxy() != nullptr) { |
1630 Variable* var = expr->class_variable_proxy()->var(); | 1630 Variable* var = expr->class_variable_proxy()->var(); |
1631 FrameStateBeforeAndAfter states(this, BailoutId::None()); | 1631 FrameStateBeforeAndAfter states(this, BailoutId::None()); |
1632 VectorSlotPair feedback = CreateVectorSlotPair( | 1632 VectorSlotPair feedback = CreateVectorSlotPair( |
1633 expr->NeedsProxySlot() ? expr->ProxySlot() | 1633 expr->NeedsProxySlot() ? expr->ProxySlot() |
1634 : FeedbackVectorSlot::Invalid()); | 1634 : FeedbackVectorSlot::Invalid()); |
1635 BuildVariableAssignment(var, literal, Token::INIT_CONST, feedback, | 1635 BuildVariableAssignment(var, literal, Token::INIT, feedback, |
1636 BailoutId::None(), states); | 1636 BailoutId::None(), states); |
1637 } | 1637 } |
1638 ast_context()->ProduceValue(literal); | 1638 ast_context()->ProduceValue(literal); |
1639 } | 1639 } |
1640 | 1640 |
1641 | 1641 |
1642 void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { | 1642 void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { |
1643 UNREACHABLE(); | 1643 UNREACHABLE(); |
1644 } | 1644 } |
1645 | 1645 |
(...skipping 1549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3195 | 3195 |
3196 Node* AstGraphBuilder::BuildThisFunctionVariable(Variable* this_function_var) { | 3196 Node* AstGraphBuilder::BuildThisFunctionVariable(Variable* this_function_var) { |
3197 if (this_function_var == nullptr) return nullptr; | 3197 if (this_function_var == nullptr) return nullptr; |
3198 | 3198 |
3199 // Retrieve the closure we were called with. | 3199 // Retrieve the closure we were called with. |
3200 Node* this_function = GetFunctionClosure(); | 3200 Node* this_function = GetFunctionClosure(); |
3201 | 3201 |
3202 // Assign the object to the {.this_function} variable. This should never lazy | 3202 // Assign the object to the {.this_function} variable. This should never lazy |
3203 // deopt, so it is fine to send invalid bailout id. | 3203 // deopt, so it is fine to send invalid bailout id. |
3204 FrameStateBeforeAndAfter states(this, BailoutId::None()); | 3204 FrameStateBeforeAndAfter states(this, BailoutId::None()); |
3205 BuildVariableAssignment(this_function_var, this_function, Token::INIT_CONST, | 3205 BuildVariableAssignment(this_function_var, this_function, Token::INIT, |
3206 VectorSlotPair(), BailoutId::None(), states); | 3206 VectorSlotPair(), BailoutId::None(), states); |
3207 return this_function; | 3207 return this_function; |
3208 } | 3208 } |
3209 | 3209 |
3210 | 3210 |
3211 Node* AstGraphBuilder::BuildNewTargetVariable(Variable* new_target_var) { | 3211 Node* AstGraphBuilder::BuildNewTargetVariable(Variable* new_target_var) { |
3212 if (new_target_var == nullptr) return nullptr; | 3212 if (new_target_var == nullptr) return nullptr; |
3213 | 3213 |
3214 // Retrieve the original constructor in case we are called as a constructor. | 3214 // Retrieve the original constructor in case we are called as a constructor. |
3215 const Operator* op = | 3215 const Operator* op = |
3216 javascript()->CallRuntime(Runtime::kGetOriginalConstructor, 0); | 3216 javascript()->CallRuntime(Runtime::kGetOriginalConstructor, 0); |
3217 Node* object = NewNode(op); | 3217 Node* object = NewNode(op); |
3218 PrepareFrameState(object, BailoutId::None()); | 3218 PrepareFrameState(object, BailoutId::None()); |
3219 | 3219 |
3220 // Assign the object to the {new.target} variable. This should never lazy | 3220 // Assign the object to the {new.target} variable. This should never lazy |
3221 // deopt, so it is fine to send invalid bailout id. | 3221 // deopt, so it is fine to send invalid bailout id. |
3222 FrameStateBeforeAndAfter states(this, BailoutId::None()); | 3222 FrameStateBeforeAndAfter states(this, BailoutId::None()); |
3223 BuildVariableAssignment(new_target_var, object, Token::INIT_CONST, | 3223 BuildVariableAssignment(new_target_var, object, Token::INIT, VectorSlotPair(), |
3224 VectorSlotPair(), BailoutId::None(), states); | 3224 BailoutId::None(), states); |
3225 return object; | 3225 return object; |
3226 } | 3226 } |
3227 | 3227 |
3228 | 3228 |
3229 Node* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole, | 3229 Node* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole, |
3230 Node* not_hole) { | 3230 Node* not_hole) { |
3231 Node* the_hole = jsgraph()->TheHoleConstant(); | 3231 Node* the_hole = jsgraph()->TheHoleConstant(); |
3232 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole); | 3232 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole); |
3233 return NewNode(common()->Select(kMachAnyTagged, BranchHint::kFalse), check, | 3233 return NewNode(common()->Select(kMachAnyTagged, BranchHint::kFalse), check, |
3234 for_hole, not_hole); | 3234 for_hole, not_hole); |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3411 case VariableLocation::UNALLOCATED: { | 3411 case VariableLocation::UNALLOCATED: { |
3412 // Global var, const, or let variable. | 3412 // Global var, const, or let variable. |
3413 Handle<Name> name = variable->name(); | 3413 Handle<Name> name = variable->name(); |
3414 Node* store = BuildGlobalStore(name, value, feedback); | 3414 Node* store = BuildGlobalStore(name, value, feedback); |
3415 states.AddToNode(store, bailout_id, combine); | 3415 states.AddToNode(store, bailout_id, combine); |
3416 return store; | 3416 return store; |
3417 } | 3417 } |
3418 case VariableLocation::PARAMETER: | 3418 case VariableLocation::PARAMETER: |
3419 case VariableLocation::LOCAL: | 3419 case VariableLocation::LOCAL: |
3420 // Local var, const, or let variable. | 3420 // Local var, const, or let variable. |
3421 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) { | 3421 if (mode == CONST_LEGACY && op == Token::INIT) { |
3422 // Perform an initialization check for legacy const variables. | 3422 // Perform an initialization check for legacy const variables. |
3423 Node* current = environment()->Lookup(variable); | 3423 Node* current = environment()->Lookup(variable); |
3424 if (current->op() != the_hole->op()) { | 3424 if (current->op() != the_hole->op()) { |
3425 value = BuildHoleCheckSilent(current, value, current); | 3425 value = BuildHoleCheckSilent(current, value, current); |
3426 } | 3426 } |
3427 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) { | 3427 } else if (mode == CONST_LEGACY && op != Token::INIT) { |
3428 // Non-initializing assignment to legacy const is | 3428 // Non-initializing assignment to legacy const is |
3429 // - exception in strict mode. | 3429 // - exception in strict mode. |
3430 // - ignored in sloppy mode. | 3430 // - ignored in sloppy mode. |
3431 if (is_strict(language_mode())) { | 3431 if (is_strict(language_mode())) { |
3432 return BuildThrowConstAssignError(bailout_id); | 3432 return BuildThrowConstAssignError(bailout_id); |
3433 } | 3433 } |
3434 return value; | 3434 return value; |
3435 } else if (mode == LET && op == Token::INIT_LET) { | 3435 } else if (mode == LET && op == Token::INIT) { |
3436 // No initialization check needed because scoping guarantees it. Note | 3436 // No initialization check needed because scoping guarantees it. Note |
3437 // that we still perform a lookup to keep the variable live, because | 3437 // that we still perform a lookup to keep the variable live, because |
3438 // baseline code might contain debug code that inspects the variable. | 3438 // baseline code might contain debug code that inspects the variable. |
3439 Node* current = environment()->Lookup(variable); | 3439 Node* current = environment()->Lookup(variable); |
3440 CHECK_NOT_NULL(current); | 3440 CHECK_NOT_NULL(current); |
3441 } else if (mode == LET && op != Token::INIT_LET) { | 3441 } else if (mode == LET && op != Token::INIT) { |
3442 // Perform an initialization check for let declared variables. | 3442 // Perform an initialization check for let declared variables. |
3443 Node* current = environment()->Lookup(variable); | 3443 Node* current = environment()->Lookup(variable); |
3444 if (current->op() == the_hole->op()) { | 3444 if (current->op() == the_hole->op()) { |
3445 return BuildThrowReferenceError(variable, bailout_id); | 3445 return BuildThrowReferenceError(variable, bailout_id); |
3446 } else if (current->opcode() == IrOpcode::kPhi) { | 3446 } else if (current->opcode() == IrOpcode::kPhi) { |
3447 BuildHoleCheckThenThrow(current, variable, value, bailout_id); | 3447 BuildHoleCheckThenThrow(current, variable, value, bailout_id); |
3448 } | 3448 } |
3449 } else if (mode == CONST && op == Token::INIT_CONST) { | 3449 } else if (mode == CONST && op == Token::INIT) { |
3450 // Perform an initialization check for const {this} variables. | 3450 // Perform an initialization check for const {this} variables. |
3451 // Note that the {this} variable is the only const variable being able | 3451 // Note that the {this} variable is the only const variable being able |
3452 // to trigger bind operations outside the TDZ, via {super} calls. | 3452 // to trigger bind operations outside the TDZ, via {super} calls. |
3453 Node* current = environment()->Lookup(variable); | 3453 Node* current = environment()->Lookup(variable); |
3454 if (current->op() != the_hole->op() && variable->is_this()) { | 3454 if (current->op() != the_hole->op() && variable->is_this()) { |
3455 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); | 3455 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); |
3456 } | 3456 } |
3457 } else if (mode == CONST && op != Token::INIT_CONST) { | 3457 } else if (mode == CONST && op != Token::INIT) { |
3458 // Assignment to const is exception in all modes. | 3458 // Assignment to const is exception in all modes. |
3459 Node* current = environment()->Lookup(variable); | 3459 Node* current = environment()->Lookup(variable); |
3460 if (current->op() == the_hole->op()) { | 3460 if (current->op() == the_hole->op()) { |
3461 return BuildThrowReferenceError(variable, bailout_id); | 3461 return BuildThrowReferenceError(variable, bailout_id); |
3462 } else if (current->opcode() == IrOpcode::kPhi) { | 3462 } else if (current->opcode() == IrOpcode::kPhi) { |
3463 BuildHoleCheckThenThrow(current, variable, value, bailout_id); | 3463 BuildHoleCheckThenThrow(current, variable, value, bailout_id); |
3464 } | 3464 } |
3465 return BuildThrowConstAssignError(bailout_id); | 3465 return BuildThrowConstAssignError(bailout_id); |
3466 } | 3466 } |
3467 environment()->Bind(variable, value); | 3467 environment()->Bind(variable, value); |
3468 return value; | 3468 return value; |
3469 case VariableLocation::CONTEXT: { | 3469 case VariableLocation::CONTEXT: { |
3470 // Context variable (potentially up the context chain). | 3470 // Context variable (potentially up the context chain). |
3471 int depth = current_scope()->ContextChainLength(variable->scope()); | 3471 int depth = current_scope()->ContextChainLength(variable->scope()); |
3472 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) { | 3472 if (mode == CONST_LEGACY && op == Token::INIT) { |
3473 // Perform an initialization check for legacy const variables. | 3473 // Perform an initialization check for legacy const variables. |
3474 const Operator* op = | 3474 const Operator* op = |
3475 javascript()->LoadContext(depth, variable->index(), false); | 3475 javascript()->LoadContext(depth, variable->index(), false); |
3476 Node* current = NewNode(op, current_context()); | 3476 Node* current = NewNode(op, current_context()); |
3477 value = BuildHoleCheckSilent(current, value, current); | 3477 value = BuildHoleCheckSilent(current, value, current); |
3478 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) { | 3478 } else if (mode == CONST_LEGACY && op != Token::INIT) { |
3479 // Non-initializing assignment to legacy const is | 3479 // Non-initializing assignment to legacy const is |
3480 // - exception in strict mode. | 3480 // - exception in strict mode. |
3481 // - ignored in sloppy mode. | 3481 // - ignored in sloppy mode. |
3482 if (is_strict(language_mode())) { | 3482 if (is_strict(language_mode())) { |
3483 return BuildThrowConstAssignError(bailout_id); | 3483 return BuildThrowConstAssignError(bailout_id); |
3484 } | 3484 } |
3485 return value; | 3485 return value; |
3486 } else if (mode == LET && op != Token::INIT_LET) { | 3486 } else if (mode == LET && op != Token::INIT) { |
3487 // Perform an initialization check for let declared variables. | 3487 // Perform an initialization check for let declared variables. |
3488 const Operator* op = | 3488 const Operator* op = |
3489 javascript()->LoadContext(depth, variable->index(), false); | 3489 javascript()->LoadContext(depth, variable->index(), false); |
3490 Node* current = NewNode(op, current_context()); | 3490 Node* current = NewNode(op, current_context()); |
3491 value = BuildHoleCheckThenThrow(current, variable, value, bailout_id); | 3491 value = BuildHoleCheckThenThrow(current, variable, value, bailout_id); |
3492 } else if (mode == CONST && op == Token::INIT_CONST) { | 3492 } else if (mode == CONST && op == Token::INIT) { |
3493 // Perform an initialization check for const {this} variables. | 3493 // Perform an initialization check for const {this} variables. |
3494 // Note that the {this} variable is the only const variable being able | 3494 // Note that the {this} variable is the only const variable being able |
3495 // to trigger bind operations outside the TDZ, via {super} calls. | 3495 // to trigger bind operations outside the TDZ, via {super} calls. |
3496 if (variable->is_this()) { | 3496 if (variable->is_this()) { |
3497 const Operator* op = | 3497 const Operator* op = |
3498 javascript()->LoadContext(depth, variable->index(), false); | 3498 javascript()->LoadContext(depth, variable->index(), false); |
3499 Node* current = NewNode(op, current_context()); | 3499 Node* current = NewNode(op, current_context()); |
3500 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); | 3500 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); |
3501 } | 3501 } |
3502 } else if (mode == CONST && op != Token::INIT_CONST) { | 3502 } else if (mode == CONST && op != Token::INIT) { |
3503 // Assignment to const is exception in all modes. | 3503 // Assignment to const is exception in all modes. |
3504 const Operator* op = | 3504 const Operator* op = |
3505 javascript()->LoadContext(depth, variable->index(), false); | 3505 javascript()->LoadContext(depth, variable->index(), false); |
3506 Node* current = NewNode(op, current_context()); | 3506 Node* current = NewNode(op, current_context()); |
3507 BuildHoleCheckThenThrow(current, variable, value, bailout_id); | 3507 BuildHoleCheckThenThrow(current, variable, value, bailout_id); |
3508 return BuildThrowConstAssignError(bailout_id); | 3508 return BuildThrowConstAssignError(bailout_id); |
3509 } | 3509 } |
3510 const Operator* op = javascript()->StoreContext(depth, variable->index()); | 3510 const Operator* op = javascript()->StoreContext(depth, variable->index()); |
3511 return NewNode(op, current_context(), value); | 3511 return NewNode(op, current_context(), value); |
3512 } | 3512 } |
(...skipping 783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4296 // Phi does not exist yet, introduce one. | 4296 // Phi does not exist yet, introduce one. |
4297 value = NewPhi(inputs, value, control); | 4297 value = NewPhi(inputs, value, control); |
4298 value->ReplaceInput(inputs - 1, other); | 4298 value->ReplaceInput(inputs - 1, other); |
4299 } | 4299 } |
4300 return value; | 4300 return value; |
4301 } | 4301 } |
4302 | 4302 |
4303 } // namespace compiler | 4303 } // namespace compiler |
4304 } // namespace internal | 4304 } // namespace internal |
4305 } // namespace v8 | 4305 } // namespace v8 |
OLD | NEW |