LCOV - code coverage report
Current view: top level - src/builtins - builtins-string.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 115 118 97.5 %
Date: 2019-01-20 Functions: 16 22 72.7 %

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

Generated by: LCOV version 1.10