LCOV - code coverage report
Current view: top level - src/runtime - runtime-strings.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 304 346 87.9 %
Date: 2017-04-26 Functions: 32 64 50.0 %

          Line data    Source code
       1             : // Copyright 2014 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/runtime/runtime-utils.h"
       6             : 
       7             : #include "src/arguments.h"
       8             : #include "src/conversions.h"
       9             : #include "src/counters.h"
      10             : #include "src/objects-inl.h"
      11             : #include "src/regexp/jsregexp-inl.h"
      12             : #include "src/string-builder.h"
      13             : #include "src/string-search.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18         510 : RUNTIME_FUNCTION(Runtime_GetSubstitution) {
      19         255 :   HandleScope scope(isolate);
      20             :   DCHECK_EQ(5, args.length());
      21         510 :   CONVERT_ARG_HANDLE_CHECKED(String, matched, 0);
      22         510 :   CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
      23         510 :   CONVERT_SMI_ARG_CHECKED(position, 2);
      24         510 :   CONVERT_ARG_HANDLE_CHECKED(String, replacement, 3);
      25         510 :   CONVERT_SMI_ARG_CHECKED(start_index, 4);
      26             : 
      27             :   // A simple match without captures.
      28         510 :   class SimpleMatch : public String::Match {
      29             :    public:
      30         255 :     SimpleMatch(Handle<String> match, Handle<String> prefix,
      31             :                 Handle<String> suffix)
      32         255 :         : match_(match), prefix_(prefix), suffix_(suffix) {}
      33             : 
      34          60 :     Handle<String> GetMatch() override { return match_; }
      35          30 :     Handle<String> GetPrefix() override { return prefix_; }
      36          30 :     Handle<String> GetSuffix() override { return suffix_; }
      37             : 
      38         255 :     int CaptureCount() override { return 0; }
      39           0 :     bool HasNamedCaptures() override { return false; }
      40           0 :     MaybeHandle<String> GetCapture(int i, bool* capture_exists) override {
      41           0 :       *capture_exists = false;
      42           0 :       return match_;  // Return arbitrary string handle.
      43             :     }
      44           0 :     MaybeHandle<String> GetNamedCapture(Handle<String> name,
      45             :                                         CaptureState* state) override {
      46           0 :       UNREACHABLE();
      47             :       *state = INVALID;
      48             :       return MaybeHandle<String>();
      49             :     }
      50             : 
      51             :    private:
      52             :     Handle<String> match_, prefix_, suffix_;
      53             :   };
      54             : 
      55             :   Handle<String> prefix =
      56         255 :       isolate->factory()->NewSubString(subject, 0, position);
      57             :   Handle<String> suffix = isolate->factory()->NewSubString(
      58         510 :       subject, position + matched->length(), subject->length());
      59         510 :   SimpleMatch match(matched, prefix, suffix);
      60             : 
      61         510 :   RETURN_RESULT_OR_FAILURE(
      62             :       isolate,
      63         255 :       String::GetSubstitution(isolate, &match, replacement, start_index));
      64             : }
      65             : 
      66             : // This may return an empty MaybeHandle if an exception is thrown or
      67             : // we abort due to reaching the recursion limit.
      68      138221 : MaybeHandle<String> StringReplaceOneCharWithString(
      69             :     Isolate* isolate, Handle<String> subject, Handle<String> search,
      70             :     Handle<String> replace, bool* found, int recursion_limit) {
      71             :   StackLimitCheck stackLimitCheck(isolate);
      72      138221 :   if (stackLimitCheck.HasOverflowed() || (recursion_limit == 0)) {
      73             :     return MaybeHandle<String>();
      74             :   }
      75      137557 :   recursion_limit--;
      76      137557 :   if (subject->IsConsString()) {
      77             :     ConsString* cons = ConsString::cast(*subject);
      78             :     Handle<String> first = Handle<String>(cons->first());
      79             :     Handle<String> second = Handle<String>(cons->second());
      80             :     Handle<String> new_first;
      81      130128 :     if (!StringReplaceOneCharWithString(isolate, first, search, replace, found,
      82      260256 :                                         recursion_limit).ToHandle(&new_first)) {
      83             :       return MaybeHandle<String>();
      84             :     }
      85        7216 :     if (*found) return isolate->factory()->NewConsString(new_first, second);
      86             : 
      87             :     Handle<String> new_second;
      88        7216 :     if (!StringReplaceOneCharWithString(isolate, second, search, replace, found,
      89             :                                         recursion_limit)
      90       14432 :              .ToHandle(&new_second)) {
      91             :       return MaybeHandle<String>();
      92             :     }
      93        7186 :     if (*found) return isolate->factory()->NewConsString(first, new_second);
      94             : 
      95             :     return subject;
      96             :   } else {
      97        7429 :     int index = String::IndexOf(isolate, subject, search, 0);
      98        7429 :     if (index == -1) return subject;
      99          60 :     *found = true;
     100          60 :     Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
     101             :     Handle<String> cons1;
     102         120 :     ASSIGN_RETURN_ON_EXCEPTION(
     103             :         isolate, cons1, isolate->factory()->NewConsString(first, replace),
     104             :         String);
     105             :     Handle<String> second =
     106          60 :         isolate->factory()->NewSubString(subject, index + 1, subject->length());
     107          60 :     return isolate->factory()->NewConsString(cons1, second);
     108             :   }
     109             : }
     110             : 
     111             : 
     112         998 : RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) {
     113         499 :   HandleScope scope(isolate);
     114             :   DCHECK_EQ(3, args.length());
     115         998 :   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
     116         998 :   CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
     117         998 :   CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
     118             : 
     119             :   // If the cons string tree is too deep, we simply abort the recursion and
     120             :   // retry with a flattened subject string.
     121             :   const int kRecursionLimit = 0x1000;
     122         499 :   bool found = false;
     123             :   Handle<String> result;
     124         499 :   if (StringReplaceOneCharWithString(isolate, subject, search, replace, &found,
     125         998 :                                      kRecursionLimit).ToHandle(&result)) {
     126             :     return *result;
     127             :   }
     128         378 :   if (isolate->has_pending_exception()) return isolate->heap()->exception();
     129             : 
     130         378 :   subject = String::Flatten(subject);
     131         378 :   if (StringReplaceOneCharWithString(isolate, subject, search, replace, &found,
     132         756 :                                      kRecursionLimit).ToHandle(&result)) {
     133             :     return *result;
     134             :   }
     135         286 :   if (isolate->has_pending_exception()) return isolate->heap()->exception();
     136             :   // In case of empty handle and no pending exception we have stack overflow.
     137         286 :   return isolate->StackOverflow();
     138             : }
     139             : 
     140             : // ES6 #sec-string.prototype.indexof
     141             : // String.prototype.indexOf(searchString [, position])
     142        6766 : RUNTIME_FUNCTION(Runtime_StringIndexOf) {
     143        3383 :   HandleScope scope(isolate);
     144             :   DCHECK_EQ(3, args.length());
     145        3383 :   return String::IndexOf(isolate, args.at(0), args.at(1), args.at(2));
     146             : }
     147             : 
     148             : // ES6 #sec-string.prototype.indexof
     149             : // String.prototype.indexOf(searchString, position)
     150             : // Fast version that assumes that does not perform conversions of the incoming
     151             : // arguments.
     152      285744 : RUNTIME_FUNCTION(Runtime_StringIndexOfUnchecked) {
     153      142872 :   HandleScope scope(isolate);
     154             :   DCHECK_EQ(3, args.length());
     155      142872 :   Handle<String> receiver_string = args.at<String>(0);
     156      142872 :   Handle<String> search_string = args.at<String>(1);
     157      142872 :   int index = std::min(std::max(args.smi_at(2), 0), receiver_string->length());
     158             : 
     159             :   return Smi::FromInt(String::IndexOf(isolate, receiver_string, search_string,
     160      142872 :                                       static_cast<uint32_t>(index)));
     161             : }
     162             : 
     163         328 : RUNTIME_FUNCTION(Runtime_StringLastIndexOf) {
     164         164 :   HandleScope handle_scope(isolate);
     165             :   return String::LastIndexOf(isolate, args.at(0), args.at(1),
     166         328 :                              isolate->factory()->undefined_value());
     167             : }
     168             : 
     169     4493478 : RUNTIME_FUNCTION(Runtime_SubString) {
     170     1497852 :   HandleScope scope(isolate);
     171             :   DCHECK_EQ(3, args.length());
     172             : 
     173     2995704 :   CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
     174             :   int start, end;
     175             :   // We have a fast integer-only case here to avoid a conversion to double in
     176             :   // the common case where from and to are Smis.
     177     4493520 :   if (args[1]->IsSmi() && args[2]->IsSmi()) {
     178     1497804 :     CONVERT_SMI_ARG_CHECKED(from_number, 1);
     179     2995608 :     CONVERT_SMI_ARG_CHECKED(to_number, 2);
     180             :     start = from_number;
     181             :     end = to_number;
     182          84 :   } else if (args[1]->IsNumber() && args[2]->IsNumber()) {
     183          72 :     CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
     184          72 :     CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
     185          36 :     start = FastD2IChecked(from_number);
     186          36 :     end = FastD2IChecked(to_number);
     187             :   } else {
     188          12 :     return isolate->ThrowIllegalOperation();
     189             :   }
     190             :   // The following condition is intentionally robust because the SubStringStub
     191             :   // delegates here and we test this in cctest/test-strings/RobustSubStringStub.
     192     2995644 :   if (end < start || start < 0 || end > string->length()) {
     193          66 :     return isolate->ThrowIllegalOperation();
     194             :   }
     195     1497774 :   isolate->counters()->sub_string_runtime()->Increment();
     196             : 
     197     2995548 :   return *isolate->factory()->NewSubString(string, start, end);
     198             : }
     199             : 
     200             : 
     201    32442000 : RUNTIME_FUNCTION(Runtime_StringAdd) {
     202    10814000 :   HandleScope scope(isolate);
     203             :   DCHECK_EQ(2, args.length());
     204    21628000 :   CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
     205    21628000 :   CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
     206    10814000 :   isolate->counters()->string_add_runtime()->Increment();
     207    21628000 :   RETURN_RESULT_OR_FAILURE(isolate,
     208    10814000 :                            isolate->factory()->NewConsString(str1, str2));
     209             : }
     210             : 
     211             : 
     212        3000 : RUNTIME_FUNCTION(Runtime_InternalizeString) {
     213        1500 :   HandleScope handles(isolate);
     214             :   DCHECK_EQ(1, args.length());
     215        3000 :   CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
     216        3000 :   return *isolate->factory()->InternalizeString(string);
     217             : }
     218             : 
     219             : 
     220      912688 : RUNTIME_FUNCTION(Runtime_StringCharCodeAtRT) {
     221      458161 :   HandleScope handle_scope(isolate);
     222             :   DCHECK_EQ(2, args.length());
     223             : 
     224      916322 :   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
     225      916322 :   CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]);
     226             : 
     227             :   // Flatten the string.  If someone wants to get a char at an index
     228             :   // in a cons string, it is likely that more indices will be
     229             :   // accessed.
     230      458161 :   subject = String::Flatten(subject);
     231             : 
     232      458161 :   if (i >= static_cast<uint32_t>(subject->length())) {
     233         313 :     return isolate->heap()->nan_value();
     234             :   }
     235             : 
     236      915696 :   return Smi::FromInt(subject->Get(i));
     237             : }
     238             : 
     239             : 
     240       21177 : RUNTIME_FUNCTION(Runtime_StringCompare) {
     241        7059 :   HandleScope handle_scope(isolate);
     242             :   DCHECK_EQ(2, args.length());
     243       14118 :   CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
     244       14118 :   CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
     245        7059 :   isolate->counters()->string_compare_runtime()->Increment();
     246        7059 :   switch (String::Compare(x, y)) {
     247             :     case ComparisonResult::kLessThan:
     248        3023 :       return Smi::FromInt(LESS);
     249             :     case ComparisonResult::kEqual:
     250           7 :       return Smi::FromInt(EQUAL);
     251             :     case ComparisonResult::kGreaterThan:
     252        4029 :       return Smi::FromInt(GREATER);
     253             :     case ComparisonResult::kUndefined:
     254             :       break;
     255             :   }
     256           0 :   UNREACHABLE();
     257        7059 :   return Smi::kZero;
     258             : }
     259             : 
     260             : 
     261      378536 : RUNTIME_FUNCTION(Runtime_StringBuilderConcat) {
     262      189268 :   HandleScope scope(isolate);
     263             :   DCHECK_EQ(3, args.length());
     264      378536 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
     265             :   int32_t array_length;
     266      189268 :   if (!args[1]->ToInt32(&array_length)) {
     267           0 :     THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
     268             :   }
     269      378536 :   CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
     270             : 
     271      189268 :   size_t actual_array_length = 0;
     272      189268 :   CHECK(TryNumberToSize(array->length(), &actual_array_length));
     273      189268 :   CHECK(array_length >= 0);
     274      189268 :   CHECK(static_cast<size_t>(array_length) <= actual_array_length);
     275             : 
     276             :   // This assumption is used by the slice encoding in one or two smis.
     277             :   DCHECK(Smi::kMaxValue >= String::kMaxLength);
     278             : 
     279      189268 :   CHECK(array->HasFastElements());
     280      189268 :   JSObject::EnsureCanContainHeapObjectElements(array);
     281             : 
     282      189268 :   int special_length = special->length();
     283      189268 :   if (!array->HasFastObjectElements()) {
     284           0 :     return isolate->Throw(isolate->heap()->illegal_argument_string());
     285             :   }
     286             : 
     287             :   int length;
     288      189268 :   bool one_byte = special->HasOnlyOneByteChars();
     289             : 
     290             :   {
     291             :     DisallowHeapAllocation no_gc;
     292      189268 :     FixedArray* fixed_array = FixedArray::cast(array->elements());
     293      189268 :     if (fixed_array->length() < array_length) {
     294           0 :       array_length = fixed_array->length();
     295             :     }
     296             : 
     297      189268 :     if (array_length == 0) {
     298           0 :       return isolate->heap()->empty_string();
     299      189268 :     } else if (array_length == 1) {
     300      140059 :       Object* first = fixed_array->get(0);
     301      140059 :       if (first->IsString()) return first;
     302             :     }
     303             :     length = StringBuilderConcatLength(special_length, fixed_array,
     304       49209 :                                        array_length, &one_byte);
     305             :   }
     306             : 
     307       49209 :   if (length == -1) {
     308           0 :     return isolate->Throw(isolate->heap()->illegal_argument_string());
     309             :   }
     310       49209 :   if (length == 0) {
     311           0 :     return isolate->heap()->empty_string();
     312             :   }
     313             : 
     314       49209 :   if (one_byte) {
     315             :     Handle<SeqOneByteString> answer;
     316       97964 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     317             :         isolate, answer, isolate->factory()->NewRawOneByteString(length));
     318             :     StringBuilderConcatHelper(*special, answer->GetChars(),
     319       48967 :                               FixedArray::cast(array->elements()),
     320      146901 :                               array_length);
     321             :     return *answer;
     322             :   } else {
     323             :     Handle<SeqTwoByteString> answer;
     324         454 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     325             :         isolate, answer, isolate->factory()->NewRawTwoByteString(length));
     326             :     StringBuilderConcatHelper(*special, answer->GetChars(),
     327         227 :                               FixedArray::cast(array->elements()),
     328         681 :                               array_length);
     329             :     return *answer;
     330      189268 :   }
     331             : }
     332             : 
     333             : 
     334      182404 : RUNTIME_FUNCTION(Runtime_StringBuilderJoin) {
     335       91202 :   HandleScope scope(isolate);
     336             :   DCHECK_EQ(3, args.length());
     337      182404 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
     338             :   int32_t array_length;
     339       91202 :   if (!args[1]->ToInt32(&array_length)) {
     340           0 :     THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
     341             :   }
     342      182404 :   CONVERT_ARG_HANDLE_CHECKED(String, separator, 2);
     343       91202 :   CHECK(array->HasFastObjectElements());
     344       91202 :   CHECK(array_length >= 0);
     345             : 
     346       91202 :   Handle<FixedArray> fixed_array(FixedArray::cast(array->elements()));
     347       91202 :   if (fixed_array->length() < array_length) {
     348           0 :     array_length = fixed_array->length();
     349             :   }
     350             : 
     351       91202 :   if (array_length == 0) {
     352           0 :     return isolate->heap()->empty_string();
     353       91202 :   } else if (array_length == 1) {
     354           0 :     Object* first = fixed_array->get(0);
     355           0 :     CHECK(first->IsString());
     356             :     return first;
     357             :   }
     358             : 
     359       91202 :   int separator_length = separator->length();
     360       91202 :   CHECK(separator_length > 0);
     361             :   int max_nof_separators =
     362       91202 :       (String::kMaxLength + separator_length - 1) / separator_length;
     363       91202 :   if (max_nof_separators < (array_length - 1)) {
     364           0 :     THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
     365             :   }
     366       91202 :   int length = (array_length - 1) * separator_length;
     367    42845161 :   for (int i = 0; i < array_length; i++) {
     368    42845182 :     Object* element_obj = fixed_array->get(i);
     369    42845182 :     CHECK(element_obj->IsString());
     370             :     String* element = String::cast(element_obj);
     371    42845182 :     int increment = element->length();
     372    42845182 :     if (increment > String::kMaxLength - length) {
     373             :       STATIC_ASSERT(String::kMaxLength < kMaxInt);
     374             :       length = kMaxInt;  // Provoke exception;
     375             :       break;
     376             :     }
     377    42845161 :     length += increment;
     378             :   }
     379             : 
     380             :   Handle<SeqTwoByteString> answer;
     381      182404 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     382             :       isolate, answer, isolate->factory()->NewRawTwoByteString(length));
     383             : 
     384             :   DisallowHeapAllocation no_gc;
     385             : 
     386       91181 :   uc16* sink = answer->GetChars();
     387             : #ifdef DEBUG
     388             :   uc16* end = sink + length;
     389             : #endif
     390             : 
     391      182362 :   CHECK(fixed_array->get(0)->IsString());
     392       91181 :   String* first = String::cast(fixed_array->get(0));
     393             :   String* separator_raw = *separator;
     394             : 
     395       91181 :   int first_length = first->length();
     396       91181 :   String::WriteToFlat(first, sink, 0, first_length);
     397       91181 :   sink += first_length;
     398             : 
     399    42741227 :   for (int i = 1; i < array_length; i++) {
     400             :     DCHECK(sink + separator_length <= end);
     401    42741227 :     String::WriteToFlat(separator_raw, sink, 0, separator_length);
     402    42741227 :     sink += separator_length;
     403             : 
     404    85482454 :     CHECK(fixed_array->get(i)->IsString());
     405    42741227 :     String* element = String::cast(fixed_array->get(i));
     406    42741227 :     int element_length = element->length();
     407             :     DCHECK(sink + element_length <= end);
     408    42741227 :     String::WriteToFlat(element, sink, 0, element_length);
     409    42741227 :     sink += element_length;
     410             :   }
     411             :   DCHECK(sink == end);
     412             : 
     413             :   // Use %_FastOneByteArrayJoin instead.
     414             :   DCHECK(!answer->IsOneByteRepresentation());
     415       91202 :   return *answer;
     416             : }
     417             : 
     418             : template <typename sinkchar>
     419        2550 : static void WriteRepeatToFlat(String* src, Vector<sinkchar> buffer, int cursor,
     420             :                               int repeat, int length) {
     421        5100 :   if (repeat == 0) return;
     422             : 
     423        2062 :   sinkchar* start = &buffer[cursor];
     424        2062 :   String::WriteToFlat<sinkchar>(src, start, 0, length);
     425             : 
     426             :   int done = 1;
     427        2062 :   sinkchar* next = start + length;
     428             : 
     429       11591 :   while (done < repeat) {
     430        9529 :     int block = Min(done, repeat - done);
     431        9529 :     int block_chars = block * length;
     432        9529 :     CopyChars(next, start, block_chars);
     433             :     next += block_chars;
     434        9529 :     done += block;
     435             :   }
     436             : }
     437             : 
     438             : template <typename Char>
     439         571 : static void JoinSparseArrayWithSeparator(FixedArray* elements,
     440             :                                          int elements_length,
     441             :                                          uint32_t array_length,
     442             :                                          String* separator,
     443             :                                          Vector<Char> buffer) {
     444             :   DisallowHeapAllocation no_gc;
     445             :   int previous_separator_position = 0;
     446             :   int separator_length = separator->length();
     447             :   DCHECK_LT(0, separator_length);
     448             :   int cursor = 0;
     449        1994 :   for (int i = 0; i < elements_length; i += 2) {
     450        1994 :     int position = NumberToInt32(elements->get(i));
     451        1994 :     String* string = String::cast(elements->get(i + 1));
     452             :     int string_length = string->length();
     453        1994 :     if (string->length() > 0) {
     454        1979 :       int repeat = position - previous_separator_position;
     455        1979 :       WriteRepeatToFlat<Char>(separator, buffer, cursor, repeat,
     456             :                               separator_length);
     457        1979 :       cursor += repeat * separator_length;
     458             :       previous_separator_position = position;
     459        1979 :       String::WriteToFlat<Char>(string, &buffer[cursor], 0, string_length);
     460        1979 :       cursor += string->length();
     461             :     }
     462             :   }
     463             : 
     464         571 :   int last_array_index = static_cast<int>(array_length - 1);
     465             :   // Array length must be representable as a signed 32-bit number,
     466             :   // otherwise the total string length would have been too large.
     467             :   DCHECK(array_length <= 0x7fffffff);  // Is int32_t.
     468         571 :   int repeat = last_array_index - previous_separator_position;
     469         571 :   WriteRepeatToFlat<Char>(separator, buffer, cursor, repeat, separator_length);
     470             :   cursor += repeat * separator_length;
     471             :   DCHECK(cursor <= buffer.length());
     472         571 : }
     473             : 
     474             : 
     475        1228 : RUNTIME_FUNCTION(Runtime_SparseJoinWithSeparator) {
     476         614 :   HandleScope scope(isolate);
     477             :   DCHECK_EQ(3, args.length());
     478        1228 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, elements_array, 0);
     479        1228 :   CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
     480        1228 :   CONVERT_ARG_HANDLE_CHECKED(String, separator, 2);
     481             :   // elements_array is fast-mode JSarray of alternating positions
     482             :   // (increasing order) and strings.
     483         614 :   CHECK(elements_array->HasFastSmiOrObjectElements());
     484             :   // array_length is length of original array (used to add separators);
     485             :   // separator is string to put between elements. Assumed to be non-empty.
     486         614 :   CHECK(array_length > 0);
     487             : 
     488             :   // Find total length of join result.
     489             :   int string_length = 0;
     490         614 :   bool is_one_byte = separator->IsOneByteRepresentation();
     491             :   bool overflow = false;
     492        1842 :   CONVERT_NUMBER_CHECKED(int, elements_length, Int32, elements_array->length());
     493         614 :   CHECK(elements_length <= elements_array->elements()->length());
     494         614 :   CHECK((elements_length & 1) == 0);  // Even length.
     495             :   FixedArray* elements = FixedArray::cast(elements_array->elements());
     496             :   {
     497             :     DisallowHeapAllocation no_gc;
     498        2009 :     for (int i = 0; i < elements_length; i += 2) {
     499        2024 :       String* string = String::cast(elements->get(i + 1));
     500        2024 :       int length = string->length();
     501        2024 :       if (is_one_byte && !string->IsOneByteRepresentation()) {
     502             :         is_one_byte = false;
     503             :       }
     504        4048 :       if (length > String::kMaxLength ||
     505        2024 :           String::kMaxLength - length < string_length) {
     506             :         overflow = true;
     507             :         break;
     508             :       }
     509        2009 :       string_length += length;
     510             :     }
     511             :   }
     512             : 
     513         614 :   int separator_length = separator->length();
     514         614 :   if (!overflow && separator_length > 0) {
     515         599 :     if (array_length <= 0x7fffffffu) {
     516         585 :       int separator_count = static_cast<int>(array_length) - 1;
     517         585 :       int remaining_length = String::kMaxLength - string_length;
     518         585 :       if ((remaining_length / separator_length) >= separator_count) {
     519         571 :         string_length += separator_length * (array_length - 1);
     520             :       } else {
     521             :         // Not room for the separators within the maximal string length.
     522             :         overflow = true;
     523             :       }
     524             :     } else {
     525             :       // Nonempty separator and at least 2^31-1 separators necessary
     526             :       // means that the string is too large to create.
     527             :       STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
     528             :       overflow = true;
     529             :     }
     530             :   }
     531         614 :   if (overflow) {
     532             :     // Throw an exception if the resulting string is too large. See
     533             :     // https://code.google.com/p/chromium/issues/detail?id=336820
     534             :     // for details.
     535          86 :     THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
     536             :   }
     537             : 
     538         571 :   if (is_one_byte) {
     539             :     Handle<SeqOneByteString> result = isolate->factory()
     540             :                                           ->NewRawOneByteString(string_length)
     541        1142 :                                           .ToHandleChecked();
     542             :     JoinSparseArrayWithSeparator<uint8_t>(
     543         571 :         FixedArray::cast(elements_array->elements()), elements_length,
     544             :         array_length, *separator,
     545        1142 :         Vector<uint8_t>(result->GetChars(), string_length));
     546             :     return *result;
     547             :   } else {
     548             :     Handle<SeqTwoByteString> result = isolate->factory()
     549             :                                           ->NewRawTwoByteString(string_length)
     550           0 :                                           .ToHandleChecked();
     551             :     JoinSparseArrayWithSeparator<uc16>(
     552           0 :         FixedArray::cast(elements_array->elements()), elements_length,
     553             :         array_length, *separator,
     554           0 :         Vector<uc16>(result->GetChars(), string_length));
     555             :     return *result;
     556         614 :   }
     557             : }
     558             : 
     559             : 
     560             : // Copies Latin1 characters to the given fixed array looking up
     561             : // one-char strings in the cache. Gives up on the first char that is
     562             : // not in the cache and fills the remainder with smi zeros. Returns
     563             : // the length of the successfully copied prefix.
     564        5453 : static int CopyCachedOneByteCharsToArray(Heap* heap, const uint8_t* chars,
     565             :                                          FixedArray* elements, int length) {
     566             :   DisallowHeapAllocation no_gc;
     567             :   FixedArray* one_byte_cache = heap->single_character_string_cache();
     568             :   Object* undefined = heap->undefined_value();
     569             :   int i;
     570        5453 :   WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
     571       23535 :   for (i = 0; i < length; ++i) {
     572       18219 :     Object* value = one_byte_cache->get(chars[i]);
     573       18219 :     if (value == undefined) break;
     574       18082 :     elements->set(i, value, mode);
     575             :   }
     576        5453 :   if (i < length) {
     577             :     DCHECK(Smi::kZero == 0);
     578         137 :     memset(elements->data_start() + i, 0, kPointerSize * (length - i));
     579             :   }
     580             : #ifdef DEBUG
     581             :   for (int j = 0; j < length; ++j) {
     582             :     Object* element = elements->get(j);
     583             :     DCHECK(element == Smi::kZero ||
     584             :            (element->IsString() && String::cast(element)->LooksValid()));
     585             :   }
     586             : #endif
     587        5453 :   return i;
     588             : }
     589             : 
     590             : 
     591             : // Converts a String to JSArray.
     592             : // For example, "foo" => ["f", "o", "o"].
     593       10990 : RUNTIME_FUNCTION(Runtime_StringToArray) {
     594        5495 :   HandleScope scope(isolate);
     595             :   DCHECK_EQ(2, args.length());
     596       10990 :   CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
     597       10990 :   CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
     598             : 
     599        5495 :   s = String::Flatten(s);
     600        5495 :   const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
     601             : 
     602             :   Handle<FixedArray> elements;
     603             :   int position = 0;
     604       10990 :   if (s->IsFlat() && s->IsOneByteRepresentation()) {
     605             :     // Try using cached chars where possible.
     606        5453 :     elements = isolate->factory()->NewUninitializedFixedArray(length);
     607             : 
     608             :     DisallowHeapAllocation no_gc;
     609        5453 :     String::FlatContent content = s->GetFlatContent();
     610        5453 :     if (content.IsOneByte()) {
     611        5453 :       Vector<const uint8_t> chars = content.ToOneByteVector();
     612             :       // Note, this will initialize all elements (not only the prefix)
     613             :       // to prevent GC from seeing partially initialized array.
     614             :       position = CopyCachedOneByteCharsToArray(isolate->heap(), chars.start(),
     615        5453 :                                                *elements, length);
     616             :     } else {
     617             :       MemsetPointer(elements->data_start(), isolate->heap()->undefined_value(),
     618           0 :                     length);
     619             :     }
     620             :   } else {
     621          42 :     elements = isolate->factory()->NewFixedArray(length);
     622             :   }
     623        8523 :   for (int i = position; i < length; ++i) {
     624             :     Handle<Object> str =
     625        8523 :         isolate->factory()->LookupSingleCharacterStringFromCode(s->Get(i));
     626        8523 :     elements->set(i, *str);
     627             :   }
     628             : 
     629             : #ifdef DEBUG
     630             :   for (int i = 0; i < length; ++i) {
     631             :     DCHECK(String::cast(elements->get(i))->length() == 1);
     632             :   }
     633             : #endif
     634             : 
     635       10990 :   return *isolate->factory()->NewJSArrayWithElements(elements);
     636             : }
     637             : 
     638             : 
     639       87368 : RUNTIME_FUNCTION(Runtime_StringLessThan) {
     640       43684 :   HandleScope handle_scope(isolate);
     641             :   DCHECK_EQ(2, args.length());
     642       87368 :   CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
     643       87368 :   CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
     644       43684 :   switch (String::Compare(x, y)) {
     645             :     case ComparisonResult::kLessThan:
     646       17885 :       return isolate->heap()->true_value();
     647             :     case ComparisonResult::kEqual:
     648             :     case ComparisonResult::kGreaterThan:
     649       25799 :       return isolate->heap()->false_value();
     650             :     case ComparisonResult::kUndefined:
     651             :       break;
     652             :   }
     653           0 :   UNREACHABLE();
     654       43684 :   return Smi::kZero;
     655             : }
     656             : 
     657    10333874 : RUNTIME_FUNCTION(Runtime_StringLessThanOrEqual) {
     658     5166937 :   HandleScope handle_scope(isolate);
     659             :   DCHECK_EQ(2, args.length());
     660    10333874 :   CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
     661    10333874 :   CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
     662     5166937 :   switch (String::Compare(x, y)) {
     663             :     case ComparisonResult::kEqual:
     664             :     case ComparisonResult::kLessThan:
     665     1511257 :       return isolate->heap()->true_value();
     666             :     case ComparisonResult::kGreaterThan:
     667     3655680 :       return isolate->heap()->false_value();
     668             :     case ComparisonResult::kUndefined:
     669             :       break;
     670             :   }
     671           0 :   UNREACHABLE();
     672     5166937 :   return Smi::kZero;
     673             : }
     674             : 
     675           0 : RUNTIME_FUNCTION(Runtime_StringGreaterThan) {
     676           0 :   HandleScope handle_scope(isolate);
     677             :   DCHECK_EQ(2, args.length());
     678           0 :   CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
     679           0 :   CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
     680           0 :   switch (String::Compare(x, y)) {
     681             :     case ComparisonResult::kGreaterThan:
     682           0 :       return isolate->heap()->true_value();
     683             :     case ComparisonResult::kEqual:
     684             :     case ComparisonResult::kLessThan:
     685           0 :       return isolate->heap()->false_value();
     686             :     case ComparisonResult::kUndefined:
     687             :       break;
     688             :   }
     689           0 :   UNREACHABLE();
     690           0 :   return Smi::kZero;
     691             : }
     692             : 
     693     4288846 : RUNTIME_FUNCTION(Runtime_StringGreaterThanOrEqual) {
     694     2144423 :   HandleScope handle_scope(isolate);
     695             :   DCHECK_EQ(2, args.length());
     696     4288846 :   CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
     697     4288846 :   CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
     698     2144423 :   switch (String::Compare(x, y)) {
     699             :     case ComparisonResult::kEqual:
     700             :     case ComparisonResult::kGreaterThan:
     701     2144423 :       return isolate->heap()->true_value();
     702             :     case ComparisonResult::kLessThan:
     703           0 :       return isolate->heap()->false_value();
     704             :     case ComparisonResult::kUndefined:
     705             :       break;
     706             :   }
     707           0 :   UNREACHABLE();
     708     2144423 :   return Smi::kZero;
     709             : }
     710             : 
     711    12219884 : RUNTIME_FUNCTION(Runtime_StringEqual) {
     712     6109942 :   HandleScope handle_scope(isolate);
     713             :   DCHECK_EQ(2, args.length());
     714    12219884 :   CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
     715    12219884 :   CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
     716     6109942 :   return isolate->heap()->ToBoolean(String::Equals(x, y));
     717             : }
     718             : 
     719           0 : RUNTIME_FUNCTION(Runtime_StringNotEqual) {
     720           0 :   HandleScope handle_scope(isolate);
     721             :   DCHECK_EQ(2, args.length());
     722           0 :   CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
     723           0 :   CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
     724           0 :   return isolate->heap()->ToBoolean(!String::Equals(x, y));
     725             : }
     726             : 
     727        1440 : RUNTIME_FUNCTION(Runtime_FlattenString) {
     728         720 :   HandleScope scope(isolate);
     729             :   DCHECK_EQ(1, args.length());
     730        1440 :   CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
     731        1440 :   return *String::Flatten(str);
     732             : }
     733             : 
     734             : 
     735    24936580 : RUNTIME_FUNCTION(Runtime_StringCharFromCode) {
     736    12468290 :   HandleScope handlescope(isolate);
     737             :   DCHECK_EQ(1, args.length());
     738    24936580 :   if (args[0]->IsNumber()) {
     739    24936580 :     CONVERT_NUMBER_CHECKED(uint32_t, code, Uint32, args[0]);
     740    12468290 :     code &= 0xffff;
     741    24936580 :     return *isolate->factory()->LookupSingleCharacterStringFromCode(code);
     742             :   }
     743           0 :   return isolate->heap()->empty_string();
     744             : }
     745             : 
     746         314 : RUNTIME_FUNCTION(Runtime_ExternalStringGetChar) {
     747             :   SealHandleScope shs(isolate);
     748             :   DCHECK_EQ(2, args.length());
     749         314 :   CONVERT_ARG_CHECKED(ExternalString, string, 0);
     750         314 :   CONVERT_INT32_ARG_CHECKED(index, 1);
     751         314 :   return Smi::FromInt(string->Get(index));
     752             : }
     753             : 
     754        3634 : RUNTIME_FUNCTION(Runtime_StringCharCodeAt) {
     755             :   SealHandleScope shs(isolate);
     756             :   DCHECK_EQ(2, args.length());
     757        3634 :   if (!args[0]->IsString()) return isolate->heap()->undefined_value();
     758        3634 :   if (!args[1]->IsNumber()) return isolate->heap()->undefined_value();
     759        1817 :   if (std::isinf(args.number_at(1))) return isolate->heap()->nan_value();
     760             :   return __RT_impl_Runtime_StringCharCodeAtRT(args, isolate);
     761             : }
     762             : 
     763             : }  // namespace internal
     764             : }  // namespace v8

Generated by: LCOV version 1.10