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