Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/runtime/runtime-strings.cc

Issue 1968953002: [runtime] Implement encodeURI as single runtime function. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix isalnum() bug Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/runtime/runtime-utils.h"
6
7 #include "src/arguments.h" 5 #include "src/arguments.h"
8 #include "src/regexp/jsregexp-inl.h" 6 #include "src/regexp/jsregexp-inl.h"
7 #include "src/runtime/runtime-utils.h"
9 #include "src/string-builder.h" 8 #include "src/string-builder.h"
9
10 #include "src/string-search.h" 10 #include "src/string-search.h"
11 11
12 namespace v8 { 12 namespace v8 {
13 namespace internal { 13 namespace internal {
14 14
15 15
16 // Perform string match of pattern on subject, starting at start index. 16 // Perform string match of pattern on subject, starting at start index.
17 // Caller must ensure that 0 <= start_index <= sub->length(), 17 // Caller must ensure that 0 <= start_index <= sub->length(),
18 // and should check that pat->length() + start_index <= sub->length(). 18 // and should check that pat->length() + start_index <= sub->length().
19 int StringMatch(Isolate* isolate, Handle<String> sub, Handle<String> pat, 19 int StringMatch(Isolate *isolate, Handle<String> sub, Handle<String> pat,
20 int start_index) { 20 int start_index) {
21 DCHECK(0 <= start_index); 21 DCHECK(0 <= start_index);
22 DCHECK(start_index <= sub->length()); 22 DCHECK(start_index <= sub->length());
23 23
24 int pattern_length = pat->length(); 24 int pattern_length = pat->length();
25 if (pattern_length == 0) return start_index; 25 if (pattern_length == 0) return start_index;
26 26
27 int subject_length = sub->length(); 27 int subject_length = sub->length();
28 if (start_index + pattern_length > subject_length) return -1; 28 if (start_index + pattern_length > subject_length) return -1;
29 29
(...skipping 20 matching lines...) Expand all
50 return SearchString(isolate, seq_sub.ToOneByteVector(), pat_vector, 50 return SearchString(isolate, seq_sub.ToOneByteVector(), pat_vector,
51 start_index); 51 start_index);
52 } 52 }
53 return SearchString(isolate, seq_sub.ToUC16Vector(), pat_vector, start_index); 53 return SearchString(isolate, seq_sub.ToUC16Vector(), pat_vector, start_index);
54 } 54 }
55 55
56 56
57 // This may return an empty MaybeHandle if an exception is thrown or 57 // This may return an empty MaybeHandle if an exception is thrown or
58 // we abort due to reaching the recursion limit. 58 // we abort due to reaching the recursion limit.
59 MaybeHandle<String> StringReplaceOneCharWithString( 59 MaybeHandle<String> StringReplaceOneCharWithString(
60 Isolate* isolate, Handle<String> subject, Handle<String> search, 60 Isolate *isolate, Handle<String> subject, Handle<String> search,
Yang 2016/05/12 07:39:21 V8's convention is to have the asterisk at the typ
Franzi 2016/05/13 09:42:02 Done.
61 Handle<String> replace, bool* found, int recursion_limit) { 61 Handle<String> replace, bool *found, int recursion_limit) {
62 StackLimitCheck stackLimitCheck(isolate); 62 StackLimitCheck stackLimitCheck(isolate);
63 if (stackLimitCheck.HasOverflowed() || (recursion_limit == 0)) { 63 if (stackLimitCheck.HasOverflowed() || (recursion_limit == 0)) {
64 return MaybeHandle<String>(); 64 return MaybeHandle<String>();
65 } 65 }
66 recursion_limit--; 66 recursion_limit--;
67 if (subject->IsConsString()) { 67 if (subject->IsConsString()) {
68 ConsString* cons = ConsString::cast(*subject); 68 ConsString *cons = ConsString::cast(*subject);
69 Handle<String> first = Handle<String>(cons->first()); 69 Handle<String> first = Handle<String>(cons->first());
70 Handle<String> second = Handle<String>(cons->second()); 70 Handle<String> second = Handle<String>(cons->second());
71 Handle<String> new_first; 71 Handle<String> new_first;
72 if (!StringReplaceOneCharWithString(isolate, first, search, replace, found, 72 if (!StringReplaceOneCharWithString(isolate, first, search, replace, found,
73 recursion_limit).ToHandle(&new_first)) { 73 recursion_limit).ToHandle(&new_first)) {
74 return MaybeHandle<String>(); 74 return MaybeHandle<String>();
75 } 75 }
76 if (*found) return isolate->factory()->NewConsString(new_first, second); 76 if (*found) return isolate->factory()->NewConsString(new_first, second);
77 77
78 Handle<String> new_second; 78 Handle<String> new_second;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 CONVERT_ARG_HANDLE_CHECKED(Object, index, 2); 138 CONVERT_ARG_HANDLE_CHECKED(Object, index, 2);
139 139
140 uint32_t start_index = 0; 140 uint32_t start_index = 0;
141 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); 141 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
142 142
143 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length())); 143 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
144 int position = StringMatch(isolate, sub, pat, start_index); 144 int position = StringMatch(isolate, sub, pat, start_index);
145 return Smi::FromInt(position); 145 return Smi::FromInt(position);
146 } 146 }
147 147
148
149 template <typename schar, typename pchar> 148 template <typename schar, typename pchar>
150 static int StringMatchBackwards(Vector<const schar> subject, 149 static int StringMatchBackwards(Vector<const schar> subject,
151 Vector<const pchar> pattern, int idx) { 150 Vector<const pchar> pattern, int idx) {
152 int pattern_length = pattern.length(); 151 int pattern_length = pattern.length();
153 DCHECK(pattern_length >= 1); 152 DCHECK(pattern_length >= 1);
154 DCHECK(idx + pattern_length <= subject.length()); 153 DCHECK(idx + pattern_length <= subject.length());
155 154
156 if (sizeof(schar) == 1 && sizeof(pchar) > 1) { 155 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
157 for (int i = 0; i < pattern_length; i++) { 156 for (int i = 0; i < pattern_length; i++) {
158 uc16 c = pattern[i]; 157 uc16 c = pattern[i];
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 339
341 RegExpImpl::GlobalCache global_cache(regexp, subject, isolate); 340 RegExpImpl::GlobalCache global_cache(regexp, subject, isolate);
342 if (global_cache.HasException()) return isolate->heap()->exception(); 341 if (global_cache.HasException()) return isolate->heap()->exception();
343 342
344 int capture_count = regexp->CaptureCount(); 343 int capture_count = regexp->CaptureCount();
345 344
346 ZoneScope zone_scope(isolate->runtime_zone()); 345 ZoneScope zone_scope(isolate->runtime_zone());
347 ZoneList<int> offsets(8, zone_scope.zone()); 346 ZoneList<int> offsets(8, zone_scope.zone());
348 347
349 while (true) { 348 while (true) {
350 int32_t* match = global_cache.FetchNext(); 349 int32_t *match = global_cache.FetchNext();
351 if (match == NULL) break; 350 if (match == NULL) break;
352 offsets.Add(match[0], zone_scope.zone()); // start 351 offsets.Add(match[0], zone_scope.zone()); // start
353 offsets.Add(match[1], zone_scope.zone()); // end 352 offsets.Add(match[1], zone_scope.zone()); // end
354 } 353 }
355 354
356 if (global_cache.HasException()) return isolate->heap()->exception(); 355 if (global_cache.HasException()) return isolate->heap()->exception();
357 356
358 if (offsets.length() == 0) { 357 if (offsets.length() == 0) {
359 // Not a single match. 358 // Not a single match.
360 return isolate->heap()->null_value(); 359 return isolate->heap()->null_value();
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 int special_length = special->length(); 446 int special_length = special->length();
448 if (!array->HasFastObjectElements()) { 447 if (!array->HasFastObjectElements()) {
449 return isolate->Throw(isolate->heap()->illegal_argument_string()); 448 return isolate->Throw(isolate->heap()->illegal_argument_string());
450 } 449 }
451 450
452 int length; 451 int length;
453 bool one_byte = special->HasOnlyOneByteChars(); 452 bool one_byte = special->HasOnlyOneByteChars();
454 453
455 { 454 {
456 DisallowHeapAllocation no_gc; 455 DisallowHeapAllocation no_gc;
457 FixedArray* fixed_array = FixedArray::cast(array->elements()); 456 FixedArray *fixed_array = FixedArray::cast(array->elements());
458 if (fixed_array->length() < array_length) { 457 if (fixed_array->length() < array_length) {
459 array_length = fixed_array->length(); 458 array_length = fixed_array->length();
460 } 459 }
461 460
462 if (array_length == 0) { 461 if (array_length == 0) {
463 return isolate->heap()->empty_string(); 462 return isolate->heap()->empty_string();
464 } else if (array_length == 1) { 463 } else if (array_length == 1) {
465 Object* first = fixed_array->get(0); 464 Object *first = fixed_array->get(0);
466 if (first->IsString()) return first; 465 if (first->IsString()) return first;
467 } 466 }
468 length = StringBuilderConcatLength(special_length, fixed_array, 467 length = StringBuilderConcatLength(special_length, fixed_array,
469 array_length, &one_byte); 468 array_length, &one_byte);
470 } 469 }
471 470
472 if (length == -1) { 471 if (length == -1) {
473 return isolate->Throw(isolate->heap()->illegal_argument_string()); 472 return isolate->Throw(isolate->heap()->illegal_argument_string());
474 } 473 }
475 474
(...skipping 30 matching lines...) Expand all
506 RUNTIME_ASSERT(array_length >= 0); 505 RUNTIME_ASSERT(array_length >= 0);
507 506
508 Handle<FixedArray> fixed_array(FixedArray::cast(array->elements())); 507 Handle<FixedArray> fixed_array(FixedArray::cast(array->elements()));
509 if (fixed_array->length() < array_length) { 508 if (fixed_array->length() < array_length) {
510 array_length = fixed_array->length(); 509 array_length = fixed_array->length();
511 } 510 }
512 511
513 if (array_length == 0) { 512 if (array_length == 0) {
514 return isolate->heap()->empty_string(); 513 return isolate->heap()->empty_string();
515 } else if (array_length == 1) { 514 } else if (array_length == 1) {
516 Object* first = fixed_array->get(0); 515 Object *first = fixed_array->get(0);
517 RUNTIME_ASSERT(first->IsString()); 516 RUNTIME_ASSERT(first->IsString());
518 return first; 517 return first;
519 } 518 }
520 519
521 int separator_length = separator->length(); 520 int separator_length = separator->length();
522 RUNTIME_ASSERT(separator_length > 0); 521 RUNTIME_ASSERT(separator_length > 0);
523 int max_nof_separators = 522 int max_nof_separators =
524 (String::kMaxLength + separator_length - 1) / separator_length; 523 (String::kMaxLength + separator_length - 1) / separator_length;
525 if (max_nof_separators < (array_length - 1)) { 524 if (max_nof_separators < (array_length - 1)) {
526 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError()); 525 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewInvalidStringLengthError());
527 } 526 }
528 int length = (array_length - 1) * separator_length; 527 int length = (array_length - 1) * separator_length;
529 for (int i = 0; i < array_length; i++) { 528 for (int i = 0; i < array_length; i++) {
530 Object* element_obj = fixed_array->get(i); 529 Object *element_obj = fixed_array->get(i);
531 RUNTIME_ASSERT(element_obj->IsString()); 530 RUNTIME_ASSERT(element_obj->IsString());
532 String* element = String::cast(element_obj); 531 String *element = String::cast(element_obj);
533 int increment = element->length(); 532 int increment = element->length();
534 if (increment > String::kMaxLength - length) { 533 if (increment > String::kMaxLength - length) {
535 STATIC_ASSERT(String::kMaxLength < kMaxInt); 534 STATIC_ASSERT(String::kMaxLength < kMaxInt);
536 length = kMaxInt; // Provoke exception; 535 length = kMaxInt; // Provoke exception;
537 break; 536 break;
538 } 537 }
539 length += increment; 538 length += increment;
540 } 539 }
541 540
542 Handle<SeqTwoByteString> answer; 541 Handle<SeqTwoByteString> answer;
543 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 542 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
544 isolate, answer, isolate->factory()->NewRawTwoByteString(length)); 543 isolate, answer, isolate->factory()->NewRawTwoByteString(length));
545 544
546 DisallowHeapAllocation no_gc; 545 DisallowHeapAllocation no_gc;
547 546
548 uc16* sink = answer->GetChars(); 547 uc16 *sink = answer->GetChars();
549 #ifdef DEBUG 548 #ifdef DEBUG
550 uc16* end = sink + length; 549 uc16* end = sink + length;
551 #endif 550 #endif
552 551
553 RUNTIME_ASSERT(fixed_array->get(0)->IsString()); 552 RUNTIME_ASSERT(fixed_array->get(0)->IsString());
554 String* first = String::cast(fixed_array->get(0)); 553 String *first = String::cast(fixed_array->get(0));
555 String* separator_raw = *separator; 554 String *separator_raw = *separator;
556 555
557 int first_length = first->length(); 556 int first_length = first->length();
558 String::WriteToFlat(first, sink, 0, first_length); 557 String::WriteToFlat(first, sink, 0, first_length);
559 sink += first_length; 558 sink += first_length;
560 559
561 for (int i = 1; i < array_length; i++) { 560 for (int i = 1; i < array_length; i++) {
562 DCHECK(sink + separator_length <= end); 561 DCHECK(sink + separator_length <= end);
563 String::WriteToFlat(separator_raw, sink, 0, separator_length); 562 String::WriteToFlat(separator_raw, sink, 0, separator_length);
564 sink += separator_length; 563 sink += separator_length;
565 564
566 RUNTIME_ASSERT(fixed_array->get(i)->IsString()); 565 RUNTIME_ASSERT(fixed_array->get(i)->IsString());
567 String* element = String::cast(fixed_array->get(i)); 566 String *element = String::cast(fixed_array->get(i));
568 int element_length = element->length(); 567 int element_length = element->length();
569 DCHECK(sink + element_length <= end); 568 DCHECK(sink + element_length <= end);
570 String::WriteToFlat(element, sink, 0, element_length); 569 String::WriteToFlat(element, sink, 0, element_length);
571 sink += element_length; 570 sink += element_length;
572 } 571 }
573 DCHECK(sink == end); 572 DCHECK(sink == end);
574 573
575 // Use %_FastOneByteArrayJoin instead. 574 // Use %_FastOneByteArrayJoin instead.
576 DCHECK(!answer->IsOneByteRepresentation()); 575 DCHECK(!answer->IsOneByteRepresentation());
577 return *answer; 576 return *answer;
578 } 577 }
579 578
580 template <typename sinkchar> 579 template <typename sinkchar>
581 static void WriteRepeatToFlat(String* src, Vector<sinkchar> buffer, int cursor, 580 static void WriteRepeatToFlat(String *src, Vector<sinkchar> buffer, int cursor,
582 int repeat, int length) { 581 int repeat, int length) {
583 if (repeat == 0) return; 582 if (repeat == 0) return;
584 583
585 sinkchar* start = &buffer[cursor]; 584 sinkchar *start = &buffer[cursor];
586 String::WriteToFlat<sinkchar>(src, start, 0, length); 585 String::WriteToFlat<sinkchar>(src, start, 0, length);
587 586
588 int done = 1; 587 int done = 1;
589 sinkchar* next = start + length; 588 sinkchar *next = start + length;
590 589
591 while (done < repeat) { 590 while (done < repeat) {
592 int block = Min(done, repeat - done); 591 int block = Min(done, repeat - done);
593 int block_chars = block * length; 592 int block_chars = block * length;
594 CopyChars(next, start, block_chars); 593 CopyChars(next, start, block_chars);
595 next += block_chars; 594 next += block_chars;
596 done += block; 595 done += block;
597 } 596 }
598 } 597 }
599 598
600 template <typename Char> 599 template <typename Char>
601 static void JoinSparseArrayWithSeparator(FixedArray* elements, 600 static void JoinSparseArrayWithSeparator(FixedArray *elements,
602 int elements_length, 601 int elements_length,
603 uint32_t array_length, 602 uint32_t array_length,
604 String* separator, 603 String *separator,
605 Vector<Char> buffer) { 604 Vector<Char> buffer) {
606 DisallowHeapAllocation no_gc; 605 DisallowHeapAllocation no_gc;
607 int previous_separator_position = 0; 606 int previous_separator_position = 0;
608 int separator_length = separator->length(); 607 int separator_length = separator->length();
609 DCHECK_LT(0, separator_length); 608 DCHECK_LT(0, separator_length);
610 int cursor = 0; 609 int cursor = 0;
611 for (int i = 0; i < elements_length; i += 2) { 610 for (int i = 0; i < elements_length; i += 2) {
612 int position = NumberToInt32(elements->get(i)); 611 int position = NumberToInt32(elements->get(i));
613 String* string = String::cast(elements->get(i + 1)); 612 String *string = String::cast(elements->get(i + 1));
614 int string_length = string->length(); 613 int string_length = string->length();
615 if (string->length() > 0) { 614 if (string->length() > 0) {
616 int repeat = position - previous_separator_position; 615 int repeat = position - previous_separator_position;
617 WriteRepeatToFlat<Char>(separator, buffer, cursor, repeat, 616 WriteRepeatToFlat<Char>(separator, buffer, cursor, repeat,
618 separator_length); 617 separator_length);
619 cursor += repeat * separator_length; 618 cursor += repeat * separator_length;
620 previous_separator_position = position; 619 previous_separator_position = position;
621 String::WriteToFlat<Char>(string, &buffer[cursor], 0, string_length); 620 String::WriteToFlat<Char>(string, &buffer[cursor], 0, string_length);
622 cursor += string->length(); 621 cursor += string->length();
623 } 622 }
(...skipping 23 matching lines...) Expand all
647 // separator is string to put between elements. Assumed to be non-empty. 646 // separator is string to put between elements. Assumed to be non-empty.
648 RUNTIME_ASSERT(array_length > 0); 647 RUNTIME_ASSERT(array_length > 0);
649 648
650 // Find total length of join result. 649 // Find total length of join result.
651 int string_length = 0; 650 int string_length = 0;
652 bool is_one_byte = separator->IsOneByteRepresentation(); 651 bool is_one_byte = separator->IsOneByteRepresentation();
653 bool overflow = false; 652 bool overflow = false;
654 CONVERT_NUMBER_CHECKED(int, elements_length, Int32, elements_array->length()); 653 CONVERT_NUMBER_CHECKED(int, elements_length, Int32, elements_array->length());
655 RUNTIME_ASSERT(elements_length <= elements_array->elements()->length()); 654 RUNTIME_ASSERT(elements_length <= elements_array->elements()->length());
656 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length. 655 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
657 FixedArray* elements = FixedArray::cast(elements_array->elements()); 656 FixedArray *elements = FixedArray::cast(elements_array->elements());
658 { 657 {
659 DisallowHeapAllocation no_gc; 658 DisallowHeapAllocation no_gc;
660 for (int i = 0; i < elements_length; i += 2) { 659 for (int i = 0; i < elements_length; i += 2) {
661 String* string = String::cast(elements->get(i + 1)); 660 String *string = String::cast(elements->get(i + 1));
662 int length = string->length(); 661 int length = string->length();
663 if (is_one_byte && !string->IsOneByteRepresentation()) { 662 if (is_one_byte && !string->IsOneByteRepresentation()) {
664 is_one_byte = false; 663 is_one_byte = false;
665 } 664 }
666 if (length > String::kMaxLength || 665 if (length > String::kMaxLength ||
667 String::kMaxLength - length < string_length) { 666 String::kMaxLength - length < string_length) {
668 overflow = true; 667 overflow = true;
669 break; 668 break;
670 } 669 }
671 string_length += length; 670 string_length += length;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
716 Vector<uc16>(result->GetChars(), string_length)); 715 Vector<uc16>(result->GetChars(), string_length));
717 return *result; 716 return *result;
718 } 717 }
719 } 718 }
720 719
721 720
722 // Copies Latin1 characters to the given fixed array looking up 721 // Copies Latin1 characters to the given fixed array looking up
723 // one-char strings in the cache. Gives up on the first char that is 722 // one-char strings in the cache. Gives up on the first char that is
724 // not in the cache and fills the remainder with smi zeros. Returns 723 // not in the cache and fills the remainder with smi zeros. Returns
725 // the length of the successfully copied prefix. 724 // the length of the successfully copied prefix.
726 static int CopyCachedOneByteCharsToArray(Heap* heap, const uint8_t* chars, 725 static int CopyCachedOneByteCharsToArray(Heap *heap, const uint8_t *chars,
727 FixedArray* elements, int length) { 726 FixedArray *elements, int length) {
728 DisallowHeapAllocation no_gc; 727 DisallowHeapAllocation no_gc;
729 FixedArray* one_byte_cache = heap->single_character_string_cache(); 728 FixedArray *one_byte_cache = heap->single_character_string_cache();
730 Object* undefined = heap->undefined_value(); 729 Object *undefined = heap->undefined_value();
731 int i; 730 int i;
732 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); 731 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
733 for (i = 0; i < length; ++i) { 732 for (i = 0; i < length; ++i) {
734 Object* value = one_byte_cache->get(chars[i]); 733 Object *value = one_byte_cache->get(chars[i]);
735 if (value == undefined) break; 734 if (value == undefined) break;
736 elements->set(i, value, mode); 735 elements->set(i, value, mode);
737 } 736 }
738 if (i < length) { 737 if (i < length) {
739 DCHECK(Smi::FromInt(0) == 0); 738 DCHECK(Smi::FromInt(0) == 0);
740 memset(elements->data_start() + i, 0, kPointerSize * (length - i)); 739 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
741 } 740 }
742 #ifdef DEBUG 741 #ifdef DEBUG
743 for (int j = 0; j < length; ++j) { 742 for (int j = 0; j < length; ++j) {
744 Object* element = elements->get(j); 743 Object* element = elements->get(j);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
799 798
800 799
801 static inline bool ToUpperOverflows(uc32 character) { 800 static inline bool ToUpperOverflows(uc32 character) {
802 // y with umlauts and the micro sign are the only characters that stop 801 // y with umlauts and the micro sign are the only characters that stop
803 // fitting into one-byte when converting to uppercase. 802 // fitting into one-byte when converting to uppercase.
804 static const uc32 yuml_code = 0xff; 803 static const uc32 yuml_code = 0xff;
805 static const uc32 micro_code = 0xb5; 804 static const uc32 micro_code = 0xb5;
806 return (character == yuml_code || character == micro_code); 805 return (character == yuml_code || character == micro_code);
807 } 806 }
808 807
809
810 template <class Converter> 808 template <class Converter>
811 MUST_USE_RESULT static Object* ConvertCaseHelper( 809 MUST_USE_RESULT static Object *ConvertCaseHelper(
812 Isolate* isolate, String* string, SeqString* result, int result_length, 810 Isolate *isolate, String *string, SeqString *result, int result_length,
813 unibrow::Mapping<Converter, 128>* mapping) { 811 unibrow::Mapping<Converter, 128> *mapping) {
814 DisallowHeapAllocation no_gc; 812 DisallowHeapAllocation no_gc;
815 // We try this twice, once with the assumption that the result is no longer 813 // We try this twice, once with the assumption that the result is no longer
816 // than the input and, if that assumption breaks, again with the exact 814 // than the input and, if that assumption breaks, again with the exact
817 // length. This may not be pretty, but it is nicer than what was here before 815 // length. This may not be pretty, but it is nicer than what was here before
818 // and I hereby claim my vaffel-is. 816 // and I hereby claim my vaffel-is.
819 // 817 //
820 // NOTE: This assumes that the upper/lower case of an ASCII 818 // NOTE: This assumes that the upper/lower case of an ASCII
821 // character is also ASCII. This is currently the case, but it 819 // character is also ASCII. This is currently the case, but it
822 // might break in the future if we implement more context and locale 820 // might break in the future if we implement more context and locale
823 // dependent upper/lower conversions. 821 // dependent upper/lower conversions.
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
939 DCHECK(dst[i] == src[i] + ('a' - 'A')); 937 DCHECK(dst[i] == src[i] + ('a' - 'A'));
940 } else { 938 } else {
941 DCHECK('a' <= src[i] && src[i] <= 'z'); 939 DCHECK('a' <= src[i] && src[i] <= 'z');
942 DCHECK(dst[i] == src[i] - ('a' - 'A')); 940 DCHECK(dst[i] == src[i] - ('a' - 'A'));
943 } 941 }
944 } 942 }
945 return (expected_changed == changed); 943 return (expected_changed == changed);
946 } 944 }
947 #endif 945 #endif
948 946
949
950 template <class Converter> 947 template <class Converter>
951 static bool FastAsciiConvert(char* dst, const char* src, int length, 948 static bool FastAsciiConvert(char *dst, const char *src, int length,
952 bool* changed_out) { 949 bool *changed_out) {
953 #ifdef DEBUG 950 #ifdef DEBUG
954 char* saved_dst = dst; 951 char* saved_dst = dst;
955 const char* saved_src = src; 952 const char* saved_src = src;
956 #endif 953 #endif
957 DisallowHeapAllocation no_gc; 954 DisallowHeapAllocation no_gc;
958 // We rely on the distance between upper and lower case letters 955 // We rely on the distance between upper and lower case letters
959 // being a known power of 2. 956 // being a known power of 2.
960 DCHECK('a' - 'A' == (1 << 5)); 957 DCHECK('a' - 'A' == (1 << 5));
961 // Boundaries for the range of input characters than require conversion. 958 // Boundaries for the range of input characters than require conversion.
962 static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1; 959 static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1;
963 static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1; 960 static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1;
964 bool changed = false; 961 bool changed = false;
965 uintptr_t or_acc = 0; 962 uintptr_t or_acc = 0;
966 const char* const limit = src + length; 963 const char *const limit = src + length;
967 964
968 // dst is newly allocated and always aligned. 965 // dst is newly allocated and always aligned.
969 DCHECK(IsAligned(reinterpret_cast<intptr_t>(dst), sizeof(uintptr_t))); 966 DCHECK(IsAligned(reinterpret_cast<intptr_t>(dst), sizeof(uintptr_t)));
970 // Only attempt processing one word at a time if src is also aligned. 967 // Only attempt processing one word at a time if src is also aligned.
971 if (IsAligned(reinterpret_cast<intptr_t>(src), sizeof(uintptr_t))) { 968 if (IsAligned(reinterpret_cast<intptr_t>(src), sizeof(uintptr_t))) {
972 // Process the prefix of the input that requires no conversion one aligned 969 // Process the prefix of the input that requires no conversion one aligned
973 // (machine) word at a time. 970 // (machine) word at a time.
974 while (src <= limit - sizeof(uintptr_t)) { 971 while (src <= limit - sizeof(uintptr_t)) {
975 const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src); 972 const uintptr_t w = *reinterpret_cast<const uintptr_t *>(src);
976 or_acc |= w; 973 or_acc |= w;
977 if (AsciiRangeMask(w, lo, hi) != 0) { 974 if (AsciiRangeMask(w, lo, hi) != 0) {
978 changed = true; 975 changed = true;
979 break; 976 break;
980 } 977 }
981 *reinterpret_cast<uintptr_t*>(dst) = w; 978 *reinterpret_cast<uintptr_t *>(dst) = w;
982 src += sizeof(uintptr_t); 979 src += sizeof(uintptr_t);
983 dst += sizeof(uintptr_t); 980 dst += sizeof(uintptr_t);
984 } 981 }
985 // Process the remainder of the input performing conversion when 982 // Process the remainder of the input performing conversion when
986 // required one word at a time. 983 // required one word at a time.
987 while (src <= limit - sizeof(uintptr_t)) { 984 while (src <= limit - sizeof(uintptr_t)) {
988 const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src); 985 const uintptr_t w = *reinterpret_cast<const uintptr_t *>(src);
989 or_acc |= w; 986 or_acc |= w;
990 uintptr_t m = AsciiRangeMask(w, lo, hi); 987 uintptr_t m = AsciiRangeMask(w, lo, hi);
991 // The mask has high (7th) bit set in every byte that needs 988 // The mask has high (7th) bit set in every byte that needs
992 // conversion and we know that the distance between cases is 989 // conversion and we know that the distance between cases is
993 // 1 << 5. 990 // 1 << 5.
994 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2); 991 *reinterpret_cast<uintptr_t *>(dst) = w ^ (m >> 2);
995 src += sizeof(uintptr_t); 992 src += sizeof(uintptr_t);
996 dst += sizeof(uintptr_t); 993 dst += sizeof(uintptr_t);
997 } 994 }
998 } 995 }
999 // Process the last few bytes of the input (or the whole input if 996 // Process the last few bytes of the input (or the whole input if
1000 // unaligned access is not supported). 997 // unaligned access is not supported).
1001 while (src < limit) { 998 while (src < limit) {
1002 char c = *src; 999 char c = *src;
1003 or_acc |= c; 1000 or_acc |= c;
1004 if (lo < c && c < hi) { 1001 if (lo < c && c < hi) {
1005 c ^= (1 << 5); 1002 c ^= (1 << 5);
1006 changed = true; 1003 changed = true;
1007 } 1004 }
1008 *dst = c; 1005 *dst = c;
1009 ++src; 1006 ++src;
1010 ++dst; 1007 ++dst;
1011 } 1008 }
1012 1009
1013 if ((or_acc & kAsciiMask) != 0) return false; 1010 if ((or_acc & kAsciiMask) != 0) return false;
1014 1011
1015 DCHECK(CheckFastAsciiConvert(saved_dst, saved_src, length, changed, 1012 DCHECK(CheckFastAsciiConvert(saved_dst, saved_src, length, changed,
1016 Converter::kIsToLower)); 1013 Converter::kIsToLower));
1017 1014
1018 *changed_out = changed; 1015 *changed_out = changed;
1019 return true; 1016 return true;
1020 } 1017 }
1021 1018
1022
1023 template <class Converter> 1019 template <class Converter>
1024 MUST_USE_RESULT static Object* ConvertCase( 1020 MUST_USE_RESULT static Object *ConvertCase(
Yang 2016/05/12 07:39:21 You probably did some auto format on your IDE. Ple
Franzi 2016/05/13 09:42:03 Acknowledged.
1025 Handle<String> s, Isolate* isolate, 1021 Handle<String> s, Isolate *isolate,
1026 unibrow::Mapping<Converter, 128>* mapping) { 1022 unibrow::Mapping<Converter, 128> *mapping) {
1027 s = String::Flatten(s); 1023 s = String::Flatten(s);
1028 int length = s->length(); 1024 int length = s->length();
1029 // Assume that the string is not empty; we need this assumption later 1025 // Assume that the string is not empty; we need this assumption later
1030 if (length == 0) return *s; 1026 if (length == 0) return *s;
1031 1027
1032 // Simpler handling of ASCII strings. 1028 // Simpler handling of ASCII strings.
1033 // 1029 //
1034 // NOTE: This assumes that the upper/lower case of an ASCII 1030 // NOTE: This assumes that the upper/lower case of an ASCII
1035 // character is also ASCII. This is currently the case, but it 1031 // character is also ASCII. This is currently the case, but it
1036 // might break in the future if we implement more context and locale 1032 // might break in the future if we implement more context and locale
1037 // dependent upper/lower conversions. 1033 // dependent upper/lower conversions.
1038 if (s->IsOneByteRepresentationUnderneath()) { 1034 if (s->IsOneByteRepresentationUnderneath()) {
1039 // Same length as input. 1035 // Same length as input.
1040 Handle<SeqOneByteString> result = 1036 Handle<SeqOneByteString> result =
1041 isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); 1037 isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
1042 DisallowHeapAllocation no_gc; 1038 DisallowHeapAllocation no_gc;
1043 String::FlatContent flat_content = s->GetFlatContent(); 1039 String::FlatContent flat_content = s->GetFlatContent();
1044 DCHECK(flat_content.IsFlat()); 1040 DCHECK(flat_content.IsFlat());
1045 bool has_changed_character = false; 1041 bool has_changed_character = false;
1046 bool is_ascii = FastAsciiConvert<Converter>( 1042 bool is_ascii = FastAsciiConvert<Converter>(
1047 reinterpret_cast<char*>(result->GetChars()), 1043 reinterpret_cast<char *>(result->GetChars()),
1048 reinterpret_cast<const char*>(flat_content.ToOneByteVector().start()), 1044 reinterpret_cast<const char *>(flat_content.ToOneByteVector().start()),
1049 length, &has_changed_character); 1045 length, &has_changed_character);
1050 // If not ASCII, we discard the result and take the 2 byte path. 1046 // If not ASCII, we discard the result and take the 2 byte path.
1051 if (is_ascii) return has_changed_character ? *result : *s; 1047 if (is_ascii) return has_changed_character ? *result : *s;
1052 } 1048 }
1053 1049
1054 Handle<SeqString> result; // Same length as input. 1050 Handle<SeqString> result; // Same length as input.
1055 if (s->IsOneByteRepresentation()) { 1051 if (s->IsOneByteRepresentation()) {
1056 result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); 1052 result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
1057 } else { 1053 } else {
1058 result = isolate->factory()->NewRawTwoByteString(length).ToHandleChecked(); 1054 result = isolate->factory()->NewRawTwoByteString(length).ToHandleChecked();
1059 } 1055 }
1060 1056
1061 Object* answer = ConvertCaseHelper(isolate, *s, *result, length, mapping); 1057 Object *answer = ConvertCaseHelper(isolate, *s, *result, length, mapping);
1062 if (answer->IsException() || answer->IsString()) return answer; 1058 if (answer->IsException() || answer->IsString()) return answer;
1063 1059
1064 DCHECK(answer->IsSmi()); 1060 DCHECK(answer->IsSmi());
1065 length = Smi::cast(answer)->value(); 1061 length = Smi::cast(answer)->value();
1066 if (s->IsOneByteRepresentation() && length > 0) { 1062 if (s->IsOneByteRepresentation() && length > 0) {
1067 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1063 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1068 isolate, result, isolate->factory()->NewRawOneByteString(length)); 1064 isolate, result, isolate->factory()->NewRawOneByteString(length));
1069 } else { 1065 } else {
1070 if (length < 0) length = -length; 1066 if (length < 0) length = -length;
1071 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1067 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
(...skipping 24 matching lines...) Expand all
1096 DCHECK(args.length() == 3); 1092 DCHECK(args.length() == 3);
1097 1093
1098 CONVERT_ARG_HANDLE_CHECKED(String, string, 0); 1094 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
1099 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1); 1095 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
1100 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2); 1096 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
1101 1097
1102 string = String::Flatten(string); 1098 string = String::Flatten(string);
1103 int length = string->length(); 1099 int length = string->length();
1104 1100
1105 int left = 0; 1101 int left = 0;
1106 UnicodeCache* unicode_cache = isolate->unicode_cache(); 1102 UnicodeCache *unicode_cache = isolate->unicode_cache();
1107 if (trimLeft) { 1103 if (trimLeft) {
1108 while (left < length && 1104 while (left < length &&
1109 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) { 1105 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) {
1110 left++; 1106 left++;
1111 } 1107 }
1112 } 1108 }
1113 1109
1114 int right = length; 1110 int right = length;
1115 if (trimRight) { 1111 if (trimRight) {
1116 while ( 1112 while (
(...skipping 27 matching lines...) Expand all
1144 if (is_one_byte) { 1140 if (is_one_byte) {
1145 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1141 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1146 isolate, result, isolate->factory()->NewRawOneByteString(length)); 1142 isolate, result, isolate->factory()->NewRawOneByteString(length));
1147 } else { 1143 } else {
1148 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1144 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1149 isolate, result, isolate->factory()->NewRawTwoByteString(length)); 1145 isolate, result, isolate->factory()->NewRawTwoByteString(length));
1150 } 1146 }
1151 return *result; 1147 return *result;
1152 } 1148 }
1153 1149
1150 bool unescapePredicateInComponent(uint16_t c) {
Yang 2016/05/12 07:39:21 CamelCase with capital first letter please. Also
Franzi 2016/05/13 09:42:03 Done.
1151 // do not escape alphanumeric or !'()*-._~
1152 if (c < 256 && isalnum(c)) {
Yang 2016/05/12 07:39:21 Let's use IsAlphaNumeric from char-predicates.h. T
Franzi 2016/05/13 09:42:03 Done.
1153 return true;
1154 }
1155 if (c == '!' || c == '\'' || c == '(' || c == ')' || c == '*' || c == '-' ||
1156 c == '.' || c == '_' || c == '~') {
Yang 2016/05/12 07:39:21 A switch would be a lot nicer to read.
Franzi 2016/05/13 09:42:02 Done.
1157 return true;
1158 }
1159
1160 return false;
1161 }
1162
1163 bool uriSeparator(uint16_t c) {
1164 // separators are #:;/?$&+,@=
1165 if (c == '#' || c == ':' || c == ';' || c == '/' || c == '?' || c == '$' ||
Yang 2016/05/12 07:39:21 Same here, a switch would be nice.
Franzi 2016/05/13 09:42:02 Done.
1166 c == '&' || c == '+' || c == ',' || c == '@' || c == '=') {
1167 return true;
1168 }
1169 return false;
1170 }
1171
1172 bool unescape(uint16_t c, bool is_url) {
Yang 2016/05/12 07:39:21 This is only used once. Let's inline it at the cal
Franzi 2016/05/13 09:42:03 Done.
1173 if (unescapePredicateInComponent(c)) {
1174 return true;
1175 }
1176 return is_url && uriSeparator(c);
1177 }
1178
1179 void uriAddEncodedOctetToBuffer(uint16_t octet, List<uint16_t> *result) {
1180 // Do I need lazy initialization?
Yang 2016/05/12 07:39:21 No. Just declare them as static const. And using a
Franzi 2016/05/13 09:42:02 Done.
1181 int hexCharCodeArray[16] = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, // 0..9
Yang 2016/05/12 07:39:21 We have a HexCharOfValue in bignum.cc. You could m
1182 65, 66, 67, 68, 69, 70}; // A..F
1183
1184 result->Add(37); // Char code of '%'.
Yang 2016/05/12 07:39:21 How about result->Add('%')
Franzi 2016/05/13 09:42:02 Done.
1185 uint16_t firstHex = octet >> 4;
1186 uint16_t secondHex = octet & 0x0F;
1187
1188 DCHECK(firstHex < 16);
1189 DCHECK(secondHex < 16);
1190
1191 result->Add(hexCharCodeArray[firstHex]);
1192 result->Add(hexCharCodeArray[secondHex]);
1193 }
1194
1195 void uriEncodeOctets(uint16_t *octets, List<uint16_t> *result) {
1196 uriAddEncodedOctetToBuffer(octets[0], result);
1197 if (octets[1]) uriAddEncodedOctetToBuffer(octets[1], result);
1198 if (octets[2]) uriAddEncodedOctetToBuffer(octets[2], result);
1199 if (octets[3]) uriAddEncodedOctetToBuffer(octets[3], result);
1200 }
1201
1202 void uriEncodeSingle(uint16_t cc, List<uint16_t> *result) {
1203 // 16 bits total, cut it in 4,6, and 6 bits
Yang 2016/05/12 07:39:21 whitespace after comma.
Franzi 2016/05/13 09:42:02 Done.
1204 uint16_t x = (cc >> 12) & 0xF;
Yang 2016/05/12 07:39:21 uint8_t should suffice.
Franzi 2016/05/13 09:42:02 Done.
1205 uint16_t y = (cc >> 6) & 63;
1206 uint16_t z = cc & 63; // get last 6 bits
1207 uint16_t octets[4] = {0, 0, 0, 0}; // TODO(franzih) 3 is enough here
1208 if (cc <= 0x007F) { // smaller than 8 bits, i.e., 128
1209 octets[0] = cc; // ascii same as UTF-8
Yang 2016/05/12 07:39:21 Instead of collecting octets, let's just call uriA
Franzi 2016/05/13 09:42:03 Done.
1210 } else if (cc <= 0x07FF) {
1211 octets[0] = y + 192; // Leading byte: 110xxxxx
1212 octets[1] = z + 128; // Continuation byte: 10xxxxxx
1213 } else {
1214 octets[0] = x + 224; // Leading byte: 1110xxxx
1215 octets[1] = y + 128; // Continuation byte: 10xxxxxx
1216 octets[2] = z + 128; // Continuation byte: 10xxxxxx
1217 }
1218
1219 uriEncodeOctets(octets, result);
1220 }
1221
1222 void uriEncodePair(uint16_t cc1, uint16_t cc2, List<uint16_t> *result) {
1223 uint16_t u = ((cc1 >> 6) & 0xF) + 1;
1224 uint16_t w = (cc1 >> 2) & 0xF;
1225 uint16_t x = cc1 & 3;
1226 uint16_t y = (cc2 >> 6) & 0xF;
1227 uint16_t z = cc2 & 63;
1228 uint16_t octets[4] = {0, 0, 0, 0};
1229 octets[0] = (u >> 2) + 240;
1230 octets[1] = (((u & 3) << 4) | w) + 128;
1231 octets[2] = ((x << 4) | y) + 128;
1232 octets[3] = z + 128;
1233 uriEncodeOctets(octets, result);
1234 }
1235
1236 RUNTIME_FUNCTION(Runtime_Encode) {
1237 HandleScope scope(isolate);
1238 DCHECK(args.length() == 2);
1239 CONVERT_ARG_HANDLE_CHECKED(String, uri, 0);
1240 CONVERT_BOOLEAN_ARG_CHECKED(is_uri, 1);
1241
1242 size_t uriLength = uri->length();
Yang 2016/05/12 07:39:20 Let's use int here.
Franzi 2016/05/13 09:42:03 Done.
1243 List<uint16_t> buffer;
Yang 2016/05/12 07:39:21 The result can only be ASCII characters, so please
Franzi 2016/05/13 09:42:03 Done.
1244
1245 for (size_t k = 0; k < uriLength; k++) {
Yang 2016/05/12 07:39:21 And int here.
Franzi 2016/05/13 09:42:02 Done.
1246 uint16_t cc1 = uri->Get(static_cast<int>(k));
Yang 2016/05/12 07:39:21 Calling Get is fairly inefficient. We should flat
Franzi 2016/05/13 09:42:02 Done. Using Get() on FlatContent.
1247
1248 if (unescape(cc1, is_uri)) {
1249 DCHECK(cc1 <= String::kMaxOneByteCharCode);
1250 buffer.Add(cc1);
1251 } else {
1252 if (cc1 >= 0xDC00 && cc1 <= 0xDFFF) {
Yang 2016/05/12 07:39:21 please do not use magic numbers here. Use unibrow:
Franzi 2016/05/13 09:42:02 Done.
1253 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewMakeURIError());
1254 }
1255 if (cc1 < 0xD800 || cc1 > 0xDBFF) {
Yang 2016/05/12 07:39:21 !unibrow::Utf16::IsLeadSurrogate
Franzi 2016/05/13 09:42:02 Done.
1256 uriEncodeSingle(cc1, &buffer);
1257 } else {
1258 k++;
1259 if (k == uriLength) {
1260 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewMakeURIError());
1261 }
1262 uint16_t cc2 = uri->Get(static_cast<int>(k));
1263 if (cc2 < 0xDC00 || cc2 > 0xDFFF) {
Yang 2016/05/12 07:39:21 Here as well.
Franzi 2016/05/13 09:42:03 Done.
1264 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewMakeURIError());
1265 }
1266 uriEncodePair(cc1, cc2, &buffer);
1267 }
1268 }
1269 }
1270
1271 Handle<String> result;
1272 int totalLength = buffer.length();
1273
1274 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1275 isolate, result, isolate->factory()->NewRawOneByteString(totalLength));
Yang 2016/05/12 07:39:21 NewStringFromAscii(buffer.ToConstVector()) would w
Franzi 2016/05/13 09:42:03 Done. I'm using NewStringFromOneByte() because buf
1276
1277 for (int i = 0; i < totalLength; i++) {
1278 uint16_t value = buffer.at(i);
1279 result->Set(i, value);
1280 }
1281 return *result;
1282 }
1283
1154 RUNTIME_FUNCTION(Runtime_StringLessThan) { 1284 RUNTIME_FUNCTION(Runtime_StringLessThan) {
1155 HandleScope handle_scope(isolate); 1285 HandleScope handle_scope(isolate);
1156 DCHECK_EQ(2, args.length()); 1286 DCHECK_EQ(2, args.length());
1157 CONVERT_ARG_HANDLE_CHECKED(String, x, 0); 1287 CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
1158 CONVERT_ARG_HANDLE_CHECKED(String, y, 1); 1288 CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
1159 switch (String::Compare(x, y)) { 1289 switch (String::Compare(x, y)) {
1160 case ComparisonResult::kLessThan: 1290 case ComparisonResult::kLessThan:
1161 return isolate->heap()->true_value(); 1291 return isolate->heap()->true_value();
1162 case ComparisonResult::kEqual: 1292 case ComparisonResult::kEqual:
1163 case ComparisonResult::kGreaterThan: 1293 case ComparisonResult::kGreaterThan:
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1258 return isolate->heap()->empty_string(); 1388 return isolate->heap()->empty_string();
1259 } 1389 }
1260 1390
1261 1391
1262 RUNTIME_FUNCTION(Runtime_StringCharAt) { 1392 RUNTIME_FUNCTION(Runtime_StringCharAt) {
1263 SealHandleScope shs(isolate); 1393 SealHandleScope shs(isolate);
1264 DCHECK(args.length() == 2); 1394 DCHECK(args.length() == 2);
1265 if (!args[0]->IsString()) return Smi::FromInt(0); 1395 if (!args[0]->IsString()) return Smi::FromInt(0);
1266 if (!args[1]->IsNumber()) return Smi::FromInt(0); 1396 if (!args[1]->IsNumber()) return Smi::FromInt(0);
1267 if (std::isinf(args.number_at(1))) return isolate->heap()->empty_string(); 1397 if (std::isinf(args.number_at(1))) return isolate->heap()->empty_string();
1268 Object* code = __RT_impl_Runtime_StringCharCodeAtRT(args, isolate); 1398 Object *code = __RT_impl_Runtime_StringCharCodeAtRT(args, isolate);
1269 if (code->IsNaN()) return isolate->heap()->empty_string(); 1399 if (code->IsNaN()) return isolate->heap()->empty_string();
1270 return __RT_impl_Runtime_StringCharFromCode(Arguments(1, &code), isolate); 1400 return __RT_impl_Runtime_StringCharFromCode(Arguments(1, &code), isolate);
1271 } 1401 }
1272 1402
1273 RUNTIME_FUNCTION(Runtime_ExternalStringGetChar) { 1403 RUNTIME_FUNCTION(Runtime_ExternalStringGetChar) {
1274 SealHandleScope shs(isolate); 1404 SealHandleScope shs(isolate);
1275 DCHECK_EQ(2, args.length()); 1405 DCHECK_EQ(2, args.length());
1276 CONVERT_ARG_CHECKED(ExternalString, string, 0); 1406 CONVERT_ARG_CHECKED(ExternalString, string, 0);
1277 CONVERT_INT32_ARG_CHECKED(index, 1); 1407 CONVERT_INT32_ARG_CHECKED(index, 1);
1278 return Smi::FromInt(string->Get(index)); 1408 return Smi::FromInt(string->Get(index));
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1322 SealHandleScope shs(isolate); 1452 SealHandleScope shs(isolate);
1323 DCHECK(args.length() == 2); 1453 DCHECK(args.length() == 2);
1324 if (!args[0]->IsString()) return isolate->heap()->undefined_value(); 1454 if (!args[0]->IsString()) return isolate->heap()->undefined_value();
1325 if (!args[1]->IsNumber()) return isolate->heap()->undefined_value(); 1455 if (!args[1]->IsNumber()) return isolate->heap()->undefined_value();
1326 if (std::isinf(args.number_at(1))) return isolate->heap()->nan_value(); 1456 if (std::isinf(args.number_at(1))) return isolate->heap()->nan_value();
1327 return __RT_impl_Runtime_StringCharCodeAtRT(args, isolate); 1457 return __RT_impl_Runtime_StringCharCodeAtRT(args, isolate);
1328 } 1458 }
1329 1459
1330 } // namespace internal 1460 } // namespace internal
1331 } // namespace v8 1461 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698