| 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 |