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 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. 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 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]) 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. 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 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 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 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 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 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 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 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 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> 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> 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 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. 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"]. 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 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 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 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 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 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 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 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 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 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 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