OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 10 matching lines...) Expand all Loading... |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #include "ast.h" | 30 #include "ast.h" |
| 31 #include "data-flow.h" |
31 #include "parser.h" | 32 #include "parser.h" |
32 #include "scopes.h" | 33 #include "scopes.h" |
33 #include "string-stream.h" | 34 #include "string-stream.h" |
34 | 35 |
35 namespace v8 { | 36 namespace v8 { |
36 namespace internal { | 37 namespace internal { |
37 | 38 |
38 | 39 |
39 VariableProxySentinel VariableProxySentinel::this_proxy_(true); | 40 VariableProxySentinel VariableProxySentinel::this_proxy_(true); |
40 VariableProxySentinel VariableProxySentinel::identifier_proxy_(false); | 41 VariableProxySentinel VariableProxySentinel::identifier_proxy_(false); |
(...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 // with the exception of +, which expresses a Number or a String. | 594 // with the exception of +, which expresses a Number or a String. |
594 return true; | 595 return true; |
595 } | 596 } |
596 } | 597 } |
597 | 598 |
598 | 599 |
599 // Compare operations always express Boolean values. | 600 // Compare operations always express Boolean values. |
600 bool CompareOperation::IsPrimitive() { return true; } | 601 bool CompareOperation::IsPrimitive() { return true; } |
601 | 602 |
602 | 603 |
| 604 // Overridden IsCritical member functions. IsCritical is true for AST nodes |
| 605 // whose evaluation is absolutely required (they are never dead) because |
| 606 // they are externally visible. |
| 607 |
| 608 // References to global variables or lookup slots are critical because they |
| 609 // may have getters. All others, including parameters rewritten to explicit |
| 610 // property references, are not critical. |
| 611 bool VariableProxy::IsCritical() { |
| 612 Variable* var = AsVariable(); |
| 613 return var != NULL && |
| 614 (var->slot() == NULL || var->slot()->type() == Slot::LOOKUP); |
| 615 } |
| 616 |
| 617 |
| 618 // Literals are never critical. |
| 619 bool Literal::IsCritical() { return false; } |
| 620 |
| 621 |
| 622 // Property assignments and throwing of reference errors are always |
| 623 // critical. Assignments to escaping variables are also critical. In |
| 624 // addition the operation of compound assignments is critical if either of |
| 625 // its operands is non-primitive (the arithmetic operations all use one of |
| 626 // ToPrimitive, ToNumber, ToInt32, or ToUint32 on each of their operands). |
| 627 // In this case, we mark the entire AST node as critical because there is |
| 628 // no binary operation node to mark. |
| 629 bool Assignment::IsCritical() { |
| 630 Variable* var = AssignedVariable(); |
| 631 return var == NULL || |
| 632 !var->IsStackAllocated() || |
| 633 (is_compound() && (!target()->IsPrimitive() || !value()->IsPrimitive())); |
| 634 } |
| 635 |
| 636 |
| 637 // Property references are always critical, because they may have getters. |
| 638 bool Property::IsCritical() { return true; } |
| 639 |
| 640 |
| 641 // Calls are always critical. |
| 642 bool Call::IsCritical() { return true; } |
| 643 |
| 644 |
| 645 // +,- use ToNumber on the value of their operand. |
| 646 bool UnaryOperation::IsCritical() { |
| 647 ASSERT(op() == Token::ADD || op() == Token::SUB); |
| 648 return !expression()->IsPrimitive(); |
| 649 } |
| 650 |
| 651 |
| 652 // Count operations targeting properties and reference errors are always |
| 653 // critical. Count operations on escaping variables are critical. Count |
| 654 // operations targeting non-primitives are also critical because they use |
| 655 // ToNumber. |
| 656 bool CountOperation::IsCritical() { |
| 657 Variable* var = AssignedVariable(); |
| 658 return var == NULL || |
| 659 !var->IsStackAllocated() || |
| 660 !expression()->IsPrimitive(); |
| 661 } |
| 662 |
| 663 |
| 664 // Arithmetic operations all use one of ToPrimitive, ToNumber, ToInt32, or |
| 665 // ToUint32 on each of their operands. |
| 666 bool BinaryOperation::IsCritical() { |
| 667 ASSERT(op() != Token::COMMA); |
| 668 ASSERT(op() != Token::OR); |
| 669 ASSERT(op() != Token::AND); |
| 670 return !left()->IsPrimitive() || !right()->IsPrimitive(); |
| 671 } |
| 672 |
| 673 |
| 674 // <, >, <=, and >= all use ToPrimitive on both their operands. |
| 675 bool CompareOperation::IsCritical() { |
| 676 ASSERT(op() != Token::EQ); |
| 677 ASSERT(op() != Token::NE); |
| 678 ASSERT(op() != Token::EQ_STRICT); |
| 679 ASSERT(op() != Token::NE_STRICT); |
| 680 ASSERT(op() != Token::INSTANCEOF); |
| 681 ASSERT(op() != Token::IN); |
| 682 return !left()->IsPrimitive() || !right()->IsPrimitive(); |
| 683 } |
| 684 |
| 685 |
| 686 static inline void MarkIfNotLive(Expression* expr, List<AstNode*>* stack) { |
| 687 if (!expr->is_live()) { |
| 688 expr->mark_as_live(); |
| 689 stack->Add(expr); |
| 690 } |
| 691 } |
| 692 |
| 693 |
| 694 // Overloaded functions for marking children of live code as live. |
| 695 void VariableProxy::ProcessNonLiveChildren( |
| 696 List<AstNode*>* stack, |
| 697 ZoneList<Expression*>* body_definitions, |
| 698 int variable_count) { |
| 699 // A reference to a stack-allocated variable depends on all the |
| 700 // definitions reaching it. |
| 701 BitVector* defs = reaching_definitions(); |
| 702 if (defs != NULL) { |
| 703 ASSERT(var()->IsStackAllocated()); |
| 704 // The first variable_count definitions are the initial parameter and |
| 705 // local declarations. |
| 706 for (int i = variable_count; i < defs->length(); i++) { |
| 707 if (defs->Contains(i)) { |
| 708 MarkIfNotLive(body_definitions->at(i - variable_count), stack); |
| 709 } |
| 710 } |
| 711 } |
| 712 } |
| 713 |
| 714 |
| 715 void Literal::ProcessNonLiveChildren(List<AstNode*>* stack, |
| 716 ZoneList<Expression*>* body_definitions, |
| 717 int variable_count) { |
| 718 // Leaf node, no children. |
| 719 } |
| 720 |
| 721 |
| 722 void Assignment::ProcessNonLiveChildren( |
| 723 List<AstNode*>* stack, |
| 724 ZoneList<Expression*>* body_definitions, |
| 725 int variable_count) { |
| 726 Property* prop = target()->AsProperty(); |
| 727 VariableProxy* proxy = target()->AsVariableProxy(); |
| 728 |
| 729 if (prop != NULL) { |
| 730 if (!prop->key()->IsPropertyName()) MarkIfNotLive(prop->key(), stack); |
| 731 MarkIfNotLive(prop->obj(), stack); |
| 732 } else if (proxy == NULL) { |
| 733 // Must be a reference error. |
| 734 ASSERT(!target()->IsValidLeftHandSide()); |
| 735 MarkIfNotLive(target(), stack); |
| 736 } else if (is_compound()) { |
| 737 // A variable assignment so lhs is an operand to the operation. |
| 738 MarkIfNotLive(target(), stack); |
| 739 } |
| 740 MarkIfNotLive(value(), stack); |
| 741 } |
| 742 |
| 743 |
| 744 void Property::ProcessNonLiveChildren(List<AstNode*>* stack, |
| 745 ZoneList<Expression*>* body_definitions, |
| 746 int variable_count) { |
| 747 if (!key()->IsPropertyName()) MarkIfNotLive(key(), stack); |
| 748 MarkIfNotLive(obj(), stack); |
| 749 } |
| 750 |
| 751 |
| 752 void Call::ProcessNonLiveChildren(List<AstNode*>* stack, |
| 753 ZoneList<Expression*>* body_definitions, |
| 754 int variable_count) { |
| 755 ZoneList<Expression*>* args = arguments(); |
| 756 for (int i = args->length() - 1; i >= 0; i--) { |
| 757 MarkIfNotLive(args->at(i), stack); |
| 758 } |
| 759 MarkIfNotLive(expression(), stack); |
| 760 } |
| 761 |
| 762 |
| 763 void UnaryOperation::ProcessNonLiveChildren( |
| 764 List<AstNode*>* stack, |
| 765 ZoneList<Expression*>* body_definitions, |
| 766 int variable_count) { |
| 767 MarkIfNotLive(expression(), stack); |
| 768 } |
| 769 |
| 770 |
| 771 void CountOperation::ProcessNonLiveChildren( |
| 772 List<AstNode*>* stack, |
| 773 ZoneList<Expression*>* body_definitions, |
| 774 int variable_count) { |
| 775 MarkIfNotLive(expression(), stack); |
| 776 } |
| 777 |
| 778 |
| 779 void BinaryOperation::ProcessNonLiveChildren( |
| 780 List<AstNode*>* stack, |
| 781 ZoneList<Expression*>* body_definitions, |
| 782 int variable_count) { |
| 783 MarkIfNotLive(right(), stack); |
| 784 MarkIfNotLive(left(), stack); |
| 785 } |
| 786 |
| 787 |
| 788 void CompareOperation::ProcessNonLiveChildren( |
| 789 List<AstNode*>* stack, |
| 790 ZoneList<Expression*>* body_definitions, |
| 791 int variable_count) { |
| 792 MarkIfNotLive(right(), stack); |
| 793 MarkIfNotLive(left(), stack); |
| 794 } |
| 795 |
| 796 |
603 // Implementation of a copy visitor. The visitor create a deep copy | 797 // Implementation of a copy visitor. The visitor create a deep copy |
604 // of ast nodes. Nodes that do not require a deep copy are copied | 798 // of ast nodes. Nodes that do not require a deep copy are copied |
605 // with the default copy constructor. | 799 // with the default copy constructor. |
606 | 800 |
607 AstNode::AstNode(AstNode* other) : num_(kNoNumber) { | 801 AstNode::AstNode(AstNode* other) : num_(kNoNumber) { |
608 // AST node number should be unique. Assert that we only copy AstNodes | 802 // AST node number should be unique. Assert that we only copy AstNodes |
609 // before node numbers are assigned. | 803 // before node numbers are assigned. |
610 ASSERT(other->num_ == kNoNumber); | 804 ASSERT(other->num_ == kNoNumber); |
611 } | 805 } |
612 | 806 |
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
977 SetStackOverflow(); | 1171 SetStackOverflow(); |
978 } | 1172 } |
979 | 1173 |
980 | 1174 |
981 void CopyAstVisitor::VisitDeclaration(Declaration* decl) { | 1175 void CopyAstVisitor::VisitDeclaration(Declaration* decl) { |
982 UNREACHABLE(); | 1176 UNREACHABLE(); |
983 } | 1177 } |
984 | 1178 |
985 | 1179 |
986 } } // namespace v8::internal | 1180 } } // namespace v8::internal |
OLD | NEW |