| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 6102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6113 | 6113 |
| 6114 // Create a number object from the value. | 6114 // Create a number object from the value. |
| 6115 return isolate->heap()->NumberFromDouble(value); | 6115 return isolate->heap()->NumberFromDouble(value); |
| 6116 } | 6116 } |
| 6117 | 6117 |
| 6118 | 6118 |
| 6119 template <class Converter> | 6119 template <class Converter> |
| 6120 MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( | 6120 MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( |
| 6121 Isolate* isolate, | 6121 Isolate* isolate, |
| 6122 String* s, | 6122 String* s, |
| 6123 String::Encoding result_encoding, |
| 6123 int length, | 6124 int length, |
| 6124 int input_string_length, | 6125 int input_string_length, |
| 6125 unibrow::Mapping<Converter, 128>* mapping) { | 6126 unibrow::Mapping<Converter, 128>* mapping) { |
| 6126 // We try this twice, once with the assumption that the result is no longer | 6127 // We try this twice, once with the assumption that the result is no longer |
| 6127 // than the input and, if that assumption breaks, again with the exact | 6128 // than the input and, if that assumption breaks, again with the exact |
| 6128 // length. This may not be pretty, but it is nicer than what was here before | 6129 // length. This may not be pretty, but it is nicer than what was here before |
| 6129 // and I hereby claim my vaffel-is. | 6130 // and I hereby claim my vaffel-is. |
| 6130 // | 6131 // |
| 6131 // Allocate the resulting string. | 6132 // Allocate the resulting string. |
| 6132 // | 6133 // |
| 6133 // NOTE: This assumes that the upper/lower case of an ASCII | 6134 // NOTE: This assumes that the upper/lower case of an ASCII |
| 6134 // character is also ASCII. This is currently the case, but it | 6135 // character is also ASCII. This is currently the case, but it |
| 6135 // might break in the future if we implement more context and locale | 6136 // might break in the future if we implement more context and locale |
| 6136 // dependent upper/lower conversions. | 6137 // dependent upper/lower conversions. |
| 6137 Object* o; | 6138 Object* o; |
| 6138 { MaybeObject* maybe_o = s->IsOneByteRepresentation() | 6139 { MaybeObject* maybe_o = result_encoding == String::ONE_BYTE_ENCODING |
| 6139 ? isolate->heap()->AllocateRawOneByteString(length) | 6140 ? isolate->heap()->AllocateRawOneByteString(length) |
| 6140 : isolate->heap()->AllocateRawTwoByteString(length); | 6141 : isolate->heap()->AllocateRawTwoByteString(length); |
| 6141 if (!maybe_o->ToObject(&o)) return maybe_o; | 6142 if (!maybe_o->ToObject(&o)) return maybe_o; |
| 6142 } | 6143 } |
| 6143 String* result = String::cast(o); | 6144 String* result = String::cast(o); |
| 6144 bool has_changed_character = false; | 6145 bool has_changed_character = false; |
| 6145 | 6146 |
| 6147 DisallowHeapAllocation no_gc; |
| 6148 |
| 6146 // Convert all characters to upper case, assuming that they will fit | 6149 // Convert all characters to upper case, assuming that they will fit |
| 6147 // in the buffer | 6150 // in the buffer |
| 6148 Access<ConsStringIteratorOp> op( | 6151 Access<ConsStringIteratorOp> op( |
| 6149 isolate->runtime_state()->string_iterator()); | 6152 isolate->runtime_state()->string_iterator()); |
| 6150 StringCharacterStream stream(s, op.value()); | 6153 StringCharacterStream stream(s, op.value()); |
| 6151 unibrow::uchar chars[Converter::kMaxWidth]; | 6154 unibrow::uchar chars[Converter::kMaxWidth]; |
| 6152 // We can assume that the string is not empty | 6155 // We can assume that the string is not empty |
| 6153 uc32 current = stream.GetNext(); | 6156 uc32 current = stream.GetNext(); |
| 6157 // y with umlauts is the only character that stops fitting into one-byte |
| 6158 // when converting to uppercase. |
| 6159 static const uc32 yuml_code = 0xff; |
| 6160 bool ignore_yuml = result->IsSeqTwoByteString() || Converter::kIsToLower; |
| 6154 for (int i = 0; i < length;) { | 6161 for (int i = 0; i < length;) { |
| 6155 bool has_next = stream.HasMore(); | 6162 bool has_next = stream.HasMore(); |
| 6156 uc32 next = has_next ? stream.GetNext() : 0; | 6163 uc32 next = has_next ? stream.GetNext() : 0; |
| 6157 int char_length = mapping->get(current, next, chars); | 6164 int char_length = mapping->get(current, next, chars); |
| 6158 if (char_length == 0) { | 6165 if (char_length == 0) { |
| 6159 // The case conversion of this character is the character itself. | 6166 // The case conversion of this character is the character itself. |
| 6160 result->Set(i, current); | 6167 result->Set(i, current); |
| 6161 i++; | 6168 i++; |
| 6162 } else if (char_length == 1) { | 6169 } else if (char_length == 1 && (ignore_yuml || current != yuml_code)) { |
| 6163 // Common case: converting the letter resulted in one character. | 6170 // Common case: converting the letter resulted in one character. |
| 6164 ASSERT(static_cast<uc32>(chars[0]) != current); | 6171 ASSERT(static_cast<uc32>(chars[0]) != current); |
| 6165 result->Set(i, chars[0]); | 6172 result->Set(i, chars[0]); |
| 6166 has_changed_character = true; | 6173 has_changed_character = true; |
| 6167 i++; | 6174 i++; |
| 6168 } else if (length == input_string_length) { | 6175 } else if (length == input_string_length) { |
| 6176 bool found_yuml = (current == yuml_code); |
| 6169 // We've assumed that the result would be as long as the | 6177 // We've assumed that the result would be as long as the |
| 6170 // input but here is a character that converts to several | 6178 // input but here is a character that converts to several |
| 6171 // characters. No matter, we calculate the exact length | 6179 // characters. No matter, we calculate the exact length |
| 6172 // of the result and try the whole thing again. | 6180 // of the result and try the whole thing again. |
| 6173 // | 6181 // |
| 6174 // Note that this leaves room for optimization. We could just | 6182 // Note that this leaves room for optimization. We could just |
| 6175 // memcpy what we already have to the result string. Also, | 6183 // memcpy what we already have to the result string. Also, |
| 6176 // the result string is the last object allocated we could | 6184 // the result string is the last object allocated we could |
| 6177 // "realloc" it and probably, in the vast majority of cases, | 6185 // "realloc" it and probably, in the vast majority of cases, |
| 6178 // extend the existing string to be able to hold the full | 6186 // extend the existing string to be able to hold the full |
| 6179 // result. | 6187 // result. |
| 6180 int next_length = 0; | 6188 int next_length = 0; |
| 6181 if (has_next) { | 6189 if (has_next) { |
| 6182 next_length = mapping->get(next, 0, chars); | 6190 next_length = mapping->get(next, 0, chars); |
| 6183 if (next_length == 0) next_length = 1; | 6191 if (next_length == 0) next_length = 1; |
| 6184 } | 6192 } |
| 6185 int current_length = i + char_length + next_length; | 6193 int current_length = i + char_length + next_length; |
| 6186 while (stream.HasMore()) { | 6194 while (stream.HasMore()) { |
| 6187 current = stream.GetNext(); | 6195 current = stream.GetNext(); |
| 6196 found_yuml |= (current == yuml_code); |
| 6188 // NOTE: we use 0 as the next character here because, while | 6197 // NOTE: we use 0 as the next character here because, while |
| 6189 // the next character may affect what a character converts to, | 6198 // the next character may affect what a character converts to, |
| 6190 // it does not in any case affect the length of what it convert | 6199 // it does not in any case affect the length of what it convert |
| 6191 // to. | 6200 // to. |
| 6192 int char_length = mapping->get(current, 0, chars); | 6201 int char_length = mapping->get(current, 0, chars); |
| 6193 if (char_length == 0) char_length = 1; | 6202 if (char_length == 0) char_length = 1; |
| 6194 current_length += char_length; | 6203 current_length += char_length; |
| 6195 if (current_length > Smi::kMaxValue) { | 6204 if (current_length > Smi::kMaxValue) { |
| 6196 isolate->context()->mark_out_of_memory(); | 6205 isolate->context()->mark_out_of_memory(); |
| 6197 return Failure::OutOfMemoryException(0x13); | 6206 return Failure::OutOfMemoryException(0x13); |
| 6198 } | 6207 } |
| 6199 } | 6208 } |
| 6200 // Try again with the real length. | 6209 // Try again with the real length. Return signed if we need |
| 6201 return Smi::FromInt(current_length); | 6210 // to allocate a two-byte string for y-umlaut to uppercase. |
| 6211 return (found_yuml && !ignore_yuml) ? Smi::FromInt(-current_length) |
| 6212 : Smi::FromInt(current_length); |
| 6202 } else { | 6213 } else { |
| 6203 for (int j = 0; j < char_length; j++) { | 6214 for (int j = 0; j < char_length; j++) { |
| 6204 result->Set(i, chars[j]); | 6215 result->Set(i, chars[j]); |
| 6205 i++; | 6216 i++; |
| 6206 } | 6217 } |
| 6207 has_changed_character = true; | 6218 has_changed_character = true; |
| 6208 } | 6219 } |
| 6209 current = next; | 6220 current = next; |
| 6210 } | 6221 } |
| 6211 if (has_changed_character) { | 6222 if (has_changed_character) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 6237 // further simplified. | 6248 // further simplified. |
| 6238 ASSERT(0 < m && m < n); | 6249 ASSERT(0 < m && m < n); |
| 6239 // Has high bit set in every w byte less than n. | 6250 // Has high bit set in every w byte less than n. |
| 6240 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w; | 6251 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w; |
| 6241 // Has high bit set in every w byte greater than m. | 6252 // Has high bit set in every w byte greater than m. |
| 6242 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m); | 6253 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m); |
| 6243 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80)); | 6254 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80)); |
| 6244 } | 6255 } |
| 6245 | 6256 |
| 6246 | 6257 |
| 6247 enum AsciiCaseConversion { | 6258 template<class Converter> |
| 6248 ASCII_TO_LOWER, | 6259 static bool FastAsciiConvert(char* dst, |
| 6249 ASCII_TO_UPPER | 6260 char* src, |
| 6250 }; | 6261 int length, |
| 6251 | 6262 bool* changed_out) { |
| 6252 | |
| 6253 template <AsciiCaseConversion dir> | |
| 6254 struct FastAsciiConverter { | |
| 6255 static bool Convert(char* dst, char* src, int length, bool* changed_out) { | |
| 6256 #ifdef DEBUG | 6263 #ifdef DEBUG |
| 6257 char* saved_dst = dst; | 6264 char* saved_dst = dst; |
| 6258 char* saved_src = src; | 6265 char* saved_src = src; |
| 6259 #endif | 6266 #endif |
| 6260 // We rely on the distance between upper and lower case letters | 6267 DisallowHeapAllocation no_gc; |
| 6261 // being a known power of 2. | 6268 // We rely on the distance between upper and lower case letters |
| 6262 ASSERT('a' - 'A' == (1 << 5)); | 6269 // being a known power of 2. |
| 6263 // Boundaries for the range of input characters than require conversion. | 6270 ASSERT('a' - 'A' == (1 << 5)); |
| 6264 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1; | 6271 // Boundaries for the range of input characters than require conversion. |
| 6265 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1; | 6272 static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1; |
| 6266 bool changed = false; | 6273 static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1; |
| 6267 uintptr_t or_acc = 0; | 6274 bool changed = false; |
| 6268 char* const limit = src + length; | 6275 uintptr_t or_acc = 0; |
| 6276 char* const limit = src + length; |
| 6269 #ifdef V8_HOST_CAN_READ_UNALIGNED | 6277 #ifdef V8_HOST_CAN_READ_UNALIGNED |
| 6270 // Process the prefix of the input that requires no conversion one | 6278 // Process the prefix of the input that requires no conversion one |
| 6271 // (machine) word at a time. | 6279 // (machine) word at a time. |
| 6272 while (src <= limit - sizeof(uintptr_t)) { | 6280 while (src <= limit - sizeof(uintptr_t)) { |
| 6273 uintptr_t w = *reinterpret_cast<uintptr_t*>(src); | 6281 uintptr_t w = *reinterpret_cast<uintptr_t*>(src); |
| 6274 or_acc |= w; | 6282 or_acc |= w; |
| 6275 if (AsciiRangeMask(w, lo, hi) != 0) { | 6283 if (AsciiRangeMask(w, lo, hi) != 0) { |
| 6276 changed = true; | 6284 changed = true; |
| 6277 break; | 6285 break; |
| 6278 } | |
| 6279 *reinterpret_cast<uintptr_t*>(dst) = w; | |
| 6280 src += sizeof(uintptr_t); | |
| 6281 dst += sizeof(uintptr_t); | |
| 6282 } | 6286 } |
| 6283 // Process the remainder of the input performing conversion when | 6287 *reinterpret_cast<uintptr_t*>(dst) = w; |
| 6284 // required one word at a time. | 6288 src += sizeof(uintptr_t); |
| 6285 while (src <= limit - sizeof(uintptr_t)) { | 6289 dst += sizeof(uintptr_t); |
| 6286 uintptr_t w = *reinterpret_cast<uintptr_t*>(src); | 6290 } |
| 6287 or_acc |= w; | 6291 // Process the remainder of the input performing conversion when |
| 6288 uintptr_t m = AsciiRangeMask(w, lo, hi); | 6292 // required one word at a time. |
| 6289 // The mask has high (7th) bit set in every byte that needs | 6293 while (src <= limit - sizeof(uintptr_t)) { |
| 6290 // conversion and we know that the distance between cases is | 6294 uintptr_t w = *reinterpret_cast<uintptr_t*>(src); |
| 6291 // 1 << 5. | 6295 or_acc |= w; |
| 6292 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2); | 6296 uintptr_t m = AsciiRangeMask(w, lo, hi); |
| 6293 src += sizeof(uintptr_t); | 6297 // The mask has high (7th) bit set in every byte that needs |
| 6294 dst += sizeof(uintptr_t); | 6298 // conversion and we know that the distance between cases is |
| 6299 // 1 << 5. |
| 6300 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2); |
| 6301 src += sizeof(uintptr_t); |
| 6302 dst += sizeof(uintptr_t); |
| 6303 } |
| 6304 #endif |
| 6305 // Process the last few bytes of the input (or the whole input if |
| 6306 // unaligned access is not supported). |
| 6307 while (src < limit) { |
| 6308 char c = *src; |
| 6309 or_acc |= c; |
| 6310 if (lo < c && c < hi) { |
| 6311 c ^= (1 << 5); |
| 6312 changed = true; |
| 6295 } | 6313 } |
| 6296 #endif | 6314 *dst = c; |
| 6297 // Process the last few bytes of the input (or the whole input if | 6315 ++src; |
| 6298 // unaligned access is not supported). | 6316 ++dst; |
| 6299 while (src < limit) { | 6317 } |
| 6300 char c = *src; | 6318 if ((or_acc & kAsciiMask) != 0) { |
| 6301 or_acc |= c; | 6319 return false; |
| 6302 if (lo < c && c < hi) { | |
| 6303 c ^= (1 << 5); | |
| 6304 changed = true; | |
| 6305 } | |
| 6306 *dst = c; | |
| 6307 ++src; | |
| 6308 ++dst; | |
| 6309 } | |
| 6310 if ((or_acc & kAsciiMask) != 0) { | |
| 6311 return false; | |
| 6312 } | |
| 6313 #ifdef DEBUG | |
| 6314 CheckConvert(saved_dst, saved_src, length, changed); | |
| 6315 #endif | |
| 6316 *changed_out = changed; | |
| 6317 return true; | |
| 6318 } | 6320 } |
| 6319 | 6321 |
| 6322 ASSERT(CheckFastAsciiConvert( |
| 6323 saved_dst, saved_src, length, changed, Converter::kIsToLower)); |
| 6324 |
| 6325 *changed_out = changed; |
| 6326 return true; |
| 6327 } |
| 6328 |
| 6320 #ifdef DEBUG | 6329 #ifdef DEBUG |
| 6321 static void CheckConvert(char* dst, char* src, int length, bool changed) { | 6330 static bool CheckFastAsciiConvert(char* dst, |
| 6322 bool expected_changed = false; | 6331 char* src, |
| 6323 for (int i = 0; i < length; i++) { | 6332 int length, |
| 6324 if (dst[i] == src[i]) continue; | 6333 bool changed, |
| 6325 expected_changed = true; | 6334 bool is_to_lower) { |
| 6326 if (dir == ASCII_TO_LOWER) { | 6335 bool expected_changed = false; |
| 6327 ASSERT('A' <= src[i] && src[i] <= 'Z'); | 6336 for (int i = 0; i < length; i++) { |
| 6328 ASSERT(dst[i] == src[i] + ('a' - 'A')); | 6337 if (dst[i] == src[i]) continue; |
| 6329 } else { | 6338 expected_changed = true; |
| 6330 ASSERT(dir == ASCII_TO_UPPER); | 6339 if (is_to_lower) { |
| 6331 ASSERT('a' <= src[i] && src[i] <= 'z'); | 6340 ASSERT('A' <= src[i] && src[i] <= 'Z'); |
| 6332 ASSERT(dst[i] == src[i] - ('a' - 'A')); | 6341 ASSERT(dst[i] == src[i] + ('a' - 'A')); |
| 6333 } | 6342 } else { |
| 6343 ASSERT('a' <= src[i] && src[i] <= 'z'); |
| 6344 ASSERT(dst[i] == src[i] - ('a' - 'A')); |
| 6334 } | 6345 } |
| 6335 ASSERT(expected_changed == changed); | |
| 6336 } | 6346 } |
| 6347 return (expected_changed == changed); |
| 6348 } |
| 6337 #endif | 6349 #endif |
| 6338 }; | |
| 6339 | |
| 6340 | |
| 6341 struct ToLowerTraits { | |
| 6342 typedef unibrow::ToLowercase UnibrowConverter; | |
| 6343 | |
| 6344 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter; | |
| 6345 }; | |
| 6346 | |
| 6347 | |
| 6348 struct ToUpperTraits { | |
| 6349 typedef unibrow::ToUppercase UnibrowConverter; | |
| 6350 | |
| 6351 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter; | |
| 6352 }; | |
| 6353 | 6350 |
| 6354 } // namespace | 6351 } // namespace |
| 6355 | 6352 |
| 6356 | 6353 |
| 6357 template <typename ConvertTraits> | 6354 template <class Converter> |
| 6358 MUST_USE_RESULT static MaybeObject* ConvertCase( | 6355 MUST_USE_RESULT static MaybeObject* ConvertCase( |
| 6359 Arguments args, | 6356 Arguments args, |
| 6360 Isolate* isolate, | 6357 Isolate* isolate, |
| 6361 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) { | 6358 unibrow::Mapping<Converter, 128>* mapping) { |
| 6362 SealHandleScope shs(isolate); | 6359 SealHandleScope shs(isolate); |
| 6363 CONVERT_ARG_CHECKED(String, s, 0); | 6360 CONVERT_ARG_CHECKED(String, s, 0); |
| 6364 s = s->TryFlattenGetString(); | 6361 s = s->TryFlattenGetString(); |
| 6365 | 6362 |
| 6366 const int length = s->length(); | 6363 const int length = s->length(); |
| 6367 // Assume that the string is not empty; we need this assumption later | 6364 // Assume that the string is not empty; we need this assumption later |
| 6368 if (length == 0) return s; | 6365 if (length == 0) return s; |
| 6369 | 6366 |
| 6370 // Simpler handling of ASCII strings. | 6367 // Simpler handling of ASCII strings. |
| 6371 // | 6368 // |
| 6372 // NOTE: This assumes that the upper/lower case of an ASCII | 6369 // NOTE: This assumes that the upper/lower case of an ASCII |
| 6373 // character is also ASCII. This is currently the case, but it | 6370 // character is also ASCII. This is currently the case, but it |
| 6374 // might break in the future if we implement more context and locale | 6371 // might break in the future if we implement more context and locale |
| 6375 // dependent upper/lower conversions. | 6372 // dependent upper/lower conversions. |
| 6376 if (s->IsSeqOneByteString()) { | 6373 if (s->IsSeqOneByteString()) { |
| 6377 Object* o; | 6374 Object* o; |
| 6378 { MaybeObject* maybe_o = isolate->heap()->AllocateRawOneByteString(length); | 6375 { MaybeObject* maybe_o = isolate->heap()->AllocateRawOneByteString(length); |
| 6379 if (!maybe_o->ToObject(&o)) return maybe_o; | 6376 if (!maybe_o->ToObject(&o)) return maybe_o; |
| 6380 } | 6377 } |
| 6381 SeqOneByteString* result = SeqOneByteString::cast(o); | 6378 SeqOneByteString* result = SeqOneByteString::cast(o); |
| 6382 bool has_changed_character; | 6379 bool has_changed_character; |
| 6383 bool is_ascii = ConvertTraits::AsciiConverter::Convert( | 6380 bool is_ascii = FastAsciiConvert<Converter>( |
| 6384 reinterpret_cast<char*>(result->GetChars()), | 6381 reinterpret_cast<char*>(result->GetChars()), |
| 6385 reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()), | 6382 reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()), |
| 6386 length, | 6383 length, |
| 6387 &has_changed_character); | 6384 &has_changed_character); |
| 6388 // If not ASCII, we discard the result and take the 2 byte path. | 6385 // If not ASCII, we discard the result and take the 2 byte path. |
| 6389 if (is_ascii) { | 6386 if (is_ascii) { |
| 6390 return has_changed_character ? result : s; | 6387 return has_changed_character ? result : s; |
| 6391 } | 6388 } |
| 6392 } | 6389 } |
| 6393 | 6390 |
| 6391 String::Encoding result_encoding = s->IsOneByteRepresentation() |
| 6392 ? String::ONE_BYTE_ENCODING : String::TWO_BYTE_ENCODING; |
| 6394 Object* answer; | 6393 Object* answer; |
| 6395 { MaybeObject* maybe_answer = | 6394 { MaybeObject* maybe_answer = ConvertCaseHelper( |
| 6396 ConvertCaseHelper(isolate, s, length, length, mapping); | 6395 isolate, s, result_encoding, length, length, mapping); |
| 6397 if (!maybe_answer->ToObject(&answer)) return maybe_answer; | 6396 if (!maybe_answer->ToObject(&answer)) return maybe_answer; |
| 6398 } | 6397 } |
| 6399 if (answer->IsSmi()) { | 6398 if (answer->IsSmi()) { |
| 6400 // Retry with correct length. | 6399 int new_length = Smi::cast(answer)->value(); |
| 6401 { MaybeObject* maybe_answer = | 6400 if (new_length < 0) { |
| 6402 ConvertCaseHelper(isolate, | 6401 result_encoding = String::TWO_BYTE_ENCODING; |
| 6403 s, Smi::cast(answer)->value(), length, mapping); | 6402 new_length = -new_length; |
| 6404 if (!maybe_answer->ToObject(&answer)) return maybe_answer; | |
| 6405 } | 6403 } |
| 6404 MaybeObject* maybe_answer = ConvertCaseHelper( |
| 6405 isolate, s, result_encoding, new_length, length, mapping); |
| 6406 if (!maybe_answer->ToObject(&answer)) return maybe_answer; |
| 6406 } | 6407 } |
| 6407 return answer; | 6408 return answer; |
| 6408 } | 6409 } |
| 6409 | 6410 |
| 6410 | 6411 |
| 6411 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) { | 6412 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) { |
| 6412 return ConvertCase<ToLowerTraits>( | 6413 return ConvertCase( |
| 6413 args, isolate, isolate->runtime_state()->to_lower_mapping()); | 6414 args, isolate, isolate->runtime_state()->to_lower_mapping()); |
| 6414 } | 6415 } |
| 6415 | 6416 |
| 6416 | 6417 |
| 6417 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) { | 6418 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) { |
| 6418 return ConvertCase<ToUpperTraits>( | 6419 return ConvertCase( |
| 6419 args, isolate, isolate->runtime_state()->to_upper_mapping()); | 6420 args, isolate, isolate->runtime_state()->to_upper_mapping()); |
| 6420 } | 6421 } |
| 6421 | 6422 |
| 6422 | 6423 |
| 6423 static inline bool IsTrimWhiteSpace(unibrow::uchar c) { | 6424 static inline bool IsTrimWhiteSpace(unibrow::uchar c) { |
| 6424 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff; | 6425 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff; |
| 6425 } | 6426 } |
| 6426 | 6427 |
| 6427 | 6428 |
| 6428 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) { | 6429 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) { |
| (...skipping 8075 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14504 // Handle last resort GC and make sure to allow future allocations | 14505 // Handle last resort GC and make sure to allow future allocations |
| 14505 // to grow the heap without causing GCs (if possible). | 14506 // to grow the heap without causing GCs (if possible). |
| 14506 isolate->counters()->gc_last_resort_from_js()->Increment(); | 14507 isolate->counters()->gc_last_resort_from_js()->Increment(); |
| 14507 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, | 14508 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, |
| 14508 "Runtime::PerformGC"); | 14509 "Runtime::PerformGC"); |
| 14509 } | 14510 } |
| 14510 } | 14511 } |
| 14511 | 14512 |
| 14512 | 14513 |
| 14513 } } // namespace v8::internal | 14514 } } // namespace v8::internal |
| OLD | NEW |