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 1210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1221 Counters::regexp_entry_runtime.Increment(); | 1221 Counters::regexp_entry_runtime.Increment(); |
1222 Handle<Object> result = RegExpImpl::Exec(regexp, | 1222 Handle<Object> result = RegExpImpl::Exec(regexp, |
1223 subject, | 1223 subject, |
1224 index, | 1224 index, |
1225 last_match_info); | 1225 last_match_info); |
1226 if (result.is_null()) return Failure::Exception(); | 1226 if (result.is_null()) return Failure::Exception(); |
1227 return *result; | 1227 return *result; |
1228 } | 1228 } |
1229 | 1229 |
1230 | 1230 |
1231 static Object* Runtime_RegExpInitializeObject(Arguments args) { | |
1232 AssertNoAllocation no_alloc; | |
1233 ASSERT(args.length() == 5); | |
1234 CONVERT_CHECKED(JSRegExp, regexp, args[0]); | |
1235 CONVERT_CHECKED(String, source, args[1]); | |
1236 | |
1237 Object* global = args[2]; | |
1238 if (!global->IsTrue()) global = Heap::false_value(); | |
1239 | |
1240 Object* ignoreCase = args[3]; | |
1241 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value(); | |
1242 | |
1243 Object* multiline = args[4]; | |
1244 if (!multiline->IsTrue()) multiline = Heap::false_value(); | |
1245 | |
1246 Map* map = regexp->map(); | |
1247 Object* constructor = map->constructor(); | |
1248 if (constructor->IsJSFunction() && | |
1249 JSFunction::cast(constructor)->initial_map() == map) { | |
1250 // If we still have the original map, set in-object properties directly. | |
1251 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source); | |
1252 // TODO(lrn): Consider skipping write barrier on booleans as well. | |
1253 // Both true and false should be in oldspace at all times. | |
1254 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global); | |
1255 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase); | |
1256 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline); | |
1257 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, | |
1258 Smi::FromInt(0), | |
1259 SKIP_WRITE_BARRIER); | |
1260 return regexp; | |
1261 } | |
1262 | |
1263 // Map has changed, so use generic, but slower, method. | |
1264 PropertyAttributes final = | |
1265 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE); | |
1266 PropertyAttributes writable = | |
1267 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); | |
1268 regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(), | |
1269 source, | |
1270 final); | |
1271 regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(), | |
1272 global, | |
1273 final); | |
1274 regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(), | |
1275 ignoreCase, | |
1276 final); | |
1277 regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(), | |
1278 multiline, | |
1279 final); | |
1280 regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(), | |
1281 Smi::FromInt(0), | |
1282 writable); | |
1283 return regexp; | |
1284 } | |
1285 | |
1286 | |
1287 static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) { | 1231 static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) { |
1288 HandleScope scope; | 1232 HandleScope scope; |
1289 ASSERT(args.length() == 1); | 1233 ASSERT(args.length() == 1); |
1290 CONVERT_ARG_CHECKED(JSArray, prototype, 0); | 1234 CONVERT_ARG_CHECKED(JSArray, prototype, 0); |
1291 // This is necessary to enable fast checks for absence of elements | 1235 // This is necessary to enable fast checks for absence of elements |
1292 // on Array.prototype and below. | 1236 // on Array.prototype and below. |
1293 prototype->set_elements(Heap::empty_fixed_array()); | 1237 prototype->set_elements(Heap::empty_fixed_array()); |
1294 return Smi::FromInt(0); | 1238 return Smi::FromInt(0); |
1295 } | 1239 } |
1296 | 1240 |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1616 return CharFromCode(code); | 1560 return CharFromCode(code); |
1617 } | 1561 } |
1618 | 1562 |
1619 | 1563 |
1620 static Object* Runtime_CharFromCode(Arguments args) { | 1564 static Object* Runtime_CharFromCode(Arguments args) { |
1621 NoHandleAllocation ha; | 1565 NoHandleAllocation ha; |
1622 ASSERT(args.length() == 1); | 1566 ASSERT(args.length() == 1); |
1623 return CharFromCode(args[0]); | 1567 return CharFromCode(args[0]); |
1624 } | 1568 } |
1625 | 1569 |
1626 | |
1627 class FixedArrayBuilder { | |
1628 public: | |
1629 explicit FixedArrayBuilder(int initial_capacity) | |
1630 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)), | |
1631 length_(0) { | |
1632 // Require a non-zero initial size. Ensures that doubling the size to | |
1633 // extend the array will work. | |
1634 ASSERT(initial_capacity > 0); | |
1635 } | |
1636 | |
1637 explicit FixedArrayBuilder(Handle<FixedArray> backing_store) | |
1638 : array_(backing_store), | |
1639 length_(0) { | |
1640 // Require a non-zero initial size. Ensures that doubling the size to | |
1641 // extend the array will work. | |
1642 ASSERT(backing_store->length() > 0); | |
1643 } | |
1644 | |
1645 bool HasCapacity(int elements) { | |
1646 int length = array_->length(); | |
1647 int required_length = length_ + elements; | |
1648 return (length >= required_length); | |
1649 } | |
1650 | |
1651 void EnsureCapacity(int elements) { | |
1652 int length = array_->length(); | |
1653 int required_length = length_ + elements; | |
1654 if (length < required_length) { | |
1655 int new_length = length; | |
1656 do { | |
1657 new_length *= 2; | |
1658 } while (new_length < required_length); | |
1659 Handle<FixedArray> extended_array = | |
1660 Factory::NewFixedArrayWithHoles(new_length); | |
1661 array_->CopyTo(0, *extended_array, 0, length_); | |
1662 array_ = extended_array; | |
1663 } | |
1664 } | |
1665 | |
1666 void Add(Object* value) { | |
1667 ASSERT(length_ < capacity()); | |
1668 array_->set(length_, value); | |
1669 length_++; | |
1670 } | |
1671 | |
1672 void Add(Smi* value) { | |
1673 ASSERT(length_ < capacity()); | |
1674 array_->set(length_, value); | |
1675 length_++; | |
1676 } | |
1677 | |
1678 Handle<FixedArray> array() { | |
1679 return array_; | |
1680 } | |
1681 | |
1682 int length() { | |
1683 return length_; | |
1684 } | |
1685 | |
1686 int capacity() { | |
1687 return array_->length(); | |
1688 } | |
1689 | |
1690 Handle<JSArray> ToJSArray() { | |
1691 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_); | |
1692 result_array->set_length(Smi::FromInt(length_)); | |
1693 return result_array; | |
1694 } | |
1695 | |
1696 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { | |
1697 target_array->set_elements(*array_); | |
1698 target_array->set_length(Smi::FromInt(length_)); | |
1699 return target_array; | |
1700 } | |
1701 | |
1702 private: | |
1703 Handle<FixedArray> array_; | |
1704 int length_; | |
1705 }; | |
1706 | |
1707 | |
1708 // Forward declarations. | 1570 // Forward declarations. |
1709 const int kStringBuilderConcatHelperLengthBits = 11; | 1571 static const int kStringBuilderConcatHelperLengthBits = 11; |
1710 const int kStringBuilderConcatHelperPositionBits = 19; | 1572 static const int kStringBuilderConcatHelperPositionBits = 19; |
1711 | 1573 |
1712 template <typename schar> | 1574 template <typename schar> |
1713 static inline void StringBuilderConcatHelper(String*, | 1575 static inline void StringBuilderConcatHelper(String*, |
1714 schar*, | 1576 schar*, |
1715 FixedArray*, | 1577 FixedArray*, |
1716 int); | 1578 int); |
1717 | 1579 |
1718 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> | 1580 typedef BitField<int, 0, 11> StringBuilderSubstringLength; |
1719 StringBuilderSubstringLength; | 1581 typedef BitField<int, 11, 19> StringBuilderSubstringPosition; |
1720 typedef BitField<int, | |
1721 kStringBuilderConcatHelperLengthBits, | |
1722 kStringBuilderConcatHelperPositionBits> | |
1723 StringBuilderSubstringPosition; | |
1724 | |
1725 | 1582 |
1726 class ReplacementStringBuilder { | 1583 class ReplacementStringBuilder { |
1727 public: | 1584 public: |
1728 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count) | 1585 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count) |
1729 : array_builder_(estimated_part_count), | 1586 : subject_(subject), |
1730 subject_(subject), | 1587 parts_(Factory::NewFixedArray(estimated_part_count)), |
| 1588 part_count_(0), |
1731 character_count_(0), | 1589 character_count_(0), |
1732 is_ascii_(subject->IsAsciiRepresentation()) { | 1590 is_ascii_(subject->IsAsciiRepresentation()) { |
1733 // Require a non-zero initial size. Ensures that doubling the size to | 1591 // Require a non-zero initial size. Ensures that doubling the size to |
1734 // extend the array will work. | 1592 // extend the array will work. |
1735 ASSERT(estimated_part_count > 0); | 1593 ASSERT(estimated_part_count > 0); |
1736 } | 1594 } |
1737 | 1595 |
1738 static inline void AddSubjectSlice(FixedArrayBuilder* builder, | 1596 void EnsureCapacity(int elements) { |
1739 int from, | 1597 int length = parts_->length(); |
1740 int to) { | 1598 int required_length = part_count_ + elements; |
| 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) { |
1741 ASSERT(from >= 0); | 1612 ASSERT(from >= 0); |
1742 int length = to - from; | 1613 int length = to - from; |
1743 ASSERT(length > 0); | 1614 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? |
1744 if (StringBuilderSubstringLength::is_valid(length) && | 1617 if (StringBuilderSubstringLength::is_valid(length) && |
1745 StringBuilderSubstringPosition::is_valid(from)) { | 1618 StringBuilderSubstringPosition::is_valid(from)) { |
1746 int encoded_slice = StringBuilderSubstringLength::encode(length) | | 1619 int encoded_slice = StringBuilderSubstringLength::encode(length) | |
1747 StringBuilderSubstringPosition::encode(from); | 1620 StringBuilderSubstringPosition::encode(from); |
1748 builder->Add(Smi::FromInt(encoded_slice)); | 1621 AddElement(Smi::FromInt(encoded_slice)); |
1749 } else { | 1622 } else { |
1750 // Otherwise encode as two smis. | 1623 // Otherwise encode as two smis. |
1751 builder->Add(Smi::FromInt(-length)); | 1624 AddElement(Smi::FromInt(-length)); |
1752 builder->Add(Smi::FromInt(from)); | 1625 AddElement(Smi::FromInt(from)); |
1753 } | 1626 } |
| 1627 IncrementCharacterCount(length); |
1754 } | 1628 } |
1755 | 1629 |
1756 | 1630 |
1757 void EnsureCapacity(int elements) { | |
1758 array_builder_.EnsureCapacity(elements); | |
1759 } | |
1760 | |
1761 | |
1762 void AddSubjectSlice(int from, int to) { | |
1763 AddSubjectSlice(&array_builder_, from, to); | |
1764 // Can we encode the slice in 11 bits for length and 19 bits for | |
1765 // start position - as used by StringBuilderConcatHelper? | |
1766 IncrementCharacterCount(to - from); | |
1767 } | |
1768 | |
1769 | |
1770 void AddString(Handle<String> string) { | 1631 void AddString(Handle<String> string) { |
1771 int length = string->length(); | 1632 int length = string->length(); |
1772 ASSERT(length > 0); | 1633 ASSERT(length > 0); |
1773 AddElement(*string); | 1634 AddElement(*string); |
1774 if (!string->IsAsciiRepresentation()) { | 1635 if (!string->IsAsciiRepresentation()) { |
1775 is_ascii_ = false; | 1636 is_ascii_ = false; |
1776 } | 1637 } |
1777 IncrementCharacterCount(length); | 1638 IncrementCharacterCount(length); |
1778 } | 1639 } |
1779 | 1640 |
1780 | 1641 |
1781 Handle<String> ToString() { | 1642 Handle<String> ToString() { |
1782 if (array_builder_.length() == 0) { | 1643 if (part_count_ == 0) { |
1783 return Factory::empty_string(); | 1644 return Factory::empty_string(); |
1784 } | 1645 } |
1785 | 1646 |
1786 Handle<String> joined_string; | 1647 Handle<String> joined_string; |
1787 if (is_ascii_) { | 1648 if (is_ascii_) { |
1788 joined_string = NewRawAsciiString(character_count_); | 1649 joined_string = NewRawAsciiString(character_count_); |
1789 AssertNoAllocation no_alloc; | 1650 AssertNoAllocation no_alloc; |
1790 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string); | 1651 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string); |
1791 char* char_buffer = seq->GetChars(); | 1652 char* char_buffer = seq->GetChars(); |
1792 StringBuilderConcatHelper(*subject_, | 1653 StringBuilderConcatHelper(*subject_, |
1793 char_buffer, | 1654 char_buffer, |
1794 *array_builder_.array(), | 1655 *parts_, |
1795 array_builder_.length()); | 1656 part_count_); |
1796 } else { | 1657 } else { |
1797 // Non-ASCII. | 1658 // Non-ASCII. |
1798 joined_string = NewRawTwoByteString(character_count_); | 1659 joined_string = NewRawTwoByteString(character_count_); |
1799 AssertNoAllocation no_alloc; | 1660 AssertNoAllocation no_alloc; |
1800 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string); | 1661 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string); |
1801 uc16* char_buffer = seq->GetChars(); | 1662 uc16* char_buffer = seq->GetChars(); |
1802 StringBuilderConcatHelper(*subject_, | 1663 StringBuilderConcatHelper(*subject_, |
1803 char_buffer, | 1664 char_buffer, |
1804 *array_builder_.array(), | 1665 *parts_, |
1805 array_builder_.length()); | 1666 part_count_); |
1806 } | 1667 } |
1807 return joined_string; | 1668 return joined_string; |
1808 } | 1669 } |
1809 | 1670 |
1810 | 1671 |
1811 void IncrementCharacterCount(int by) { | 1672 void IncrementCharacterCount(int by) { |
1812 if (character_count_ > String::kMaxLength - by) { | 1673 if (character_count_ > String::kMaxLength - by) { |
1813 V8::FatalProcessOutOfMemory("String.replace result too large."); | 1674 V8::FatalProcessOutOfMemory("String.replace result too large."); |
1814 } | 1675 } |
1815 character_count_ += by; | 1676 character_count_ += by; |
1816 } | 1677 } |
1817 | 1678 |
1818 Handle<JSArray> GetParts() { | 1679 private: |
1819 Handle<JSArray> result = | |
1820 Factory::NewJSArrayWithElements(array_builder_.array()); | |
1821 result->set_length(Smi::FromInt(array_builder_.length())); | |
1822 return result; | |
1823 } | |
1824 | 1680 |
1825 private: | |
1826 Handle<String> NewRawAsciiString(int size) { | 1681 Handle<String> NewRawAsciiString(int size) { |
1827 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String); | 1682 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String); |
1828 } | 1683 } |
1829 | 1684 |
1830 | 1685 |
1831 Handle<String> NewRawTwoByteString(int size) { | 1686 Handle<String> NewRawTwoByteString(int size) { |
1832 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String); | 1687 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String); |
1833 } | 1688 } |
1834 | 1689 |
1835 | 1690 |
1836 void AddElement(Object* element) { | 1691 void AddElement(Object* element) { |
1837 ASSERT(element->IsSmi() || element->IsString()); | 1692 ASSERT(element->IsSmi() || element->IsString()); |
1838 ASSERT(array_builder_.capacity() > array_builder_.length()); | 1693 ASSERT(parts_->length() > part_count_); |
1839 array_builder_.Add(element); | 1694 parts_->set(part_count_, element); |
| 1695 part_count_++; |
1840 } | 1696 } |
1841 | 1697 |
1842 FixedArrayBuilder array_builder_; | |
1843 Handle<String> subject_; | 1698 Handle<String> subject_; |
| 1699 Handle<FixedArray> parts_; |
| 1700 int part_count_; |
1844 int character_count_; | 1701 int character_count_; |
1845 bool is_ascii_; | 1702 bool is_ascii_; |
1846 }; | 1703 }; |
1847 | 1704 |
1848 | 1705 |
1849 class CompiledReplacement { | 1706 class CompiledReplacement { |
1850 public: | 1707 public: |
1851 CompiledReplacement() | 1708 CompiledReplacement() |
1852 : parts_(1), replacement_substrings_(0) {} | 1709 : parts_(1), replacement_substrings_(0) {} |
1853 | 1710 |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2241 | 2098 |
2242 ASSERT(last_match_info->HasFastElements()); | 2099 ASSERT(last_match_info->HasFastElements()); |
2243 | 2100 |
2244 return StringReplaceRegExpWithString(subject, | 2101 return StringReplaceRegExpWithString(subject, |
2245 regexp, | 2102 regexp, |
2246 replacement, | 2103 replacement, |
2247 last_match_info); | 2104 last_match_info); |
2248 } | 2105 } |
2249 | 2106 |
2250 | 2107 |
| 2108 |
2251 // Cap on the maximal shift in the Boyer-Moore implementation. By setting a | 2109 // Cap on the maximal shift in the Boyer-Moore implementation. By setting a |
2252 // limit, we can fix the size of tables. | 2110 // limit, we can fix the size of tables. |
2253 static const int kBMMaxShift = 0xff; | 2111 static const int kBMMaxShift = 0xff; |
2254 // Reduce alphabet to this size. | 2112 // Reduce alphabet to this size. |
2255 static const int kBMAlphabetSize = 0x100; | 2113 static const int kBMAlphabetSize = 0x100; |
2256 // For patterns below this length, the skip length of Boyer-Moore is too short | 2114 // For patterns below this length, the skip length of Boyer-Moore is too short |
2257 // to compensate for the algorithmic overhead compared to simple brute force. | 2115 // to compensate for the algorithmic overhead compared to simple brute force. |
2258 static const int kBMMinPatternLength = 5; | 2116 static const int kBMMinPatternLength = 5; |
2259 | 2117 |
2260 // Holds the two buffers used by Boyer-Moore string search's Good Suffix | 2118 // 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... |
3004 int from = offsets.at(i * 2); | 2862 int from = offsets.at(i * 2); |
3005 int to = offsets.at(i * 2 + 1); | 2863 int to = offsets.at(i * 2 + 1); |
3006 elements->set(i, *Factory::NewSubString(subject, from, to)); | 2864 elements->set(i, *Factory::NewSubString(subject, from, to)); |
3007 } | 2865 } |
3008 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements); | 2866 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements); |
3009 result->set_length(Smi::FromInt(matches)); | 2867 result->set_length(Smi::FromInt(matches)); |
3010 return *result; | 2868 return *result; |
3011 } | 2869 } |
3012 | 2870 |
3013 | 2871 |
3014 // Two smis before and after the match, for very long strings. | |
3015 const int kMaxBuilderEntriesPerRegExpMatch = 5; | |
3016 | |
3017 | |
3018 static void SetLastMatchInfoNoCaptures(Handle<String> subject, | |
3019 Handle<JSArray> last_match_info, | |
3020 int match_start, | |
3021 int match_end) { | |
3022 // Fill last_match_info with a single capture. | |
3023 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead); | |
3024 AssertNoAllocation no_gc; | |
3025 FixedArray* elements = FixedArray::cast(last_match_info->elements()); | |
3026 RegExpImpl::SetLastCaptureCount(elements, 2); | |
3027 RegExpImpl::SetLastInput(elements, *subject); | |
3028 RegExpImpl::SetLastSubject(elements, *subject); | |
3029 RegExpImpl::SetCapture(elements, 0, match_start); | |
3030 RegExpImpl::SetCapture(elements, 1, match_end); | |
3031 } | |
3032 | |
3033 | |
3034 template <typename schar> | |
3035 static bool SearchCharMultiple(Vector<schar> subject, | |
3036 String* pattern, | |
3037 schar pattern_char, | |
3038 FixedArrayBuilder* builder, | |
3039 int* match_pos) { | |
3040 // Position of last match. | |
3041 int pos = *match_pos; | |
3042 int subject_length = subject.length(); | |
3043 while (pos < subject_length) { | |
3044 int match_end = pos + 1; | |
3045 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { | |
3046 *match_pos = pos; | |
3047 return false; | |
3048 } | |
3049 int new_pos = SingleCharIndexOf(subject, pattern_char, match_end); | |
3050 if (new_pos >= 0) { | |
3051 // Match has been found. | |
3052 if (new_pos > match_end) { | |
3053 ReplacementStringBuilder::AddSubjectSlice(builder, match_end, new_pos); | |
3054 } | |
3055 pos = new_pos; | |
3056 builder->Add(pattern); | |
3057 } else { | |
3058 break; | |
3059 } | |
3060 } | |
3061 if (pos + 1 < subject_length) { | |
3062 ReplacementStringBuilder::AddSubjectSlice(builder, pos + 1, subject_length); | |
3063 } | |
3064 *match_pos = pos; | |
3065 return true; | |
3066 } | |
3067 | |
3068 | |
3069 static bool SearchCharMultiple(Handle<String> subject, | |
3070 Handle<String> pattern, | |
3071 Handle<JSArray> last_match_info, | |
3072 FixedArrayBuilder* builder) { | |
3073 ASSERT(subject->IsFlat()); | |
3074 ASSERT_EQ(1, pattern->length()); | |
3075 uc16 pattern_char = pattern->Get(0); | |
3076 // Treating position before first as initial "previous match position". | |
3077 int match_pos = -1; | |
3078 | |
3079 for (;;) { // Break when search complete. | |
3080 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); | |
3081 AssertNoAllocation no_gc; | |
3082 if (subject->IsAsciiRepresentation()) { | |
3083 if (pattern_char > String::kMaxAsciiCharCode) { | |
3084 break; | |
3085 } | |
3086 Vector<const char> subject_vector = subject->ToAsciiVector(); | |
3087 char pattern_ascii_char = static_cast<char>(pattern_char); | |
3088 bool complete = SearchCharMultiple<const char>(subject_vector, | |
3089 *pattern, | |
3090 pattern_ascii_char, | |
3091 builder, | |
3092 &match_pos); | |
3093 if (complete) break; | |
3094 } else { | |
3095 Vector<const uc16> subject_vector = subject->ToUC16Vector(); | |
3096 bool complete = SearchCharMultiple<const uc16>(subject_vector, | |
3097 *pattern, | |
3098 pattern_char, | |
3099 builder, | |
3100 &match_pos); | |
3101 if (complete) break; | |
3102 } | |
3103 } | |
3104 | |
3105 if (match_pos >= 0) { | |
3106 SetLastMatchInfoNoCaptures(subject, | |
3107 last_match_info, | |
3108 match_pos, | |
3109 match_pos + 1); | |
3110 return true; | |
3111 } | |
3112 return false; // No matches at all. | |
3113 } | |
3114 | |
3115 | |
3116 template <typename schar, typename pchar> | |
3117 static bool SearchStringMultiple(Vector<schar> subject, | |
3118 String* pattern, | |
3119 Vector<pchar> pattern_string, | |
3120 FixedArrayBuilder* builder, | |
3121 int* match_pos) { | |
3122 int pos = *match_pos; | |
3123 int subject_length = subject.length(); | |
3124 int pattern_length = pattern_string.length(); | |
3125 int max_search_start = subject_length - pattern_length; | |
3126 bool is_ascii = (sizeof(schar) == 1); | |
3127 StringSearchStrategy strategy = | |
3128 InitializeStringSearch(pattern_string, is_ascii); | |
3129 switch (strategy) { | |
3130 case SEARCH_FAIL: return false; | |
3131 case SEARCH_SHORT: | |
3132 while (pos <= max_search_start) { | |
3133 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { | |
3134 *match_pos = pos; | |
3135 return false; | |
3136 } | |
3137 // Position of end of previous match. | |
3138 int match_end = pos + pattern_length; | |
3139 int new_pos = SimpleIndexOf(subject, pattern_string, match_end); | |
3140 if (new_pos >= 0) { | |
3141 // A match. | |
3142 if (new_pos > match_end) { | |
3143 ReplacementStringBuilder::AddSubjectSlice(builder, | |
3144 match_end, | |
3145 new_pos); | |
3146 } | |
3147 pos = new_pos; | |
3148 builder->Add(pattern); | |
3149 } else { | |
3150 break; | |
3151 } | |
3152 } | |
3153 break; | |
3154 case SEARCH_LONG: | |
3155 while (pos <= max_search_start) { | |
3156 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { | |
3157 *match_pos = pos; | |
3158 return false; | |
3159 } | |
3160 int new_pos = ComplexIndexOf(subject, | |
3161 pattern_string, | |
3162 pos + pattern_length); | |
3163 if (new_pos >= 0) { | |
3164 // A match has been found. | |
3165 if (new_pos > pos) { | |
3166 ReplacementStringBuilder::AddSubjectSlice(builder, pos, new_pos); | |
3167 } | |
3168 pos = new_pos; | |
3169 builder->Add(pattern); | |
3170 } else { | |
3171 break; | |
3172 } | |
3173 } | |
3174 break; | |
3175 } | |
3176 if (pos < max_search_start) { | |
3177 ReplacementStringBuilder::AddSubjectSlice(builder, | |
3178 pos + pattern_length, | |
3179 subject_length); | |
3180 } | |
3181 *match_pos = pos; | |
3182 return true; | |
3183 } | |
3184 | |
3185 | |
3186 static bool SearchStringMultiple(Handle<String> subject, | |
3187 Handle<String> pattern, | |
3188 Handle<JSArray> last_match_info, | |
3189 FixedArrayBuilder* builder) { | |
3190 ASSERT(subject->IsFlat()); | |
3191 ASSERT(pattern->IsFlat()); | |
3192 ASSERT(pattern->length() > 1); | |
3193 | |
3194 // Treating as if a previous match was before first character. | |
3195 int match_pos = -pattern->length(); | |
3196 | |
3197 for (;;) { // Break when search complete. | |
3198 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); | |
3199 AssertNoAllocation no_gc; | |
3200 if (subject->IsAsciiRepresentation()) { | |
3201 Vector<const char> subject_vector = subject->ToAsciiVector(); | |
3202 if (pattern->IsAsciiRepresentation()) { | |
3203 if (SearchStringMultiple(subject_vector, | |
3204 *pattern, | |
3205 pattern->ToAsciiVector(), | |
3206 builder, | |
3207 &match_pos)) break; | |
3208 } else { | |
3209 if (SearchStringMultiple(subject_vector, | |
3210 *pattern, | |
3211 pattern->ToUC16Vector(), | |
3212 builder, | |
3213 &match_pos)) break; | |
3214 } | |
3215 } else { | |
3216 Vector<const uc16> subject_vector = subject->ToUC16Vector(); | |
3217 if (pattern->IsAsciiRepresentation()) { | |
3218 if (SearchStringMultiple(subject_vector, | |
3219 *pattern, | |
3220 pattern->ToAsciiVector(), | |
3221 builder, | |
3222 &match_pos)) break; | |
3223 } else { | |
3224 if (SearchStringMultiple(subject_vector, | |
3225 *pattern, | |
3226 pattern->ToUC16Vector(), | |
3227 builder, | |
3228 &match_pos)) break; | |
3229 } | |
3230 } | |
3231 } | |
3232 | |
3233 if (match_pos >= 0) { | |
3234 SetLastMatchInfoNoCaptures(subject, | |
3235 last_match_info, | |
3236 match_pos, | |
3237 match_pos + pattern->length()); | |
3238 return true; | |
3239 } | |
3240 return false; // No matches at all. | |
3241 } | |
3242 | |
3243 | |
3244 static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple( | |
3245 Handle<String> subject, | |
3246 Handle<JSRegExp> regexp, | |
3247 Handle<JSArray> last_match_array, | |
3248 FixedArrayBuilder* builder) { | |
3249 ASSERT(subject->IsFlat()); | |
3250 int match_start = -1; | |
3251 int match_end = 0; | |
3252 int pos = 0; | |
3253 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); | |
3254 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; | |
3255 | |
3256 OffsetsVector registers(required_registers); | |
3257 Vector<int> register_vector(registers.vector(), registers.length()); | |
3258 int subject_length = subject->length(); | |
3259 | |
3260 for (;;) { // Break on failure, return on exception. | |
3261 RegExpImpl::IrregexpResult result = | |
3262 RegExpImpl::IrregexpExecOnce(regexp, | |
3263 subject, | |
3264 pos, | |
3265 register_vector); | |
3266 if (result == RegExpImpl::RE_SUCCESS) { | |
3267 match_start = register_vector[0]; | |
3268 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); | |
3269 if (match_end < match_start) { | |
3270 ReplacementStringBuilder::AddSubjectSlice(builder, | |
3271 match_end, | |
3272 match_start); | |
3273 } | |
3274 match_end = register_vector[1]; | |
3275 HandleScope loop_scope; | |
3276 builder->Add(*Factory::NewSubString(subject, match_start, match_end)); | |
3277 if (match_start != match_end) { | |
3278 pos = match_end; | |
3279 } else { | |
3280 pos = match_end + 1; | |
3281 if (pos > subject_length) break; | |
3282 } | |
3283 } else if (result == RegExpImpl::RE_FAILURE) { | |
3284 break; | |
3285 } else { | |
3286 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); | |
3287 return result; | |
3288 } | |
3289 } | |
3290 | |
3291 if (match_start >= 0) { | |
3292 if (match_end < subject_length) { | |
3293 ReplacementStringBuilder::AddSubjectSlice(builder, | |
3294 match_end, | |
3295 subject_length); | |
3296 } | |
3297 SetLastMatchInfoNoCaptures(subject, | |
3298 last_match_array, | |
3299 match_start, | |
3300 match_end); | |
3301 return RegExpImpl::RE_SUCCESS; | |
3302 } else { | |
3303 return RegExpImpl::RE_FAILURE; // No matches at all. | |
3304 } | |
3305 } | |
3306 | |
3307 | |
3308 static RegExpImpl::IrregexpResult SearchRegExpMultiple( | |
3309 Handle<String> subject, | |
3310 Handle<JSRegExp> regexp, | |
3311 Handle<JSArray> last_match_array, | |
3312 FixedArrayBuilder* builder) { | |
3313 | |
3314 ASSERT(subject->IsFlat()); | |
3315 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); | |
3316 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; | |
3317 | |
3318 OffsetsVector registers(required_registers); | |
3319 Vector<int> register_vector(registers.vector(), registers.length()); | |
3320 | |
3321 RegExpImpl::IrregexpResult result = | |
3322 RegExpImpl::IrregexpExecOnce(regexp, | |
3323 subject, | |
3324 0, | |
3325 register_vector); | |
3326 | |
3327 int capture_count = regexp->CaptureCount(); | |
3328 int subject_length = subject->length(); | |
3329 | |
3330 // Position to search from. | |
3331 int pos = 0; | |
3332 // End of previous match. Differs from pos if match was empty. | |
3333 int match_end = 0; | |
3334 if (result == RegExpImpl::RE_SUCCESS) { | |
3335 // Need to keep a copy of the previous match for creating last_match_info | |
3336 // at the end, so we have two vectors that we swap between. | |
3337 OffsetsVector registers2(required_registers); | |
3338 Vector<int> prev_register_vector(registers2.vector(), registers2.length()); | |
3339 | |
3340 do { | |
3341 int match_start = register_vector[0]; | |
3342 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); | |
3343 if (match_end < match_start) { | |
3344 ReplacementStringBuilder::AddSubjectSlice(builder, | |
3345 match_end, | |
3346 match_start); | |
3347 } | |
3348 match_end = register_vector[1]; | |
3349 | |
3350 { | |
3351 // Avoid accumulating new handles inside loop. | |
3352 HandleScope temp_scope; | |
3353 // Arguments array to replace function is match, captures, index and | |
3354 // subject, i.e., 3 + capture count in total. | |
3355 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count); | |
3356 elements->set(0, *Factory::NewSubString(subject, | |
3357 match_start, | |
3358 match_end)); | |
3359 for (int i = 1; i <= capture_count; i++) { | |
3360 Handle<String> substring = | |
3361 Factory::NewSubString(subject, | |
3362 register_vector[i * 2], | |
3363 register_vector[i * 2 + 1]); | |
3364 elements->set(i, *substring); | |
3365 } | |
3366 elements->set(capture_count + 1, Smi::FromInt(match_start)); | |
3367 elements->set(capture_count + 2, *subject); | |
3368 builder->Add(*Factory::NewJSArrayWithElements(elements)); | |
3369 } | |
3370 // Swap register vectors, so the last successful match is in | |
3371 // prev_register_vector. | |
3372 Vector<int> tmp = prev_register_vector; | |
3373 prev_register_vector = register_vector; | |
3374 register_vector = tmp; | |
3375 | |
3376 if (match_end > match_start) { | |
3377 pos = match_end; | |
3378 } else { | |
3379 pos = match_end + 1; | |
3380 if (pos > subject_length) { | |
3381 break; | |
3382 } | |
3383 } | |
3384 | |
3385 result = RegExpImpl::IrregexpExecOnce(regexp, | |
3386 subject, | |
3387 pos, | |
3388 register_vector); | |
3389 } while (result == RegExpImpl::RE_SUCCESS); | |
3390 | |
3391 if (result != RegExpImpl::RE_EXCEPTION) { | |
3392 // Finished matching, with at least one match. | |
3393 if (match_end < subject_length) { | |
3394 ReplacementStringBuilder::AddSubjectSlice(builder, | |
3395 match_end, | |
3396 subject_length); | |
3397 } | |
3398 | |
3399 int last_match_capture_count = (capture_count + 1) * 2; | |
3400 int last_match_array_size = | |
3401 last_match_capture_count + RegExpImpl::kLastMatchOverhead; | |
3402 last_match_array->EnsureSize(last_match_array_size); | |
3403 AssertNoAllocation no_gc; | |
3404 FixedArray* elements = FixedArray::cast(last_match_array->elements()); | |
3405 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count); | |
3406 RegExpImpl::SetLastSubject(elements, *subject); | |
3407 RegExpImpl::SetLastInput(elements, *subject); | |
3408 for (int i = 0; i < last_match_capture_count; i++) { | |
3409 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]); | |
3410 } | |
3411 return RegExpImpl::RE_SUCCESS; | |
3412 } | |
3413 } | |
3414 // No matches at all, return failure or exception result directly. | |
3415 return result; | |
3416 } | |
3417 | |
3418 | |
3419 static Object* Runtime_RegExpExecMultiple(Arguments args) { | |
3420 ASSERT(args.length() == 4); | |
3421 HandleScope handles; | |
3422 | |
3423 CONVERT_ARG_CHECKED(String, subject, 1); | |
3424 if (!subject->IsFlat()) { FlattenString(subject); } | |
3425 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); | |
3426 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2); | |
3427 CONVERT_ARG_CHECKED(JSArray, result_array, 3); | |
3428 | |
3429 ASSERT(last_match_info->HasFastElements()); | |
3430 ASSERT(regexp->GetFlags().is_global()); | |
3431 Handle<FixedArray> result_elements; | |
3432 if (result_array->HasFastElements()) { | |
3433 result_elements = | |
3434 Handle<FixedArray>(FixedArray::cast(result_array->elements())); | |
3435 } else { | |
3436 result_elements = Factory::NewFixedArrayWithHoles(16); | |
3437 } | |
3438 FixedArrayBuilder builder(result_elements); | |
3439 | |
3440 if (regexp->TypeTag() == JSRegExp::ATOM) { | |
3441 Handle<String> pattern( | |
3442 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex))); | |
3443 int pattern_length = pattern->length(); | |
3444 if (pattern_length == 1) { | |
3445 if (SearchCharMultiple(subject, pattern, last_match_info, &builder)) { | |
3446 return *builder.ToJSArray(result_array); | |
3447 } | |
3448 return Heap::null_value(); | |
3449 } | |
3450 | |
3451 if (!pattern->IsFlat()) FlattenString(pattern); | |
3452 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) { | |
3453 return *builder.ToJSArray(result_array); | |
3454 } | |
3455 return Heap::null_value(); | |
3456 } | |
3457 | |
3458 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); | |
3459 | |
3460 RegExpImpl::IrregexpResult result; | |
3461 if (regexp->CaptureCount() == 0) { | |
3462 result = SearchRegExpNoCaptureMultiple(subject, | |
3463 regexp, | |
3464 last_match_info, | |
3465 &builder); | |
3466 } else { | |
3467 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder); | |
3468 } | |
3469 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array); | |
3470 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value(); | |
3471 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); | |
3472 return Failure::Exception(); | |
3473 } | |
3474 | |
3475 | |
3476 static Object* Runtime_NumberToRadixString(Arguments args) { | 2872 static Object* Runtime_NumberToRadixString(Arguments args) { |
3477 NoHandleAllocation ha; | 2873 NoHandleAllocation ha; |
3478 ASSERT(args.length() == 2); | 2874 ASSERT(args.length() == 2); |
3479 | 2875 |
3480 // Fast case where the result is a one character string. | 2876 // Fast case where the result is a one character string. |
3481 if (args[0]->IsSmi() && args[1]->IsSmi()) { | 2877 if (args[0]->IsSmi() && args[1]->IsSmi()) { |
3482 int value = Smi::cast(args[0])->value(); | 2878 int value = Smi::cast(args[0])->value(); |
3483 int radix = Smi::cast(args[1])->value(); | 2879 int radix = Smi::cast(args[1])->value(); |
3484 if (value >= 0 && value < radix) { | 2880 if (value >= 0 && value < radix) { |
3485 RUNTIME_ASSERT(radix <= 36); | 2881 RUNTIME_ASSERT(radix <= 36); |
(...skipping 6546 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10032 } else { | 9428 } else { |
10033 // Handle last resort GC and make sure to allow future allocations | 9429 // Handle last resort GC and make sure to allow future allocations |
10034 // to grow the heap without causing GCs (if possible). | 9430 // to grow the heap without causing GCs (if possible). |
10035 Counters::gc_last_resort_from_js.Increment(); | 9431 Counters::gc_last_resort_from_js.Increment(); |
10036 Heap::CollectAllGarbage(false); | 9432 Heap::CollectAllGarbage(false); |
10037 } | 9433 } |
10038 } | 9434 } |
10039 | 9435 |
10040 | 9436 |
10041 } } // namespace v8::internal | 9437 } } // namespace v8::internal |
OLD | NEW |