LCOV - code coverage report
Current view: top level - src/builtins - builtins-string.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 103 193 53.4 %
Date: 2017-04-26 Functions: 18 45 40.0 %

          Line data    Source code
       1             : // Copyright 2016 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/builtins/builtins-utils.h"
       6             : #include "src/builtins/builtins.h"
       7             : #include "src/conversions.h"
       8             : #include "src/counters.h"
       9             : #include "src/objects-inl.h"
      10             : #include "src/regexp/regexp-utils.h"
      11             : #include "src/string-case.h"
      12             : #include "src/unicode-inl.h"
      13             : #include "src/unicode.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : namespace {  // for String.fromCodePoint
      19             : 
      20    16974232 : bool IsValidCodePoint(Isolate* isolate, Handle<Object> value) {
      21    16974232 :   if (!value->IsNumber() && !Object::ToNumber(value).ToHandle(&value)) {
      22             :     return false;
      23             :   }
      24             : 
      25    16974232 :   if (Object::ToInteger(isolate, value).ToHandleChecked()->Number() !=
      26             :       value->Number()) {
      27             :     return false;
      28             :   }
      29             : 
      30    33948211 :   if (value->Number() < 0 || value->Number() > 0x10FFFF) {
      31             :     return false;
      32             :   }
      33             : 
      34    16974020 :   return true;
      35             : }
      36             : 
      37    16974260 : uc32 NextCodePoint(Isolate* isolate, BuiltinArguments args, int index) {
      38    16974260 :   Handle<Object> value = args.at(1 + index);
      39    33948520 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::ToNumber(value), -1);
      40    16974232 :   if (!IsValidCodePoint(isolate, value)) {
      41             :     isolate->Throw(*isolate->factory()->NewRangeError(
      42         424 :         MessageTemplate::kInvalidCodePoint, value));
      43             :     return -1;
      44             :   }
      45             :   return DoubleToUint32(value->Number());
      46             : }
      47             : 
      48             : }  // namespace
      49             : 
      50             : // ES6 section 21.1.2.2 String.fromCodePoint ( ...codePoints )
      51    46793970 : BUILTIN(StringFromCodePoint) {
      52             :   HandleScope scope(isolate);
      53    15597990 :   int const length = args.length() - 1;
      54    15597990 :   if (length == 0) return isolate->heap()->empty_string();
      55             :   DCHECK_LT(0, length);
      56             : 
      57             :   // Optimistically assume that the resulting String contains only one byte
      58             :   // characters.
      59             :   List<uint8_t> one_byte_buffer(length);
      60             :   uc32 code = 0;
      61             :   int index;
      62    16289814 :   for (index = 0; index < length; index++) {
      63    16286118 :     code = NextCodePoint(isolate, args, index);
      64    16286118 :     if (code < 0) {
      65         240 :       return isolate->heap()->exception();
      66             :     }
      67    16285878 :     if (code > String::kMaxOneByteCharCode) {
      68             :       break;
      69             :     }
      70      691838 :     one_byte_buffer.Add(code);
      71             :   }
      72             : 
      73    15597736 :   if (index == length) {
      74       11088 :     RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromOneByte(
      75             :                                           one_byte_buffer.ToConstVector()));
      76             :   }
      77             : 
      78    15594040 :   List<uc16> two_byte_buffer(length - index);
      79             : 
      80             :   while (true) {
      81    16282182 :     if (code <= static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) {
      82      913934 :       two_byte_buffer.Add(code);
      83             :     } else {
      84    30736496 :       two_byte_buffer.Add(unibrow::Utf16::LeadSurrogate(code));
      85    15368248 :       two_byte_buffer.Add(unibrow::Utf16::TrailSurrogate(code));
      86             :     }
      87             : 
      88    16282182 :     if (++index == length) {
      89             :       break;
      90             :     }
      91      688142 :     code = NextCodePoint(isolate, args, index);
      92      688142 :     if (code < 0) {
      93           0 :       return isolate->heap()->exception();
      94             :     }
      95             :   }
      96             : 
      97             :   Handle<SeqTwoByteString> result;
      98    31188080 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
      99             :       isolate, result,
     100             :       isolate->factory()->NewRawTwoByteString(one_byte_buffer.length() +
     101             :                                               two_byte_buffer.length()));
     102             : 
     103    15594040 :   CopyChars(result->GetChars(), one_byte_buffer.ToConstVector().start(),
     104    31188080 :             one_byte_buffer.length());
     105             :   CopyChars(result->GetChars() + one_byte_buffer.length(),
     106    15594040 :             two_byte_buffer.ToConstVector().start(), two_byte_buffer.length());
     107             : 
     108    15594040 :   return *result;
     109             : }
     110             : 
     111             : // ES6 section 21.1.3.6
     112             : // String.prototype.endsWith ( searchString [ , endPosition ] )
     113       11511 : BUILTIN(StringPrototypeEndsWith) {
     114             :   HandleScope handle_scope(isolate);
     115        8178 :   TO_THIS_STRING(str, "String.prototype.endsWith");
     116             : 
     117             :   // Check if the search string is a regExp and fail if it is.
     118        3557 :   Handle<Object> search = args.atOrUndefined(isolate, 1);
     119        3557 :   Maybe<bool> is_reg_exp = RegExpUtils::IsRegExp(isolate, search);
     120        3557 :   if (is_reg_exp.IsNothing()) {
     121             :     DCHECK(isolate->has_pending_exception());
     122           0 :     return isolate->heap()->exception();
     123             :   }
     124        3557 :   if (is_reg_exp.FromJust()) {
     125         210 :     THROW_NEW_ERROR_RETURN_FAILURE(
     126             :         isolate, NewTypeError(MessageTemplate::kFirstArgumentNotRegExp,
     127             :                               isolate->factory()->NewStringFromStaticChars(
     128             :                                   "String.prototype.endsWith")));
     129             :   }
     130             :   Handle<String> search_string;
     131        6974 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
     132             :                                      Object::ToString(isolate, search));
     133             : 
     134             :   Handle<Object> position = args.atOrUndefined(isolate, 2);
     135             :   int end;
     136             : 
     137        3487 :   if (position->IsUndefined(isolate)) {
     138             :     end = str->length();
     139             :   } else {
     140        2142 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
     141             :                                        Object::ToInteger(isolate, position));
     142        2142 :     end = str->ToValidIndex(*position);
     143             :   }
     144             : 
     145        3487 :   int start = end - search_string->length();
     146        3487 :   if (start < 0) return isolate->heap()->false_value();
     147             : 
     148        2003 :   str = String::Flatten(str);
     149        2003 :   search_string = String::Flatten(search_string);
     150             : 
     151             :   DisallowHeapAllocation no_gc;  // ensure vectors stay valid
     152        2003 :   String::FlatContent str_content = str->GetFlatContent();
     153        2003 :   String::FlatContent search_content = search_string->GetFlatContent();
     154             : 
     155        2003 :   if (str_content.IsOneByte() && search_content.IsOneByte()) {
     156        1751 :     Vector<const uint8_t> str_vector = str_content.ToOneByteVector();
     157        1751 :     Vector<const uint8_t> search_vector = search_content.ToOneByteVector();
     158             : 
     159        1751 :     return isolate->heap()->ToBoolean(memcmp(str_vector.start() + start,
     160             :                                              search_vector.start(),
     161        3502 :                                              search_string->length()) == 0);
     162             :   }
     163             : 
     164         252 :   FlatStringReader str_reader(isolate, str);
     165         252 :   FlatStringReader search_reader(isolate, search_string);
     166             : 
     167        1736 :   for (int i = 0; i < search_string->length(); i++) {
     168        1344 :     if (str_reader.Get(start + i) != search_reader.Get(i)) {
     169          56 :       return isolate->heap()->false_value();
     170             :     }
     171             :   }
     172         196 :   return isolate->heap()->true_value();
     173             : }
     174             : 
     175             : // ES6 section 21.1.3.7
     176             : // String.prototype.includes ( searchString [ , position ] )
     177        6177 : BUILTIN(StringPrototypeIncludes) {
     178             :   HandleScope handle_scope(isolate);
     179        4286 :   TO_THIS_STRING(str, "String.prototype.includes");
     180             : 
     181             :   // Check if the search string is a regExp and fail if it is.
     182        1947 :   Handle<Object> search = args.atOrUndefined(isolate, 1);
     183        1947 :   Maybe<bool> is_reg_exp = RegExpUtils::IsRegExp(isolate, search);
     184        1947 :   if (is_reg_exp.IsNothing()) {
     185             :     DCHECK(isolate->has_pending_exception());
     186           0 :     return isolate->heap()->exception();
     187             :   }
     188        1947 :   if (is_reg_exp.FromJust()) {
     189         294 :     THROW_NEW_ERROR_RETURN_FAILURE(
     190             :         isolate, NewTypeError(MessageTemplate::kFirstArgumentNotRegExp,
     191             :                               isolate->factory()->NewStringFromStaticChars(
     192             :                                   "String.prototype.includes")));
     193             :   }
     194             :   Handle<String> search_string;
     195        3698 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
     196             :                                      Object::ToString(isolate, search));
     197             :   Handle<Object> position;
     198        1849 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     199             :       isolate, position,
     200             :       Object::ToInteger(isolate, args.atOrUndefined(isolate, 2)));
     201             : 
     202             :   uint32_t index = str->ToValidIndex(*position);
     203        1849 :   int index_in_str = String::IndexOf(isolate, str, search_string, index);
     204        3698 :   return *isolate->factory()->ToBoolean(index_in_str != -1);
     205             : }
     206             : 
     207             : // ES6 section 21.1.3.9
     208             : // String.prototype.lastIndexOf ( searchString [ , position ] )
     209        8223 : BUILTIN(StringPrototypeLastIndexOf) {
     210             :   HandleScope handle_scope(isolate);
     211             :   return String::LastIndexOf(isolate, args.receiver(),
     212             :                              args.atOrUndefined(isolate, 1),
     213        5482 :                              args.atOrUndefined(isolate, 2));
     214             : }
     215             : 
     216             : // ES6 section 21.1.3.10 String.prototype.localeCompare ( that )
     217             : //
     218             : // This function is implementation specific.  For now, we do not
     219             : // do anything locale specific.
     220             : // If internationalization is enabled, then intl.js will override this function
     221             : // and provide the proper functionality, so this is just a fallback.
     222           0 : BUILTIN(StringPrototypeLocaleCompare) {
     223             :   HandleScope handle_scope(isolate);
     224             :   DCHECK_EQ(2, args.length());
     225             : 
     226           0 :   TO_THIS_STRING(str1, "String.prototype.localeCompare");
     227             :   Handle<String> str2;
     228           0 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str2,
     229             :                                      Object::ToString(isolate, args.at(1)));
     230             : 
     231           0 :   if (str1.is_identical_to(str2)) return Smi::kZero;  // Equal.
     232             :   int str1_length = str1->length();
     233             :   int str2_length = str2->length();
     234             : 
     235             :   // Decide trivial cases without flattening.
     236           0 :   if (str1_length == 0) {
     237           0 :     if (str2_length == 0) return Smi::kZero;  // Equal.
     238           0 :     return Smi::FromInt(-str2_length);
     239             :   } else {
     240           0 :     if (str2_length == 0) return Smi::FromInt(str1_length);
     241             :   }
     242             : 
     243           0 :   int end = str1_length < str2_length ? str1_length : str2_length;
     244             : 
     245             :   // No need to flatten if we are going to find the answer on the first
     246             :   // character. At this point we know there is at least one character
     247             :   // in each string, due to the trivial case handling above.
     248           0 :   int d = str1->Get(0) - str2->Get(0);
     249           0 :   if (d != 0) return Smi::FromInt(d);
     250             : 
     251           0 :   str1 = String::Flatten(str1);
     252           0 :   str2 = String::Flatten(str2);
     253             : 
     254             :   DisallowHeapAllocation no_gc;
     255           0 :   String::FlatContent flat1 = str1->GetFlatContent();
     256           0 :   String::FlatContent flat2 = str2->GetFlatContent();
     257             : 
     258           0 :   for (int i = 0; i < end; i++) {
     259           0 :     if (flat1.Get(i) != flat2.Get(i)) {
     260           0 :       return Smi::FromInt(flat1.Get(i) - flat2.Get(i));
     261             :     }
     262             :   }
     263             : 
     264           0 :   return Smi::FromInt(str1_length - str2_length);
     265             : }
     266             : 
     267             : #ifndef V8_INTL_SUPPORT
     268             : // ES6 section 21.1.3.12 String.prototype.normalize ( [form] )
     269             : //
     270             : // Simply checks the argument is valid and returns the string itself.
     271             : // If internationalization is enabled, then intl.js will override this function
     272             : // and provide the proper functionality, so this is just a fallback.
     273             : BUILTIN(StringPrototypeNormalize) {
     274             :   HandleScope handle_scope(isolate);
     275             :   TO_THIS_STRING(string, "String.prototype.normalize");
     276             : 
     277             :   Handle<Object> form_input = args.atOrUndefined(isolate, 1);
     278             :   if (form_input->IsUndefined(isolate)) return *string;
     279             : 
     280             :   Handle<String> form;
     281             :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, form,
     282             :                                      Object::ToString(isolate, form_input));
     283             : 
     284             :   if (!(String::Equals(form,
     285             :                        isolate->factory()->NewStringFromStaticChars("NFC")) ||
     286             :         String::Equals(form,
     287             :                        isolate->factory()->NewStringFromStaticChars("NFD")) ||
     288             :         String::Equals(form,
     289             :                        isolate->factory()->NewStringFromStaticChars("NFKC")) ||
     290             :         String::Equals(form,
     291             :                        isolate->factory()->NewStringFromStaticChars("NFKD")))) {
     292             :     Handle<String> valid_forms =
     293             :         isolate->factory()->NewStringFromStaticChars("NFC, NFD, NFKC, NFKD");
     294             :     THROW_NEW_ERROR_RETURN_FAILURE(
     295             :         isolate,
     296             :         NewRangeError(MessageTemplate::kNormalizationForm, valid_forms));
     297             :   }
     298             : 
     299             :   return *string;
     300             : }
     301             : #endif  // !V8_INTL_SUPPORT
     302             : 
     303       52302 : BUILTIN(StringPrototypeStartsWith) {
     304             :   HandleScope handle_scope(isolate);
     305       35372 :   TO_THIS_STRING(str, "String.prototype.startsWith");
     306             : 
     307             :   // Check if the search string is a regExp and fail if it is.
     308       17154 :   Handle<Object> search = args.atOrUndefined(isolate, 1);
     309       17154 :   Maybe<bool> is_reg_exp = RegExpUtils::IsRegExp(isolate, search);
     310       17154 :   if (is_reg_exp.IsNothing()) {
     311             :     DCHECK(isolate->has_pending_exception());
     312           0 :     return isolate->heap()->exception();
     313             :   }
     314       17154 :   if (is_reg_exp.FromJust()) {
     315         339 :     THROW_NEW_ERROR_RETURN_FAILURE(
     316             :         isolate, NewTypeError(MessageTemplate::kFirstArgumentNotRegExp,
     317             :                               isolate->factory()->NewStringFromStaticChars(
     318             :                                   "String.prototype.startsWith")));
     319             :   }
     320             :   Handle<String> search_string;
     321       34082 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
     322             :                                      Object::ToString(isolate, search));
     323             : 
     324             :   Handle<Object> position = args.atOrUndefined(isolate, 2);
     325             :   int start;
     326             : 
     327       17041 :   if (position->IsUndefined(isolate)) {
     328             :     start = 0;
     329             :   } else {
     330        2030 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
     331             :                                        Object::ToInteger(isolate, position));
     332        2030 :     start = str->ToValidIndex(*position);
     333             :   }
     334             : 
     335       34082 :   if (start + search_string->length() > str->length()) {
     336         894 :     return isolate->heap()->false_value();
     337             :   }
     338             : 
     339       16147 :   FlatStringReader str_reader(isolate, String::Flatten(str));
     340       16147 :   FlatStringReader search_reader(isolate, String::Flatten(search_string));
     341             : 
     342      193480 :   for (int i = 0; i < search_string->length(); i++) {
     343      183950 :     if (str_reader.Get(start + i) != search_reader.Get(i)) {
     344       11382 :       return isolate->heap()->false_value();
     345             :     }
     346             :   }
     347        4765 :   return isolate->heap()->true_value();
     348             : }
     349             : 
     350             : // ES6 section 21.1.3.27 String.prototype.trim ()
     351     5510814 : BUILTIN(StringPrototypeTrim) {
     352             :   HandleScope scope(isolate);
     353     3674416 :   TO_THIS_STRING(string, "String.prototype.trim");
     354     3673336 :   return *String::Trim(string, String::kTrim);
     355             : }
     356             : 
     357             : // Non-standard WebKit extension
     358        2646 : BUILTIN(StringPrototypeTrimLeft) {
     359             :   HandleScope scope(isolate);
     360        1764 :   TO_THIS_STRING(string, "String.prototype.trimLeft");
     361        1764 :   return *String::Trim(string, String::kTrimLeft);
     362             : }
     363             : 
     364             : // Non-standard WebKit extension
     365        1512 : BUILTIN(StringPrototypeTrimRight) {
     366             :   HandleScope scope(isolate);
     367        1008 :   TO_THIS_STRING(string, "String.prototype.trimRight");
     368        1008 :   return *String::Trim(string, String::kTrimRight);
     369             : }
     370             : 
     371             : namespace {
     372             : 
     373             : inline bool ToUpperOverflows(uc32 character) {
     374             :   // y with umlauts and the micro sign are the only characters that stop
     375             :   // fitting into one-byte when converting to uppercase.
     376             :   static const uc32 yuml_code = 0xff;
     377             :   static const uc32 micro_code = 0xb5;
     378           0 :   return (character == yuml_code || character == micro_code);
     379             : }
     380             : 
     381             : template <class Converter>
     382           0 : MUST_USE_RESULT static Object* ConvertCaseHelper(
     383             :     Isolate* isolate, String* string, SeqString* result, int result_length,
     384             :     unibrow::Mapping<Converter, 128>* mapping) {
     385             :   DisallowHeapAllocation no_gc;
     386             :   // We try this twice, once with the assumption that the result is no longer
     387             :   // than the input and, if that assumption breaks, again with the exact
     388             :   // length.  This may not be pretty, but it is nicer than what was here before
     389             :   // and I hereby claim my vaffel-is.
     390             :   //
     391             :   // NOTE: This assumes that the upper/lower case of an ASCII
     392             :   // character is also ASCII.  This is currently the case, but it
     393             :   // might break in the future if we implement more context and locale
     394             :   // dependent upper/lower conversions.
     395             :   bool has_changed_character = false;
     396             : 
     397             :   // Convert all characters to upper case, assuming that they will fit
     398             :   // in the buffer
     399             :   StringCharacterStream stream(string);
     400             :   unibrow::uchar chars[Converter::kMaxWidth];
     401             :   // We can assume that the string is not empty
     402           0 :   uc32 current = stream.GetNext();
     403             :   bool ignore_overflow = Converter::kIsToLower || result->IsSeqTwoByteString();
     404           0 :   for (int i = 0; i < result_length;) {
     405           0 :     bool has_next = stream.HasMore();
     406           0 :     uc32 next = has_next ? stream.GetNext() : 0;
     407           0 :     int char_length = mapping->get(current, next, chars);
     408           0 :     if (char_length == 0) {
     409             :       // The case conversion of this character is the character itself.
     410           0 :       result->Set(i, current);
     411           0 :       i++;
     412           0 :     } else if (char_length == 1 &&
     413             :                (ignore_overflow || !ToUpperOverflows(current))) {
     414             :       // Common case: converting the letter resulted in one character.
     415             :       DCHECK(static_cast<uc32>(chars[0]) != current);
     416           0 :       result->Set(i, chars[0]);
     417             :       has_changed_character = true;
     418           0 :       i++;
     419           0 :     } else if (result_length == string->length()) {
     420             :       bool overflows = ToUpperOverflows(current);
     421             :       // We've assumed that the result would be as long as the
     422             :       // input but here is a character that converts to several
     423             :       // characters.  No matter, we calculate the exact length
     424             :       // of the result and try the whole thing again.
     425             :       //
     426             :       // Note that this leaves room for optimization.  We could just
     427             :       // memcpy what we already have to the result string.  Also,
     428             :       // the result string is the last object allocated we could
     429             :       // "realloc" it and probably, in the vast majority of cases,
     430             :       // extend the existing string to be able to hold the full
     431             :       // result.
     432             :       int next_length = 0;
     433           0 :       if (has_next) {
     434           0 :         next_length = mapping->get(next, 0, chars);
     435           0 :         if (next_length == 0) next_length = 1;
     436             :       }
     437           0 :       int current_length = i + char_length + next_length;
     438           0 :       while (stream.HasMore()) {
     439           0 :         current = stream.GetNext();
     440           0 :         overflows |= ToUpperOverflows(current);
     441             :         // NOTE: we use 0 as the next character here because, while
     442             :         // the next character may affect what a character converts to,
     443             :         // it does not in any case affect the length of what it convert
     444             :         // to.
     445           0 :         int char_length = mapping->get(current, 0, chars);
     446           0 :         if (char_length == 0) char_length = 1;
     447           0 :         current_length += char_length;
     448           0 :         if (current_length > String::kMaxLength) {
     449             :           AllowHeapAllocation allocate_error_and_return;
     450           0 :           THROW_NEW_ERROR_RETURN_FAILURE(isolate,
     451             :                                          NewInvalidStringLengthError());
     452             :         }
     453             :       }
     454             :       // Try again with the real length.  Return signed if we need
     455             :       // to allocate a two-byte string for to uppercase.
     456           0 :       return (overflows && !ignore_overflow) ? Smi::FromInt(-current_length)
     457           0 :                                              : Smi::FromInt(current_length);
     458             :     } else {
     459           0 :       for (int j = 0; j < char_length; j++) {
     460           0 :         result->Set(i, chars[j]);
     461           0 :         i++;
     462             :       }
     463             :       has_changed_character = true;
     464             :     }
     465             :     current = next;
     466             :   }
     467           0 :   if (has_changed_character) {
     468             :     return result;
     469             :   } else {
     470             :     // If we didn't actually change anything in doing the conversion
     471             :     // we simple return the result and let the converted string
     472             :     // become garbage; there is no reason to keep two identical strings
     473             :     // alive.
     474           0 :     return string;
     475             :   }
     476             : }
     477             : 
     478             : template <class Converter>
     479           0 : MUST_USE_RESULT static Object* ConvertCase(
     480             :     Handle<String> s, Isolate* isolate,
     481             :     unibrow::Mapping<Converter, 128>* mapping) {
     482           0 :   s = String::Flatten(s);
     483             :   int length = s->length();
     484             :   // Assume that the string is not empty; we need this assumption later
     485           0 :   if (length == 0) return *s;
     486             : 
     487             :   // Simpler handling of ASCII strings.
     488             :   //
     489             :   // NOTE: This assumes that the upper/lower case of an ASCII
     490             :   // character is also ASCII.  This is currently the case, but it
     491             :   // might break in the future if we implement more context and locale
     492             :   // dependent upper/lower conversions.
     493           0 :   if (s->IsOneByteRepresentationUnderneath()) {
     494             :     // Same length as input.
     495             :     Handle<SeqOneByteString> result =
     496           0 :         isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
     497             :     DisallowHeapAllocation no_gc;
     498           0 :     String::FlatContent flat_content = s->GetFlatContent();
     499             :     DCHECK(flat_content.IsFlat());
     500           0 :     bool has_changed_character = false;
     501             :     int index_to_first_unprocessed = FastAsciiConvert<Converter::kIsToLower>(
     502           0 :         reinterpret_cast<char*>(result->GetChars()),
     503           0 :         reinterpret_cast<const char*>(flat_content.ToOneByteVector().start()),
     504           0 :         length, &has_changed_character);
     505             :     // If not ASCII, we discard the result and take the 2 byte path.
     506           0 :     if (index_to_first_unprocessed == length)
     507           0 :       return has_changed_character ? *result : *s;
     508             :   }
     509             : 
     510             :   Handle<SeqString> result;  // Same length as input.
     511           0 :   if (s->IsOneByteRepresentation()) {
     512           0 :     result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
     513             :   } else {
     514           0 :     result = isolate->factory()->NewRawTwoByteString(length).ToHandleChecked();
     515             :   }
     516             : 
     517           0 :   Object* answer = ConvertCaseHelper(isolate, *s, *result, length, mapping);
     518           0 :   if (answer->IsException(isolate) || answer->IsString()) return answer;
     519             : 
     520             :   DCHECK(answer->IsSmi());
     521             :   length = Smi::cast(answer)->value();
     522           0 :   if (s->IsOneByteRepresentation() && length > 0) {
     523           0 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     524             :         isolate, result, isolate->factory()->NewRawOneByteString(length));
     525             :   } else {
     526           0 :     if (length < 0) length = -length;
     527           0 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     528             :         isolate, result, isolate->factory()->NewRawTwoByteString(length));
     529             :   }
     530           0 :   return ConvertCaseHelper(isolate, *s, *result, length, mapping);
     531             : }
     532             : 
     533             : }  // namespace
     534             : 
     535           0 : BUILTIN(StringPrototypeToLocaleLowerCase) {
     536             :   HandleScope scope(isolate);
     537           0 :   TO_THIS_STRING(string, "String.prototype.toLocaleLowerCase");
     538             :   return ConvertCase(string, isolate,
     539           0 :                      isolate->runtime_state()->to_lower_mapping());
     540             : }
     541             : 
     542           0 : BUILTIN(StringPrototypeToLocaleUpperCase) {
     543             :   HandleScope scope(isolate);
     544           0 :   TO_THIS_STRING(string, "String.prototype.toLocaleUpperCase");
     545             :   return ConvertCase(string, isolate,
     546           0 :                      isolate->runtime_state()->to_upper_mapping());
     547             : }
     548             : 
     549           0 : BUILTIN(StringPrototypeToLowerCase) {
     550             :   HandleScope scope(isolate);
     551           0 :   TO_THIS_STRING(string, "String.prototype.toLowerCase");
     552             :   return ConvertCase(string, isolate,
     553           0 :                      isolate->runtime_state()->to_lower_mapping());
     554             : }
     555             : 
     556           0 : BUILTIN(StringPrototypeToUpperCase) {
     557             :   HandleScope scope(isolate);
     558           0 :   TO_THIS_STRING(string, "String.prototype.toUpperCase");
     559             :   return ConvertCase(string, isolate,
     560           0 :                      isolate->runtime_state()->to_upper_mapping());
     561             : }
     562             : 
     563             : }  // namespace internal
     564             : }  // namespace v8

Generated by: LCOV version 1.10