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