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