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