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/compile-time-value.h" | 7 #include "src/ast/compile-time-value.h" |
8 #include "src/ast/scopes.h" | 8 #include "src/ast/scopes.h" |
9 #include "src/compilation-info.h" | 9 #include "src/compilation-info.h" |
10 #include "src/compiler.h" | 10 #include "src/compiler.h" |
(...skipping 907 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
918 if (!CheckStackOverflow()) { | 918 if (!CheckStackOverflow()) { |
919 VisitNoStackOverflowCheck(expr); | 919 VisitNoStackOverflowCheck(expr); |
920 } else { | 920 } else { |
921 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); | 921 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); |
922 } | 922 } |
923 } | 923 } |
924 | 924 |
925 | 925 |
926 void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) { | 926 void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) { |
927 Variable* variable = decl->proxy()->var(); | 927 Variable* variable = decl->proxy()->var(); |
928 DCHECK(!variable->binding_needs_init()); | |
929 switch (variable->location()) { | 928 switch (variable->location()) { |
930 case VariableLocation::UNALLOCATED: { | 929 case VariableLocation::UNALLOCATED: { |
| 930 DCHECK(!variable->binding_needs_init()); |
931 globals()->push_back(variable->name()); | 931 globals()->push_back(variable->name()); |
932 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot(); | 932 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot(); |
933 DCHECK(!slot.IsInvalid()); | 933 DCHECK(!slot.IsInvalid()); |
934 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate())); | 934 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate())); |
935 globals()->push_back(isolate()->factory()->undefined_value()); | 935 globals()->push_back(isolate()->factory()->undefined_value()); |
936 break; | 936 break; |
937 } | 937 } |
938 case VariableLocation::PARAMETER: | 938 case VariableLocation::PARAMETER: |
939 case VariableLocation::LOCAL: | 939 case VariableLocation::LOCAL: |
| 940 if (variable->binding_needs_init()) { |
| 941 Node* value = jsgraph()->TheHoleConstant(); |
| 942 environment()->Bind(variable, value); |
| 943 } |
| 944 break; |
940 case VariableLocation::CONTEXT: | 945 case VariableLocation::CONTEXT: |
| 946 if (variable->binding_needs_init()) { |
| 947 Node* value = jsgraph()->TheHoleConstant(); |
| 948 const Operator* op = javascript()->StoreContext(0, variable->index()); |
| 949 NewNode(op, value); |
| 950 } |
941 break; | 951 break; |
942 case VariableLocation::LOOKUP: | 952 case VariableLocation::LOOKUP: |
943 case VariableLocation::MODULE: | 953 case VariableLocation::MODULE: |
944 UNREACHABLE(); | 954 UNREACHABLE(); |
945 } | 955 } |
946 } | 956 } |
947 | 957 |
948 | 958 |
949 void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) { | 959 void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) { |
950 Variable* variable = decl->proxy()->var(); | 960 Variable* variable = decl->proxy()->var(); |
(...skipping 1517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2468 PrepareFrameState(object, BailoutId::None()); | 2478 PrepareFrameState(object, BailoutId::None()); |
2469 | 2479 |
2470 // Assign the object to the {arguments} variable. This should never lazy | 2480 // Assign the object to the {arguments} variable. This should never lazy |
2471 // deopt, so it is fine to send invalid bailout id. | 2481 // deopt, so it is fine to send invalid bailout id. |
2472 DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated()); | 2482 DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated()); |
2473 BuildVariableAssignment(arguments, object, Token::ASSIGN, VectorSlotPair(), | 2483 BuildVariableAssignment(arguments, object, Token::ASSIGN, VectorSlotPair(), |
2474 BailoutId::None()); | 2484 BailoutId::None()); |
2475 return object; | 2485 return object; |
2476 } | 2486 } |
2477 | 2487 |
| 2488 Node* AstGraphBuilder::BuildHoleCheckThenThrow(Node* value, Variable* variable, |
| 2489 Node* not_hole, |
| 2490 BailoutId bailout_id) { |
| 2491 IfBuilder hole_check(this); |
| 2492 Node* the_hole = jsgraph()->TheHoleConstant(); |
| 2493 Node* check = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), |
| 2494 value, the_hole); |
| 2495 hole_check.If(check); |
| 2496 hole_check.Then(); |
| 2497 Node* error = BuildThrowReferenceError(variable, bailout_id); |
| 2498 environment()->Push(error); |
| 2499 hole_check.Else(); |
| 2500 environment()->Push(not_hole); |
| 2501 hole_check.End(); |
| 2502 return environment()->Pop(); |
| 2503 } |
| 2504 |
| 2505 |
| 2506 Node* AstGraphBuilder::BuildHoleCheckElseThrow(Node* value, Variable* variable, |
| 2507 Node* for_hole, |
| 2508 BailoutId bailout_id) { |
| 2509 IfBuilder hole_check(this); |
| 2510 Node* the_hole = jsgraph()->TheHoleConstant(); |
| 2511 Node* check = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), |
| 2512 value, the_hole); |
| 2513 hole_check.If(check); |
| 2514 hole_check.Then(); |
| 2515 environment()->Push(for_hole); |
| 2516 hole_check.Else(); |
| 2517 Node* error = BuildThrowReferenceError(variable, bailout_id); |
| 2518 environment()->Push(error); |
| 2519 hole_check.End(); |
| 2520 return environment()->Pop(); |
| 2521 } |
| 2522 |
2478 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, | 2523 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, |
2479 BailoutId bailout_id, | 2524 BailoutId bailout_id, |
2480 const VectorSlotPair& feedback, | 2525 const VectorSlotPair& feedback, |
2481 OutputFrameStateCombine combine, | 2526 OutputFrameStateCombine combine, |
2482 TypeofMode typeof_mode) { | 2527 TypeofMode typeof_mode) { |
2483 DCHECK(!variable->binding_needs_init()); | 2528 Node* the_hole = jsgraph()->TheHoleConstant(); |
2484 switch (variable->location()) { | 2529 switch (variable->location()) { |
2485 case VariableLocation::UNALLOCATED: { | 2530 case VariableLocation::UNALLOCATED: { |
2486 // Global var, const, or let variable. | 2531 // Global var, const, or let variable. |
2487 Handle<Name> name = variable->name(); | 2532 Handle<Name> name = variable->name(); |
2488 if (Node* node = TryLoadGlobalConstant(name)) return node; | 2533 if (Node* node = TryLoadGlobalConstant(name)) return node; |
2489 Node* value = BuildGlobalLoad(name, feedback, typeof_mode); | 2534 Node* value = BuildGlobalLoad(name, feedback, typeof_mode); |
2490 PrepareFrameState(value, bailout_id, combine); | 2535 PrepareFrameState(value, bailout_id, combine); |
2491 return value; | 2536 return value; |
2492 } | 2537 } |
2493 case VariableLocation::PARAMETER: | 2538 case VariableLocation::PARAMETER: |
2494 case VariableLocation::LOCAL: | 2539 case VariableLocation::LOCAL: { |
2495 // Local variable. | 2540 // Local var, const, or let variable. |
2496 return environment()->Lookup(variable); | 2541 Node* value = environment()->Lookup(variable); |
| 2542 if (variable->binding_needs_init()) { |
| 2543 // Perform check for uninitialized let/const variables. |
| 2544 if (value->op() == the_hole->op()) { |
| 2545 value = BuildThrowReferenceError(variable, bailout_id); |
| 2546 } else if (value->opcode() == IrOpcode::kPhi) { |
| 2547 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id); |
| 2548 } |
| 2549 } |
| 2550 return value; |
| 2551 } |
2497 case VariableLocation::CONTEXT: { | 2552 case VariableLocation::CONTEXT: { |
2498 // Context variable (potentially up the context chain). | 2553 // Context variable (potentially up the context chain). |
2499 int depth = current_scope()->ContextChainLength(variable->scope()); | 2554 int depth = current_scope()->ContextChainLength(variable->scope()); |
2500 // TODO(mstarzinger): The {maybe_assigned} flag computed during variable | 2555 // TODO(mstarzinger): The {maybe_assigned} flag computed during variable |
2501 // resolution is highly inaccurate and cannot be trusted. We are only | 2556 // resolution is highly inaccurate and cannot be trusted. We are only |
2502 // taking this information into account when asm.js compilation is used. | 2557 // taking this information into account when asm.js compilation is used. |
2503 bool immutable = variable->maybe_assigned() == kNotAssigned && | 2558 bool immutable = variable->maybe_assigned() == kNotAssigned && |
2504 info()->is_function_context_specializing(); | 2559 info()->is_function_context_specializing(); |
2505 const Operator* op = | 2560 const Operator* op = |
2506 javascript()->LoadContext(depth, variable->index(), immutable); | 2561 javascript()->LoadContext(depth, variable->index(), immutable); |
2507 return NewNode(op); | 2562 Node* value = NewNode(op); |
| 2563 // TODO(titzer): initialization checks are redundant for already |
| 2564 // initialized immutable context loads, but only specialization knows. |
| 2565 // Maybe specializer should be a parameter to the graph builder? |
| 2566 if (variable->binding_needs_init()) { |
| 2567 // Perform check for uninitialized let/const variables. |
| 2568 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id); |
| 2569 } |
| 2570 return value; |
2508 } | 2571 } |
2509 case VariableLocation::LOOKUP: | 2572 case VariableLocation::LOOKUP: |
2510 case VariableLocation::MODULE: | 2573 case VariableLocation::MODULE: |
2511 UNREACHABLE(); | 2574 UNREACHABLE(); |
2512 } | 2575 } |
2513 UNREACHABLE(); | 2576 UNREACHABLE(); |
2514 return nullptr; | 2577 return nullptr; |
2515 } | 2578 } |
2516 | 2579 |
2517 | 2580 |
(...skipping 21 matching lines...) Expand all Loading... |
2539 UNREACHABLE(); | 2602 UNREACHABLE(); |
2540 } | 2603 } |
2541 UNREACHABLE(); | 2604 UNREACHABLE(); |
2542 return nullptr; | 2605 return nullptr; |
2543 } | 2606 } |
2544 | 2607 |
2545 Node* AstGraphBuilder::BuildVariableAssignment( | 2608 Node* AstGraphBuilder::BuildVariableAssignment( |
2546 Variable* variable, Node* value, Token::Value op, | 2609 Variable* variable, Node* value, Token::Value op, |
2547 const VectorSlotPair& feedback, BailoutId bailout_id, | 2610 const VectorSlotPair& feedback, BailoutId bailout_id, |
2548 OutputFrameStateCombine combine) { | 2611 OutputFrameStateCombine combine) { |
2549 DCHECK(!variable->binding_needs_init()); | 2612 Node* the_hole = jsgraph()->TheHoleConstant(); |
| 2613 VariableMode mode = variable->mode(); |
2550 switch (variable->location()) { | 2614 switch (variable->location()) { |
2551 case VariableLocation::UNALLOCATED: { | 2615 case VariableLocation::UNALLOCATED: { |
2552 // Global var, const, or let variable. | 2616 // Global var, const, or let variable. |
2553 Handle<Name> name = variable->name(); | 2617 Handle<Name> name = variable->name(); |
2554 Node* store = BuildGlobalStore(name, value, feedback); | 2618 Node* store = BuildGlobalStore(name, value, feedback); |
2555 PrepareFrameState(store, bailout_id, combine); | 2619 PrepareFrameState(store, bailout_id, combine); |
2556 return store; | 2620 return store; |
2557 } | 2621 } |
2558 case VariableLocation::PARAMETER: | 2622 case VariableLocation::PARAMETER: |
2559 case VariableLocation::LOCAL: | 2623 case VariableLocation::LOCAL: |
2560 DCHECK(!variable->is_this()); | 2624 // Local var, const, or let variable. |
2561 if (variable->mode() == CONST && op != Token::INIT) { | 2625 if (mode == LET && op == Token::INIT) { |
| 2626 // No initialization check needed because scoping guarantees it. Note |
| 2627 // that we still perform a lookup to keep the variable live, because |
| 2628 // baseline code might contain debug code that inspects the variable. |
| 2629 Node* current = environment()->Lookup(variable); |
| 2630 CHECK_NOT_NULL(current); |
| 2631 } else if (mode == LET && op != Token::INIT && |
| 2632 variable->binding_needs_init()) { |
| 2633 // Perform an initialization check for let declared variables. |
| 2634 Node* current = environment()->Lookup(variable); |
| 2635 if (current->op() == the_hole->op()) { |
| 2636 return BuildThrowReferenceError(variable, bailout_id); |
| 2637 } else if (current->opcode() == IrOpcode::kPhi) { |
| 2638 BuildHoleCheckThenThrow(current, variable, value, bailout_id); |
| 2639 } |
| 2640 } else if (mode == CONST && op == Token::INIT) { |
| 2641 // Perform an initialization check for const {this} variables. |
| 2642 // Note that the {this} variable is the only const variable being able |
| 2643 // to trigger bind operations outside the TDZ, via {super} calls. |
| 2644 Node* current = environment()->Lookup(variable); |
| 2645 if (current->op() != the_hole->op() && variable->is_this()) { |
| 2646 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); |
| 2647 } |
| 2648 } else if (mode == CONST && op != Token::INIT && |
| 2649 variable->is_sloppy_function_name()) { |
2562 // Non-initializing assignment to sloppy function names is | 2650 // Non-initializing assignment to sloppy function names is |
2563 // - exception in strict mode. | 2651 // - exception in strict mode. |
2564 // - ignored in sloppy mode. | 2652 // - ignored in sloppy mode. |
2565 DCHECK(variable->is_sloppy_function_name()); | 2653 DCHECK(!variable->binding_needs_init()); |
2566 if (variable->throw_on_const_assignment(language_mode())) { | 2654 if (variable->throw_on_const_assignment(language_mode())) { |
2567 return BuildThrowConstAssignError(bailout_id); | 2655 return BuildThrowConstAssignError(bailout_id); |
2568 } | 2656 } |
2569 return value; | 2657 return value; |
| 2658 } else if (mode == CONST && op != Token::INIT) { |
| 2659 if (variable->binding_needs_init()) { |
| 2660 Node* current = environment()->Lookup(variable); |
| 2661 if (current->op() == the_hole->op()) { |
| 2662 return BuildThrowReferenceError(variable, bailout_id); |
| 2663 } else if (current->opcode() == IrOpcode::kPhi) { |
| 2664 BuildHoleCheckThenThrow(current, variable, value, bailout_id); |
| 2665 } |
| 2666 } |
| 2667 // Assignment to const is exception in all modes. |
| 2668 return BuildThrowConstAssignError(bailout_id); |
2570 } | 2669 } |
2571 environment()->Bind(variable, value); | 2670 environment()->Bind(variable, value); |
2572 return value; | 2671 return value; |
2573 case VariableLocation::CONTEXT: { | 2672 case VariableLocation::CONTEXT: { |
2574 DCHECK(!variable->is_this()); | |
2575 // Context variable (potentially up the context chain). | 2673 // Context variable (potentially up the context chain). |
2576 if (variable->mode() == CONST && op != Token::INIT) { | 2674 int depth = current_scope()->ContextChainLength(variable->scope()); |
| 2675 if (mode == LET && op != Token::INIT && variable->binding_needs_init()) { |
| 2676 // Perform an initialization check for let declared variables. |
| 2677 const Operator* op = |
| 2678 javascript()->LoadContext(depth, variable->index(), false); |
| 2679 Node* current = NewNode(op); |
| 2680 value = BuildHoleCheckThenThrow(current, variable, value, bailout_id); |
| 2681 } else if (mode == CONST && op == Token::INIT) { |
| 2682 // Perform an initialization check for const {this} variables. |
| 2683 // Note that the {this} variable is the only const variable being able |
| 2684 // to trigger bind operations outside the TDZ, via {super} calls. |
| 2685 if (variable->is_this()) { |
| 2686 const Operator* op = |
| 2687 javascript()->LoadContext(depth, variable->index(), false); |
| 2688 Node* current = NewNode(op); |
| 2689 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); |
| 2690 } |
| 2691 } else if (mode == CONST && op != Token::INIT && |
| 2692 variable->is_sloppy_function_name()) { |
2577 // Non-initializing assignment to sloppy function names is | 2693 // Non-initializing assignment to sloppy function names is |
2578 // - exception in strict mode. | 2694 // - exception in strict mode. |
2579 // - ignored in sloppy mode. | 2695 // - ignored in sloppy mode. |
2580 DCHECK(variable->is_sloppy_function_name()); | 2696 DCHECK(!variable->binding_needs_init()); |
2581 if (variable->throw_on_const_assignment(language_mode())) { | 2697 if (variable->throw_on_const_assignment(language_mode())) { |
2582 return BuildThrowConstAssignError(bailout_id); | 2698 return BuildThrowConstAssignError(bailout_id); |
2583 } | 2699 } |
2584 return value; | 2700 return value; |
| 2701 } else if (mode == CONST && op != Token::INIT) { |
| 2702 if (variable->binding_needs_init()) { |
| 2703 const Operator* op = |
| 2704 javascript()->LoadContext(depth, variable->index(), false); |
| 2705 Node* current = NewNode(op); |
| 2706 BuildHoleCheckThenThrow(current, variable, value, bailout_id); |
| 2707 } |
| 2708 // Assignment to const is exception in all modes. |
| 2709 return BuildThrowConstAssignError(bailout_id); |
2585 } | 2710 } |
2586 int depth = current_scope()->ContextChainLength(variable->scope()); | |
2587 const Operator* op = javascript()->StoreContext(depth, variable->index()); | 2711 const Operator* op = javascript()->StoreContext(depth, variable->index()); |
2588 return NewNode(op, value); | 2712 return NewNode(op, value); |
2589 } | 2713 } |
2590 case VariableLocation::LOOKUP: | 2714 case VariableLocation::LOOKUP: |
2591 case VariableLocation::MODULE: | 2715 case VariableLocation::MODULE: |
2592 UNREACHABLE(); | 2716 UNREACHABLE(); |
2593 } | 2717 } |
2594 UNREACHABLE(); | 2718 UNREACHABLE(); |
2595 return nullptr; | 2719 return nullptr; |
2596 } | 2720 } |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2693 Node* AstGraphBuilder::BuildThrowError(Node* exception, BailoutId bailout_id) { | 2817 Node* AstGraphBuilder::BuildThrowError(Node* exception, BailoutId bailout_id) { |
2694 const Operator* op = javascript()->CallRuntime(Runtime::kThrow); | 2818 const Operator* op = javascript()->CallRuntime(Runtime::kThrow); |
2695 Node* call = NewNode(op, exception); | 2819 Node* call = NewNode(op, exception); |
2696 PrepareFrameState(call, bailout_id); | 2820 PrepareFrameState(call, bailout_id); |
2697 Node* control = NewNode(common()->Throw(), call); | 2821 Node* control = NewNode(common()->Throw(), call); |
2698 UpdateControlDependencyToLeaveFunction(control); | 2822 UpdateControlDependencyToLeaveFunction(control); |
2699 return call; | 2823 return call; |
2700 } | 2824 } |
2701 | 2825 |
2702 | 2826 |
| 2827 Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable, |
| 2828 BailoutId bailout_id) { |
| 2829 Node* variable_name = jsgraph()->Constant(variable->name()); |
| 2830 const Operator* op = javascript()->CallRuntime(Runtime::kThrowReferenceError); |
| 2831 Node* call = NewNode(op, variable_name); |
| 2832 PrepareFrameState(call, bailout_id); |
| 2833 Node* control = NewNode(common()->Throw(), call); |
| 2834 UpdateControlDependencyToLeaveFunction(control); |
| 2835 return call; |
| 2836 } |
| 2837 |
| 2838 |
2703 Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) { | 2839 Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) { |
2704 const Operator* op = | 2840 const Operator* op = |
2705 javascript()->CallRuntime(Runtime::kThrowConstAssignError); | 2841 javascript()->CallRuntime(Runtime::kThrowConstAssignError); |
2706 Node* call = NewNode(op); | 2842 Node* call = NewNode(op); |
2707 PrepareFrameState(call, bailout_id); | 2843 PrepareFrameState(call, bailout_id); |
2708 Node* control = NewNode(common()->Throw(), call); | 2844 Node* control = NewNode(common()->Throw(), call); |
2709 UpdateControlDependencyToLeaveFunction(control); | 2845 UpdateControlDependencyToLeaveFunction(control); |
2710 return call; | 2846 return call; |
2711 } | 2847 } |
2712 | 2848 |
(...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3166 float invocation_frequency, LoopAssignmentAnalysis* loop_assignment, | 3302 float invocation_frequency, LoopAssignmentAnalysis* loop_assignment, |
3167 SourcePositionTable* source_positions, int inlining_id) | 3303 SourcePositionTable* source_positions, int inlining_id) |
3168 : AstGraphBuilder(local_zone, info, jsgraph, invocation_frequency, | 3304 : AstGraphBuilder(local_zone, info, jsgraph, invocation_frequency, |
3169 loop_assignment), | 3305 loop_assignment), |
3170 source_positions_(source_positions), | 3306 source_positions_(source_positions), |
3171 start_position_(info->shared_info()->start_position(), inlining_id) {} | 3307 start_position_(info->shared_info()->start_position(), inlining_id) {} |
3172 | 3308 |
3173 } // namespace compiler | 3309 } // namespace compiler |
3174 } // namespace internal | 3310 } // namespace internal |
3175 } // namespace v8 | 3311 } // namespace v8 |
OLD | NEW |