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