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 1059 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1070 return *target; | 1070 return *target; |
1071 } | 1071 } |
1072 | 1072 |
1073 | 1073 |
1074 static Object* CharCodeAt(String* subject, Object* index) { | 1074 static Object* CharCodeAt(String* subject, Object* index) { |
1075 uint32_t i = 0; | 1075 uint32_t i = 0; |
1076 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value(); | 1076 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value(); |
1077 // Flatten the string. If someone wants to get a char at an index | 1077 // Flatten the string. If someone wants to get a char at an index |
1078 // in a cons string, it is likely that more indices will be | 1078 // in a cons string, it is likely that more indices will be |
1079 // accessed. | 1079 // accessed. |
1080 subject->TryFlattenIfNotFlat(StringShape(subject)); | 1080 subject->TryFlattenIfNotFlat(); |
1081 StringShape shape(subject); | 1081 if (i >= static_cast<uint32_t>(subject->length())) { |
1082 if (i >= static_cast<uint32_t>(subject->length(shape))) { | |
1083 return Heap::nan_value(); | 1082 return Heap::nan_value(); |
1084 } | 1083 } |
1085 return Smi::FromInt(subject->Get(shape, i)); | 1084 return Smi::FromInt(subject->Get(i)); |
1086 } | 1085 } |
1087 | 1086 |
1088 | 1087 |
1089 static Object* Runtime_StringCharCodeAt(Arguments args) { | 1088 static Object* Runtime_StringCharCodeAt(Arguments args) { |
1090 NoHandleAllocation ha; | 1089 NoHandleAllocation ha; |
1091 ASSERT(args.length() == 2); | 1090 ASSERT(args.length() == 2); |
1092 | 1091 |
1093 CONVERT_CHECKED(String, subject, args[0]); | 1092 CONVERT_CHECKED(String, subject, args[0]); |
1094 Object* index = args[1]; | 1093 Object* index = args[1]; |
1095 return CharCodeAt(subject, index); | 1094 return CharCodeAt(subject, index); |
(...skipping 11 matching lines...) Expand all Loading... |
1107 } | 1106 } |
1108 return Heap::empty_string(); | 1107 return Heap::empty_string(); |
1109 } | 1108 } |
1110 | 1109 |
1111 // Forward declarations. | 1110 // Forward declarations. |
1112 static const int kStringBuilderConcatHelperLengthBits = 11; | 1111 static const int kStringBuilderConcatHelperLengthBits = 11; |
1113 static const int kStringBuilderConcatHelperPositionBits = 19; | 1112 static const int kStringBuilderConcatHelperPositionBits = 19; |
1114 | 1113 |
1115 template <typename schar> | 1114 template <typename schar> |
1116 static inline void StringBuilderConcatHelper(String*, | 1115 static inline void StringBuilderConcatHelper(String*, |
1117 StringShape, | |
1118 schar*, | 1116 schar*, |
1119 FixedArray*, | 1117 FixedArray*, |
1120 int); | 1118 int); |
1121 | 1119 |
1122 typedef BitField<int, 0, 11> StringBuilderSubstringLength; | 1120 typedef BitField<int, 0, 11> StringBuilderSubstringLength; |
1123 typedef BitField<int, 11, 19> StringBuilderSubstringPosition; | 1121 typedef BitField<int, 11, 19> StringBuilderSubstringPosition; |
1124 | 1122 |
1125 class ReplacementStringBuilder { | 1123 class ReplacementStringBuilder { |
1126 public: | 1124 public: |
1127 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count) | 1125 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1163 AddElement(Smi::FromInt(encoded_slice)); | 1161 AddElement(Smi::FromInt(encoded_slice)); |
1164 } else { | 1162 } else { |
1165 Handle<String> slice = Factory::NewStringSlice(subject_, from, to); | 1163 Handle<String> slice = Factory::NewStringSlice(subject_, from, to); |
1166 AddElement(*slice); | 1164 AddElement(*slice); |
1167 } | 1165 } |
1168 IncrementCharacterCount(length); | 1166 IncrementCharacterCount(length); |
1169 } | 1167 } |
1170 | 1168 |
1171 | 1169 |
1172 void AddString(Handle<String> string) { | 1170 void AddString(Handle<String> string) { |
1173 StringShape shape(*string); | 1171 int length = string->length(); |
1174 int length = string->length(shape); | |
1175 ASSERT(length > 0); | 1172 ASSERT(length > 0); |
1176 AddElement(*string); | 1173 AddElement(*string); |
1177 if (!shape.IsAsciiRepresentation()) { | 1174 if (!StringShape(*string).IsAsciiRepresentation()) { |
1178 is_ascii_ = false; | 1175 is_ascii_ = false; |
1179 } | 1176 } |
1180 IncrementCharacterCount(length); | 1177 IncrementCharacterCount(length); |
1181 } | 1178 } |
1182 | 1179 |
1183 | 1180 |
1184 Handle<String> ToString() { | 1181 Handle<String> ToString() { |
1185 if (part_count_ == 0) { | 1182 if (part_count_ == 0) { |
1186 return Factory::empty_string(); | 1183 return Factory::empty_string(); |
1187 } | 1184 } |
1188 | 1185 |
1189 Handle<String> joined_string; | 1186 Handle<String> joined_string; |
1190 if (is_ascii_) { | 1187 if (is_ascii_) { |
1191 joined_string = NewRawAsciiString(character_count_); | 1188 joined_string = NewRawAsciiString(character_count_); |
1192 AssertNoAllocation no_alloc; | 1189 AssertNoAllocation no_alloc; |
1193 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string); | 1190 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string); |
1194 char* char_buffer = seq->GetChars(); | 1191 char* char_buffer = seq->GetChars(); |
1195 StringBuilderConcatHelper(*subject_, | 1192 StringBuilderConcatHelper(*subject_, |
1196 StringShape(*subject_), | |
1197 char_buffer, | 1193 char_buffer, |
1198 *parts_, | 1194 *parts_, |
1199 part_count_); | 1195 part_count_); |
1200 } else { | 1196 } else { |
1201 // Non-ASCII. | 1197 // Non-ASCII. |
1202 joined_string = NewRawTwoByteString(character_count_); | 1198 joined_string = NewRawTwoByteString(character_count_); |
1203 AssertNoAllocation no_alloc; | 1199 AssertNoAllocation no_alloc; |
1204 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string); | 1200 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string); |
1205 uc16* char_buffer = seq->GetChars(); | 1201 uc16* char_buffer = seq->GetChars(); |
1206 StringBuilderConcatHelper(*subject_, | 1202 StringBuilderConcatHelper(*subject_, |
1207 StringShape(*subject_), | |
1208 char_buffer, | 1203 char_buffer, |
1209 *parts_, | 1204 *parts_, |
1210 part_count_); | 1205 part_count_); |
1211 } | 1206 } |
1212 return joined_string; | 1207 return joined_string; |
1213 } | 1208 } |
1214 | 1209 |
1215 | 1210 |
1216 void IncrementCharacterCount(int by) { | 1211 void IncrementCharacterCount(int by) { |
1217 if (character_count_ > Smi::kMaxValue - by) { | 1212 if (character_count_ > Smi::kMaxValue - by) { |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1425 } | 1420 } |
1426 | 1421 |
1427 ZoneList<ReplacementPart> parts_; | 1422 ZoneList<ReplacementPart> parts_; |
1428 ZoneList<Handle<String> > replacement_substrings_; | 1423 ZoneList<Handle<String> > replacement_substrings_; |
1429 }; | 1424 }; |
1430 | 1425 |
1431 | 1426 |
1432 void CompiledReplacement::Compile(Handle<String> replacement, | 1427 void CompiledReplacement::Compile(Handle<String> replacement, |
1433 int capture_count, | 1428 int capture_count, |
1434 int subject_length) { | 1429 int subject_length) { |
1435 StringShape shape(*replacement); | 1430 ASSERT(replacement->IsFlat()); |
1436 ASSERT(replacement->IsFlat(shape)); | 1431 if (StringShape(*replacement).IsAsciiRepresentation()) { |
1437 if (shape.IsAsciiRepresentation()) { | |
1438 AssertNoAllocation no_alloc; | 1432 AssertNoAllocation no_alloc; |
1439 ParseReplacementPattern(&parts_, | 1433 ParseReplacementPattern(&parts_, |
1440 replacement->ToAsciiVector(), | 1434 replacement->ToAsciiVector(), |
1441 capture_count, | 1435 capture_count, |
1442 subject_length); | 1436 subject_length); |
1443 } else { | 1437 } else { |
1444 ASSERT(shape.IsTwoByteRepresentation()); | 1438 ASSERT(StringShape(*replacement).IsTwoByteRepresentation()); |
1445 AssertNoAllocation no_alloc; | 1439 AssertNoAllocation no_alloc; |
1446 | 1440 |
1447 ParseReplacementPattern(&parts_, | 1441 ParseReplacementPattern(&parts_, |
1448 replacement->ToUC16Vector(), | 1442 replacement->ToUC16Vector(), |
1449 capture_count, | 1443 capture_count, |
1450 subject_length); | 1444 subject_length); |
1451 } | 1445 } |
1452 // Find substrings of replacement string and create them as String objects.. | 1446 // Find substrings of replacement string and create them as String objects.. |
1453 int substring_index = 0; | 1447 int substring_index = 0; |
1454 for (int i = 0, n = parts_.length(); i < n; i++) { | 1448 for (int i = 0, n = parts_.length(); i < n; i++) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1507 } | 1501 } |
1508 } | 1502 } |
1509 } | 1503 } |
1510 | 1504 |
1511 | 1505 |
1512 | 1506 |
1513 static Object* StringReplaceRegExpWithString(String* subject, | 1507 static Object* StringReplaceRegExpWithString(String* subject, |
1514 JSRegExp* regexp, | 1508 JSRegExp* regexp, |
1515 String* replacement, | 1509 String* replacement, |
1516 JSArray* last_match_info) { | 1510 JSArray* last_match_info) { |
1517 ASSERT(subject->IsFlat(StringShape(subject))); | 1511 ASSERT(subject->IsFlat()); |
1518 ASSERT(replacement->IsFlat(StringShape(replacement))); | 1512 ASSERT(replacement->IsFlat()); |
1519 | 1513 |
1520 HandleScope handles; | 1514 HandleScope handles; |
1521 | 1515 |
1522 int length = subject->length(); | 1516 int length = subject->length(); |
1523 Handle<String> subject_handle(subject); | 1517 Handle<String> subject_handle(subject); |
1524 Handle<JSRegExp> regexp_handle(regexp); | 1518 Handle<JSRegExp> regexp_handle(regexp); |
1525 Handle<String> replacement_handle(replacement); | 1519 Handle<String> replacement_handle(replacement); |
1526 Handle<JSArray> last_match_info_handle(last_match_info); | 1520 Handle<JSArray> last_match_info_handle(last_match_info); |
1527 Handle<Object> match = RegExpImpl::Exec(regexp_handle, | 1521 Handle<Object> match = RegExpImpl::Exec(regexp_handle, |
1528 subject_handle, | 1522 subject_handle, |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1612 } | 1606 } |
1613 | 1607 |
1614 return *(builder.ToString()); | 1608 return *(builder.ToString()); |
1615 } | 1609 } |
1616 | 1610 |
1617 | 1611 |
1618 static Object* Runtime_StringReplaceRegExpWithString(Arguments args) { | 1612 static Object* Runtime_StringReplaceRegExpWithString(Arguments args) { |
1619 ASSERT(args.length() == 4); | 1613 ASSERT(args.length() == 4); |
1620 | 1614 |
1621 CONVERT_CHECKED(String, subject, args[0]); | 1615 CONVERT_CHECKED(String, subject, args[0]); |
1622 StringShape subject_shape(subject); | 1616 if (!subject->IsFlat()) { |
1623 if (!subject->IsFlat(subject_shape)) { | 1617 Object* flat_subject = subject->TryFlatten(); |
1624 Object* flat_subject = subject->TryFlatten(subject_shape); | |
1625 if (flat_subject->IsFailure()) { | 1618 if (flat_subject->IsFailure()) { |
1626 return flat_subject; | 1619 return flat_subject; |
1627 } | 1620 } |
1628 subject = String::cast(flat_subject); | 1621 subject = String::cast(flat_subject); |
1629 } | 1622 } |
1630 | 1623 |
1631 CONVERT_CHECKED(String, replacement, args[2]); | 1624 CONVERT_CHECKED(String, replacement, args[2]); |
1632 StringShape replacement_shape(replacement); | 1625 if (!replacement->IsFlat()) { |
1633 if (!replacement->IsFlat(replacement_shape)) { | 1626 Object* flat_replacement = replacement->TryFlatten(); |
1634 Object* flat_replacement = replacement->TryFlatten(replacement_shape); | |
1635 if (flat_replacement->IsFailure()) { | 1627 if (flat_replacement->IsFailure()) { |
1636 return flat_replacement; | 1628 return flat_replacement; |
1637 } | 1629 } |
1638 replacement = String::cast(flat_replacement); | 1630 replacement = String::cast(flat_replacement); |
1639 } | 1631 } |
1640 | 1632 |
1641 CONVERT_CHECKED(JSRegExp, regexp, args[1]); | 1633 CONVERT_CHECKED(JSRegExp, regexp, args[1]); |
1642 CONVERT_CHECKED(JSArray, last_match_info, args[3]); | 1634 CONVERT_CHECKED(JSArray, last_match_info, args[3]); |
1643 | 1635 |
1644 ASSERT(last_match_info->HasFastElements()); | 1636 ASSERT(last_match_info->HasFastElements()); |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1995 return BoyerMooreIndexOf(sub, pat, idx); | 1987 return BoyerMooreIndexOf(sub, pat, idx); |
1996 } | 1988 } |
1997 | 1989 |
1998 // Perform string match of pattern on subject, starting at start index. | 1990 // Perform string match of pattern on subject, starting at start index. |
1999 // Caller must ensure that 0 <= start_index <= sub->length(), | 1991 // Caller must ensure that 0 <= start_index <= sub->length(), |
2000 // and should check that pat->length() + start_index <= sub->length() | 1992 // and should check that pat->length() + start_index <= sub->length() |
2001 int Runtime::StringMatch(Handle<String> sub, | 1993 int Runtime::StringMatch(Handle<String> sub, |
2002 Handle<String> pat, | 1994 Handle<String> pat, |
2003 int start_index) { | 1995 int start_index) { |
2004 ASSERT(0 <= start_index); | 1996 ASSERT(0 <= start_index); |
2005 StringShape sub_shape(*sub); | 1997 ASSERT(start_index <= sub->length()); |
2006 ASSERT(start_index <= sub->length(sub_shape)); | |
2007 | 1998 |
2008 int pattern_length = pat->length(); | 1999 int pattern_length = pat->length(); |
2009 if (pattern_length == 0) return start_index; | 2000 if (pattern_length == 0) return start_index; |
2010 | 2001 |
2011 int subject_length = sub->length(sub_shape); | 2002 int subject_length = sub->length(); |
2012 if (start_index + pattern_length > subject_length) return -1; | 2003 if (start_index + pattern_length > subject_length) return -1; |
2013 | 2004 |
2014 if (!sub->IsFlat(sub_shape)) { | 2005 if (!sub->IsFlat()) { |
2015 FlattenString(sub); | 2006 FlattenString(sub); |
2016 sub_shape = StringShape(*sub); | |
2017 } | 2007 } |
2018 StringShape pat_shape(*pat); | |
2019 // Searching for one specific character is common. For one | 2008 // Searching for one specific character is common. For one |
2020 // character patterns linear search is necessary, so any smart | 2009 // character patterns linear search is necessary, so any smart |
2021 // algorithm is unnecessary overhead. | 2010 // algorithm is unnecessary overhead. |
2022 if (pattern_length == 1) { | 2011 if (pattern_length == 1) { |
2023 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid | 2012 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid |
2024 if (sub_shape.IsAsciiRepresentation()) { | 2013 if (StringShape(*sub).IsAsciiRepresentation()) { |
2025 uc16 pchar = pat->Get(pat_shape, 0); | 2014 uc16 pchar = pat->Get(0); |
2026 if (pchar > String::kMaxAsciiCharCode) { | 2015 if (pchar > String::kMaxAsciiCharCode) { |
2027 return -1; | 2016 return -1; |
2028 } | 2017 } |
2029 Vector<const char> ascii_vector = | 2018 Vector<const char> ascii_vector = |
2030 sub->ToAsciiVector().SubVector(start_index, subject_length); | 2019 sub->ToAsciiVector().SubVector(start_index, subject_length); |
2031 const void* pos = memchr(ascii_vector.start(), | 2020 const void* pos = memchr(ascii_vector.start(), |
2032 static_cast<const char>(pchar), | 2021 static_cast<const char>(pchar), |
2033 static_cast<size_t>(ascii_vector.length())); | 2022 static_cast<size_t>(ascii_vector.length())); |
2034 if (pos == NULL) { | 2023 if (pos == NULL) { |
2035 return -1; | 2024 return -1; |
2036 } | 2025 } |
2037 return reinterpret_cast<const char*>(pos) - ascii_vector.start() | 2026 return reinterpret_cast<const char*>(pos) - ascii_vector.start() |
2038 + start_index; | 2027 + start_index; |
2039 } | 2028 } |
2040 return SingleCharIndexOf(sub->ToUC16Vector(), | 2029 return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index); |
2041 pat->Get(pat_shape, 0), | |
2042 start_index); | |
2043 } | 2030 } |
2044 | 2031 |
2045 if (!pat->IsFlat(pat_shape)) { | 2032 if (!pat->IsFlat()) { |
2046 FlattenString(pat); | 2033 FlattenString(pat); |
2047 pat_shape = StringShape(*pat); | |
2048 sub_shape = StringShape(*sub); | |
2049 } | 2034 } |
2050 | 2035 |
2051 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid | 2036 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid |
2052 // dispatch on type of strings | 2037 // dispatch on type of strings |
2053 if (pat_shape.IsAsciiRepresentation()) { | 2038 if (StringShape(*pat).IsAsciiRepresentation()) { |
2054 Vector<const char> pat_vector = pat->ToAsciiVector(); | 2039 Vector<const char> pat_vector = pat->ToAsciiVector(); |
2055 if (sub_shape.IsAsciiRepresentation()) { | 2040 if (StringShape(*sub).IsAsciiRepresentation()) { |
2056 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); | 2041 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); |
2057 } | 2042 } |
2058 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); | 2043 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); |
2059 } | 2044 } |
2060 Vector<const uc16> pat_vector = pat->ToUC16Vector(); | 2045 Vector<const uc16> pat_vector = pat->ToUC16Vector(); |
2061 if (sub_shape.IsAsciiRepresentation()) { | 2046 if (StringShape(*sub).IsAsciiRepresentation()) { |
2062 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); | 2047 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index); |
2063 } | 2048 } |
2064 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); | 2049 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index); |
2065 } | 2050 } |
2066 | 2051 |
2067 | 2052 |
2068 static Object* Runtime_StringIndexOf(Arguments args) { | 2053 static Object* Runtime_StringIndexOf(Arguments args) { |
2069 HandleScope scope; // create a new handle scope | 2054 HandleScope scope; // create a new handle scope |
2070 ASSERT(args.length() == 3); | 2055 ASSERT(args.length() == 3); |
2071 | 2056 |
(...skipping 11 matching lines...) Expand all Loading... |
2083 | 2068 |
2084 | 2069 |
2085 static Object* Runtime_StringLastIndexOf(Arguments args) { | 2070 static Object* Runtime_StringLastIndexOf(Arguments args) { |
2086 NoHandleAllocation ha; | 2071 NoHandleAllocation ha; |
2087 ASSERT(args.length() == 3); | 2072 ASSERT(args.length() == 3); |
2088 | 2073 |
2089 CONVERT_CHECKED(String, sub, args[0]); | 2074 CONVERT_CHECKED(String, sub, args[0]); |
2090 CONVERT_CHECKED(String, pat, args[1]); | 2075 CONVERT_CHECKED(String, pat, args[1]); |
2091 Object* index = args[2]; | 2076 Object* index = args[2]; |
2092 | 2077 |
2093 sub->TryFlattenIfNotFlat(StringShape(sub)); | 2078 sub->TryFlattenIfNotFlat(); |
2094 pat->TryFlattenIfNotFlat(StringShape(pat)); | 2079 pat->TryFlattenIfNotFlat(); |
2095 | |
2096 StringShape sub_shape(sub); | |
2097 StringShape pat_shape(pat); | |
2098 | 2080 |
2099 uint32_t start_index; | 2081 uint32_t start_index; |
2100 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); | 2082 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); |
2101 | 2083 |
2102 uint32_t pattern_length = pat->length(pat_shape); | 2084 uint32_t pattern_length = pat->length(); |
2103 uint32_t sub_length = sub->length(sub_shape); | 2085 uint32_t sub_length = sub->length(); |
2104 | 2086 |
2105 if (start_index + pattern_length > sub_length) { | 2087 if (start_index + pattern_length > sub_length) { |
2106 start_index = sub_length - pattern_length; | 2088 start_index = sub_length - pattern_length; |
2107 } | 2089 } |
2108 | 2090 |
2109 for (int i = start_index; i >= 0; i--) { | 2091 for (int i = start_index; i >= 0; i--) { |
2110 bool found = true; | 2092 bool found = true; |
2111 for (uint32_t j = 0; j < pattern_length; j++) { | 2093 for (uint32_t j = 0; j < pattern_length; j++) { |
2112 if (sub->Get(sub_shape, i + j) != pat->Get(pat_shape, j)) { | 2094 if (sub->Get(i + j) != pat->Get(j)) { |
2113 found = false; | 2095 found = false; |
2114 break; | 2096 break; |
2115 } | 2097 } |
2116 } | 2098 } |
2117 if (found) return Smi::FromInt(i); | 2099 if (found) return Smi::FromInt(i); |
2118 } | 2100 } |
2119 | 2101 |
2120 return Smi::FromInt(-1); | 2102 return Smi::FromInt(-1); |
2121 } | 2103 } |
2122 | 2104 |
2123 | 2105 |
2124 static Object* Runtime_StringLocaleCompare(Arguments args) { | 2106 static Object* Runtime_StringLocaleCompare(Arguments args) { |
2125 NoHandleAllocation ha; | 2107 NoHandleAllocation ha; |
2126 ASSERT(args.length() == 2); | 2108 ASSERT(args.length() == 2); |
2127 | 2109 |
2128 CONVERT_CHECKED(String, str1, args[0]); | 2110 CONVERT_CHECKED(String, str1, args[0]); |
2129 CONVERT_CHECKED(String, str2, args[1]); | 2111 CONVERT_CHECKED(String, str2, args[1]); |
2130 | 2112 |
2131 if (str1 == str2) return Smi::FromInt(0); // Equal. | 2113 if (str1 == str2) return Smi::FromInt(0); // Equal. |
2132 StringShape shape1(str1); | 2114 int str1_length = str1->length(); |
2133 StringShape shape2(str2); | 2115 int str2_length = str2->length(); |
2134 int str1_length = str1->length(shape1); | |
2135 int str2_length = str2->length(shape2); | |
2136 | 2116 |
2137 // Decide trivial cases without flattening. | 2117 // Decide trivial cases without flattening. |
2138 if (str1_length == 0) { | 2118 if (str1_length == 0) { |
2139 if (str2_length == 0) return Smi::FromInt(0); // Equal. | 2119 if (str2_length == 0) return Smi::FromInt(0); // Equal. |
2140 return Smi::FromInt(-str2_length); | 2120 return Smi::FromInt(-str2_length); |
2141 } else { | 2121 } else { |
2142 if (str2_length == 0) return Smi::FromInt(str1_length); | 2122 if (str2_length == 0) return Smi::FromInt(str1_length); |
2143 } | 2123 } |
2144 | 2124 |
2145 int end = str1_length < str2_length ? str1_length : str2_length; | 2125 int end = str1_length < str2_length ? str1_length : str2_length; |
2146 | 2126 |
2147 // No need to flatten if we are going to find the answer on the first | 2127 // No need to flatten if we are going to find the answer on the first |
2148 // character. At this point we know there is at least one character | 2128 // character. At this point we know there is at least one character |
2149 // in each string, due to the trivial case handling above. | 2129 // in each string, due to the trivial case handling above. |
2150 int d = str1->Get(shape1, 0) - str2->Get(shape2, 0); | 2130 int d = str1->Get(0) - str2->Get(0); |
2151 if (d != 0) return Smi::FromInt(d); | 2131 if (d != 0) return Smi::FromInt(d); |
2152 | 2132 |
2153 str1->TryFlattenIfNotFlat(shape1); // Shapes are no longer valid now! | 2133 str1->TryFlattenIfNotFlat(); |
2154 str2->TryFlattenIfNotFlat(shape2); | 2134 str2->TryFlattenIfNotFlat(); |
2155 | 2135 |
2156 static StringInputBuffer buf1; | 2136 static StringInputBuffer buf1; |
2157 static StringInputBuffer buf2; | 2137 static StringInputBuffer buf2; |
2158 | 2138 |
2159 buf1.Reset(str1); | 2139 buf1.Reset(str1); |
2160 buf2.Reset(str2); | 2140 buf2.Reset(str2); |
2161 | 2141 |
2162 for (int i = 0; i < end; i++) { | 2142 for (int i = 0; i < end; i++) { |
2163 uint16_t char1 = buf1.GetNext(); | 2143 uint16_t char1 = buf1.GetNext(); |
2164 uint16_t char2 = buf2.GetNext(); | 2144 uint16_t char2 = buf2.GetNext(); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2279 char* str = DoubleToPrecisionCString(value, f); | 2259 char* str = DoubleToPrecisionCString(value, f); |
2280 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); | 2260 Object* res = Heap::AllocateStringFromAscii(CStrVector(str)); |
2281 DeleteArray(str); | 2261 DeleteArray(str); |
2282 return res; | 2262 return res; |
2283 } | 2263 } |
2284 | 2264 |
2285 | 2265 |
2286 // Returns a single character string where first character equals | 2266 // Returns a single character string where first character equals |
2287 // string->Get(index). | 2267 // string->Get(index). |
2288 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { | 2268 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { |
2289 StringShape shape(*string); | 2269 if (index < static_cast<uint32_t>(string->length())) { |
2290 if (index < static_cast<uint32_t>(string->length(shape))) { | 2270 string->TryFlattenIfNotFlat(); |
2291 string->TryFlattenIfNotFlat(shape); // Invalidates shape! | |
2292 return LookupSingleCharacterStringFromCode( | 2271 return LookupSingleCharacterStringFromCode( |
2293 string->Get(StringShape(*string), index)); | 2272 string->Get(index)); |
2294 } | 2273 } |
2295 return Execution::CharAt(string, index); | 2274 return Execution::CharAt(string, index); |
2296 } | 2275 } |
2297 | 2276 |
2298 | 2277 |
2299 Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) { | 2278 Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) { |
2300 // Handle [] indexing on Strings | 2279 // Handle [] indexing on Strings |
2301 if (object->IsString()) { | 2280 if (object->IsString()) { |
2302 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); | 2281 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); |
2303 if (!result->IsUndefined()) return *result; | 2282 if (!result->IsUndefined()) return *result; |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2474 return *value; | 2453 return *value; |
2475 } | 2454 } |
2476 | 2455 |
2477 if (key->IsString()) { | 2456 if (key->IsString()) { |
2478 Handle<Object> result; | 2457 Handle<Object> result; |
2479 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { | 2458 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { |
2480 ASSERT(attr == NONE); | 2459 ASSERT(attr == NONE); |
2481 result = SetElement(js_object, index, value); | 2460 result = SetElement(js_object, index, value); |
2482 } else { | 2461 } else { |
2483 Handle<String> key_string = Handle<String>::cast(key); | 2462 Handle<String> key_string = Handle<String>::cast(key); |
2484 key_string->TryFlattenIfNotFlat(StringShape(*key_string)); | 2463 key_string->TryFlattenIfNotFlat(); |
2485 result = SetProperty(js_object, key_string, value, attr); | 2464 result = SetProperty(js_object, key_string, value, attr); |
2486 } | 2465 } |
2487 if (result.is_null()) return Failure::Exception(); | 2466 if (result.is_null()) return Failure::Exception(); |
2488 return *value; | 2467 return *value; |
2489 } | 2468 } |
2490 | 2469 |
2491 // Call-back into JavaScript to convert the key to a string. | 2470 // Call-back into JavaScript to convert the key to a string. |
2492 bool has_pending_exception = false; | 2471 bool has_pending_exception = false; |
2493 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 2472 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); |
2494 if (has_pending_exception) return Failure::Exception(); | 2473 if (has_pending_exception) return Failure::Exception(); |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2768 // host objects gives that it is okay to return "object" | 2747 // host objects gives that it is okay to return "object" |
2769 return Heap::object_symbol(); | 2748 return Heap::object_symbol(); |
2770 } | 2749 } |
2771 } | 2750 } |
2772 | 2751 |
2773 | 2752 |
2774 static Object* Runtime_StringToNumber(Arguments args) { | 2753 static Object* Runtime_StringToNumber(Arguments args) { |
2775 NoHandleAllocation ha; | 2754 NoHandleAllocation ha; |
2776 ASSERT(args.length() == 1); | 2755 ASSERT(args.length() == 1); |
2777 CONVERT_CHECKED(String, subject, args[0]); | 2756 CONVERT_CHECKED(String, subject, args[0]); |
2778 subject->TryFlattenIfNotFlat(StringShape(subject)); | 2757 subject->TryFlattenIfNotFlat(); |
2779 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX)); | 2758 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX)); |
2780 } | 2759 } |
2781 | 2760 |
2782 | 2761 |
2783 static Object* Runtime_StringFromCharCodeArray(Arguments args) { | 2762 static Object* Runtime_StringFromCharCodeArray(Arguments args) { |
2784 NoHandleAllocation ha; | 2763 NoHandleAllocation ha; |
2785 ASSERT(args.length() == 1); | 2764 ASSERT(args.length() == 1); |
2786 | 2765 |
2787 CONVERT_CHECKED(JSArray, codes, args[0]); | 2766 CONVERT_CHECKED(JSArray, codes, args[0]); |
2788 int length = Smi::cast(codes->length())->value(); | 2767 int length = Smi::cast(codes->length())->value(); |
2789 | 2768 |
2790 // Check if the string can be ASCII. | 2769 // Check if the string can be ASCII. |
2791 int i; | 2770 int i; |
2792 for (i = 0; i < length; i++) { | 2771 for (i = 0; i < length; i++) { |
2793 Object* element = codes->GetElement(i); | 2772 Object* element = codes->GetElement(i); |
2794 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); | 2773 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); |
2795 if ((chr & 0xffff) > String::kMaxAsciiCharCode) | 2774 if ((chr & 0xffff) > String::kMaxAsciiCharCode) |
2796 break; | 2775 break; |
2797 } | 2776 } |
2798 | 2777 |
2799 Object* object = NULL; | 2778 Object* object = NULL; |
2800 if (i == length) { // The string is ASCII. | 2779 if (i == length) { // The string is ASCII. |
2801 object = Heap::AllocateRawAsciiString(length); | 2780 object = Heap::AllocateRawAsciiString(length); |
2802 } else { // The string is not ASCII. | 2781 } else { // The string is not ASCII. |
2803 object = Heap::AllocateRawTwoByteString(length); | 2782 object = Heap::AllocateRawTwoByteString(length); |
2804 } | 2783 } |
2805 | 2784 |
2806 if (object->IsFailure()) return object; | 2785 if (object->IsFailure()) return object; |
2807 String* result = String::cast(object); | 2786 String* result = String::cast(object); |
2808 StringShape result_shape(result); | |
2809 for (int i = 0; i < length; i++) { | 2787 for (int i = 0; i < length; i++) { |
2810 Object* element = codes->GetElement(i); | 2788 Object* element = codes->GetElement(i); |
2811 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); | 2789 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); |
2812 result->Set(result_shape, i, chr & 0xffff); | 2790 result->Set(i, chr & 0xffff); |
2813 } | 2791 } |
2814 return result; | 2792 return result; |
2815 } | 2793 } |
2816 | 2794 |
2817 | 2795 |
2818 // kNotEscaped is generated by the following: | 2796 // kNotEscaped is generated by the following: |
2819 // | 2797 // |
2820 // #!/bin/perl | 2798 // #!/bin/perl |
2821 // for (my $i = 0; $i < 256; $i++) { | 2799 // for (my $i = 0; $i < 256; $i++) { |
2822 // print "\n" if $i % 16 == 0; | 2800 // print "\n" if $i % 16 == 0; |
(...skipping 28 matching lines...) Expand all Loading... |
2851 return kNotEscaped[character] != 0; | 2829 return kNotEscaped[character] != 0; |
2852 } | 2830 } |
2853 | 2831 |
2854 | 2832 |
2855 static Object* Runtime_URIEscape(Arguments args) { | 2833 static Object* Runtime_URIEscape(Arguments args) { |
2856 const char hex_chars[] = "0123456789ABCDEF"; | 2834 const char hex_chars[] = "0123456789ABCDEF"; |
2857 NoHandleAllocation ha; | 2835 NoHandleAllocation ha; |
2858 ASSERT(args.length() == 1); | 2836 ASSERT(args.length() == 1); |
2859 CONVERT_CHECKED(String, source, args[0]); | 2837 CONVERT_CHECKED(String, source, args[0]); |
2860 | 2838 |
2861 source->TryFlattenIfNotFlat(StringShape(source)); | 2839 source->TryFlattenIfNotFlat(); |
2862 | 2840 |
2863 int escaped_length = 0; | 2841 int escaped_length = 0; |
2864 int length = source->length(); | 2842 int length = source->length(); |
2865 { | 2843 { |
2866 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); | 2844 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); |
2867 buffer->Reset(source); | 2845 buffer->Reset(source); |
2868 while (buffer->has_more()) { | 2846 while (buffer->has_more()) { |
2869 uint16_t character = buffer->GetNext(); | 2847 uint16_t character = buffer->GetNext(); |
2870 if (character >= 256) { | 2848 if (character >= 256) { |
2871 escaped_length += 6; | 2849 escaped_length += 6; |
2872 } else if (IsNotEscaped(character)) { | 2850 } else if (IsNotEscaped(character)) { |
2873 escaped_length++; | 2851 escaped_length++; |
2874 } else { | 2852 } else { |
2875 escaped_length += 3; | 2853 escaped_length += 3; |
2876 } | 2854 } |
2877 // We don't allow strings that are longer than Smi range. | 2855 // We don't allow strings that are longer than Smi range. |
2878 if (!Smi::IsValid(escaped_length)) { | 2856 if (!Smi::IsValid(escaped_length)) { |
2879 Top::context()->mark_out_of_memory(); | 2857 Top::context()->mark_out_of_memory(); |
2880 return Failure::OutOfMemoryException(); | 2858 return Failure::OutOfMemoryException(); |
2881 } | 2859 } |
2882 } | 2860 } |
2883 } | 2861 } |
2884 // No length change implies no change. Return original string if no change. | 2862 // No length change implies no change. Return original string if no change. |
2885 if (escaped_length == length) { | 2863 if (escaped_length == length) { |
2886 return source; | 2864 return source; |
2887 } | 2865 } |
2888 Object* o = Heap::AllocateRawAsciiString(escaped_length); | 2866 Object* o = Heap::AllocateRawAsciiString(escaped_length); |
2889 if (o->IsFailure()) return o; | 2867 if (o->IsFailure()) return o; |
2890 String* destination = String::cast(o); | 2868 String* destination = String::cast(o); |
2891 StringShape dshape(destination); | |
2892 int dest_position = 0; | 2869 int dest_position = 0; |
2893 | 2870 |
2894 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); | 2871 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); |
2895 buffer->Rewind(); | 2872 buffer->Rewind(); |
2896 while (buffer->has_more()) { | 2873 while (buffer->has_more()) { |
2897 uint16_t chr = buffer->GetNext(); | 2874 uint16_t chr = buffer->GetNext(); |
2898 if (chr >= 256) { | 2875 if (chr >= 256) { |
2899 destination->Set(dshape, dest_position, '%'); | 2876 destination->Set(dest_position, '%'); |
2900 destination->Set(dshape, dest_position+1, 'u'); | 2877 destination->Set(dest_position+1, 'u'); |
2901 destination->Set(dshape, dest_position+2, hex_chars[chr >> 12]); | 2878 destination->Set(dest_position+2, hex_chars[chr >> 12]); |
2902 destination->Set(dshape, dest_position+3, hex_chars[(chr >> 8) & 0xf]); | 2879 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]); |
2903 destination->Set(dshape, dest_position+4, hex_chars[(chr >> 4) & 0xf]); | 2880 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]); |
2904 destination->Set(dshape, dest_position+5, hex_chars[chr & 0xf]); | 2881 destination->Set(dest_position+5, hex_chars[chr & 0xf]); |
2905 dest_position += 6; | 2882 dest_position += 6; |
2906 } else if (IsNotEscaped(chr)) { | 2883 } else if (IsNotEscaped(chr)) { |
2907 destination->Set(dshape, dest_position, chr); | 2884 destination->Set(dest_position, chr); |
2908 dest_position++; | 2885 dest_position++; |
2909 } else { | 2886 } else { |
2910 destination->Set(dshape, dest_position, '%'); | 2887 destination->Set(dest_position, '%'); |
2911 destination->Set(dshape, dest_position+1, hex_chars[chr >> 4]); | 2888 destination->Set(dest_position+1, hex_chars[chr >> 4]); |
2912 destination->Set(dshape, dest_position+2, hex_chars[chr & 0xf]); | 2889 destination->Set(dest_position+2, hex_chars[chr & 0xf]); |
2913 dest_position += 3; | 2890 dest_position += 3; |
2914 } | 2891 } |
2915 } | 2892 } |
2916 return destination; | 2893 return destination; |
2917 } | 2894 } |
2918 | 2895 |
2919 | 2896 |
2920 static inline int TwoDigitHex(uint16_t character1, uint16_t character2) { | 2897 static inline int TwoDigitHex(uint16_t character1, uint16_t character2) { |
2921 static const signed char kHexValue['g'] = { | 2898 static const signed char kHexValue['g'] = { |
2922 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2899 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
2923 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2900 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
2924 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2901 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
2925 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, | 2902 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, |
2926 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2903 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
2927 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 2904 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
2928 -1, 10, 11, 12, 13, 14, 15 }; | 2905 -1, 10, 11, 12, 13, 14, 15 }; |
2929 | 2906 |
2930 if (character1 > 'f') return -1; | 2907 if (character1 > 'f') return -1; |
2931 int hi = kHexValue[character1]; | 2908 int hi = kHexValue[character1]; |
2932 if (hi == -1) return -1; | 2909 if (hi == -1) return -1; |
2933 if (character2 > 'f') return -1; | 2910 if (character2 > 'f') return -1; |
2934 int lo = kHexValue[character2]; | 2911 int lo = kHexValue[character2]; |
2935 if (lo == -1) return -1; | 2912 if (lo == -1) return -1; |
2936 return (hi << 4) + lo; | 2913 return (hi << 4) + lo; |
2937 } | 2914 } |
2938 | 2915 |
2939 | 2916 |
2940 static inline int Unescape(String* source, | 2917 static inline int Unescape(String* source, |
2941 StringShape shape, | |
2942 int i, | 2918 int i, |
2943 int length, | 2919 int length, |
2944 int* step) { | 2920 int* step) { |
2945 uint16_t character = source->Get(shape, i); | 2921 uint16_t character = source->Get(i); |
2946 int32_t hi = 0; | 2922 int32_t hi = 0; |
2947 int32_t lo = 0; | 2923 int32_t lo = 0; |
2948 if (character == '%' && | 2924 if (character == '%' && |
2949 i <= length - 6 && | 2925 i <= length - 6 && |
2950 source->Get(shape, i + 1) == 'u' && | 2926 source->Get(i + 1) == 'u' && |
2951 (hi = TwoDigitHex(source->Get(shape, i + 2), | 2927 (hi = TwoDigitHex(source->Get(i + 2), |
2952 source->Get(shape, i + 3))) != -1 && | 2928 source->Get(i + 3))) != -1 && |
2953 (lo = TwoDigitHex(source->Get(shape, i + 4), | 2929 (lo = TwoDigitHex(source->Get(i + 4), |
2954 source->Get(shape, i + 5))) != -1) { | 2930 source->Get(i + 5))) != -1) { |
2955 *step = 6; | 2931 *step = 6; |
2956 return (hi << 8) + lo; | 2932 return (hi << 8) + lo; |
2957 } else if (character == '%' && | 2933 } else if (character == '%' && |
2958 i <= length - 3 && | 2934 i <= length - 3 && |
2959 (lo = TwoDigitHex(source->Get(shape, i + 1), | 2935 (lo = TwoDigitHex(source->Get(i + 1), |
2960 source->Get(shape, i + 2))) != -1) { | 2936 source->Get(i + 2))) != -1) { |
2961 *step = 3; | 2937 *step = 3; |
2962 return lo; | 2938 return lo; |
2963 } else { | 2939 } else { |
2964 *step = 1; | 2940 *step = 1; |
2965 return character; | 2941 return character; |
2966 } | 2942 } |
2967 } | 2943 } |
2968 | 2944 |
2969 | 2945 |
2970 static Object* Runtime_URIUnescape(Arguments args) { | 2946 static Object* Runtime_URIUnescape(Arguments args) { |
2971 NoHandleAllocation ha; | 2947 NoHandleAllocation ha; |
2972 ASSERT(args.length() == 1); | 2948 ASSERT(args.length() == 1); |
2973 CONVERT_CHECKED(String, source, args[0]); | 2949 CONVERT_CHECKED(String, source, args[0]); |
2974 | 2950 |
2975 source->TryFlattenIfNotFlat(StringShape(source)); | 2951 source->TryFlattenIfNotFlat(); |
2976 StringShape source_shape(source); | |
2977 | 2952 |
2978 bool ascii = true; | 2953 bool ascii = true; |
2979 int length = source->length(source_shape); | 2954 int length = source->length(); |
2980 | 2955 |
2981 int unescaped_length = 0; | 2956 int unescaped_length = 0; |
2982 for (int i = 0; i < length; unescaped_length++) { | 2957 for (int i = 0; i < length; unescaped_length++) { |
2983 int step; | 2958 int step; |
2984 if (Unescape(source, | 2959 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) { |
2985 source_shape, | |
2986 i, | |
2987 length, | |
2988 &step) > | |
2989 String::kMaxAsciiCharCode) | |
2990 ascii = false; | 2960 ascii = false; |
| 2961 } |
2991 i += step; | 2962 i += step; |
2992 } | 2963 } |
2993 | 2964 |
2994 // No length change implies no change. Return original string if no change. | 2965 // No length change implies no change. Return original string if no change. |
2995 if (unescaped_length == length) | 2966 if (unescaped_length == length) |
2996 return source; | 2967 return source; |
2997 | 2968 |
2998 Object* o = ascii ? | 2969 Object* o = ascii ? |
2999 Heap::AllocateRawAsciiString(unescaped_length) : | 2970 Heap::AllocateRawAsciiString(unescaped_length) : |
3000 Heap::AllocateRawTwoByteString(unescaped_length); | 2971 Heap::AllocateRawTwoByteString(unescaped_length); |
3001 if (o->IsFailure()) return o; | 2972 if (o->IsFailure()) return o; |
3002 String* destination = String::cast(o); | 2973 String* destination = String::cast(o); |
3003 StringShape destination_shape(destination); | |
3004 | 2974 |
3005 int dest_position = 0; | 2975 int dest_position = 0; |
3006 for (int i = 0; i < length; dest_position++) { | 2976 for (int i = 0; i < length; dest_position++) { |
3007 int step; | 2977 int step; |
3008 destination->Set(destination_shape, | 2978 destination->Set(dest_position, Unescape(source, i, length, &step)); |
3009 dest_position, | |
3010 Unescape(source, source_shape, i, length, &step)); | |
3011 i += step; | 2979 i += step; |
3012 } | 2980 } |
3013 return destination; | 2981 return destination; |
3014 } | 2982 } |
3015 | 2983 |
3016 | 2984 |
3017 static Object* Runtime_StringParseInt(Arguments args) { | 2985 static Object* Runtime_StringParseInt(Arguments args) { |
3018 NoHandleAllocation ha; | 2986 NoHandleAllocation ha; |
3019 | 2987 |
3020 CONVERT_CHECKED(String, s, args[0]); | 2988 CONVERT_CHECKED(String, s, args[0]); |
3021 CONVERT_DOUBLE_CHECKED(n, args[1]); | 2989 CONVERT_DOUBLE_CHECKED(n, args[1]); |
3022 int radix = FastD2I(n); | 2990 int radix = FastD2I(n); |
3023 | 2991 |
3024 s->TryFlattenIfNotFlat(StringShape(s)); | 2992 s->TryFlattenIfNotFlat(); |
3025 | 2993 |
3026 StringShape shape(s); | 2994 int len = s->length(); |
3027 | |
3028 int len = s->length(shape); | |
3029 int i; | 2995 int i; |
3030 | 2996 |
3031 // Skip leading white space. | 2997 // Skip leading white space. |
3032 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(shape, i)); i++) ; | 2998 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ; |
3033 if (i == len) return Heap::nan_value(); | 2999 if (i == len) return Heap::nan_value(); |
3034 | 3000 |
3035 // Compute the sign (default to +). | 3001 // Compute the sign (default to +). |
3036 int sign = 1; | 3002 int sign = 1; |
3037 if (s->Get(shape, i) == '-') { | 3003 if (s->Get(i) == '-') { |
3038 sign = -1; | 3004 sign = -1; |
3039 i++; | 3005 i++; |
3040 } else if (s->Get(shape, i) == '+') { | 3006 } else if (s->Get(i) == '+') { |
3041 i++; | 3007 i++; |
3042 } | 3008 } |
3043 | 3009 |
3044 // Compute the radix if 0. | 3010 // Compute the radix if 0. |
3045 if (radix == 0) { | 3011 if (radix == 0) { |
3046 radix = 10; | 3012 radix = 10; |
3047 if (i < len && s->Get(shape, i) == '0') { | 3013 if (i < len && s->Get(i) == '0') { |
3048 radix = 8; | 3014 radix = 8; |
3049 if (i + 1 < len) { | 3015 if (i + 1 < len) { |
3050 int c = s->Get(shape, i + 1); | 3016 int c = s->Get(i + 1); |
3051 if (c == 'x' || c == 'X') { | 3017 if (c == 'x' || c == 'X') { |
3052 radix = 16; | 3018 radix = 16; |
3053 i += 2; | 3019 i += 2; |
3054 } | 3020 } |
3055 } | 3021 } |
3056 } | 3022 } |
3057 } else if (radix == 16) { | 3023 } else if (radix == 16) { |
3058 // Allow 0x or 0X prefix if radix is 16. | 3024 // Allow 0x or 0X prefix if radix is 16. |
3059 if (i + 1 < len && s->Get(shape, i) == '0') { | 3025 if (i + 1 < len && s->Get(i) == '0') { |
3060 int c = s->Get(shape, i + 1); | 3026 int c = s->Get(i + 1); |
3061 if (c == 'x' || c == 'X') i += 2; | 3027 if (c == 'x' || c == 'X') i += 2; |
3062 } | 3028 } |
3063 } | 3029 } |
3064 | 3030 |
3065 RUNTIME_ASSERT(2 <= radix && radix <= 36); | 3031 RUNTIME_ASSERT(2 <= radix && radix <= 36); |
3066 double value; | 3032 double value; |
3067 int end_index = StringToInt(s, i, radix, &value); | 3033 int end_index = StringToInt(s, i, radix, &value); |
3068 if (end_index != i) { | 3034 if (end_index != i) { |
3069 return Heap::NumberFromDouble(sign * value); | 3035 return Heap::NumberFromDouble(sign * value); |
3070 } | 3036 } |
(...skipping 11 matching lines...) Expand all Loading... |
3082 // Create a number object from the value. | 3048 // Create a number object from the value. |
3083 return Heap::NumberFromDouble(value); | 3049 return Heap::NumberFromDouble(value); |
3084 } | 3050 } |
3085 | 3051 |
3086 | 3052 |
3087 static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping; | 3053 static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping; |
3088 static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping; | 3054 static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping; |
3089 | 3055 |
3090 | 3056 |
3091 template <class Converter> | 3057 template <class Converter> |
3092 static Object* ConvertCase(Arguments args, | 3058 static Object* ConvertCaseHelper(String* s, |
3093 unibrow::Mapping<Converter, 128>* mapping) { | 3059 int length, |
3094 NoHandleAllocation ha; | 3060 int input_string_length, |
3095 | 3061 unibrow::Mapping<Converter, 128>* mapping) { |
3096 CONVERT_CHECKED(String, s, args[0]); | 3062 // We try this twice, once with the assumption that the result is no longer |
3097 s->TryFlattenIfNotFlat(StringShape(s)); | 3063 // than the input and, if that assumption breaks, again with the exact |
3098 StringShape shape(s); | 3064 // length. This may not be pretty, but it is nicer than what was here before |
3099 | 3065 // and I hereby claim my vaffel-is. |
3100 int raw_string_length = s->length(shape); | 3066 // |
3101 // Assume that the string is not empty; we need this assumption later | |
3102 if (raw_string_length == 0) return s; | |
3103 int length = raw_string_length; | |
3104 | |
3105 | |
3106 // We try this twice, once with the assumption that the result is | |
3107 // no longer than the input and, if that assumption breaks, again | |
3108 // with the exact length. This is implemented using a goto back | |
3109 // to this label if we discover that the assumption doesn't hold. | |
3110 // I apologize sincerely for this and will give a vaffel-is to | |
3111 // the first person who can implement it in a nicer way. | |
3112 try_convert: | |
3113 | |
3114 // Allocate the resulting string. | 3067 // Allocate the resulting string. |
3115 // | 3068 // |
3116 // NOTE: This assumes that the upper/lower case of an ascii | 3069 // NOTE: This assumes that the upper/lower case of an ascii |
3117 // character is also ascii. This is currently the case, but it | 3070 // character is also ascii. This is currently the case, but it |
3118 // might break in the future if we implement more context and locale | 3071 // might break in the future if we implement more context and locale |
3119 // dependent upper/lower conversions. | 3072 // dependent upper/lower conversions. |
3120 Object* o = shape.IsAsciiRepresentation() | 3073 Object* o = StringShape(s).IsAsciiRepresentation() |
3121 ? Heap::AllocateRawAsciiString(length) | 3074 ? Heap::AllocateRawAsciiString(length) |
3122 : Heap::AllocateRawTwoByteString(length); | 3075 : Heap::AllocateRawTwoByteString(length); |
3123 if (o->IsFailure()) return o; | 3076 if (o->IsFailure()) return o; |
3124 String* result = String::cast(o); | 3077 String* result = String::cast(o); |
3125 StringShape result_shape(result); | |
3126 bool has_changed_character = false; | 3078 bool has_changed_character = false; |
3127 | 3079 |
3128 // Convert all characters to upper case, assuming that they will fit | 3080 // Convert all characters to upper case, assuming that they will fit |
3129 // in the buffer | 3081 // in the buffer |
3130 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); | 3082 Access<StringInputBuffer> buffer(&runtime_string_input_buffer); |
3131 buffer->Reset(s); | 3083 buffer->Reset(s); |
3132 unibrow::uchar chars[Converter::kMaxWidth]; | 3084 unibrow::uchar chars[Converter::kMaxWidth]; |
3133 int i = 0; | |
3134 // We can assume that the string is not empty | 3085 // We can assume that the string is not empty |
3135 uc32 current = buffer->GetNext(); | 3086 uc32 current = buffer->GetNext(); |
3136 while (i < length) { | 3087 for (int i = 0; i < length; ) { |
3137 bool has_next = buffer->has_more(); | 3088 bool has_next = buffer->has_more(); |
3138 uc32 next = has_next ? buffer->GetNext() : 0; | 3089 uc32 next = has_next ? buffer->GetNext() : 0; |
3139 int char_length = mapping->get(current, next, chars); | 3090 int char_length = mapping->get(current, next, chars); |
3140 if (char_length == 0) { | 3091 if (char_length == 0) { |
3141 // The case conversion of this character is the character itself. | 3092 // The case conversion of this character is the character itself. |
3142 result->Set(result_shape, i, current); | 3093 result->Set(i, current); |
3143 i++; | 3094 i++; |
3144 } else if (char_length == 1) { | 3095 } else if (char_length == 1) { |
3145 // Common case: converting the letter resulted in one character. | 3096 // Common case: converting the letter resulted in one character. |
3146 ASSERT(static_cast<uc32>(chars[0]) != current); | 3097 ASSERT(static_cast<uc32>(chars[0]) != current); |
3147 result->Set(result_shape, i, chars[0]); | 3098 result->Set(i, chars[0]); |
3148 has_changed_character = true; | 3099 has_changed_character = true; |
3149 i++; | 3100 i++; |
3150 } else if (length == raw_string_length) { | 3101 } else if (length == input_string_length) { |
3151 // We've assumed that the result would be as long as the | 3102 // We've assumed that the result would be as long as the |
3152 // input but here is a character that converts to several | 3103 // input but here is a character that converts to several |
3153 // characters. No matter, we calculate the exact length | 3104 // characters. No matter, we calculate the exact length |
3154 // of the result and try the whole thing again. | 3105 // of the result and try the whole thing again. |
3155 // | 3106 // |
3156 // Note that this leaves room for optimization. We could just | 3107 // Note that this leaves room for optimization. We could just |
3157 // memcpy what we already have to the result string. Also, | 3108 // memcpy what we already have to the result string. Also, |
3158 // the result string is the last object allocated we could | 3109 // the result string is the last object allocated we could |
3159 // "realloc" it and probably, in the vast majority of cases, | 3110 // "realloc" it and probably, in the vast majority of cases, |
3160 // extend the existing string to be able to hold the full | 3111 // extend the existing string to be able to hold the full |
3161 // result. | 3112 // result. |
3162 int next_length = 0; | 3113 int next_length = 0; |
3163 if (has_next) { | 3114 if (has_next) { |
3164 next_length = mapping->get(next, 0, chars); | 3115 next_length = mapping->get(next, 0, chars); |
3165 if (next_length == 0) next_length = 1; | 3116 if (next_length == 0) next_length = 1; |
3166 } | 3117 } |
3167 int current_length = i + char_length + next_length; | 3118 int current_length = i + char_length + next_length; |
3168 while (buffer->has_more()) { | 3119 while (buffer->has_more()) { |
3169 current = buffer->GetNext(); | 3120 current = buffer->GetNext(); |
3170 // NOTE: we use 0 as the next character here because, while | 3121 // NOTE: we use 0 as the next character here because, while |
3171 // the next character may affect what a character converts to, | 3122 // the next character may affect what a character converts to, |
3172 // it does not in any case affect the length of what it convert | 3123 // it does not in any case affect the length of what it convert |
3173 // to. | 3124 // to. |
3174 int char_length = mapping->get(current, 0, chars); | 3125 int char_length = mapping->get(current, 0, chars); |
3175 if (char_length == 0) char_length = 1; | 3126 if (char_length == 0) char_length = 1; |
3176 current_length += char_length; | 3127 current_length += char_length; |
| 3128 if (current_length > Smi::kMaxValue) { |
| 3129 Top::context()->mark_out_of_memory(); |
| 3130 return Failure::OutOfMemoryException(); |
| 3131 } |
3177 } | 3132 } |
3178 length = current_length; | 3133 // Try again with the real length. |
3179 goto try_convert; | 3134 return Smi::FromInt(current_length); |
3180 } else { | 3135 } else { |
3181 for (int j = 0; j < char_length; j++) { | 3136 for (int j = 0; j < char_length; j++) { |
3182 result->Set(result_shape, i, chars[j]); | 3137 result->Set(i, chars[j]); |
3183 i++; | 3138 i++; |
3184 } | 3139 } |
3185 has_changed_character = true; | 3140 has_changed_character = true; |
3186 } | 3141 } |
3187 current = next; | 3142 current = next; |
3188 } | 3143 } |
3189 if (has_changed_character) { | 3144 if (has_changed_character) { |
3190 return result; | 3145 return result; |
3191 } else { | 3146 } else { |
3192 // If we didn't actually change anything in doing the conversion | 3147 // If we didn't actually change anything in doing the conversion |
3193 // we simple return the result and let the converted string | 3148 // we simple return the result and let the converted string |
3194 // become garbage; there is no reason to keep two identical strings | 3149 // become garbage; there is no reason to keep two identical strings |
3195 // alive. | 3150 // alive. |
3196 return s; | 3151 return s; |
3197 } | 3152 } |
3198 } | 3153 } |
3199 | 3154 |
3200 | 3155 |
| 3156 template <class Converter> |
| 3157 static Object* ConvertCase(Arguments args, |
| 3158 unibrow::Mapping<Converter, 128>* mapping) { |
| 3159 NoHandleAllocation ha; |
| 3160 |
| 3161 CONVERT_CHECKED(String, s, args[0]); |
| 3162 s->TryFlattenIfNotFlat(); |
| 3163 |
| 3164 int input_string_length = s->length(); |
| 3165 // Assume that the string is not empty; we need this assumption later |
| 3166 if (input_string_length == 0) return s; |
| 3167 int length = input_string_length; |
| 3168 |
| 3169 Object* answer = ConvertCaseHelper(s, length, length, mapping); |
| 3170 if (answer->IsSmi()) { |
| 3171 // Retry with correct length. |
| 3172 answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping); |
| 3173 } |
| 3174 return answer; // This may be a failure. |
| 3175 } |
| 3176 |
| 3177 |
3201 static Object* Runtime_StringToLowerCase(Arguments args) { | 3178 static Object* Runtime_StringToLowerCase(Arguments args) { |
3202 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping); | 3179 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping); |
3203 } | 3180 } |
3204 | 3181 |
3205 | 3182 |
3206 static Object* Runtime_StringToUpperCase(Arguments args) { | 3183 static Object* Runtime_StringToUpperCase(Arguments args) { |
3207 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping); | 3184 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping); |
3208 } | 3185 } |
3209 | 3186 |
3210 | 3187 |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3377 if (length_sum > Smi::kMaxValue || length_sum < 0) { | 3354 if (length_sum > Smi::kMaxValue || length_sum < 0) { |
3378 Top::context()->mark_out_of_memory(); | 3355 Top::context()->mark_out_of_memory(); |
3379 return Failure::OutOfMemoryException(); | 3356 return Failure::OutOfMemoryException(); |
3380 } | 3357 } |
3381 return Heap::AllocateConsString(str1, str2); | 3358 return Heap::AllocateConsString(str1, str2); |
3382 } | 3359 } |
3383 | 3360 |
3384 | 3361 |
3385 template<typename sinkchar> | 3362 template<typename sinkchar> |
3386 static inline void StringBuilderConcatHelper(String* special, | 3363 static inline void StringBuilderConcatHelper(String* special, |
3387 StringShape special_shape, | |
3388 sinkchar* sink, | 3364 sinkchar* sink, |
3389 FixedArray* fixed_array, | 3365 FixedArray* fixed_array, |
3390 int array_length) { | 3366 int array_length) { |
3391 int position = 0; | 3367 int position = 0; |
3392 for (int i = 0; i < array_length; i++) { | 3368 for (int i = 0; i < array_length; i++) { |
3393 Object* element = fixed_array->get(i); | 3369 Object* element = fixed_array->get(i); |
3394 if (element->IsSmi()) { | 3370 if (element->IsSmi()) { |
3395 int encoded_slice = Smi::cast(element)->value(); | 3371 int encoded_slice = Smi::cast(element)->value(); |
3396 int pos = StringBuilderSubstringPosition::decode(encoded_slice); | 3372 int pos = StringBuilderSubstringPosition::decode(encoded_slice); |
3397 int len = StringBuilderSubstringLength::decode(encoded_slice); | 3373 int len = StringBuilderSubstringLength::decode(encoded_slice); |
3398 String::WriteToFlat(special, | 3374 String::WriteToFlat(special, |
3399 special_shape, | |
3400 sink + position, | 3375 sink + position, |
3401 pos, | 3376 pos, |
3402 pos + len); | 3377 pos + len); |
3403 position += len; | 3378 position += len; |
3404 } else { | 3379 } else { |
3405 String* string = String::cast(element); | 3380 String* string = String::cast(element); |
3406 StringShape shape(string); | 3381 int element_length = string->length(); |
3407 int element_length = string->length(shape); | 3382 String::WriteToFlat(string, sink + position, 0, element_length); |
3408 String::WriteToFlat(string, shape, sink + position, 0, element_length); | |
3409 position += element_length; | 3383 position += element_length; |
3410 } | 3384 } |
3411 } | 3385 } |
3412 } | 3386 } |
3413 | 3387 |
3414 | 3388 |
3415 static Object* Runtime_StringBuilderConcat(Arguments args) { | 3389 static Object* Runtime_StringBuilderConcat(Arguments args) { |
3416 NoHandleAllocation ha; | 3390 NoHandleAllocation ha; |
3417 ASSERT(args.length() == 2); | 3391 ASSERT(args.length() == 2); |
3418 CONVERT_CHECKED(JSArray, array, args[0]); | 3392 CONVERT_CHECKED(JSArray, array, args[0]); |
3419 CONVERT_CHECKED(String, special, args[1]); | 3393 CONVERT_CHECKED(String, special, args[1]); |
3420 StringShape special_shape(special); | 3394 int special_length = special->length(); |
3421 int special_length = special->length(special_shape); | |
3422 Object* smi_array_length = array->length(); | 3395 Object* smi_array_length = array->length(); |
3423 if (!smi_array_length->IsSmi()) { | 3396 if (!smi_array_length->IsSmi()) { |
3424 Top::context()->mark_out_of_memory(); | 3397 Top::context()->mark_out_of_memory(); |
3425 return Failure::OutOfMemoryException(); | 3398 return Failure::OutOfMemoryException(); |
3426 } | 3399 } |
3427 int array_length = Smi::cast(smi_array_length)->value(); | 3400 int array_length = Smi::cast(smi_array_length)->value(); |
3428 if (!array->HasFastElements()) { | 3401 if (!array->HasFastElements()) { |
3429 return Top::Throw(Heap::illegal_argument_symbol()); | 3402 return Top::Throw(Heap::illegal_argument_symbol()); |
3430 } | 3403 } |
3431 FixedArray* fixed_array = FixedArray::cast(array->elements()); | 3404 FixedArray* fixed_array = FixedArray::cast(array->elements()); |
3432 if (fixed_array->length() < array_length) { | 3405 if (fixed_array->length() < array_length) { |
3433 array_length = fixed_array->length(); | 3406 array_length = fixed_array->length(); |
3434 } | 3407 } |
3435 | 3408 |
3436 if (array_length == 0) { | 3409 if (array_length == 0) { |
3437 return Heap::empty_string(); | 3410 return Heap::empty_string(); |
3438 } else if (array_length == 1) { | 3411 } else if (array_length == 1) { |
3439 Object* first = fixed_array->get(0); | 3412 Object* first = fixed_array->get(0); |
3440 if (first->IsString()) return first; | 3413 if (first->IsString()) return first; |
3441 } | 3414 } |
3442 | 3415 |
3443 bool ascii = special_shape.IsAsciiRepresentation(); | 3416 bool ascii = StringShape(special).IsAsciiRepresentation(); |
3444 int position = 0; | 3417 int position = 0; |
3445 for (int i = 0; i < array_length; i++) { | 3418 for (int i = 0; i < array_length; i++) { |
3446 Object* elt = fixed_array->get(i); | 3419 Object* elt = fixed_array->get(i); |
3447 if (elt->IsSmi()) { | 3420 if (elt->IsSmi()) { |
3448 int len = Smi::cast(elt)->value(); | 3421 int len = Smi::cast(elt)->value(); |
3449 int pos = len >> 11; | 3422 int pos = len >> 11; |
3450 len &= 0x7ff; | 3423 len &= 0x7ff; |
3451 if (pos + len > special_length) { | 3424 if (pos + len > special_length) { |
3452 return Top::Throw(Heap::illegal_argument_symbol()); | 3425 return Top::Throw(Heap::illegal_argument_symbol()); |
3453 } | 3426 } |
3454 position += len; | 3427 position += len; |
3455 } else if (elt->IsString()) { | 3428 } else if (elt->IsString()) { |
3456 String* element = String::cast(elt); | 3429 String* element = String::cast(elt); |
3457 StringShape element_shape(element); | 3430 int element_length = element->length(); |
3458 int element_length = element->length(element_shape); | |
3459 if (!Smi::IsValid(element_length + position)) { | 3431 if (!Smi::IsValid(element_length + position)) { |
3460 Top::context()->mark_out_of_memory(); | 3432 Top::context()->mark_out_of_memory(); |
3461 return Failure::OutOfMemoryException(); | 3433 return Failure::OutOfMemoryException(); |
3462 } | 3434 } |
3463 position += element_length; | 3435 position += element_length; |
3464 if (ascii && !element_shape.IsAsciiRepresentation()) { | 3436 if (ascii && !StringShape(element).IsAsciiRepresentation()) { |
3465 ascii = false; | 3437 ascii = false; |
3466 } | 3438 } |
3467 } else { | 3439 } else { |
3468 return Top::Throw(Heap::illegal_argument_symbol()); | 3440 return Top::Throw(Heap::illegal_argument_symbol()); |
3469 } | 3441 } |
3470 } | 3442 } |
3471 | 3443 |
3472 int length = position; | 3444 int length = position; |
3473 Object* object; | 3445 Object* object; |
3474 | 3446 |
3475 if (ascii) { | 3447 if (ascii) { |
3476 object = Heap::AllocateRawAsciiString(length); | 3448 object = Heap::AllocateRawAsciiString(length); |
3477 if (object->IsFailure()) return object; | 3449 if (object->IsFailure()) return object; |
3478 SeqAsciiString* answer = SeqAsciiString::cast(object); | 3450 SeqAsciiString* answer = SeqAsciiString::cast(object); |
3479 StringBuilderConcatHelper(special, | 3451 StringBuilderConcatHelper(special, |
3480 special_shape, | |
3481 answer->GetChars(), | 3452 answer->GetChars(), |
3482 fixed_array, | 3453 fixed_array, |
3483 array_length); | 3454 array_length); |
3484 return answer; | 3455 return answer; |
3485 } else { | 3456 } else { |
3486 object = Heap::AllocateRawTwoByteString(length); | 3457 object = Heap::AllocateRawTwoByteString(length); |
3487 if (object->IsFailure()) return object; | 3458 if (object->IsFailure()) return object; |
3488 SeqTwoByteString* answer = SeqTwoByteString::cast(object); | 3459 SeqTwoByteString* answer = SeqTwoByteString::cast(object); |
3489 StringBuilderConcatHelper(special, | 3460 StringBuilderConcatHelper(special, |
3490 special_shape, | |
3491 answer->GetChars(), | 3461 answer->GetChars(), |
3492 fixed_array, | 3462 fixed_array, |
3493 array_length); | 3463 array_length); |
3494 return answer; | 3464 return answer; |
3495 } | 3465 } |
3496 } | 3466 } |
3497 | 3467 |
3498 | 3468 |
3499 static Object* Runtime_NumberOr(Arguments args) { | 3469 static Object* Runtime_NumberOr(Arguments args) { |
3500 NoHandleAllocation ha; | 3470 NoHandleAllocation ha; |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3675 } | 3645 } |
3676 | 3646 |
3677 | 3647 |
3678 static Object* Runtime_StringCompare(Arguments args) { | 3648 static Object* Runtime_StringCompare(Arguments args) { |
3679 NoHandleAllocation ha; | 3649 NoHandleAllocation ha; |
3680 ASSERT(args.length() == 2); | 3650 ASSERT(args.length() == 2); |
3681 | 3651 |
3682 CONVERT_CHECKED(String, x, args[0]); | 3652 CONVERT_CHECKED(String, x, args[0]); |
3683 CONVERT_CHECKED(String, y, args[1]); | 3653 CONVERT_CHECKED(String, y, args[1]); |
3684 | 3654 |
3685 StringShape x_shape(x); | |
3686 StringShape y_shape(y); | |
3687 | |
3688 // A few fast case tests before we flatten. | 3655 // A few fast case tests before we flatten. |
3689 if (x == y) return Smi::FromInt(EQUAL); | 3656 if (x == y) return Smi::FromInt(EQUAL); |
3690 if (y->length(y_shape) == 0) { | 3657 if (y->length() == 0) { |
3691 if (x->length(x_shape) == 0) return Smi::FromInt(EQUAL); | 3658 if (x->length() == 0) return Smi::FromInt(EQUAL); |
3692 return Smi::FromInt(GREATER); | 3659 return Smi::FromInt(GREATER); |
3693 } else if (x->length(x_shape) == 0) { | 3660 } else if (x->length() == 0) { |
3694 return Smi::FromInt(LESS); | 3661 return Smi::FromInt(LESS); |
3695 } | 3662 } |
3696 | 3663 |
3697 int d = x->Get(x_shape, 0) - y->Get(y_shape, 0); | 3664 int d = x->Get(0) - y->Get(0); |
3698 if (d < 0) return Smi::FromInt(LESS); | 3665 if (d < 0) return Smi::FromInt(LESS); |
3699 else if (d > 0) return Smi::FromInt(GREATER); | 3666 else if (d > 0) return Smi::FromInt(GREATER); |
3700 | 3667 |
3701 x->TryFlattenIfNotFlat(x_shape); // Shapes are no longer valid! | 3668 x->TryFlattenIfNotFlat(); |
3702 y->TryFlattenIfNotFlat(y_shape); | 3669 y->TryFlattenIfNotFlat(); |
3703 | 3670 |
3704 static StringInputBuffer bufx; | 3671 static StringInputBuffer bufx; |
3705 static StringInputBuffer bufy; | 3672 static StringInputBuffer bufy; |
3706 bufx.Reset(x); | 3673 bufx.Reset(x); |
3707 bufy.Reset(y); | 3674 bufy.Reset(y); |
3708 while (bufx.has_more() && bufy.has_more()) { | 3675 while (bufx.has_more() && bufy.has_more()) { |
3709 int d = bufx.GetNext() - bufy.GetNext(); | 3676 int d = bufx.GetNext() - bufy.GetNext(); |
3710 if (d < 0) return Smi::FromInt(LESS); | 3677 if (d < 0) return Smi::FromInt(LESS); |
3711 else if (d > 0) return Smi::FromInt(GREATER); | 3678 else if (d > 0) return Smi::FromInt(GREATER); |
3712 } | 3679 } |
(...skipping 2960 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6673 } else { | 6640 } else { |
6674 // Handle last resort GC and make sure to allow future allocations | 6641 // Handle last resort GC and make sure to allow future allocations |
6675 // to grow the heap without causing GCs (if possible). | 6642 // to grow the heap without causing GCs (if possible). |
6676 Counters::gc_last_resort_from_js.Increment(); | 6643 Counters::gc_last_resort_from_js.Increment(); |
6677 Heap::CollectAllGarbage(); | 6644 Heap::CollectAllGarbage(); |
6678 } | 6645 } |
6679 } | 6646 } |
6680 | 6647 |
6681 | 6648 |
6682 } } // namespace v8::internal | 6649 } } // namespace v8::internal |
OLD | NEW |