| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 403 ZoneSplayTree<Config>* tree() { return &tree_; } | 403 ZoneSplayTree<Config>* tree() { return &tree_; } |
| 404 ZoneSplayTree<Config> tree_; | 404 ZoneSplayTree<Config> tree_; |
| 405 }; | 405 }; |
| 406 | 406 |
| 407 | 407 |
| 408 #define FOR_EACH_NODE_TYPE(VISIT) \ | 408 #define FOR_EACH_NODE_TYPE(VISIT) \ |
| 409 VISIT(End) \ | 409 VISIT(End) \ |
| 410 VISIT(Action) \ | 410 VISIT(Action) \ |
| 411 VISIT(Choice) \ | 411 VISIT(Choice) \ |
| 412 VISIT(BackReference) \ | 412 VISIT(BackReference) \ |
| 413 VISIT(Assertion) \ |
| 413 VISIT(Text) | 414 VISIT(Text) |
| 414 | 415 |
| 415 | 416 |
| 416 #define FOR_EACH_REG_EXP_TREE_TYPE(VISIT) \ | 417 #define FOR_EACH_REG_EXP_TREE_TYPE(VISIT) \ |
| 417 VISIT(Disjunction) \ | 418 VISIT(Disjunction) \ |
| 418 VISIT(Alternative) \ | 419 VISIT(Alternative) \ |
| 419 VISIT(Assertion) \ | 420 VISIT(Assertion) \ |
| 420 VISIT(CharacterClass) \ | 421 VISIT(CharacterClass) \ |
| 421 VISIT(Atom) \ | 422 VISIT(Atom) \ |
| 422 VISIT(Quantifier) \ | 423 VISIT(Quantifier) \ |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 uint32_t value_; | 581 uint32_t value_; |
| 581 }; | 582 }; |
| 582 | 583 |
| 583 | 584 |
| 584 class RegExpNode: public ZoneObject { | 585 class RegExpNode: public ZoneObject { |
| 585 public: | 586 public: |
| 586 RegExpNode() : trace_count_(0) { } | 587 RegExpNode() : trace_count_(0) { } |
| 587 virtual ~RegExpNode(); | 588 virtual ~RegExpNode(); |
| 588 virtual void Accept(NodeVisitor* visitor) = 0; | 589 virtual void Accept(NodeVisitor* visitor) = 0; |
| 589 // Generates a goto to this node or actually generates the code at this point. | 590 // Generates a goto to this node or actually generates the code at this point. |
| 590 // Until the implementation is complete we will return true for success and | 591 virtual void Emit(RegExpCompiler* compiler, Trace* trace) = 0; |
| 591 // false for failure. | |
| 592 virtual bool Emit(RegExpCompiler* compiler, Trace* trace) = 0; | |
| 593 // How many characters must this node consume at a minimum in order to | 592 // How many characters must this node consume at a minimum in order to |
| 594 // succeed. | 593 // succeed. If we have found at least 'still_to_find' characters that |
| 595 virtual int EatsAtLeast(int recursion_depth) = 0; | 594 // must be consumed there is no need to ask any following nodes whether |
| 595 // they are sure to eat any more characters. |
| 596 virtual int EatsAtLeast(int still_to_find, int recursion_depth) = 0; |
| 596 // Emits some quick code that checks whether the preloaded characters match. | 597 // Emits some quick code that checks whether the preloaded characters match. |
| 597 // Falls through on certain failure, jumps to the label on possible success. | 598 // Falls through on certain failure, jumps to the label on possible success. |
| 598 // If the node cannot make a quick check it does nothing and returns false. | 599 // If the node cannot make a quick check it does nothing and returns false. |
| 599 bool EmitQuickCheck(RegExpCompiler* compiler, | 600 bool EmitQuickCheck(RegExpCompiler* compiler, |
| 600 Trace* trace, | 601 Trace* trace, |
| 601 bool preload_has_checked_bounds, | 602 bool preload_has_checked_bounds, |
| 602 Label* on_possible_success, | 603 Label* on_possible_success, |
| 603 QuickCheckDetails* details_return, | 604 QuickCheckDetails* details_return, |
| 604 bool fall_through_on_failure); | 605 bool fall_through_on_failure); |
| 605 // For a given number of characters this returns a mask and a value. The | 606 // For a given number of characters this returns a mask and a value. The |
| 606 // next n characters are anded with the mask and compared with the value. | 607 // next n characters are anded with the mask and compared with the value. |
| 607 // A comparison failure indicates the node cannot match the next n characters. | 608 // A comparison failure indicates the node cannot match the next n characters. |
| 608 // A comparison success indicates the node may match. | 609 // A comparison success indicates the node may match. |
| 609 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 610 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 610 RegExpCompiler* compiler, | 611 RegExpCompiler* compiler, |
| 611 int characters_filled_in) = 0; | 612 int characters_filled_in) = 0; |
| 612 static const int kNodeIsTooComplexForGreedyLoops = -1; | 613 static const int kNodeIsTooComplexForGreedyLoops = -1; |
| 613 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } | 614 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } |
| 614 Label* label() { return &label_; } | 615 Label* label() { return &label_; } |
| 615 // If non-generic code is generated for a node (ie the node is not at the | 616 // If non-generic code is generated for a node (ie the node is not at the |
| 616 // start of the trace) then it cannot be reused. This variable sets a limit | 617 // start of the trace) then it cannot be reused. This variable sets a limit |
| 617 // on how often we allow that to happen before we insist on starting a new | 618 // on how often we allow that to happen before we insist on starting a new |
| 618 // trace and generating generic code for a node that can be reused by flushing | 619 // trace and generating generic code for a node that can be reused by flushing |
| 619 // the deferred actions in the current trace and generating a goto. | 620 // the deferred actions in the current trace and generating a goto. |
| 620 static const int kMaxCopiesCodeGenerated = 10; | 621 static const int kMaxCopiesCodeGenerated = 10; |
| 621 | 622 |
| 622 // Propagates the given interest information forward. When seeing | |
| 623 // \bfoo for instance, the \b is implemented by propagating forward | |
| 624 // to the 'foo' string that it should only succeed if its first | |
| 625 // character is a letter xor the previous character was a letter. | |
| 626 virtual RegExpNode* PropagateForward(NodeInfo* info) = 0; | |
| 627 | |
| 628 NodeInfo* info() { return &info_; } | 623 NodeInfo* info() { return &info_; } |
| 629 | 624 |
| 630 void AddSibling(RegExpNode* node) { siblings_.Add(node); } | 625 void AddSibling(RegExpNode* node) { siblings_.Add(node); } |
| 631 | 626 |
| 632 // Static version of EnsureSibling that expresses the fact that the | 627 // Static version of EnsureSibling that expresses the fact that the |
| 633 // result has the same type as the input. | 628 // result has the same type as the input. |
| 634 template <class C> | 629 template <class C> |
| 635 static C* EnsureSibling(C* node, NodeInfo* info, bool* cloned) { | 630 static C* EnsureSibling(C* node, NodeInfo* info, bool* cloned) { |
| 636 return static_cast<C*>(node->EnsureSibling(info, cloned)); | 631 return static_cast<C*>(node->EnsureSibling(info, cloned)); |
| 637 } | 632 } |
| 638 | 633 |
| 639 SiblingList* siblings() { return &siblings_; } | 634 SiblingList* siblings() { return &siblings_; } |
| 640 void set_siblings(SiblingList* other) { siblings_ = *other; } | 635 void set_siblings(SiblingList* other) { siblings_ = *other; } |
| 641 | 636 |
| 642 protected: | 637 protected: |
| 643 enum LimitResult { DONE, FAIL, CONTINUE }; | 638 enum LimitResult { DONE, CONTINUE }; |
| 644 LimitResult LimitVersions(RegExpCompiler* compiler, Trace* trace); | 639 LimitResult LimitVersions(RegExpCompiler* compiler, Trace* trace); |
| 645 | 640 |
| 646 // Returns a sibling of this node whose interests and assumptions | 641 // Returns a sibling of this node whose interests and assumptions |
| 647 // match the ones in the given node info. If no sibling exists NULL | 642 // match the ones in the given node info. If no sibling exists NULL |
| 648 // is returned. | 643 // is returned. |
| 649 RegExpNode* TryGetSibling(NodeInfo* info); | 644 RegExpNode* TryGetSibling(NodeInfo* info); |
| 650 | 645 |
| 651 // Returns a sibling of this node whose interests match the ones in | 646 // Returns a sibling of this node whose interests match the ones in |
| 652 // the given node info. The info must not contain any assertions. | 647 // the given node info. The info must not contain any assertions. |
| 653 // If no node exists a new one will be created by cloning the current | 648 // If no node exists a new one will be created by cloning the current |
| 654 // node. The result will always be an instance of the same concrete | 649 // node. The result will always be an instance of the same concrete |
| 655 // class as this node. | 650 // class as this node. |
| 656 RegExpNode* EnsureSibling(NodeInfo* info, bool* cloned); | 651 RegExpNode* EnsureSibling(NodeInfo* info, bool* cloned); |
| 657 | 652 |
| 658 // Returns a clone of this node initialized using the copy constructor | 653 // Returns a clone of this node initialized using the copy constructor |
| 659 // of its concrete class. Note that the node may have to be pre- | 654 // of its concrete class. Note that the node may have to be pre- |
| 660 // processed before it is on a useable state. | 655 // processed before it is on a usable state. |
| 661 virtual RegExpNode* Clone() = 0; | 656 virtual RegExpNode* Clone() = 0; |
| 662 | 657 |
| 663 private: | 658 private: |
| 664 Label label_; | 659 Label label_; |
| 665 NodeInfo info_; | 660 NodeInfo info_; |
| 666 SiblingList siblings_; | 661 SiblingList siblings_; |
| 667 // This variable keeps track of how many times code has been generated for | 662 // This variable keeps track of how many times code has been generated for |
| 668 // this node (in different traces). We don't keep track of where the | 663 // this node (in different traces). We don't keep track of where the |
| 669 // generated code is located unless the code is generated at the start of | 664 // generated code is located unless the code is generated at the start of |
| 670 // a trace, in which case it is generic and can be reused by flushing the | 665 // a trace, in which case it is generic and can be reused by flushing the |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 717 SET_REGISTER, | 712 SET_REGISTER, |
| 718 INCREMENT_REGISTER, | 713 INCREMENT_REGISTER, |
| 719 STORE_POSITION, | 714 STORE_POSITION, |
| 720 BEGIN_SUBMATCH, | 715 BEGIN_SUBMATCH, |
| 721 POSITIVE_SUBMATCH_SUCCESS, | 716 POSITIVE_SUBMATCH_SUCCESS, |
| 722 EMPTY_MATCH_CHECK, | 717 EMPTY_MATCH_CHECK, |
| 723 CLEAR_CAPTURES | 718 CLEAR_CAPTURES |
| 724 }; | 719 }; |
| 725 static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success); | 720 static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success); |
| 726 static ActionNode* IncrementRegister(int reg, RegExpNode* on_success); | 721 static ActionNode* IncrementRegister(int reg, RegExpNode* on_success); |
| 727 static ActionNode* StorePosition(int reg, RegExpNode* on_success); | 722 static ActionNode* StorePosition(int reg, |
| 723 bool is_capture, |
| 724 RegExpNode* on_success); |
| 728 static ActionNode* ClearCaptures(Interval range, RegExpNode* on_success); | 725 static ActionNode* ClearCaptures(Interval range, RegExpNode* on_success); |
| 729 static ActionNode* BeginSubmatch(int stack_pointer_reg, | 726 static ActionNode* BeginSubmatch(int stack_pointer_reg, |
| 730 int position_reg, | 727 int position_reg, |
| 731 RegExpNode* on_success); | 728 RegExpNode* on_success); |
| 732 static ActionNode* PositiveSubmatchSuccess(int stack_pointer_reg, | 729 static ActionNode* PositiveSubmatchSuccess(int stack_pointer_reg, |
| 733 int restore_reg, | 730 int restore_reg, |
| 731 int clear_capture_count, |
| 732 int clear_capture_from, |
| 734 RegExpNode* on_success); | 733 RegExpNode* on_success); |
| 735 static ActionNode* EmptyMatchCheck(int start_register, | 734 static ActionNode* EmptyMatchCheck(int start_register, |
| 736 int repetition_register, | 735 int repetition_register, |
| 737 int repetition_limit, | 736 int repetition_limit, |
| 738 RegExpNode* on_success); | 737 RegExpNode* on_success); |
| 739 virtual void Accept(NodeVisitor* visitor); | 738 virtual void Accept(NodeVisitor* visitor); |
| 740 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); | 739 virtual void Emit(RegExpCompiler* compiler, Trace* trace); |
| 741 virtual int EatsAtLeast(int recursion_depth); | 740 virtual int EatsAtLeast(int still_to_find, int recursion_depth); |
| 742 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 741 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 743 RegExpCompiler* compiler, | 742 RegExpCompiler* compiler, |
| 744 int filled_in) { | 743 int filled_in) { |
| 745 return on_success()->GetQuickCheckDetails(details, compiler, filled_in); | 744 return on_success()->GetQuickCheckDetails(details, compiler, filled_in); |
| 746 } | 745 } |
| 747 virtual RegExpNode* PropagateForward(NodeInfo* info); | |
| 748 Type type() { return type_; } | 746 Type type() { return type_; } |
| 749 // TODO(erikcorry): We should allow some action nodes in greedy loops. | 747 // TODO(erikcorry): We should allow some action nodes in greedy loops. |
| 750 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } | 748 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } |
| 751 virtual ActionNode* Clone() { return new ActionNode(*this); } | 749 virtual ActionNode* Clone() { return new ActionNode(*this); } |
| 752 | 750 |
| 753 private: | 751 private: |
| 754 union { | 752 union { |
| 755 struct { | 753 struct { |
| 756 int reg; | 754 int reg; |
| 757 int value; | 755 int value; |
| 758 } u_store_register; | 756 } u_store_register; |
| 759 struct { | 757 struct { |
| 760 int reg; | 758 int reg; |
| 761 } u_increment_register; | 759 } u_increment_register; |
| 762 struct { | 760 struct { |
| 763 int reg; | 761 int reg; |
| 762 bool is_capture; |
| 764 } u_position_register; | 763 } u_position_register; |
| 765 struct { | 764 struct { |
| 766 int stack_pointer_register; | 765 int stack_pointer_register; |
| 767 int current_position_register; | 766 int current_position_register; |
| 767 int clear_register_count; |
| 768 int clear_register_from; |
| 768 } u_submatch; | 769 } u_submatch; |
| 769 struct { | 770 struct { |
| 770 int start_register; | 771 int start_register; |
| 771 int repetition_register; | 772 int repetition_register; |
| 772 int repetition_limit; | 773 int repetition_limit; |
| 773 } u_empty_match_check; | 774 } u_empty_match_check; |
| 774 struct { | 775 struct { |
| 775 int range_from; | 776 int range_from; |
| 776 int range_to; | 777 int range_to; |
| 777 } u_clear_captures; | 778 } u_clear_captures; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 790 RegExpNode* on_success) | 791 RegExpNode* on_success) |
| 791 : SeqRegExpNode(on_success), | 792 : SeqRegExpNode(on_success), |
| 792 elms_(elms) { } | 793 elms_(elms) { } |
| 793 TextNode(RegExpCharacterClass* that, | 794 TextNode(RegExpCharacterClass* that, |
| 794 RegExpNode* on_success) | 795 RegExpNode* on_success) |
| 795 : SeqRegExpNode(on_success), | 796 : SeqRegExpNode(on_success), |
| 796 elms_(new ZoneList<TextElement>(1)) { | 797 elms_(new ZoneList<TextElement>(1)) { |
| 797 elms_->Add(TextElement::CharClass(that)); | 798 elms_->Add(TextElement::CharClass(that)); |
| 798 } | 799 } |
| 799 virtual void Accept(NodeVisitor* visitor); | 800 virtual void Accept(NodeVisitor* visitor); |
| 800 virtual RegExpNode* PropagateForward(NodeInfo* info); | 801 virtual void Emit(RegExpCompiler* compiler, Trace* trace); |
| 801 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); | 802 virtual int EatsAtLeast(int still_to_find, int recursion_depth); |
| 802 virtual int EatsAtLeast(int recursion_depth); | |
| 803 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 803 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 804 RegExpCompiler* compiler, | 804 RegExpCompiler* compiler, |
| 805 int characters_filled_in); | 805 int characters_filled_in); |
| 806 ZoneList<TextElement>* elements() { return elms_; } | 806 ZoneList<TextElement>* elements() { return elms_; } |
| 807 void MakeCaseIndependent(); | 807 void MakeCaseIndependent(); |
| 808 virtual int GreedyLoopTextLength(); | 808 virtual int GreedyLoopTextLength(); |
| 809 virtual TextNode* Clone() { | 809 virtual TextNode* Clone() { |
| 810 TextNode* result = new TextNode(*this); | 810 TextNode* result = new TextNode(*this); |
| 811 result->CalculateOffsets(); | 811 result->CalculateOffsets(); |
| 812 return result; | 812 return result; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 824 TextEmitPassType pass, | 824 TextEmitPassType pass, |
| 825 bool preloaded, | 825 bool preloaded, |
| 826 Trace* trace, | 826 Trace* trace, |
| 827 bool first_element_checked, | 827 bool first_element_checked, |
| 828 int* checked_up_to); | 828 int* checked_up_to); |
| 829 int Length(); | 829 int Length(); |
| 830 ZoneList<TextElement>* elms_; | 830 ZoneList<TextElement>* elms_; |
| 831 }; | 831 }; |
| 832 | 832 |
| 833 | 833 |
| 834 class AssertionNode: public SeqRegExpNode { |
| 835 public: |
| 836 enum AssertionNodeType { |
| 837 AT_END, |
| 838 AT_START, |
| 839 AT_BOUNDARY, |
| 840 AT_NON_BOUNDARY, |
| 841 AFTER_NEWLINE |
| 842 }; |
| 843 static AssertionNode* AtEnd(RegExpNode* on_success) { |
| 844 return new AssertionNode(AT_END, on_success); |
| 845 } |
| 846 static AssertionNode* AtStart(RegExpNode* on_success) { |
| 847 return new AssertionNode(AT_START, on_success); |
| 848 } |
| 849 static AssertionNode* AtBoundary(RegExpNode* on_success) { |
| 850 return new AssertionNode(AT_BOUNDARY, on_success); |
| 851 } |
| 852 static AssertionNode* AtNonBoundary(RegExpNode* on_success) { |
| 853 return new AssertionNode(AT_NON_BOUNDARY, on_success); |
| 854 } |
| 855 static AssertionNode* AfterNewline(RegExpNode* on_success) { |
| 856 return new AssertionNode(AFTER_NEWLINE, on_success); |
| 857 } |
| 858 virtual void Accept(NodeVisitor* visitor); |
| 859 virtual void Emit(RegExpCompiler* compiler, Trace* trace); |
| 860 virtual int EatsAtLeast(int still_to_find, int recursion_depth); |
| 861 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 862 RegExpCompiler* compiler, |
| 863 int filled_in) { |
| 864 return on_success()->GetQuickCheckDetails(details, compiler, filled_in); |
| 865 } |
| 866 virtual AssertionNode* Clone() { return new AssertionNode(*this); } |
| 867 AssertionNodeType type() { return type_; } |
| 868 private: |
| 869 AssertionNode(AssertionNodeType t, RegExpNode* on_success) |
| 870 : SeqRegExpNode(on_success), type_(t) { } |
| 871 AssertionNodeType type_; |
| 872 }; |
| 873 |
| 874 |
| 834 class BackReferenceNode: public SeqRegExpNode { | 875 class BackReferenceNode: public SeqRegExpNode { |
| 835 public: | 876 public: |
| 836 BackReferenceNode(int start_reg, | 877 BackReferenceNode(int start_reg, |
| 837 int end_reg, | 878 int end_reg, |
| 838 RegExpNode* on_success) | 879 RegExpNode* on_success) |
| 839 : SeqRegExpNode(on_success), | 880 : SeqRegExpNode(on_success), |
| 840 start_reg_(start_reg), | 881 start_reg_(start_reg), |
| 841 end_reg_(end_reg) { } | 882 end_reg_(end_reg) { } |
| 842 virtual void Accept(NodeVisitor* visitor); | 883 virtual void Accept(NodeVisitor* visitor); |
| 843 int start_register() { return start_reg_; } | 884 int start_register() { return start_reg_; } |
| 844 int end_register() { return end_reg_; } | 885 int end_register() { return end_reg_; } |
| 845 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); | 886 virtual void Emit(RegExpCompiler* compiler, Trace* trace); |
| 846 virtual int EatsAtLeast(int recursion_depth) { return 0; } | 887 virtual int EatsAtLeast(int still_to_find, int recursion_depth); |
| 847 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 888 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 848 RegExpCompiler* compiler, | 889 RegExpCompiler* compiler, |
| 849 int characters_filled_in) { | 890 int characters_filled_in) { |
| 850 return; | 891 return; |
| 851 } | 892 } |
| 852 virtual RegExpNode* PropagateForward(NodeInfo* info); | |
| 853 virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); } | 893 virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); } |
| 854 | 894 |
| 855 private: | 895 private: |
| 856 int start_reg_; | 896 int start_reg_; |
| 857 int end_reg_; | 897 int end_reg_; |
| 858 }; | 898 }; |
| 859 | 899 |
| 860 | 900 |
| 861 class EndNode: public RegExpNode { | 901 class EndNode: public RegExpNode { |
| 862 public: | 902 public: |
| 863 enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS }; | 903 enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS }; |
| 864 explicit EndNode(Action action) : action_(action) { } | 904 explicit EndNode(Action action) : action_(action) { } |
| 865 virtual void Accept(NodeVisitor* visitor); | 905 virtual void Accept(NodeVisitor* visitor); |
| 866 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); | 906 virtual void Emit(RegExpCompiler* compiler, Trace* trace); |
| 867 virtual int EatsAtLeast(int recursion_depth) { return 0; } | 907 virtual int EatsAtLeast(int still_to_find, int recursion_depth) { return 0; } |
| 868 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 908 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 869 RegExpCompiler* compiler, | 909 RegExpCompiler* compiler, |
| 870 int characters_filled_in) { | 910 int characters_filled_in) { |
| 871 // Returning 0 from EatsAtLeast should ensure we never get here. | 911 // Returning 0 from EatsAtLeast should ensure we never get here. |
| 872 UNREACHABLE(); | 912 UNREACHABLE(); |
| 873 } | 913 } |
| 874 virtual RegExpNode* PropagateForward(NodeInfo* info); | |
| 875 virtual EndNode* Clone() { return new EndNode(*this); } | 914 virtual EndNode* Clone() { return new EndNode(*this); } |
| 876 | 915 |
| 877 protected: | |
| 878 void EmitInfoChecks(RegExpMacroAssembler* macro, Trace* trace); | |
| 879 | |
| 880 private: | 916 private: |
| 881 Action action_; | 917 Action action_; |
| 882 }; | 918 }; |
| 883 | 919 |
| 884 | 920 |
| 885 class NegativeSubmatchSuccess: public EndNode { | 921 class NegativeSubmatchSuccess: public EndNode { |
| 886 public: | 922 public: |
| 887 NegativeSubmatchSuccess(int stack_pointer_reg, int position_reg) | 923 NegativeSubmatchSuccess(int stack_pointer_reg, |
| 924 int position_reg, |
| 925 int clear_capture_count, |
| 926 int clear_capture_start) |
| 888 : EndNode(NEGATIVE_SUBMATCH_SUCCESS), | 927 : EndNode(NEGATIVE_SUBMATCH_SUCCESS), |
| 889 stack_pointer_register_(stack_pointer_reg), | 928 stack_pointer_register_(stack_pointer_reg), |
| 890 current_position_register_(position_reg) { } | 929 current_position_register_(position_reg), |
| 891 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); | 930 clear_capture_count_(clear_capture_count), |
| 931 clear_capture_start_(clear_capture_start) { } |
| 932 virtual void Emit(RegExpCompiler* compiler, Trace* trace); |
| 892 | 933 |
| 893 private: | 934 private: |
| 894 int stack_pointer_register_; | 935 int stack_pointer_register_; |
| 895 int current_position_register_; | 936 int current_position_register_; |
| 937 int clear_capture_count_; |
| 938 int clear_capture_start_; |
| 896 }; | 939 }; |
| 897 | 940 |
| 898 | 941 |
| 899 class Guard: public ZoneObject { | 942 class Guard: public ZoneObject { |
| 900 public: | 943 public: |
| 901 enum Relation { LT, GEQ }; | 944 enum Relation { LT, GEQ }; |
| 902 Guard(int reg, Relation op, int value) | 945 Guard(int reg, Relation op, int value) |
| 903 : reg_(reg), | 946 : reg_(reg), |
| 904 op_(op), | 947 op_(op), |
| 905 value_(value) { } | 948 value_(value) { } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 934 class ChoiceNode: public RegExpNode { | 977 class ChoiceNode: public RegExpNode { |
| 935 public: | 978 public: |
| 936 explicit ChoiceNode(int expected_size) | 979 explicit ChoiceNode(int expected_size) |
| 937 : alternatives_(new ZoneList<GuardedAlternative>(expected_size)), | 980 : alternatives_(new ZoneList<GuardedAlternative>(expected_size)), |
| 938 table_(NULL), | 981 table_(NULL), |
| 939 being_calculated_(false) { } | 982 being_calculated_(false) { } |
| 940 virtual void Accept(NodeVisitor* visitor); | 983 virtual void Accept(NodeVisitor* visitor); |
| 941 void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); } | 984 void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); } |
| 942 ZoneList<GuardedAlternative>* alternatives() { return alternatives_; } | 985 ZoneList<GuardedAlternative>* alternatives() { return alternatives_; } |
| 943 DispatchTable* GetTable(bool ignore_case); | 986 DispatchTable* GetTable(bool ignore_case); |
| 944 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); | 987 virtual void Emit(RegExpCompiler* compiler, Trace* trace); |
| 945 virtual int EatsAtLeast(int recursion_depth); | 988 virtual int EatsAtLeast(int still_to_find, int recursion_depth); |
| 946 int EatsAtLeastHelper(int recursion_depth, RegExpNode* ignore_this_node); | 989 int EatsAtLeastHelper(int still_to_find, |
| 990 int recursion_depth, |
| 991 RegExpNode* ignore_this_node); |
| 947 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 992 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 948 RegExpCompiler* compiler, | 993 RegExpCompiler* compiler, |
| 949 int characters_filled_in); | 994 int characters_filled_in); |
| 950 virtual RegExpNode* PropagateForward(NodeInfo* info); | |
| 951 virtual ChoiceNode* Clone() { return new ChoiceNode(*this); } | 995 virtual ChoiceNode* Clone() { return new ChoiceNode(*this); } |
| 952 | 996 |
| 953 bool being_calculated() { return being_calculated_; } | 997 bool being_calculated() { return being_calculated_; } |
| 954 void set_being_calculated(bool b) { being_calculated_ = b; } | 998 void set_being_calculated(bool b) { being_calculated_ = b; } |
| 999 virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; } |
| 955 | 1000 |
| 956 protected: | 1001 protected: |
| 957 int GreedyLoopTextLength(GuardedAlternative *alternative); | 1002 int GreedyLoopTextLength(GuardedAlternative *alternative); |
| 958 ZoneList<GuardedAlternative>* alternatives_; | 1003 ZoneList<GuardedAlternative>* alternatives_; |
| 959 | 1004 |
| 960 private: | 1005 private: |
| 961 friend class DispatchTableConstructor; | 1006 friend class DispatchTableConstructor; |
| 962 friend class Analysis; | 1007 friend class Analysis; |
| 963 void GenerateGuard(RegExpMacroAssembler* macro_assembler, | 1008 void GenerateGuard(RegExpMacroAssembler* macro_assembler, |
| 964 Guard *guard, | 1009 Guard *guard, |
| 965 Trace* trace); | 1010 Trace* trace); |
| 966 int CalculatePreloadCharacters(RegExpCompiler* compiler); | 1011 int CalculatePreloadCharacters(RegExpCompiler* compiler); |
| 967 bool EmitOutOfLineContinuation(RegExpCompiler* compiler, | 1012 void EmitOutOfLineContinuation(RegExpCompiler* compiler, |
| 968 Trace* trace, | 1013 Trace* trace, |
| 969 GuardedAlternative alternative, | 1014 GuardedAlternative alternative, |
| 970 AlternativeGeneration* alt_gen, | 1015 AlternativeGeneration* alt_gen, |
| 971 int preload_characters, | 1016 int preload_characters, |
| 972 bool next_expects_preload); | 1017 bool next_expects_preload); |
| 973 DispatchTable* table_; | 1018 DispatchTable* table_; |
| 974 bool being_calculated_; | 1019 bool being_calculated_; |
| 975 }; | 1020 }; |
| 976 | 1021 |
| 977 | 1022 |
| 1023 class NegativeLookaheadChoiceNode: public ChoiceNode { |
| 1024 public: |
| 1025 explicit NegativeLookaheadChoiceNode(GuardedAlternative this_must_fail, |
| 1026 GuardedAlternative then_do_this) |
| 1027 : ChoiceNode(2) { |
| 1028 AddAlternative(this_must_fail); |
| 1029 AddAlternative(then_do_this); |
| 1030 } |
| 1031 virtual int EatsAtLeast(int still_to_find, int recursion_depth); |
| 1032 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 1033 RegExpCompiler* compiler, |
| 1034 int characters_filled_in); |
| 1035 // For a negative lookahead we don't emit the quick check for the |
| 1036 // alternative that is expected to fail. This is because quick check code |
| 1037 // starts by loading enough characters for the alternative that takes fewest |
| 1038 // characters, but on a negative lookahead the negative branch did not take |
| 1039 // part in that calculation (EatsAtLeast) so the assumptions don't hold. |
| 1040 virtual bool try_to_emit_quick_check_for_alternative(int i) { return i != 0; } |
| 1041 }; |
| 1042 |
| 1043 |
| 978 class LoopChoiceNode: public ChoiceNode { | 1044 class LoopChoiceNode: public ChoiceNode { |
| 979 public: | 1045 public: |
| 980 explicit LoopChoiceNode(bool body_can_be_zero_length) | 1046 explicit LoopChoiceNode(bool body_can_be_zero_length) |
| 981 : ChoiceNode(2), | 1047 : ChoiceNode(2), |
| 982 loop_node_(NULL), | 1048 loop_node_(NULL), |
| 983 continue_node_(NULL), | 1049 continue_node_(NULL), |
| 984 body_can_be_zero_length_(body_can_be_zero_length) { } | 1050 body_can_be_zero_length_(body_can_be_zero_length) { } |
| 985 void AddLoopAlternative(GuardedAlternative alt); | 1051 void AddLoopAlternative(GuardedAlternative alt); |
| 986 void AddContinueAlternative(GuardedAlternative alt); | 1052 void AddContinueAlternative(GuardedAlternative alt); |
| 987 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); | 1053 virtual void Emit(RegExpCompiler* compiler, Trace* trace); |
| 988 virtual int EatsAtLeast(int recursion_depth); // Returns 0. | 1054 virtual int EatsAtLeast(int still_to_find, int recursion_depth); |
| 989 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 1055 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 990 RegExpCompiler* compiler, | 1056 RegExpCompiler* compiler, |
| 991 int characters_filled_in); | 1057 int characters_filled_in); |
| 992 virtual LoopChoiceNode* Clone() { return new LoopChoiceNode(*this); } | 1058 virtual LoopChoiceNode* Clone() { return new LoopChoiceNode(*this); } |
| 993 RegExpNode* loop_node() { return loop_node_; } | 1059 RegExpNode* loop_node() { return loop_node_; } |
| 994 RegExpNode* continue_node() { return continue_node_; } | 1060 RegExpNode* continue_node() { return continue_node_; } |
| 995 bool body_can_be_zero_length() { return body_can_be_zero_length_; } | 1061 bool body_can_be_zero_length() { return body_can_be_zero_length_; } |
| 996 virtual void Accept(NodeVisitor* visitor); | 1062 virtual void Accept(NodeVisitor* visitor); |
| 997 | 1063 |
| 998 private: | 1064 private: |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1030 bool Mentions(int reg); | 1096 bool Mentions(int reg); |
| 1031 int reg() { return reg_; } | 1097 int reg() { return reg_; } |
| 1032 ActionNode::Type type() { return type_; } | 1098 ActionNode::Type type() { return type_; } |
| 1033 private: | 1099 private: |
| 1034 ActionNode::Type type_; | 1100 ActionNode::Type type_; |
| 1035 int reg_; | 1101 int reg_; |
| 1036 DeferredAction* next_; | 1102 DeferredAction* next_; |
| 1037 friend class Trace; | 1103 friend class Trace; |
| 1038 }; | 1104 }; |
| 1039 | 1105 |
| 1040 class DeferredCapture: public DeferredAction { | 1106 class DeferredCapture : public DeferredAction { |
| 1041 public: | 1107 public: |
| 1042 DeferredCapture(int reg, Trace* trace) | 1108 DeferredCapture(int reg, bool is_capture, Trace* trace) |
| 1043 : DeferredAction(ActionNode::STORE_POSITION, reg), | 1109 : DeferredAction(ActionNode::STORE_POSITION, reg), |
| 1044 cp_offset_(trace->cp_offset()) { } | 1110 cp_offset_(trace->cp_offset()), |
| 1111 is_capture_(is_capture) { } |
| 1045 int cp_offset() { return cp_offset_; } | 1112 int cp_offset() { return cp_offset_; } |
| 1113 bool is_capture() { return is_capture_; } |
| 1046 private: | 1114 private: |
| 1047 int cp_offset_; | 1115 int cp_offset_; |
| 1116 bool is_capture_; |
| 1048 void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; } | 1117 void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; } |
| 1049 }; | 1118 }; |
| 1050 | 1119 |
| 1051 class DeferredSetRegister :public DeferredAction { | 1120 class DeferredSetRegister : public DeferredAction { |
| 1052 public: | 1121 public: |
| 1053 DeferredSetRegister(int reg, int value) | 1122 DeferredSetRegister(int reg, int value) |
| 1054 : DeferredAction(ActionNode::SET_REGISTER, reg), | 1123 : DeferredAction(ActionNode::SET_REGISTER, reg), |
| 1055 value_(value) { } | 1124 value_(value) { } |
| 1056 int value() { return value_; } | 1125 int value() { return value_; } |
| 1057 private: | 1126 private: |
| 1058 int value_; | 1127 int value_; |
| 1059 }; | 1128 }; |
| 1060 | 1129 |
| 1061 class DeferredClearCaptures : public DeferredAction { | 1130 class DeferredClearCaptures : public DeferredAction { |
| 1062 public: | 1131 public: |
| 1063 explicit DeferredClearCaptures(Interval range) | 1132 explicit DeferredClearCaptures(Interval range) |
| 1064 : DeferredAction(ActionNode::CLEAR_CAPTURES, -1), | 1133 : DeferredAction(ActionNode::CLEAR_CAPTURES, -1), |
| 1065 range_(range) { } | 1134 range_(range) { } |
| 1066 Interval range() { return range_; } | 1135 Interval range() { return range_; } |
| 1067 private: | 1136 private: |
| 1068 Interval range_; | 1137 Interval range_; |
| 1069 }; | 1138 }; |
| 1070 | 1139 |
| 1071 class DeferredIncrementRegister: public DeferredAction { | 1140 class DeferredIncrementRegister : public DeferredAction { |
| 1072 public: | 1141 public: |
| 1073 explicit DeferredIncrementRegister(int reg) | 1142 explicit DeferredIncrementRegister(int reg) |
| 1074 : DeferredAction(ActionNode::INCREMENT_REGISTER, reg) { } | 1143 : DeferredAction(ActionNode::INCREMENT_REGISTER, reg) { } |
| 1075 }; | 1144 }; |
| 1076 | 1145 |
| 1077 Trace() | 1146 Trace() |
| 1078 : cp_offset_(0), | 1147 : cp_offset_(0), |
| 1079 actions_(NULL), | 1148 actions_(NULL), |
| 1080 backtrack_(NULL), | 1149 backtrack_(NULL), |
| 1081 stop_node_(NULL), | 1150 stop_node_(NULL), |
| 1082 loop_label_(NULL), | 1151 loop_label_(NULL), |
| 1083 characters_preloaded_(0), | 1152 characters_preloaded_(0), |
| 1084 bound_checked_up_to_(0) { } | 1153 bound_checked_up_to_(0) { } |
| 1085 // End the trace. This involves flushing the deferred actions in the trace | 1154 // End the trace. This involves flushing the deferred actions in the trace |
| 1086 // and pushing a backtrack location onto the backtrack stack. Once this is | 1155 // and pushing a backtrack location onto the backtrack stack. Once this is |
| 1087 // done we can start a new trace or go to one that has already been | 1156 // done we can start a new trace or go to one that has already been |
| 1088 // generated. | 1157 // generated. |
| 1089 bool Flush(RegExpCompiler* compiler, RegExpNode* successor); | 1158 void Flush(RegExpCompiler* compiler, RegExpNode* successor); |
| 1090 int cp_offset() { return cp_offset_; } | 1159 int cp_offset() { return cp_offset_; } |
| 1091 DeferredAction* actions() { return actions_; } | 1160 DeferredAction* actions() { return actions_; } |
| 1092 // A trivial trace is one that has no deferred actions or other state that | 1161 // A trivial trace is one that has no deferred actions or other state that |
| 1093 // affects the assumptions used when generating code. There is no recorded | 1162 // affects the assumptions used when generating code. There is no recorded |
| 1094 // backtrack location in a trivial trace, so with a trivial trace we will | 1163 // backtrack location in a trivial trace, so with a trivial trace we will |
| 1095 // generate code that, on a failure to match, gets the backtrack location | 1164 // generate code that, on a failure to match, gets the backtrack location |
| 1096 // from the backtrack stack rather than using a direct jump instruction. We | 1165 // from the backtrack stack rather than using a direct jump instruction. We |
| 1097 // always start code generation with a trivial trace and non-trivial traces | 1166 // always start code generation with a trivial trace and non-trivial traces |
| 1098 // are created as we emit code for nodes or add to the list of deferred | 1167 // are created as we emit code for nodes or add to the list of deferred |
| 1099 // actions in the trace. The location of the code generated for a node using | 1168 // actions in the trace. The location of the code generated for a node using |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1126 actions_ = new_action; | 1195 actions_ = new_action; |
| 1127 } | 1196 } |
| 1128 void set_backtrack(Label* backtrack) { backtrack_ = backtrack; } | 1197 void set_backtrack(Label* backtrack) { backtrack_ = backtrack; } |
| 1129 void set_stop_node(RegExpNode* node) { stop_node_ = node; } | 1198 void set_stop_node(RegExpNode* node) { stop_node_ = node; } |
| 1130 void set_loop_label(Label* label) { loop_label_ = label; } | 1199 void set_loop_label(Label* label) { loop_label_ = label; } |
| 1131 void set_characters_preloaded(int cpre) { characters_preloaded_ = cpre; } | 1200 void set_characters_preloaded(int cpre) { characters_preloaded_ = cpre; } |
| 1132 void set_bound_checked_up_to(int to) { bound_checked_up_to_ = to; } | 1201 void set_bound_checked_up_to(int to) { bound_checked_up_to_ = to; } |
| 1133 void set_quick_check_performed(QuickCheckDetails* d) { | 1202 void set_quick_check_performed(QuickCheckDetails* d) { |
| 1134 quick_check_performed_ = *d; | 1203 quick_check_performed_ = *d; |
| 1135 } | 1204 } |
| 1136 void clear_quick_check_performed() { | 1205 void InvalidateCurrentCharacter(); |
| 1137 } | 1206 void AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler); |
| 1138 void AdvanceCurrentPositionInTrace(int by, bool ascii); | |
| 1139 private: | 1207 private: |
| 1140 int FindAffectedRegisters(OutSet* affected_registers); | 1208 int FindAffectedRegisters(OutSet* affected_registers); |
| 1141 void PerformDeferredActions(RegExpMacroAssembler* macro, | 1209 void PerformDeferredActions(RegExpMacroAssembler* macro, |
| 1142 int max_register, | 1210 int max_register, |
| 1143 OutSet& affected_registers); | 1211 OutSet& affected_registers, |
| 1212 OutSet* registers_to_pop, |
| 1213 OutSet* registers_to_clear); |
| 1144 void RestoreAffectedRegisters(RegExpMacroAssembler* macro, | 1214 void RestoreAffectedRegisters(RegExpMacroAssembler* macro, |
| 1145 int max_register, | 1215 int max_register, |
| 1146 OutSet& affected_registers); | 1216 OutSet& registers_to_pop, |
| 1147 void PushAffectedRegisters(RegExpMacroAssembler* macro, | 1217 OutSet& registers_to_clear); |
| 1148 int max_register, | |
| 1149 OutSet& affected_registers); | |
| 1150 int cp_offset_; | 1218 int cp_offset_; |
| 1151 DeferredAction* actions_; | 1219 DeferredAction* actions_; |
| 1152 Label* backtrack_; | 1220 Label* backtrack_; |
| 1153 RegExpNode* stop_node_; | 1221 RegExpNode* stop_node_; |
| 1154 Label* loop_label_; | 1222 Label* loop_label_; |
| 1155 int characters_preloaded_; | 1223 int characters_preloaded_; |
| 1156 int bound_checked_up_to_; | 1224 int bound_checked_up_to_; |
| 1157 QuickCheckDetails quick_check_performed_; | 1225 QuickCheckDetails quick_check_performed_; |
| 1158 }; | 1226 }; |
| 1159 | 1227 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1254 Handle<String> pattern, | 1322 Handle<String> pattern, |
| 1255 bool is_ascii); | 1323 bool is_ascii); |
| 1256 | 1324 |
| 1257 static void DotPrint(const char* label, RegExpNode* node, bool ignore_case); | 1325 static void DotPrint(const char* label, RegExpNode* node, bool ignore_case); |
| 1258 }; | 1326 }; |
| 1259 | 1327 |
| 1260 | 1328 |
| 1261 } } // namespace v8::internal | 1329 } } // namespace v8::internal |
| 1262 | 1330 |
| 1263 #endif // V8_JSREGEXP_H_ | 1331 #endif // V8_JSREGEXP_H_ |
| OLD | NEW |