OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |