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