| 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 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 // The successors are a list of sets that contain the same values | 342 // The successors are a list of sets that contain the same values |
| 343 // as this set and the one more value that is not present in this | 343 // as this set and the one more value that is not present in this |
| 344 // set. | 344 // set. |
| 345 ZoneList<OutSet*>* successors() { return successors_; } | 345 ZoneList<OutSet*>* successors() { return successors_; } |
| 346 | 346 |
| 347 OutSet(uint32_t first, ZoneList<unsigned>* remaining) | 347 OutSet(uint32_t first, ZoneList<unsigned>* remaining) |
| 348 : first_(first), remaining_(remaining), successors_(NULL) { } | 348 : first_(first), remaining_(remaining), successors_(NULL) { } |
| 349 uint32_t first_; | 349 uint32_t first_; |
| 350 ZoneList<unsigned>* remaining_; | 350 ZoneList<unsigned>* remaining_; |
| 351 ZoneList<OutSet*>* successors_; | 351 ZoneList<OutSet*>* successors_; |
| 352 friend class GenerationVariant; | 352 friend class Trace; |
| 353 }; | 353 }; |
| 354 | 354 |
| 355 | 355 |
| 356 // A mapping from integers, specified as ranges, to a set of integers. | 356 // A mapping from integers, specified as ranges, to a set of integers. |
| 357 // Used for mapping character ranges to choices. | 357 // Used for mapping character ranges to choices. |
| 358 class DispatchTable : public ZoneObject { | 358 class DispatchTable : public ZoneObject { |
| 359 public: | 359 public: |
| 360 class Entry { | 360 class Entry { |
| 361 public: | 361 public: |
| 362 Entry() : from_(0), to_(0), out_set_(NULL) { } | 362 Entry() : from_(0), to_(0), out_set_(NULL) { } |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 int length(); | 442 int length(); |
| 443 Type type; | 443 Type type; |
| 444 union { | 444 union { |
| 445 RegExpAtom* u_atom; | 445 RegExpAtom* u_atom; |
| 446 RegExpCharacterClass* u_char_class; | 446 RegExpCharacterClass* u_char_class; |
| 447 } data; | 447 } data; |
| 448 int cp_offset; | 448 int cp_offset; |
| 449 }; | 449 }; |
| 450 | 450 |
| 451 | 451 |
| 452 class GenerationVariant; | 452 class Trace; |
| 453 | 453 |
| 454 | 454 |
| 455 struct NodeInfo { | 455 struct NodeInfo { |
| 456 enum TriBool { | 456 enum TriBool { |
| 457 UNKNOWN = -1, FALSE = 0, TRUE = 1 | 457 UNKNOWN = -1, FALSE = 0, TRUE = 1 |
| 458 }; | 458 }; |
| 459 | 459 |
| 460 NodeInfo() | 460 NodeInfo() |
| 461 : being_analyzed(false), | 461 : being_analyzed(false), |
| 462 been_analyzed(false), | 462 been_analyzed(false), |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 int characters_; | 576 int characters_; |
| 577 Position positions_[4]; | 577 Position positions_[4]; |
| 578 // These values are the condensate of the above array after Rationalize(). | 578 // These values are the condensate of the above array after Rationalize(). |
| 579 uint32_t mask_; | 579 uint32_t mask_; |
| 580 uint32_t value_; | 580 uint32_t value_; |
| 581 }; | 581 }; |
| 582 | 582 |
| 583 | 583 |
| 584 class RegExpNode: public ZoneObject { | 584 class RegExpNode: public ZoneObject { |
| 585 public: | 585 public: |
| 586 RegExpNode() : variants_generated_(0) { } | 586 RegExpNode() : trace_count_(0) { } |
| 587 virtual ~RegExpNode(); | 587 virtual ~RegExpNode(); |
| 588 virtual void Accept(NodeVisitor* visitor) = 0; | 588 virtual void Accept(NodeVisitor* visitor) = 0; |
| 589 // Generates a goto to this node or actually generates the code at this point. | 589 // 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 | 590 // Until the implementation is complete we will return true for success and |
| 591 // false for failure. | 591 // false for failure. |
| 592 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant) = 0; | 592 virtual bool Emit(RegExpCompiler* compiler, Trace* trace) = 0; |
| 593 // How many characters must this node consume at a minimum in order to | 593 // How many characters must this node consume at a minimum in order to |
| 594 // succeed. | 594 // succeed. |
| 595 virtual int EatsAtLeast(int recursion_depth) = 0; | 595 virtual int EatsAtLeast(int recursion_depth) = 0; |
| 596 // Emits some quick code that checks whether the preloaded characters match. | 596 // Emits some quick code that checks whether the preloaded characters match. |
| 597 // Falls through on certain failure, jumps to the label on possible success. | 597 // 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. | 598 // If the node cannot make a quick check it does nothing and returns false. |
| 599 bool EmitQuickCheck(RegExpCompiler* compiler, | 599 bool EmitQuickCheck(RegExpCompiler* compiler, |
| 600 GenerationVariant* variant, | 600 Trace* trace, |
| 601 bool preload_has_checked_bounds, | 601 bool preload_has_checked_bounds, |
| 602 Label* on_possible_success, | 602 Label* on_possible_success, |
| 603 QuickCheckDetails* details_return, | 603 QuickCheckDetails* details_return, |
| 604 bool fall_through_on_failure); | 604 bool fall_through_on_failure); |
| 605 // For a given number of characters this returns a mask and a value. The | 605 // 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. | 606 // 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. | 607 // A comparison failure indicates the node cannot match the next n characters. |
| 608 // A comparison success indicates the node may match. | 608 // A comparison success indicates the node may match. |
| 609 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 609 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 610 RegExpCompiler* compiler, | 610 RegExpCompiler* compiler, |
| 611 int characters_filled_in) = 0; | 611 int characters_filled_in) = 0; |
| 612 static const int kNodeIsTooComplexForGreedyLoops = -1; | 612 static const int kNodeIsTooComplexForGreedyLoops = -1; |
| 613 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } | 613 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } |
| 614 Label* label() { return &label_; } | 614 Label* label() { return &label_; } |
| 615 static const int kMaxVariantsGenerated = 10; | 615 // 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 // 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 // the deferred actions in the current trace and generating a goto. |
| 620 static const int kMaxCopiesCodeGenerated = 10; |
| 616 | 621 |
| 617 // Propagates the given interest information forward. When seeing | 622 // Propagates the given interest information forward. When seeing |
| 618 // \bfoo for instance, the \b is implemented by propagating forward | 623 // \bfoo for instance, the \b is implemented by propagating forward |
| 619 // to the 'foo' string that it should only succeed if its first | 624 // to the 'foo' string that it should only succeed if its first |
| 620 // character is a letter xor the previous character was a letter. | 625 // character is a letter xor the previous character was a letter. |
| 621 virtual RegExpNode* PropagateForward(NodeInfo* info) = 0; | 626 virtual RegExpNode* PropagateForward(NodeInfo* info) = 0; |
| 622 | 627 |
| 623 NodeInfo* info() { return &info_; } | 628 NodeInfo* info() { return &info_; } |
| 624 | 629 |
| 625 void AddSibling(RegExpNode* node) { siblings_.Add(node); } | 630 void AddSibling(RegExpNode* node) { siblings_.Add(node); } |
| 626 | 631 |
| 627 // Static version of EnsureSibling that expresses the fact that the | 632 // Static version of EnsureSibling that expresses the fact that the |
| 628 // result has the same type as the input. | 633 // result has the same type as the input. |
| 629 template <class C> | 634 template <class C> |
| 630 static C* EnsureSibling(C* node, NodeInfo* info, bool* cloned) { | 635 static C* EnsureSibling(C* node, NodeInfo* info, bool* cloned) { |
| 631 return static_cast<C*>(node->EnsureSibling(info, cloned)); | 636 return static_cast<C*>(node->EnsureSibling(info, cloned)); |
| 632 } | 637 } |
| 633 | 638 |
| 634 SiblingList* siblings() { return &siblings_; } | 639 SiblingList* siblings() { return &siblings_; } |
| 635 void set_siblings(SiblingList* other) { siblings_ = *other; } | 640 void set_siblings(SiblingList* other) { siblings_ = *other; } |
| 636 | 641 |
| 637 protected: | 642 protected: |
| 638 enum LimitResult { DONE, FAIL, CONTINUE }; | 643 enum LimitResult { DONE, FAIL, CONTINUE }; |
| 639 LimitResult LimitVersions(RegExpCompiler* compiler, | 644 LimitResult LimitVersions(RegExpCompiler* compiler, Trace* trace); |
| 640 GenerationVariant* variant); | |
| 641 | 645 |
| 642 // Returns a sibling of this node whose interests and assumptions | 646 // Returns a sibling of this node whose interests and assumptions |
| 643 // match the ones in the given node info. If no sibling exists NULL | 647 // match the ones in the given node info. If no sibling exists NULL |
| 644 // is returned. | 648 // is returned. |
| 645 RegExpNode* TryGetSibling(NodeInfo* info); | 649 RegExpNode* TryGetSibling(NodeInfo* info); |
| 646 | 650 |
| 647 // Returns a sibling of this node whose interests match the ones in | 651 // Returns a sibling of this node whose interests match the ones in |
| 648 // the given node info. The info must not contain any assertions. | 652 // the given node info. The info must not contain any assertions. |
| 649 // If no node exists a new one will be created by cloning the current | 653 // If no node exists a new one will be created by cloning the current |
| 650 // node. The result will always be an instance of the same concrete | 654 // node. The result will always be an instance of the same concrete |
| 651 // class as this node. | 655 // class as this node. |
| 652 RegExpNode* EnsureSibling(NodeInfo* info, bool* cloned); | 656 RegExpNode* EnsureSibling(NodeInfo* info, bool* cloned); |
| 653 | 657 |
| 654 // Returns a clone of this node initialized using the copy constructor | 658 // Returns a clone of this node initialized using the copy constructor |
| 655 // of its concrete class. Note that the node may have to be pre- | 659 // of its concrete class. Note that the node may have to be pre- |
| 656 // processed before it is on a useable state. | 660 // processed before it is on a useable state. |
| 657 virtual RegExpNode* Clone() = 0; | 661 virtual RegExpNode* Clone() = 0; |
| 658 | 662 |
| 659 private: | 663 private: |
| 660 Label label_; | 664 Label label_; |
| 661 NodeInfo info_; | 665 NodeInfo info_; |
| 662 SiblingList siblings_; | 666 SiblingList siblings_; |
| 663 int variants_generated_; | 667 // 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 |
| 669 // 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 |
| 671 // deferred operations in the current trace and generating a goto. |
| 672 int trace_count_; |
| 673 }; |
| 674 |
| 675 |
| 676 // A simple closed interval. |
| 677 class Interval { |
| 678 public: |
| 679 Interval() : from_(kNone), to_(kNone) { } |
| 680 Interval(int from, int to) : from_(from), to_(to) { } |
| 681 Interval Union(Interval that) { |
| 682 if (that.from_ == kNone) |
| 683 return *this; |
| 684 else if (from_ == kNone) |
| 685 return that; |
| 686 else |
| 687 return Interval(Min(from_, that.from_), Max(to_, that.to_)); |
| 688 } |
| 689 bool Contains(int value) { |
| 690 return (from_ <= value) && (value <= to_); |
| 691 } |
| 692 bool is_empty() { return from_ == kNone; } |
| 693 int from() { return from_; } |
| 694 int to() { return to_; } |
| 695 static Interval Empty() { return Interval(); } |
| 696 static const int kNone = -1; |
| 697 private: |
| 698 int from_; |
| 699 int to_; |
| 664 }; | 700 }; |
| 665 | 701 |
| 666 | 702 |
| 667 class SeqRegExpNode: public RegExpNode { | 703 class SeqRegExpNode: public RegExpNode { |
| 668 public: | 704 public: |
| 669 explicit SeqRegExpNode(RegExpNode* on_success) | 705 explicit SeqRegExpNode(RegExpNode* on_success) |
| 670 : on_success_(on_success) { } | 706 : on_success_(on_success) { } |
| 671 RegExpNode* on_success() { return on_success_; } | 707 RegExpNode* on_success() { return on_success_; } |
| 672 void set_on_success(RegExpNode* node) { on_success_ = node; } | 708 void set_on_success(RegExpNode* node) { on_success_ = node; } |
| 673 private: | 709 private: |
| 674 RegExpNode* on_success_; | 710 RegExpNode* on_success_; |
| 675 }; | 711 }; |
| 676 | 712 |
| 677 | 713 |
| 678 class ActionNode: public SeqRegExpNode { | 714 class ActionNode: public SeqRegExpNode { |
| 679 public: | 715 public: |
| 680 enum Type { | 716 enum Type { |
| 681 SET_REGISTER, | 717 SET_REGISTER, |
| 682 INCREMENT_REGISTER, | 718 INCREMENT_REGISTER, |
| 683 STORE_POSITION, | 719 STORE_POSITION, |
| 684 BEGIN_SUBMATCH, | 720 BEGIN_SUBMATCH, |
| 685 POSITIVE_SUBMATCH_SUCCESS | 721 POSITIVE_SUBMATCH_SUCCESS, |
| 722 EMPTY_MATCH_CHECK, |
| 723 CLEAR_CAPTURES |
| 686 }; | 724 }; |
| 687 static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success); | 725 static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success); |
| 688 static ActionNode* IncrementRegister(int reg, RegExpNode* on_success); | 726 static ActionNode* IncrementRegister(int reg, RegExpNode* on_success); |
| 689 static ActionNode* StorePosition(int reg, RegExpNode* on_success); | 727 static ActionNode* StorePosition(int reg, RegExpNode* on_success); |
| 690 static ActionNode* BeginSubmatch( | 728 static ActionNode* ClearCaptures(Interval range, RegExpNode* on_success); |
| 691 int stack_pointer_reg, | 729 static ActionNode* BeginSubmatch(int stack_pointer_reg, |
| 692 int position_reg, | 730 int position_reg, |
| 693 RegExpNode* on_success); | 731 RegExpNode* on_success); |
| 694 static ActionNode* PositiveSubmatchSuccess( | 732 static ActionNode* PositiveSubmatchSuccess(int stack_pointer_reg, |
| 695 int stack_pointer_reg, | 733 int restore_reg, |
| 696 int restore_reg, | 734 RegExpNode* on_success); |
| 697 RegExpNode* on_success); | 735 static ActionNode* EmptyMatchCheck(int start_register, |
| 736 int repetition_register, |
| 737 int repetition_limit, |
| 738 RegExpNode* on_success); |
| 698 virtual void Accept(NodeVisitor* visitor); | 739 virtual void Accept(NodeVisitor* visitor); |
| 699 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 740 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
| 700 virtual int EatsAtLeast(int recursion_depth); | 741 virtual int EatsAtLeast(int recursion_depth); |
| 701 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 742 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 702 RegExpCompiler* compiler, | 743 RegExpCompiler* compiler, |
| 703 int filled_in) { | 744 int filled_in) { |
| 704 return on_success()->GetQuickCheckDetails(details, compiler, filled_in); | 745 return on_success()->GetQuickCheckDetails(details, compiler, filled_in); |
| 705 } | 746 } |
| 706 virtual RegExpNode* PropagateForward(NodeInfo* info); | 747 virtual RegExpNode* PropagateForward(NodeInfo* info); |
| 707 Type type() { return type_; } | 748 Type type() { return type_; } |
| 708 // TODO(erikcorry): We should allow some action nodes in greedy loops. | 749 // TODO(erikcorry): We should allow some action nodes in greedy loops. |
| 709 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } | 750 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } |
| 710 virtual ActionNode* Clone() { return new ActionNode(*this); } | 751 virtual ActionNode* Clone() { return new ActionNode(*this); } |
| 711 | 752 |
| 712 private: | 753 private: |
| 713 union { | 754 union { |
| 714 struct { | 755 struct { |
| 715 int reg; | 756 int reg; |
| 716 int value; | 757 int value; |
| 717 } u_store_register; | 758 } u_store_register; |
| 718 struct { | 759 struct { |
| 719 int reg; | 760 int reg; |
| 720 } u_increment_register; | 761 } u_increment_register; |
| 721 struct { | 762 struct { |
| 722 int reg; | 763 int reg; |
| 723 } u_position_register; | 764 } u_position_register; |
| 724 struct { | 765 struct { |
| 725 int stack_pointer_register; | 766 int stack_pointer_register; |
| 726 int current_position_register; | 767 int current_position_register; |
| 727 } u_submatch; | 768 } u_submatch; |
| 769 struct { |
| 770 int start_register; |
| 771 int repetition_register; |
| 772 int repetition_limit; |
| 773 } u_empty_match_check; |
| 774 struct { |
| 775 int range_from; |
| 776 int range_to; |
| 777 } u_clear_captures; |
| 728 } data_; | 778 } data_; |
| 729 ActionNode(Type type, RegExpNode* on_success) | 779 ActionNode(Type type, RegExpNode* on_success) |
| 730 : SeqRegExpNode(on_success), | 780 : SeqRegExpNode(on_success), |
| 731 type_(type) { } | 781 type_(type) { } |
| 732 Type type_; | 782 Type type_; |
| 733 friend class DotPrinter; | 783 friend class DotPrinter; |
| 734 }; | 784 }; |
| 735 | 785 |
| 736 | 786 |
| 737 class TextNode: public SeqRegExpNode { | 787 class TextNode: public SeqRegExpNode { |
| 738 public: | 788 public: |
| 739 TextNode(ZoneList<TextElement>* elms, | 789 TextNode(ZoneList<TextElement>* elms, |
| 740 RegExpNode* on_success) | 790 RegExpNode* on_success) |
| 741 : SeqRegExpNode(on_success), | 791 : SeqRegExpNode(on_success), |
| 742 elms_(elms) { } | 792 elms_(elms) { } |
| 743 TextNode(RegExpCharacterClass* that, | 793 TextNode(RegExpCharacterClass* that, |
| 744 RegExpNode* on_success) | 794 RegExpNode* on_success) |
| 745 : SeqRegExpNode(on_success), | 795 : SeqRegExpNode(on_success), |
| 746 elms_(new ZoneList<TextElement>(1)) { | 796 elms_(new ZoneList<TextElement>(1)) { |
| 747 elms_->Add(TextElement::CharClass(that)); | 797 elms_->Add(TextElement::CharClass(that)); |
| 748 } | 798 } |
| 749 virtual void Accept(NodeVisitor* visitor); | 799 virtual void Accept(NodeVisitor* visitor); |
| 750 virtual RegExpNode* PropagateForward(NodeInfo* info); | 800 virtual RegExpNode* PropagateForward(NodeInfo* info); |
| 751 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 801 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
| 752 virtual int EatsAtLeast(int recursion_depth); | 802 virtual int EatsAtLeast(int recursion_depth); |
| 753 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 803 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 754 RegExpCompiler* compiler, | 804 RegExpCompiler* compiler, |
| 755 int characters_filled_in); | 805 int characters_filled_in); |
| 756 ZoneList<TextElement>* elements() { return elms_; } | 806 ZoneList<TextElement>* elements() { return elms_; } |
| 757 void MakeCaseIndependent(); | 807 void MakeCaseIndependent(); |
| 758 virtual int GreedyLoopTextLength(); | 808 virtual int GreedyLoopTextLength(); |
| 759 virtual TextNode* Clone() { | 809 virtual TextNode* Clone() { |
| 760 TextNode* result = new TextNode(*this); | 810 TextNode* result = new TextNode(*this); |
| 761 result->CalculateOffsets(); | 811 result->CalculateOffsets(); |
| 762 return result; | 812 return result; |
| 763 } | 813 } |
| 764 void CalculateOffsets(); | 814 void CalculateOffsets(); |
| 765 | 815 |
| 766 private: | 816 private: |
| 767 enum TextEmitPassType { | 817 enum TextEmitPassType { |
| 768 NON_ASCII_MATCH, | 818 NON_ASCII_MATCH, |
| 769 CHARACTER_MATCH, | 819 CHARACTER_MATCH, |
| 770 CASE_CHARACTER_MATCH, | 820 CASE_CHARACTER_MATCH, |
| 771 CHARACTER_CLASS_MATCH | 821 CHARACTER_CLASS_MATCH |
| 772 }; | 822 }; |
| 773 void TextEmitPass(RegExpCompiler* compiler, | 823 void TextEmitPass(RegExpCompiler* compiler, |
| 774 TextEmitPassType pass, | 824 TextEmitPassType pass, |
| 775 bool preloaded, | 825 bool preloaded, |
| 776 GenerationVariant* variant, | 826 Trace* trace, |
| 777 bool first_element_checked, | 827 bool first_element_checked, |
| 778 int* checked_up_to); | 828 int* checked_up_to); |
| 779 int Length(); | 829 int Length(); |
| 780 ZoneList<TextElement>* elms_; | 830 ZoneList<TextElement>* elms_; |
| 781 }; | 831 }; |
| 782 | 832 |
| 783 | 833 |
| 784 class BackReferenceNode: public SeqRegExpNode { | 834 class BackReferenceNode: public SeqRegExpNode { |
| 785 public: | 835 public: |
| 786 BackReferenceNode(int start_reg, | 836 BackReferenceNode(int start_reg, |
| 787 int end_reg, | 837 int end_reg, |
| 788 RegExpNode* on_success) | 838 RegExpNode* on_success) |
| 789 : SeqRegExpNode(on_success), | 839 : SeqRegExpNode(on_success), |
| 790 start_reg_(start_reg), | 840 start_reg_(start_reg), |
| 791 end_reg_(end_reg) { } | 841 end_reg_(end_reg) { } |
| 792 virtual void Accept(NodeVisitor* visitor); | 842 virtual void Accept(NodeVisitor* visitor); |
| 793 int start_register() { return start_reg_; } | 843 int start_register() { return start_reg_; } |
| 794 int end_register() { return end_reg_; } | 844 int end_register() { return end_reg_; } |
| 795 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 845 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
| 796 virtual int EatsAtLeast(int recursion_depth) { return 0; } | 846 virtual int EatsAtLeast(int recursion_depth) { return 0; } |
| 797 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 847 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 798 RegExpCompiler* compiler, | 848 RegExpCompiler* compiler, |
| 799 int characters_filled_in) { | 849 int characters_filled_in) { |
| 800 return; | 850 return; |
| 801 } | 851 } |
| 802 virtual RegExpNode* PropagateForward(NodeInfo* info); | 852 virtual RegExpNode* PropagateForward(NodeInfo* info); |
| 803 virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); } | 853 virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); } |
| 804 | 854 |
| 805 private: | 855 private: |
| 806 int start_reg_; | 856 int start_reg_; |
| 807 int end_reg_; | 857 int end_reg_; |
| 808 }; | 858 }; |
| 809 | 859 |
| 810 | 860 |
| 811 class EndNode: public RegExpNode { | 861 class EndNode: public RegExpNode { |
| 812 public: | 862 public: |
| 813 enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS }; | 863 enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS }; |
| 814 explicit EndNode(Action action) : action_(action) { } | 864 explicit EndNode(Action action) : action_(action) { } |
| 815 virtual void Accept(NodeVisitor* visitor); | 865 virtual void Accept(NodeVisitor* visitor); |
| 816 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 866 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
| 817 virtual int EatsAtLeast(int recursion_depth) { return 0; } | 867 virtual int EatsAtLeast(int recursion_depth) { return 0; } |
| 818 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 868 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 819 RegExpCompiler* compiler, | 869 RegExpCompiler* compiler, |
| 820 int characters_filled_in) { | 870 int characters_filled_in) { |
| 821 // Returning 0 from EatsAtLeast should ensure we never get here. | 871 // Returning 0 from EatsAtLeast should ensure we never get here. |
| 822 UNREACHABLE(); | 872 UNREACHABLE(); |
| 823 } | 873 } |
| 824 virtual RegExpNode* PropagateForward(NodeInfo* info); | 874 virtual RegExpNode* PropagateForward(NodeInfo* info); |
| 825 virtual EndNode* Clone() { return new EndNode(*this); } | 875 virtual EndNode* Clone() { return new EndNode(*this); } |
| 826 | 876 |
| 827 protected: | 877 protected: |
| 828 void EmitInfoChecks(RegExpMacroAssembler* macro, GenerationVariant* variant); | 878 void EmitInfoChecks(RegExpMacroAssembler* macro, Trace* trace); |
| 829 | 879 |
| 830 private: | 880 private: |
| 831 Action action_; | 881 Action action_; |
| 832 }; | 882 }; |
| 833 | 883 |
| 834 | 884 |
| 835 class NegativeSubmatchSuccess: public EndNode { | 885 class NegativeSubmatchSuccess: public EndNode { |
| 836 public: | 886 public: |
| 837 NegativeSubmatchSuccess(int stack_pointer_reg, int position_reg) | 887 NegativeSubmatchSuccess(int stack_pointer_reg, int position_reg) |
| 838 : EndNode(NEGATIVE_SUBMATCH_SUCCESS), | 888 : EndNode(NEGATIVE_SUBMATCH_SUCCESS), |
| 839 stack_pointer_register_(stack_pointer_reg), | 889 stack_pointer_register_(stack_pointer_reg), |
| 840 current_position_register_(position_reg) { } | 890 current_position_register_(position_reg) { } |
| 841 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 891 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
| 842 | 892 |
| 843 private: | 893 private: |
| 844 int stack_pointer_register_; | 894 int stack_pointer_register_; |
| 845 int current_position_register_; | 895 int current_position_register_; |
| 846 }; | 896 }; |
| 847 | 897 |
| 848 | 898 |
| 849 class Guard: public ZoneObject { | 899 class Guard: public ZoneObject { |
| 850 public: | 900 public: |
| 851 enum Relation { LT, GEQ }; | 901 enum Relation { LT, GEQ }; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 884 class ChoiceNode: public RegExpNode { | 934 class ChoiceNode: public RegExpNode { |
| 885 public: | 935 public: |
| 886 explicit ChoiceNode(int expected_size) | 936 explicit ChoiceNode(int expected_size) |
| 887 : alternatives_(new ZoneList<GuardedAlternative>(expected_size)), | 937 : alternatives_(new ZoneList<GuardedAlternative>(expected_size)), |
| 888 table_(NULL), | 938 table_(NULL), |
| 889 being_calculated_(false) { } | 939 being_calculated_(false) { } |
| 890 virtual void Accept(NodeVisitor* visitor); | 940 virtual void Accept(NodeVisitor* visitor); |
| 891 void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); } | 941 void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); } |
| 892 ZoneList<GuardedAlternative>* alternatives() { return alternatives_; } | 942 ZoneList<GuardedAlternative>* alternatives() { return alternatives_; } |
| 893 DispatchTable* GetTable(bool ignore_case); | 943 DispatchTable* GetTable(bool ignore_case); |
| 894 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 944 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
| 895 virtual int EatsAtLeast(int recursion_depth); | 945 virtual int EatsAtLeast(int recursion_depth); |
| 896 int EatsAtLeastHelper(int recursion_depth, RegExpNode* ignore_this_node); | 946 int EatsAtLeastHelper(int recursion_depth, RegExpNode* ignore_this_node); |
| 897 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 947 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 898 RegExpCompiler* compiler, | 948 RegExpCompiler* compiler, |
| 899 int characters_filled_in); | 949 int characters_filled_in); |
| 900 virtual RegExpNode* PropagateForward(NodeInfo* info); | 950 virtual RegExpNode* PropagateForward(NodeInfo* info); |
| 901 virtual ChoiceNode* Clone() { return new ChoiceNode(*this); } | 951 virtual ChoiceNode* Clone() { return new ChoiceNode(*this); } |
| 902 | 952 |
| 903 bool being_calculated() { return being_calculated_; } | 953 bool being_calculated() { return being_calculated_; } |
| 904 void set_being_calculated(bool b) { being_calculated_ = b; } | 954 void set_being_calculated(bool b) { being_calculated_ = b; } |
| 905 | 955 |
| 906 protected: | 956 protected: |
| 907 int GreedyLoopTextLength(GuardedAlternative *alternative); | 957 int GreedyLoopTextLength(GuardedAlternative *alternative); |
| 908 ZoneList<GuardedAlternative>* alternatives_; | 958 ZoneList<GuardedAlternative>* alternatives_; |
| 909 | 959 |
| 910 private: | 960 private: |
| 911 friend class DispatchTableConstructor; | 961 friend class DispatchTableConstructor; |
| 912 friend class Analysis; | 962 friend class Analysis; |
| 913 void GenerateGuard(RegExpMacroAssembler* macro_assembler, | 963 void GenerateGuard(RegExpMacroAssembler* macro_assembler, |
| 914 Guard *guard, | 964 Guard *guard, |
| 915 GenerationVariant* variant); | 965 Trace* trace); |
| 916 int CalculatePreloadCharacters(RegExpCompiler* compiler); | 966 int CalculatePreloadCharacters(RegExpCompiler* compiler); |
| 917 bool EmitOutOfLineContinuation(RegExpCompiler* compiler, | 967 bool EmitOutOfLineContinuation(RegExpCompiler* compiler, |
| 918 GenerationVariant* variant, | 968 Trace* trace, |
| 919 GuardedAlternative alternative, | 969 GuardedAlternative alternative, |
| 920 AlternativeGeneration* alt_gen, | 970 AlternativeGeneration* alt_gen, |
| 921 int preload_characters, | 971 int preload_characters, |
| 922 bool next_expects_preload); | 972 bool next_expects_preload); |
| 923 DispatchTable* table_; | 973 DispatchTable* table_; |
| 924 bool being_calculated_; | 974 bool being_calculated_; |
| 925 }; | 975 }; |
| 926 | 976 |
| 927 | 977 |
| 928 class LoopChoiceNode: public ChoiceNode { | 978 class LoopChoiceNode: public ChoiceNode { |
| 929 public: | 979 public: |
| 930 explicit LoopChoiceNode(bool body_can_be_zero_length) | 980 explicit LoopChoiceNode(bool body_can_be_zero_length) |
| 931 : ChoiceNode(2), | 981 : ChoiceNode(2), |
| 932 loop_node_(NULL), | 982 loop_node_(NULL), |
| 933 continue_node_(NULL), | 983 continue_node_(NULL), |
| 934 body_can_be_zero_length_(body_can_be_zero_length) { } | 984 body_can_be_zero_length_(body_can_be_zero_length) { } |
| 935 void AddLoopAlternative(GuardedAlternative alt); | 985 void AddLoopAlternative(GuardedAlternative alt); |
| 936 void AddContinueAlternative(GuardedAlternative alt); | 986 void AddContinueAlternative(GuardedAlternative alt); |
| 937 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); | 987 virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
| 938 virtual int EatsAtLeast(int recursion_depth); // Returns 0. | 988 virtual int EatsAtLeast(int recursion_depth); // Returns 0. |
| 939 virtual void GetQuickCheckDetails(QuickCheckDetails* details, | 989 virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
| 940 RegExpCompiler* compiler, | 990 RegExpCompiler* compiler, |
| 941 int characters_filled_in); | 991 int characters_filled_in); |
| 942 virtual LoopChoiceNode* Clone() { return new LoopChoiceNode(*this); } | 992 virtual LoopChoiceNode* Clone() { return new LoopChoiceNode(*this); } |
| 943 RegExpNode* loop_node() { return loop_node_; } | 993 RegExpNode* loop_node() { return loop_node_; } |
| 944 RegExpNode* continue_node() { return continue_node_; } | 994 RegExpNode* continue_node() { return continue_node_; } |
| 945 bool body_can_be_zero_length() { return body_can_be_zero_length_; } | 995 bool body_can_be_zero_length() { return body_can_be_zero_length_; } |
| 946 virtual void Accept(NodeVisitor* visitor); | 996 virtual void Accept(NodeVisitor* visitor); |
| 947 | 997 |
| 948 private: | 998 private: |
| 949 // AddAlternative is made private for loop nodes because alternatives | 999 // AddAlternative is made private for loop nodes because alternatives |
| 950 // should not be added freely, we need to keep track of which node | 1000 // should not be added freely, we need to keep track of which node |
| 951 // goes back to the node itself. | 1001 // goes back to the node itself. |
| 952 void AddAlternative(GuardedAlternative node) { | 1002 void AddAlternative(GuardedAlternative node) { |
| 953 ChoiceNode::AddAlternative(node); | 1003 ChoiceNode::AddAlternative(node); |
| 954 } | 1004 } |
| 955 | 1005 |
| 956 RegExpNode* loop_node_; | 1006 RegExpNode* loop_node_; |
| 957 RegExpNode* continue_node_; | 1007 RegExpNode* continue_node_; |
| 958 bool body_can_be_zero_length_; | 1008 bool body_can_be_zero_length_; |
| 959 }; | 1009 }; |
| 960 | 1010 |
| 961 | 1011 |
| 962 // There are many ways to generate code for a node. This class encapsulates | 1012 // There are many ways to generate code for a node. This class encapsulates |
| 963 // the current way we should be generating. In other words it encapsulates | 1013 // the current way we should be generating. In other words it encapsulates |
| 964 // the current state of the code generator. | 1014 // the current state of the code generator. The effect of this is that we |
| 965 class GenerationVariant { | 1015 // generate code for paths that the matcher can take through the regular |
| 1016 // expression. A given node in the regexp can be code-generated several times |
| 1017 // as it can be part of several traces. For example for the regexp: |
| 1018 // /foo(bar|ip)baz/ the code to match baz will be generated twice, once as part |
| 1019 // of the foo-bar-baz trace and once as part of the foo-ip-baz trace. The code |
| 1020 // to match foo is generated only once (the traces have a common prefix). The |
| 1021 // code to store the capture is deferred and generated (twice) after the places |
| 1022 // where baz has been matched. |
| 1023 class Trace { |
| 966 public: | 1024 public: |
| 967 class DeferredAction { | 1025 class DeferredAction { |
| 968 public: | 1026 public: |
| 969 DeferredAction(ActionNode::Type type, int reg) | 1027 DeferredAction(ActionNode::Type type, int reg) |
| 970 : type_(type), reg_(reg), next_(NULL) { } | 1028 : type_(type), reg_(reg), next_(NULL) { } |
| 971 DeferredAction* next() { return next_; } | 1029 DeferredAction* next() { return next_; } |
| 1030 bool Mentions(int reg); |
| 972 int reg() { return reg_; } | 1031 int reg() { return reg_; } |
| 973 ActionNode::Type type() { return type_; } | 1032 ActionNode::Type type() { return type_; } |
| 974 private: | 1033 private: |
| 975 ActionNode::Type type_; | 1034 ActionNode::Type type_; |
| 976 int reg_; | 1035 int reg_; |
| 977 DeferredAction* next_; | 1036 DeferredAction* next_; |
| 978 friend class GenerationVariant; | 1037 friend class Trace; |
| 979 }; | 1038 }; |
| 980 | 1039 |
| 981 class DeferredCapture: public DeferredAction { | 1040 class DeferredCapture: public DeferredAction { |
| 982 public: | 1041 public: |
| 983 DeferredCapture(int reg, GenerationVariant* variant) | 1042 DeferredCapture(int reg, Trace* trace) |
| 984 : DeferredAction(ActionNode::STORE_POSITION, reg), | 1043 : DeferredAction(ActionNode::STORE_POSITION, reg), |
| 985 cp_offset_(variant->cp_offset()) { } | 1044 cp_offset_(trace->cp_offset()) { } |
| 986 int cp_offset() { return cp_offset_; } | 1045 int cp_offset() { return cp_offset_; } |
| 987 private: | 1046 private: |
| 988 int cp_offset_; | 1047 int cp_offset_; |
| 989 void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; } | 1048 void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; } |
| 990 }; | 1049 }; |
| 991 | 1050 |
| 992 class DeferredSetRegister :public DeferredAction { | 1051 class DeferredSetRegister :public DeferredAction { |
| 993 public: | 1052 public: |
| 994 DeferredSetRegister(int reg, int value) | 1053 DeferredSetRegister(int reg, int value) |
| 995 : DeferredAction(ActionNode::SET_REGISTER, reg), | 1054 : DeferredAction(ActionNode::SET_REGISTER, reg), |
| 996 value_(value) { } | 1055 value_(value) { } |
| 997 int value() { return value_; } | 1056 int value() { return value_; } |
| 998 private: | 1057 private: |
| 999 int value_; | 1058 int value_; |
| 1000 }; | 1059 }; |
| 1001 | 1060 |
| 1061 class DeferredClearCaptures : public DeferredAction { |
| 1062 public: |
| 1063 explicit DeferredClearCaptures(Interval range) |
| 1064 : DeferredAction(ActionNode::CLEAR_CAPTURES, -1), |
| 1065 range_(range) { } |
| 1066 Interval range() { return range_; } |
| 1067 private: |
| 1068 Interval range_; |
| 1069 }; |
| 1070 |
| 1002 class DeferredIncrementRegister: public DeferredAction { | 1071 class DeferredIncrementRegister: public DeferredAction { |
| 1003 public: | 1072 public: |
| 1004 explicit DeferredIncrementRegister(int reg) | 1073 explicit DeferredIncrementRegister(int reg) |
| 1005 : DeferredAction(ActionNode::INCREMENT_REGISTER, reg) { } | 1074 : DeferredAction(ActionNode::INCREMENT_REGISTER, reg) { } |
| 1006 }; | 1075 }; |
| 1007 | 1076 |
| 1008 GenerationVariant() | 1077 Trace() |
| 1009 : cp_offset_(0), | 1078 : cp_offset_(0), |
| 1010 actions_(NULL), | 1079 actions_(NULL), |
| 1011 backtrack_(NULL), | 1080 backtrack_(NULL), |
| 1012 stop_node_(NULL), | 1081 stop_node_(NULL), |
| 1013 loop_label_(NULL), | 1082 loop_label_(NULL), |
| 1014 characters_preloaded_(0), | 1083 characters_preloaded_(0), |
| 1015 bound_checked_up_to_(0) { } | 1084 bound_checked_up_to_(0) { } |
| 1085 // 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 |
| 1087 // done we can start a new trace or go to one that has already been |
| 1088 // generated. |
| 1016 bool Flush(RegExpCompiler* compiler, RegExpNode* successor); | 1089 bool Flush(RegExpCompiler* compiler, RegExpNode* successor); |
| 1017 int cp_offset() { return cp_offset_; } | 1090 int cp_offset() { return cp_offset_; } |
| 1018 DeferredAction* actions() { return actions_; } | 1091 DeferredAction* actions() { return actions_; } |
| 1092 // 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 |
| 1094 // 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 |
| 1096 // 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 |
| 1098 // 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 |
| 1100 // a trivial trace is recorded in a label in the node so that gotos can be |
| 1101 // generated to that code. |
| 1019 bool is_trivial() { | 1102 bool is_trivial() { |
| 1020 return backtrack_ == NULL && | 1103 return backtrack_ == NULL && |
| 1021 actions_ == NULL && | 1104 actions_ == NULL && |
| 1022 cp_offset_ == 0 && | 1105 cp_offset_ == 0 && |
| 1023 characters_preloaded_ == 0 && | 1106 characters_preloaded_ == 0 && |
| 1024 bound_checked_up_to_ == 0 && | 1107 bound_checked_up_to_ == 0 && |
| 1025 quick_check_performed_.characters() == 0; | 1108 quick_check_performed_.characters() == 0; |
| 1026 } | 1109 } |
| 1027 Label* backtrack() { return backtrack_; } | 1110 Label* backtrack() { return backtrack_; } |
| 1028 Label* loop_label() { return loop_label_; } | 1111 Label* loop_label() { return loop_label_; } |
| 1029 RegExpNode* stop_node() { return stop_node_; } | 1112 RegExpNode* stop_node() { return stop_node_; } |
| 1030 int characters_preloaded() { return characters_preloaded_; } | 1113 int characters_preloaded() { return characters_preloaded_; } |
| 1031 int bound_checked_up_to() { return bound_checked_up_to_; } | 1114 int bound_checked_up_to() { return bound_checked_up_to_; } |
| 1032 QuickCheckDetails* quick_check_performed() { return &quick_check_performed_; } | 1115 QuickCheckDetails* quick_check_performed() { return &quick_check_performed_; } |
| 1033 bool mentions_reg(int reg); | 1116 bool mentions_reg(int reg); |
| 1034 // These set methods and AdvanceVariant should be used only on new | 1117 // Returns true if a deferred position store exists to the specified |
| 1035 // GenerationVariants - the intention is that GenerationVariants are | 1118 // register and stores the offset in the out-parameter. Otherwise |
| 1036 // immutable after creation. | 1119 // returns false. |
| 1120 bool GetStoredPosition(int reg, int* cp_offset); |
| 1121 // These set methods and AdvanceCurrentPositionInTrace should be used only on |
| 1122 // new traces - the intention is that traces are immutable after creation. |
| 1037 void add_action(DeferredAction* new_action) { | 1123 void add_action(DeferredAction* new_action) { |
| 1038 ASSERT(new_action->next_ == NULL); | 1124 ASSERT(new_action->next_ == NULL); |
| 1039 new_action->next_ = actions_; | 1125 new_action->next_ = actions_; |
| 1040 actions_ = new_action; | 1126 actions_ = new_action; |
| 1041 } | 1127 } |
| 1042 void set_backtrack(Label* backtrack) { backtrack_ = backtrack; } | 1128 void set_backtrack(Label* backtrack) { backtrack_ = backtrack; } |
| 1043 void set_stop_node(RegExpNode* node) { stop_node_ = node; } | 1129 void set_stop_node(RegExpNode* node) { stop_node_ = node; } |
| 1044 void set_loop_label(Label* label) { loop_label_ = label; } | 1130 void set_loop_label(Label* label) { loop_label_ = label; } |
| 1045 void set_characters_preloaded(int cpre) { characters_preloaded_ = cpre; } | 1131 void set_characters_preloaded(int cpre) { characters_preloaded_ = cpre; } |
| 1046 void set_bound_checked_up_to(int to) { bound_checked_up_to_ = to; } | 1132 void set_bound_checked_up_to(int to) { bound_checked_up_to_ = to; } |
| 1047 void set_quick_check_performed(QuickCheckDetails* d) { | 1133 void set_quick_check_performed(QuickCheckDetails* d) { |
| 1048 quick_check_performed_ = *d; | 1134 quick_check_performed_ = *d; |
| 1049 } | 1135 } |
| 1050 void clear_quick_check_performed() { | 1136 void clear_quick_check_performed() { |
| 1051 } | 1137 } |
| 1052 void AdvanceVariant(int by, bool ascii); | 1138 void AdvanceCurrentPositionInTrace(int by, bool ascii); |
| 1053 private: | 1139 private: |
| 1054 int FindAffectedRegisters(OutSet* affected_registers); | 1140 int FindAffectedRegisters(OutSet* affected_registers); |
| 1055 void PerformDeferredActions(RegExpMacroAssembler* macro, | 1141 void PerformDeferredActions(RegExpMacroAssembler* macro, |
| 1056 int max_register, | 1142 int max_register, |
| 1057 OutSet& affected_registers); | 1143 OutSet& affected_registers); |
| 1058 void RestoreAffectedRegisters(RegExpMacroAssembler* macro, | 1144 void RestoreAffectedRegisters(RegExpMacroAssembler* macro, |
| 1059 int max_register, | 1145 int max_register, |
| 1060 OutSet& affected_registers); | 1146 OutSet& affected_registers); |
| 1061 void PushAffectedRegisters(RegExpMacroAssembler* macro, | 1147 void PushAffectedRegisters(RegExpMacroAssembler* macro, |
| 1062 int max_register, | 1148 int max_register, |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1168 Handle<String> pattern, | 1254 Handle<String> pattern, |
| 1169 bool is_ascii); | 1255 bool is_ascii); |
| 1170 | 1256 |
| 1171 static void DotPrint(const char* label, RegExpNode* node, bool ignore_case); | 1257 static void DotPrint(const char* label, RegExpNode* node, bool ignore_case); |
| 1172 }; | 1258 }; |
| 1173 | 1259 |
| 1174 | 1260 |
| 1175 } } // namespace v8::internal | 1261 } } // namespace v8::internal |
| 1176 | 1262 |
| 1177 #endif // V8_JSREGEXP_H_ | 1263 #endif // V8_JSREGEXP_H_ |
| OLD | NEW |