Chromium Code Reviews| 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 |