| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 1549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1560 return CharFromCode(code); | 1560 return CharFromCode(code); |
| 1561 } | 1561 } |
| 1562 | 1562 |
| 1563 | 1563 |
| 1564 static Object* Runtime_CharFromCode(Arguments args) { | 1564 static Object* Runtime_CharFromCode(Arguments args) { |
| 1565 NoHandleAllocation ha; | 1565 NoHandleAllocation ha; |
| 1566 ASSERT(args.length() == 1); | 1566 ASSERT(args.length() == 1); |
| 1567 return CharFromCode(args[0]); | 1567 return CharFromCode(args[0]); |
| 1568 } | 1568 } |
| 1569 | 1569 |
| 1570 |
| 1571 class FixedArrayBuilder { |
| 1572 public: |
| 1573 explicit FixedArrayBuilder(int initial_capacity) |
| 1574 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)), |
| 1575 length_(0) { |
| 1576 // Require a non-zero initial size. Ensures that doubling the size to |
| 1577 // extend the array will work. |
| 1578 ASSERT(initial_capacity > 0); |
| 1579 } |
| 1580 |
| 1581 explicit FixedArrayBuilder(Handle<FixedArray> backing_store) |
| 1582 : array_(backing_store), |
| 1583 length_(0) { |
| 1584 // Require a non-zero initial size. Ensures that doubling the size to |
| 1585 // extend the array will work. |
| 1586 ASSERT(backing_store->length() > 0); |
| 1587 } |
| 1588 |
| 1589 bool HasCapacity(int elements) { |
| 1590 int length = array_->length(); |
| 1591 int required_length = length_ + elements; |
| 1592 return (length >= required_length); |
| 1593 } |
| 1594 |
| 1595 void EnsureCapacity(int elements) { |
| 1596 int length = array_->length(); |
| 1597 int required_length = length_ + elements; |
| 1598 if (length < required_length) { |
| 1599 int new_length = length; |
| 1600 do { |
| 1601 new_length *= 2; |
| 1602 } while (new_length < required_length); |
| 1603 Handle<FixedArray> extended_array = |
| 1604 Factory::NewFixedArrayWithHoles(new_length); |
| 1605 array_->CopyTo(0, *extended_array, 0, length_); |
| 1606 array_ = extended_array; |
| 1607 } |
| 1608 } |
| 1609 |
| 1610 void Add(Object* value) { |
| 1611 ASSERT(length_ < capacity()); |
| 1612 array_->set(length_, value); |
| 1613 length_++; |
| 1614 } |
| 1615 |
| 1616 void Add(Smi* value) { |
| 1617 ASSERT(length_ < capacity()); |
| 1618 array_->set(length_, value); |
| 1619 length_++; |
| 1620 } |
| 1621 |
| 1622 Handle<FixedArray> array() { |
| 1623 return array_; |
| 1624 } |
| 1625 |
| 1626 int length() { |
| 1627 return length_; |
| 1628 } |
| 1629 |
| 1630 int capacity() { |
| 1631 return array_->length(); |
| 1632 } |
| 1633 |
| 1634 Handle<JSArray> ToJSArray() { |
| 1635 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_); |
| 1636 result_array->set_length(Smi::FromInt(length_)); |
| 1637 return result_array; |
| 1638 } |
| 1639 |
| 1640 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { |
| 1641 target_array->set_elements(*array_); |
| 1642 target_array->set_length(Smi::FromInt(length_)); |
| 1643 return target_array; |
| 1644 } |
| 1645 |
| 1646 private: |
| 1647 Handle<FixedArray> array_; |
| 1648 int length_; |
| 1649 }; |
| 1650 |
| 1651 |
| 1570 // Forward declarations. | 1652 // Forward declarations. |
| 1571 static const int kStringBuilderConcatHelperLengthBits = 11; | 1653 const int kStringBuilderConcatHelperLengthBits = 11; |
| 1572 static const int kStringBuilderConcatHelperPositionBits = 19; | 1654 const int kStringBuilderConcatHelperPositionBits = 19; |
| 1573 | 1655 |
| 1574 template <typename schar> | 1656 template <typename schar> |
| 1575 static inline void StringBuilderConcatHelper(String*, | 1657 static inline void StringBuilderConcatHelper(String*, |
| 1576 schar*, | 1658 schar*, |
| 1577 FixedArray*, | 1659 FixedArray*, |
| 1578 int); | 1660 int); |
| 1579 | 1661 |
| 1580 typedef BitField<int, 0, 11> StringBuilderSubstringLength; | 1662 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> |
| 1581 typedef BitField<int, 11, 19> StringBuilderSubstringPosition; | 1663 StringBuilderSubstringLength; |
| 1664 typedef BitField<int, |
| 1665 kStringBuilderConcatHelperLengthBits, |
| 1666 kStringBuilderConcatHelperPositionBits> |
| 1667 StringBuilderSubstringPosition; |
| 1668 |
| 1582 | 1669 |
| 1583 class ReplacementStringBuilder { | 1670 class ReplacementStringBuilder { |
| 1584 public: | 1671 public: |
| 1585 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count) | 1672 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count) |
| 1586 : subject_(subject), | 1673 : array_builder_(estimated_part_count), |
| 1587 parts_(Factory::NewFixedArray(estimated_part_count)), | 1674 subject_(subject), |
| 1588 part_count_(0), | |
| 1589 character_count_(0), | 1675 character_count_(0), |
| 1590 is_ascii_(subject->IsAsciiRepresentation()) { | 1676 is_ascii_(subject->IsAsciiRepresentation()) { |
| 1591 // Require a non-zero initial size. Ensures that doubling the size to | 1677 // Require a non-zero initial size. Ensures that doubling the size to |
| 1592 // extend the array will work. | 1678 // extend the array will work. |
| 1593 ASSERT(estimated_part_count > 0); | 1679 ASSERT(estimated_part_count > 0); |
| 1594 } | 1680 } |
| 1595 | 1681 |
| 1596 void EnsureCapacity(int elements) { | 1682 static inline void AddSubjectSlice(FixedArrayBuilder* builder, |
| 1597 int length = parts_->length(); | 1683 int from, |
| 1598 int required_length = part_count_ + elements; | 1684 int to) { |
| 1599 if (length < required_length) { | |
| 1600 int new_length = length; | |
| 1601 do { | |
| 1602 new_length *= 2; | |
| 1603 } while (new_length < required_length); | |
| 1604 Handle<FixedArray> extended_array = | |
| 1605 Factory::NewFixedArray(new_length); | |
| 1606 parts_->CopyTo(0, *extended_array, 0, part_count_); | |
| 1607 parts_ = extended_array; | |
| 1608 } | |
| 1609 } | |
| 1610 | |
| 1611 void AddSubjectSlice(int from, int to) { | |
| 1612 ASSERT(from >= 0); | 1685 ASSERT(from >= 0); |
| 1613 int length = to - from; | 1686 int length = to - from; |
| 1614 ASSERT(length > 0); | 1687 ASSERT(length > 0); |
| 1615 // Can we encode the slice in 11 bits for length and 19 bits for | |
| 1616 // start position - as used by StringBuilderConcatHelper? | |
| 1617 if (StringBuilderSubstringLength::is_valid(length) && | 1688 if (StringBuilderSubstringLength::is_valid(length) && |
| 1618 StringBuilderSubstringPosition::is_valid(from)) { | 1689 StringBuilderSubstringPosition::is_valid(from)) { |
| 1619 int encoded_slice = StringBuilderSubstringLength::encode(length) | | 1690 int encoded_slice = StringBuilderSubstringLength::encode(length) | |
| 1620 StringBuilderSubstringPosition::encode(from); | 1691 StringBuilderSubstringPosition::encode(from); |
| 1621 AddElement(Smi::FromInt(encoded_slice)); | 1692 builder->Add(Smi::FromInt(encoded_slice)); |
| 1622 } else { | 1693 } else { |
| 1623 // Otherwise encode as two smis. | 1694 // Otherwise encode as two smis. |
| 1624 AddElement(Smi::FromInt(-length)); | 1695 builder->Add(Smi::FromInt(-length)); |
| 1625 AddElement(Smi::FromInt(from)); | 1696 builder->Add(Smi::FromInt(from)); |
| 1626 } | 1697 } |
| 1627 IncrementCharacterCount(length); | |
| 1628 } | 1698 } |
| 1629 | 1699 |
| 1630 | 1700 |
| 1701 void EnsureCapacity(int elements) { |
| 1702 array_builder_.EnsureCapacity(elements); |
| 1703 } |
| 1704 |
| 1705 |
| 1706 void AddSubjectSlice(int from, int to) { |
| 1707 AddSubjectSlice(&array_builder_, from, to); |
| 1708 // Can we encode the slice in 11 bits for length and 19 bits for |
| 1709 // start position - as used by StringBuilderConcatHelper? |
| 1710 IncrementCharacterCount(to - from); |
| 1711 } |
| 1712 |
| 1713 |
| 1631 void AddString(Handle<String> string) { | 1714 void AddString(Handle<String> string) { |
| 1632 int length = string->length(); | 1715 int length = string->length(); |
| 1633 ASSERT(length > 0); | 1716 ASSERT(length > 0); |
| 1634 AddElement(*string); | 1717 AddElement(*string); |
| 1635 if (!string->IsAsciiRepresentation()) { | 1718 if (!string->IsAsciiRepresentation()) { |
| 1636 is_ascii_ = false; | 1719 is_ascii_ = false; |
| 1637 } | 1720 } |
| 1638 IncrementCharacterCount(length); | 1721 IncrementCharacterCount(length); |
| 1639 } | 1722 } |
| 1640 | 1723 |
| 1641 | 1724 |
| 1642 Handle<String> ToString() { | 1725 Handle<String> ToString() { |
| 1643 if (part_count_ == 0) { | 1726 if (array_builder_.length() == 0) { |
| 1644 return Factory::empty_string(); | 1727 return Factory::empty_string(); |
| 1645 } | 1728 } |
| 1646 | 1729 |
| 1647 Handle<String> joined_string; | 1730 Handle<String> joined_string; |
| 1648 if (is_ascii_) { | 1731 if (is_ascii_) { |
| 1649 joined_string = NewRawAsciiString(character_count_); | 1732 joined_string = NewRawAsciiString(character_count_); |
| 1650 AssertNoAllocation no_alloc; | 1733 AssertNoAllocation no_alloc; |
| 1651 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string); | 1734 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string); |
| 1652 char* char_buffer = seq->GetChars(); | 1735 char* char_buffer = seq->GetChars(); |
| 1653 StringBuilderConcatHelper(*subject_, | 1736 StringBuilderConcatHelper(*subject_, |
| 1654 char_buffer, | 1737 char_buffer, |
| 1655 *parts_, | 1738 *array_builder_.array(), |
| 1656 part_count_); | 1739 array_builder_.length()); |
| 1657 } else { | 1740 } else { |
| 1658 // Non-ASCII. | 1741 // Non-ASCII. |
| 1659 joined_string = NewRawTwoByteString(character_count_); | 1742 joined_string = NewRawTwoByteString(character_count_); |
| 1660 AssertNoAllocation no_alloc; | 1743 AssertNoAllocation no_alloc; |
| 1661 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string); | 1744 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string); |
| 1662 uc16* char_buffer = seq->GetChars(); | 1745 uc16* char_buffer = seq->GetChars(); |
| 1663 StringBuilderConcatHelper(*subject_, | 1746 StringBuilderConcatHelper(*subject_, |
| 1664 char_buffer, | 1747 char_buffer, |
| 1665 *parts_, | 1748 *array_builder_.array(), |
| 1666 part_count_); | 1749 array_builder_.length()); |
| 1667 } | 1750 } |
| 1668 return joined_string; | 1751 return joined_string; |
| 1669 } | 1752 } |
| 1670 | 1753 |
| 1671 | 1754 |
| 1672 void IncrementCharacterCount(int by) { | 1755 void IncrementCharacterCount(int by) { |
| 1673 if (character_count_ > String::kMaxLength - by) { | 1756 if (character_count_ > String::kMaxLength - by) { |
| 1674 V8::FatalProcessOutOfMemory("String.replace result too large."); | 1757 V8::FatalProcessOutOfMemory("String.replace result too large."); |
| 1675 } | 1758 } |
| 1676 character_count_ += by; | 1759 character_count_ += by; |
| 1677 } | 1760 } |
| 1678 | 1761 |
| 1762 Handle<JSArray> GetParts() { |
| 1763 Handle<JSArray> result = |
| 1764 Factory::NewJSArrayWithElements(array_builder_.array()); |
| 1765 result->set_length(Smi::FromInt(array_builder_.length())); |
| 1766 return result; |
| 1767 } |
| 1768 |
| 1679 private: | 1769 private: |
| 1680 | |
| 1681 Handle<String> NewRawAsciiString(int size) { | 1770 Handle<String> NewRawAsciiString(int size) { |
| 1682 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String); | 1771 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String); |
| 1683 } | 1772 } |
| 1684 | 1773 |
| 1685 | 1774 |
| 1686 Handle<String> NewRawTwoByteString(int size) { | 1775 Handle<String> NewRawTwoByteString(int size) { |
| 1687 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String); | 1776 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String); |
| 1688 } | 1777 } |
| 1689 | 1778 |
| 1690 | 1779 |
| 1691 void AddElement(Object* element) { | 1780 void AddElement(Object* element) { |
| 1692 ASSERT(element->IsSmi() || element->IsString()); | 1781 ASSERT(element->IsSmi() || element->IsString()); |
| 1693 ASSERT(parts_->length() > part_count_); | 1782 ASSERT(array_builder_.capacity() > array_builder_.length()); |
| 1694 parts_->set(part_count_, element); | 1783 array_builder_.Add(element); |
| 1695 part_count_++; | |
| 1696 } | 1784 } |
| 1697 | 1785 |
| 1786 FixedArrayBuilder array_builder_; |
| 1698 Handle<String> subject_; | 1787 Handle<String> subject_; |
| 1699 Handle<FixedArray> parts_; | |
| 1700 int part_count_; | |
| 1701 int character_count_; | 1788 int character_count_; |
| 1702 bool is_ascii_; | 1789 bool is_ascii_; |
| 1703 }; | 1790 }; |
| 1704 | 1791 |
| 1705 | 1792 |
| 1706 class CompiledReplacement { | 1793 class CompiledReplacement { |
| 1707 public: | 1794 public: |
| 1708 CompiledReplacement() | 1795 CompiledReplacement() |
| 1709 : parts_(1), replacement_substrings_(0) {} | 1796 : parts_(1), replacement_substrings_(0) {} |
| 1710 | 1797 |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2098 | 2185 |
| 2099 ASSERT(last_match_info->HasFastElements()); | 2186 ASSERT(last_match_info->HasFastElements()); |
| 2100 | 2187 |
| 2101 return StringReplaceRegExpWithString(subject, | 2188 return StringReplaceRegExpWithString(subject, |
| 2102 regexp, | 2189 regexp, |
| 2103 replacement, | 2190 replacement, |
| 2104 last_match_info); | 2191 last_match_info); |
| 2105 } | 2192 } |
| 2106 | 2193 |
| 2107 | 2194 |
| 2108 | |
| 2109 // Cap on the maximal shift in the Boyer-Moore implementation. By setting a | 2195 // Cap on the maximal shift in the Boyer-Moore implementation. By setting a |
| 2110 // limit, we can fix the size of tables. | 2196 // limit, we can fix the size of tables. |
| 2111 static const int kBMMaxShift = 0xff; | 2197 static const int kBMMaxShift = 0xff; |
| 2112 // Reduce alphabet to this size. | 2198 // Reduce alphabet to this size. |
| 2113 static const int kBMAlphabetSize = 0x100; | 2199 static const int kBMAlphabetSize = 0x100; |
| 2114 // For patterns below this length, the skip length of Boyer-Moore is too short | 2200 // For patterns below this length, the skip length of Boyer-Moore is too short |
| 2115 // to compensate for the algorithmic overhead compared to simple brute force. | 2201 // to compensate for the algorithmic overhead compared to simple brute force. |
| 2116 static const int kBMMinPatternLength = 5; | 2202 static const int kBMMinPatternLength = 5; |
| 2117 | 2203 |
| 2118 // Holds the two buffers used by Boyer-Moore string search's Good Suffix | 2204 // Holds the two buffers used by Boyer-Moore string search's Good Suffix |
| (...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2862 int from = offsets.at(i * 2); | 2948 int from = offsets.at(i * 2); |
| 2863 int to = offsets.at(i * 2 + 1); | 2949 int to = offsets.at(i * 2 + 1); |
| 2864 elements->set(i, *Factory::NewSubString(subject, from, to)); | 2950 elements->set(i, *Factory::NewSubString(subject, from, to)); |
| 2865 } | 2951 } |
| 2866 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements); | 2952 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements); |
| 2867 result->set_length(Smi::FromInt(matches)); | 2953 result->set_length(Smi::FromInt(matches)); |
| 2868 return *result; | 2954 return *result; |
| 2869 } | 2955 } |
| 2870 | 2956 |
| 2871 | 2957 |
| 2958 // Two smis before and after the match, for very long strings. |
| 2959 const int kMaxBuilderEntriesPerRegExpMatch = 5; |
| 2960 |
| 2961 |
| 2962 static void SetLastMatchInfoNoCaptures(Handle<String> subject, |
| 2963 Handle<JSArray> last_match_info, |
| 2964 int match_start, |
| 2965 int match_end) { |
| 2966 // Fill last_match_info with a single capture. |
| 2967 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead); |
| 2968 AssertNoAllocation no_gc; |
| 2969 FixedArray* elements = FixedArray::cast(last_match_info->elements()); |
| 2970 RegExpImpl::SetLastCaptureCount(elements, 2); |
| 2971 RegExpImpl::SetLastInput(elements, *subject); |
| 2972 RegExpImpl::SetLastSubject(elements, *subject); |
| 2973 RegExpImpl::SetCapture(elements, 0, match_start); |
| 2974 RegExpImpl::SetCapture(elements, 1, match_end); |
| 2975 } |
| 2976 |
| 2977 |
| 2978 template <typename schar> |
| 2979 static bool SearchCharMultiple(Vector<schar> subject, |
| 2980 String* pattern, |
| 2981 schar pattern_char, |
| 2982 FixedArrayBuilder* builder, |
| 2983 int* match_pos) { |
| 2984 // Position of last match. |
| 2985 int pos = *match_pos; |
| 2986 int subject_length = subject.length(); |
| 2987 while (pos < subject_length) { |
| 2988 int match_end = pos + 1; |
| 2989 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { |
| 2990 *match_pos = pos; |
| 2991 return false; |
| 2992 } |
| 2993 int new_pos = SingleCharIndexOf(subject, pattern_char, match_end); |
| 2994 if (new_pos >= 0) { |
| 2995 // Match has been found. |
| 2996 if (new_pos > match_end) { |
| 2997 ReplacementStringBuilder::AddSubjectSlice(builder, match_end, new_pos); |
| 2998 } |
| 2999 pos = new_pos; |
| 3000 builder->Add(pattern); |
| 3001 } else { |
| 3002 break; |
| 3003 } |
| 3004 } |
| 3005 if (pos + 1 < subject_length) { |
| 3006 ReplacementStringBuilder::AddSubjectSlice(builder, pos + 1, subject_length); |
| 3007 } |
| 3008 *match_pos = pos; |
| 3009 return true; |
| 3010 } |
| 3011 |
| 3012 |
| 3013 static bool SearchCharMultiple(Handle<String> subject, |
| 3014 Handle<String> pattern, |
| 3015 Handle<JSArray> last_match_info, |
| 3016 FixedArrayBuilder* builder) { |
| 3017 ASSERT(subject->IsFlat()); |
| 3018 ASSERT_EQ(1, pattern->length()); |
| 3019 uc16 pattern_char = pattern->Get(0); |
| 3020 // Treating position before first as initial "previous match position". |
| 3021 int match_pos = -1; |
| 3022 |
| 3023 for (;;) { // Break when search complete. |
| 3024 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); |
| 3025 AssertNoAllocation no_gc; |
| 3026 if (subject->IsAsciiRepresentation()) { |
| 3027 if (pattern_char > String::kMaxAsciiCharCode) { |
| 3028 break; |
| 3029 } |
| 3030 Vector<const char> subject_vector = subject->ToAsciiVector(); |
| 3031 char pattern_ascii_char = static_cast<char>(pattern_char); |
| 3032 bool complete = SearchCharMultiple<const char>(subject_vector, |
| 3033 *pattern, |
| 3034 pattern_ascii_char, |
| 3035 builder, |
| 3036 &match_pos); |
| 3037 if (complete) break; |
| 3038 } else { |
| 3039 Vector<const uc16> subject_vector = subject->ToUC16Vector(); |
| 3040 bool complete = SearchCharMultiple<const uc16>(subject_vector, |
| 3041 *pattern, |
| 3042 pattern_char, |
| 3043 builder, |
| 3044 &match_pos); |
| 3045 if (complete) break; |
| 3046 } |
| 3047 } |
| 3048 |
| 3049 if (match_pos >= 0) { |
| 3050 SetLastMatchInfoNoCaptures(subject, |
| 3051 last_match_info, |
| 3052 match_pos, |
| 3053 match_pos + 1); |
| 3054 return true; |
| 3055 } |
| 3056 return false; // No matches at all. |
| 3057 } |
| 3058 |
| 3059 |
| 3060 template <typename schar, typename pchar> |
| 3061 static bool SearchStringMultiple(Vector<schar> subject, |
| 3062 String* pattern, |
| 3063 Vector<pchar> pattern_string, |
| 3064 FixedArrayBuilder* builder, |
| 3065 int* match_pos) { |
| 3066 int pos = *match_pos; |
| 3067 int subject_length = subject.length(); |
| 3068 int pattern_length = pattern_string.length(); |
| 3069 int max_search_start = subject_length - pattern_length; |
| 3070 bool is_ascii = (sizeof(schar) == 1); |
| 3071 StringSearchStrategy strategy = |
| 3072 InitializeStringSearch(pattern_string, is_ascii); |
| 3073 switch (strategy) { |
| 3074 case SEARCH_FAIL: return false; |
| 3075 case SEARCH_SHORT: |
| 3076 while (pos <= max_search_start) { |
| 3077 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { |
| 3078 *match_pos = pos; |
| 3079 return false; |
| 3080 } |
| 3081 // Position of end of previous match. |
| 3082 int match_end = pos + pattern_length; |
| 3083 int new_pos = SimpleIndexOf(subject, pattern_string, match_end); |
| 3084 if (new_pos >= 0) { |
| 3085 // A match. |
| 3086 if (new_pos > match_end) { |
| 3087 ReplacementStringBuilder::AddSubjectSlice(builder, |
| 3088 match_end, |
| 3089 new_pos); |
| 3090 } |
| 3091 pos = new_pos; |
| 3092 builder->Add(pattern); |
| 3093 } else { |
| 3094 break; |
| 3095 } |
| 3096 } |
| 3097 break; |
| 3098 case SEARCH_LONG: |
| 3099 while (pos <= max_search_start) { |
| 3100 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { |
| 3101 *match_pos = pos; |
| 3102 return false; |
| 3103 } |
| 3104 int new_pos = ComplexIndexOf(subject, |
| 3105 pattern_string, |
| 3106 pos + pattern_length); |
| 3107 if (new_pos >= 0) { |
| 3108 // A match has been found. |
| 3109 if (new_pos > pos) { |
| 3110 ReplacementStringBuilder::AddSubjectSlice(builder, pos, new_pos); |
| 3111 } |
| 3112 pos = new_pos; |
| 3113 builder->Add(pattern); |
| 3114 } else { |
| 3115 break; |
| 3116 } |
| 3117 } |
| 3118 break; |
| 3119 } |
| 3120 if (pos < max_search_start) { |
| 3121 ReplacementStringBuilder::AddSubjectSlice(builder, |
| 3122 pos + pattern_length, |
| 3123 subject_length); |
| 3124 } |
| 3125 *match_pos = pos; |
| 3126 return true; |
| 3127 } |
| 3128 |
| 3129 |
| 3130 static bool SearchStringMultiple(Handle<String> subject, |
| 3131 Handle<String> pattern, |
| 3132 Handle<JSArray> last_match_info, |
| 3133 FixedArrayBuilder* builder) { |
| 3134 ASSERT(subject->IsFlat()); |
| 3135 ASSERT(pattern->IsFlat()); |
| 3136 ASSERT(pattern->length() > 1); |
| 3137 |
| 3138 // Treating as if a previous match was before first character. |
| 3139 int match_pos = -pattern->length(); |
| 3140 |
| 3141 for (;;) { // Break when search complete. |
| 3142 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); |
| 3143 AssertNoAllocation no_gc; |
| 3144 if (subject->IsAsciiRepresentation()) { |
| 3145 Vector<const char> subject_vector = subject->ToAsciiVector(); |
| 3146 if (pattern->IsAsciiRepresentation()) { |
| 3147 if (SearchStringMultiple(subject_vector, |
| 3148 *pattern, |
| 3149 pattern->ToAsciiVector(), |
| 3150 builder, |
| 3151 &match_pos)) break; |
| 3152 } else { |
| 3153 if (SearchStringMultiple(subject_vector, |
| 3154 *pattern, |
| 3155 pattern->ToUC16Vector(), |
| 3156 builder, |
| 3157 &match_pos)) break; |
| 3158 } |
| 3159 } else { |
| 3160 Vector<const uc16> subject_vector = subject->ToUC16Vector(); |
| 3161 if (pattern->IsAsciiRepresentation()) { |
| 3162 if (SearchStringMultiple(subject_vector, |
| 3163 *pattern, |
| 3164 pattern->ToAsciiVector(), |
| 3165 builder, |
| 3166 &match_pos)) break; |
| 3167 } else { |
| 3168 if (SearchStringMultiple(subject_vector, |
| 3169 *pattern, |
| 3170 pattern->ToUC16Vector(), |
| 3171 builder, |
| 3172 &match_pos)) break; |
| 3173 } |
| 3174 } |
| 3175 } |
| 3176 |
| 3177 if (match_pos >= 0) { |
| 3178 SetLastMatchInfoNoCaptures(subject, |
| 3179 last_match_info, |
| 3180 match_pos, |
| 3181 match_pos + pattern->length()); |
| 3182 return true; |
| 3183 } |
| 3184 return false; // No matches at all. |
| 3185 } |
| 3186 |
| 3187 |
| 3188 static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple( |
| 3189 Handle<String> subject, |
| 3190 Handle<JSRegExp> regexp, |
| 3191 Handle<JSArray> last_match_array, |
| 3192 FixedArrayBuilder* builder) { |
| 3193 ASSERT(subject->IsFlat()); |
| 3194 int match_start = -1; |
| 3195 int match_end = 0; |
| 3196 int pos = 0; |
| 3197 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); |
| 3198 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; |
| 3199 |
| 3200 OffsetsVector registers(required_registers); |
| 3201 Vector<int> register_vector(registers.vector(), registers.length()); |
| 3202 int subject_length = subject->length(); |
| 3203 |
| 3204 for (;;) { // Break on failure, return on exception. |
| 3205 RegExpImpl::IrregexpResult result = |
| 3206 RegExpImpl::IrregexpExecOnce(regexp, |
| 3207 subject, |
| 3208 pos, |
| 3209 register_vector); |
| 3210 if (result == RegExpImpl::RE_SUCCESS) { |
| 3211 match_start = register_vector[0]; |
| 3212 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); |
| 3213 if (match_end < match_start) { |
| 3214 ReplacementStringBuilder::AddSubjectSlice(builder, |
| 3215 match_end, |
| 3216 match_start); |
| 3217 } |
| 3218 match_end = register_vector[1]; |
| 3219 HandleScope loop_scope; |
| 3220 builder->Add(*Factory::NewSubString(subject, match_start, match_end)); |
| 3221 if (match_start != match_end) { |
| 3222 pos = match_end; |
| 3223 } else { |
| 3224 pos = match_end + 1; |
| 3225 if (pos > subject_length) break; |
| 3226 } |
| 3227 } else if (result == RegExpImpl::RE_FAILURE) { |
| 3228 break; |
| 3229 } else { |
| 3230 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); |
| 3231 return result; |
| 3232 } |
| 3233 } |
| 3234 |
| 3235 if (match_start >= 0) { |
| 3236 if (match_end < subject_length) { |
| 3237 ReplacementStringBuilder::AddSubjectSlice(builder, |
| 3238 match_end, |
| 3239 subject_length); |
| 3240 } |
| 3241 SetLastMatchInfoNoCaptures(subject, |
| 3242 last_match_array, |
| 3243 match_start, |
| 3244 match_end); |
| 3245 return RegExpImpl::RE_SUCCESS; |
| 3246 } else { |
| 3247 return RegExpImpl::RE_FAILURE; // No matches at all. |
| 3248 } |
| 3249 } |
| 3250 |
| 3251 |
| 3252 static RegExpImpl::IrregexpResult SearchRegExpMultiple( |
| 3253 Handle<String> subject, |
| 3254 Handle<JSRegExp> regexp, |
| 3255 Handle<JSArray> last_match_array, |
| 3256 FixedArrayBuilder* builder) { |
| 3257 |
| 3258 ASSERT(subject->IsFlat()); |
| 3259 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); |
| 3260 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; |
| 3261 |
| 3262 OffsetsVector registers(required_registers); |
| 3263 Vector<int> register_vector(registers.vector(), registers.length()); |
| 3264 |
| 3265 RegExpImpl::IrregexpResult result = |
| 3266 RegExpImpl::IrregexpExecOnce(regexp, |
| 3267 subject, |
| 3268 0, |
| 3269 register_vector); |
| 3270 |
| 3271 int capture_count = regexp->CaptureCount(); |
| 3272 int subject_length = subject->length(); |
| 3273 |
| 3274 // Position to search from. |
| 3275 int pos = 0; |
| 3276 // End of previous match. Differs from pos if match was empty. |
| 3277 int match_end = 0; |
| 3278 if (result == RegExpImpl::RE_SUCCESS) { |
| 3279 // Need to keep a copy of the previous match for creating last_match_info |
| 3280 // at the end, so we have two vectors that we swap between. |
| 3281 OffsetsVector registers2(required_registers); |
| 3282 Vector<int> prev_register_vector(registers2.vector(), registers2.length()); |
| 3283 |
| 3284 do { |
| 3285 int match_start = register_vector[0]; |
| 3286 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); |
| 3287 if (match_end < match_start) { |
| 3288 ReplacementStringBuilder::AddSubjectSlice(builder, |
| 3289 match_end, |
| 3290 match_start); |
| 3291 } |
| 3292 match_end = register_vector[1]; |
| 3293 |
| 3294 { |
| 3295 // Avoid accumulating new handles inside loop. |
| 3296 HandleScope temp_scope; |
| 3297 // Arguments array to replace function is match, captures, index and |
| 3298 // subject, i.e., 3 + capture count in total. |
| 3299 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count); |
| 3300 elements->set(0, *Factory::NewSubString(subject, |
| 3301 match_start, |
| 3302 match_end)); |
| 3303 for (int i = 1; i <= capture_count; i++) { |
| 3304 int start = register_vector[i * 2]; |
| 3305 if (start >= 0) { |
| 3306 int end = register_vector[i * 2 + 1]; |
| 3307 ASSERT(start <= end); |
| 3308 Handle<String> substring = Factory::NewSubString(subject, start, end
); |
| 3309 elements->set(i, *substring); |
| 3310 } else { |
| 3311 ASSERT(register_vector[i * 2 + 1] < 0); |
| 3312 elements->set(i, Heap::undefined_value()); |
| 3313 } |
| 3314 } |
| 3315 elements->set(capture_count + 1, Smi::FromInt(match_start)); |
| 3316 elements->set(capture_count + 2, *subject); |
| 3317 builder->Add(*Factory::NewJSArrayWithElements(elements)); |
| 3318 } |
| 3319 // Swap register vectors, so the last successful match is in |
| 3320 // prev_register_vector. |
| 3321 Vector<int> tmp = prev_register_vector; |
| 3322 prev_register_vector = register_vector; |
| 3323 register_vector = tmp; |
| 3324 |
| 3325 if (match_end > match_start) { |
| 3326 pos = match_end; |
| 3327 } else { |
| 3328 pos = match_end + 1; |
| 3329 if (pos > subject_length) { |
| 3330 break; |
| 3331 } |
| 3332 } |
| 3333 |
| 3334 result = RegExpImpl::IrregexpExecOnce(regexp, |
| 3335 subject, |
| 3336 pos, |
| 3337 register_vector); |
| 3338 } while (result == RegExpImpl::RE_SUCCESS); |
| 3339 |
| 3340 if (result != RegExpImpl::RE_EXCEPTION) { |
| 3341 // Finished matching, with at least one match. |
| 3342 if (match_end < subject_length) { |
| 3343 ReplacementStringBuilder::AddSubjectSlice(builder, |
| 3344 match_end, |
| 3345 subject_length); |
| 3346 } |
| 3347 |
| 3348 int last_match_capture_count = (capture_count + 1) * 2; |
| 3349 int last_match_array_size = |
| 3350 last_match_capture_count + RegExpImpl::kLastMatchOverhead; |
| 3351 last_match_array->EnsureSize(last_match_array_size); |
| 3352 AssertNoAllocation no_gc; |
| 3353 FixedArray* elements = FixedArray::cast(last_match_array->elements()); |
| 3354 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count); |
| 3355 RegExpImpl::SetLastSubject(elements, *subject); |
| 3356 RegExpImpl::SetLastInput(elements, *subject); |
| 3357 for (int i = 0; i < last_match_capture_count; i++) { |
| 3358 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]); |
| 3359 } |
| 3360 return RegExpImpl::RE_SUCCESS; |
| 3361 } |
| 3362 } |
| 3363 // No matches at all, return failure or exception result directly. |
| 3364 return result; |
| 3365 } |
| 3366 |
| 3367 |
| 3368 static Object* Runtime_RegExpExecMultiple(Arguments args) { |
| 3369 ASSERT(args.length() == 4); |
| 3370 HandleScope handles; |
| 3371 |
| 3372 CONVERT_ARG_CHECKED(String, subject, 1); |
| 3373 if (!subject->IsFlat()) { FlattenString(subject); } |
| 3374 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); |
| 3375 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2); |
| 3376 CONVERT_ARG_CHECKED(JSArray, result_array, 3); |
| 3377 |
| 3378 ASSERT(last_match_info->HasFastElements()); |
| 3379 ASSERT(regexp->GetFlags().is_global()); |
| 3380 Handle<FixedArray> result_elements; |
| 3381 if (result_array->HasFastElements()) { |
| 3382 result_elements = |
| 3383 Handle<FixedArray>(FixedArray::cast(result_array->elements())); |
| 3384 } else { |
| 3385 result_elements = Factory::NewFixedArrayWithHoles(16); |
| 3386 } |
| 3387 FixedArrayBuilder builder(result_elements); |
| 3388 |
| 3389 if (regexp->TypeTag() == JSRegExp::ATOM) { |
| 3390 Handle<String> pattern( |
| 3391 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex))); |
| 3392 int pattern_length = pattern->length(); |
| 3393 if (pattern_length == 1) { |
| 3394 if (SearchCharMultiple(subject, pattern, last_match_info, &builder)) { |
| 3395 return *builder.ToJSArray(result_array); |
| 3396 } |
| 3397 return Heap::null_value(); |
| 3398 } |
| 3399 |
| 3400 if (!pattern->IsFlat()) FlattenString(pattern); |
| 3401 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) { |
| 3402 return *builder.ToJSArray(result_array); |
| 3403 } |
| 3404 return Heap::null_value(); |
| 3405 } |
| 3406 |
| 3407 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); |
| 3408 |
| 3409 RegExpImpl::IrregexpResult result; |
| 3410 if (regexp->CaptureCount() == 0) { |
| 3411 result = SearchRegExpNoCaptureMultiple(subject, |
| 3412 regexp, |
| 3413 last_match_info, |
| 3414 &builder); |
| 3415 } else { |
| 3416 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder); |
| 3417 } |
| 3418 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array); |
| 3419 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value(); |
| 3420 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); |
| 3421 return Failure::Exception(); |
| 3422 } |
| 3423 |
| 3424 |
| 2872 static Object* Runtime_NumberToRadixString(Arguments args) { | 3425 static Object* Runtime_NumberToRadixString(Arguments args) { |
| 2873 NoHandleAllocation ha; | 3426 NoHandleAllocation ha; |
| 2874 ASSERT(args.length() == 2); | 3427 ASSERT(args.length() == 2); |
| 2875 | 3428 |
| 2876 // Fast case where the result is a one character string. | 3429 // Fast case where the result is a one character string. |
| 2877 if (args[0]->IsSmi() && args[1]->IsSmi()) { | 3430 if (args[0]->IsSmi() && args[1]->IsSmi()) { |
| 2878 int value = Smi::cast(args[0])->value(); | 3431 int value = Smi::cast(args[0])->value(); |
| 2879 int radix = Smi::cast(args[1])->value(); | 3432 int radix = Smi::cast(args[1])->value(); |
| 2880 if (value >= 0 && value < radix) { | 3433 if (value >= 0 && value < radix) { |
| 2881 RUNTIME_ASSERT(radix <= 36); | 3434 RUNTIME_ASSERT(radix <= 36); |
| (...skipping 6546 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9428 } else { | 9981 } else { |
| 9429 // Handle last resort GC and make sure to allow future allocations | 9982 // Handle last resort GC and make sure to allow future allocations |
| 9430 // to grow the heap without causing GCs (if possible). | 9983 // to grow the heap without causing GCs (if possible). |
| 9431 Counters::gc_last_resort_from_js.Increment(); | 9984 Counters::gc_last_resort_from_js.Increment(); |
| 9432 Heap::CollectAllGarbage(false); | 9985 Heap::CollectAllGarbage(false); |
| 9433 } | 9986 } |
| 9434 } | 9987 } |
| 9435 | 9988 |
| 9436 | 9989 |
| 9437 } } // namespace v8::internal | 9990 } } // namespace v8::internal |
| OLD | NEW |