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

Side by Side Diff: src/builtins/builtins-string-gen.cc

Issue 2752143004: [refactor] Separate generated builtins and C++ builtins into separate files (Closed)
Patch Set: tentative gcmole fix Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins-string.cc ('k') | src/builtins/builtins-symbol.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2017 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/builtins/builtins-regexp.h" 5 #include "src/builtins/builtins-regexp-gen.h"
6 #include "src/builtins/builtins-utils.h" 6 #include "src/builtins/builtins-utils-gen.h"
7 #include "src/builtins/builtins.h" 7 #include "src/builtins/builtins.h"
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/code-stub-assembler.h" 9 #include "src/code-stub-assembler.h"
10 #include "src/conversions.h" 10 #include "src/objects.h"
11 #include "src/counters.h"
12 #include "src/objects-inl.h"
13 #include "src/regexp/regexp-utils.h"
14 #include "src/string-case.h"
15 #include "src/unicode-inl.h"
16 #include "src/unicode.h"
17 11
18 namespace v8 { 12 namespace v8 {
19 namespace internal { 13 namespace internal {
20 14
21 typedef CodeStubAssembler::RelationalComparisonMode RelationalComparisonMode; 15 typedef CodeStubAssembler::RelationalComparisonMode RelationalComparisonMode;
22 16
23 class StringBuiltinsAssembler : public CodeStubAssembler { 17 class StringBuiltinsAssembler : public CodeStubAssembler {
24 public: 18 public:
25 explicit StringBuiltinsAssembler(compiler::CodeAssemblerState* state) 19 explicit StringBuiltinsAssembler(compiler::CodeAssemblerState* state)
26 : CodeStubAssembler(state) {} 20 : CodeStubAssembler(state) {}
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 } 356 }
363 357
364 Bind(&if_done); 358 Bind(&if_done);
365 { 359 {
366 // All characters up to the min length are equal, decide based on 360 // All characters up to the min length are equal, decide based on
367 // string length. 361 // string length.
368 GotoIf(SmiEqual(lhs_length, rhs_length), &if_equal); 362 GotoIf(SmiEqual(lhs_length, rhs_length), &if_equal);
369 BranchIfSmiLessThan(lhs_length, rhs_length, &if_less, &if_greater); 363 BranchIfSmiLessThan(lhs_length, rhs_length, &if_less, &if_greater);
370 } 364 }
371 } 365 }
372 } 366 }
373 367
374 Bind(&if_notbothonebyteseqstrings); 368 Bind(&if_notbothonebyteseqstrings);
375 { 369 {
376 // Try to unwrap indirect strings, restart the above attempt on success. 370 // Try to unwrap indirect strings, restart the above attempt on success.
377 MaybeDerefIndirectStrings(&var_left, lhs_instance_type, &var_right, 371 MaybeDerefIndirectStrings(&var_left, lhs_instance_type, &var_right,
378 rhs_instance_type, &restart); 372 rhs_instance_type, &restart);
379 // TODO(bmeurer): Add support for two byte string relational comparisons. 373 // TODO(bmeurer): Add support for two byte string relational comparisons.
380 switch (mode) {
381 case RelationalComparisonMode::kLessThan:
382 TailCallRuntime(Runtime::kStringLessThan, context, lhs, rhs);
383 break;
384 case RelationalComparisonMode::kLessThanOrEqual:
385 TailCallRuntime(Runtime::kStringLessThanOrEqual, context, lhs, rhs);
386 break;
387 case RelationalComparisonMode::kGreaterThan:
388 TailCallRuntime(Runtime::kStringGreaterThan, context, lhs, rhs);
389 break;
390 case RelationalComparisonMode::kGreaterThanOrEqual:
391 TailCallRuntime(Runtime::kStringGreaterThanOrEqual, context, lhs,
392 rhs);
393 break;
394 }
395 }
396
397 Bind(&if_less);
398 switch (mode) { 374 switch (mode) {
399 case RelationalComparisonMode::kLessThan: 375 case RelationalComparisonMode::kLessThan:
376 TailCallRuntime(Runtime::kStringLessThan, context, lhs, rhs);
377 break;
400 case RelationalComparisonMode::kLessThanOrEqual: 378 case RelationalComparisonMode::kLessThanOrEqual:
401 Return(BooleanConstant(true)); 379 TailCallRuntime(Runtime::kStringLessThanOrEqual, context, lhs, rhs);
402 break; 380 break;
381 case RelationalComparisonMode::kGreaterThan:
382 TailCallRuntime(Runtime::kStringGreaterThan, context, lhs, rhs);
383 break;
384 case RelationalComparisonMode::kGreaterThanOrEqual:
385 TailCallRuntime(Runtime::kStringGreaterThanOrEqual, context, lhs, rhs);
386 break;
387 }
388 }
403 389
404 case RelationalComparisonMode::kGreaterThan: 390 Bind(&if_less);
405 case RelationalComparisonMode::kGreaterThanOrEqual: 391 switch (mode) {
406 Return(BooleanConstant(false)); 392 case RelationalComparisonMode::kLessThan:
407 break; 393 case RelationalComparisonMode::kLessThanOrEqual:
394 Return(BooleanConstant(true));
395 break;
396
397 case RelationalComparisonMode::kGreaterThan:
398 case RelationalComparisonMode::kGreaterThanOrEqual:
399 Return(BooleanConstant(false));
400 break;
408 } 401 }
409 402
410 Bind(&if_equal); 403 Bind(&if_equal);
411 switch (mode) { 404 switch (mode) {
412 case RelationalComparisonMode::kLessThan: 405 case RelationalComparisonMode::kLessThan:
413 case RelationalComparisonMode::kGreaterThan: 406 case RelationalComparisonMode::kGreaterThan:
414 Return(BooleanConstant(false)); 407 Return(BooleanConstant(false));
415 break; 408 break;
416 409
417 case RelationalComparisonMode::kLessThanOrEqual: 410 case RelationalComparisonMode::kLessThanOrEqual:
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
584 StoreNoWriteBarrier(MachineRepresentation::kWord16, two_byte_result, 577 StoreNoWriteBarrier(MachineRepresentation::kWord16, two_byte_result,
585 offset, code16); 578 offset, code16);
586 max_index.Bind(IntPtrAdd(max_index.value(), IntPtrConstant(1))); 579 max_index.Bind(IntPtrAdd(max_index.value(), IntPtrConstant(1)));
587 }, 580 },
588 max_index.value()); 581 max_index.value());
589 582
590 arguments.PopAndReturn(two_byte_result); 583 arguments.PopAndReturn(two_byte_result);
591 } 584 }
592 } 585 }
593 586
594 namespace { // for String.fromCodePoint
595
596 bool IsValidCodePoint(Isolate* isolate, Handle<Object> value) {
597 if (!value->IsNumber() && !Object::ToNumber(value).ToHandle(&value)) {
598 return false;
599 }
600
601 if (Object::ToInteger(isolate, value).ToHandleChecked()->Number() !=
602 value->Number()) {
603 return false;
604 }
605
606 if (value->Number() < 0 || value->Number() > 0x10FFFF) {
607 return false;
608 }
609
610 return true;
611 }
612
613 uc32 NextCodePoint(Isolate* isolate, BuiltinArguments args, int index) {
614 Handle<Object> value = args.at(1 + index);
615 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::ToNumber(value), -1);
616 if (!IsValidCodePoint(isolate, value)) {
617 isolate->Throw(*isolate->factory()->NewRangeError(
618 MessageTemplate::kInvalidCodePoint, value));
619 return -1;
620 }
621 return DoubleToUint32(value->Number());
622 }
623
624 } // namespace
625
626 // ES6 section 21.1.2.2 String.fromCodePoint ( ...codePoints )
627 BUILTIN(StringFromCodePoint) {
628 HandleScope scope(isolate);
629 int const length = args.length() - 1;
630 if (length == 0) return isolate->heap()->empty_string();
631 DCHECK_LT(0, length);
632
633 // Optimistically assume that the resulting String contains only one byte
634 // characters.
635 List<uint8_t> one_byte_buffer(length);
636 uc32 code = 0;
637 int index;
638 for (index = 0; index < length; index++) {
639 code = NextCodePoint(isolate, args, index);
640 if (code < 0) {
641 return isolate->heap()->exception();
642 }
643 if (code > String::kMaxOneByteCharCode) {
644 break;
645 }
646 one_byte_buffer.Add(code);
647 }
648
649 if (index == length) {
650 RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromOneByte(
651 one_byte_buffer.ToConstVector()));
652 }
653
654 List<uc16> two_byte_buffer(length - index);
655
656 while (true) {
657 if (code <= static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) {
658 two_byte_buffer.Add(code);
659 } else {
660 two_byte_buffer.Add(unibrow::Utf16::LeadSurrogate(code));
661 two_byte_buffer.Add(unibrow::Utf16::TrailSurrogate(code));
662 }
663
664 if (++index == length) {
665 break;
666 }
667 code = NextCodePoint(isolate, args, index);
668 if (code < 0) {
669 return isolate->heap()->exception();
670 }
671 }
672
673 Handle<SeqTwoByteString> result;
674 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
675 isolate, result,
676 isolate->factory()->NewRawTwoByteString(one_byte_buffer.length() +
677 two_byte_buffer.length()));
678
679 CopyChars(result->GetChars(), one_byte_buffer.ToConstVector().start(),
680 one_byte_buffer.length());
681 CopyChars(result->GetChars() + one_byte_buffer.length(),
682 two_byte_buffer.ToConstVector().start(), two_byte_buffer.length());
683
684 return *result;
685 }
686
687 // ES6 section 21.1.3.1 String.prototype.charAt ( pos ) 587 // ES6 section 21.1.3.1 String.prototype.charAt ( pos )
688 TF_BUILTIN(StringPrototypeCharAt, CodeStubAssembler) { 588 TF_BUILTIN(StringPrototypeCharAt, CodeStubAssembler) {
689 Node* receiver = Parameter(0); 589 Node* receiver = Parameter(0);
690 Node* position = Parameter(1); 590 Node* position = Parameter(1);
691 Node* context = Parameter(4); 591 Node* context = Parameter(4);
692 592
693 // Check that {receiver} is coercible to Object and convert it to a String. 593 // Check that {receiver} is coercible to Object and convert it to a String.
694 receiver = ToThisString(context, receiver, "String.prototype.charAt"); 594 receiver = ToThisString(context, receiver, "String.prototype.charAt");
695 595
696 // Convert the {position} to a Smi and check that it's in bounds of the 596 // Convert the {position} to a Smi and check that it's in bounds of the
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 653
754 Bind(&if_positioninbounds); 654 Bind(&if_positioninbounds);
755 } 655 }
756 656
757 // Load the character at the {position} from the {receiver}. 657 // Load the character at the {position} from the {receiver}.
758 Node* value = StringCharCodeAt(receiver, position); 658 Node* value = StringCharCodeAt(receiver, position);
759 Node* result = SmiFromWord32(value); 659 Node* result = SmiFromWord32(value);
760 Return(result); 660 Return(result);
761 } 661 }
762 662
763 // ES6 section 21.1.3.6
764 // String.prototype.endsWith ( searchString [ , endPosition ] )
765 BUILTIN(StringPrototypeEndsWith) {
766 HandleScope handle_scope(isolate);
767 TO_THIS_STRING(str, "String.prototype.endsWith");
768
769 // Check if the search string is a regExp and fail if it is.
770 Handle<Object> search = args.atOrUndefined(isolate, 1);
771 Maybe<bool> is_reg_exp = RegExpUtils::IsRegExp(isolate, search);
772 if (is_reg_exp.IsNothing()) {
773 DCHECK(isolate->has_pending_exception());
774 return isolate->heap()->exception();
775 }
776 if (is_reg_exp.FromJust()) {
777 THROW_NEW_ERROR_RETURN_FAILURE(
778 isolate, NewTypeError(MessageTemplate::kFirstArgumentNotRegExp,
779 isolate->factory()->NewStringFromStaticChars(
780 "String.prototype.endsWith")));
781 }
782 Handle<String> search_string;
783 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
784 Object::ToString(isolate, search));
785
786 Handle<Object> position = args.atOrUndefined(isolate, 2);
787 int end;
788
789 if (position->IsUndefined(isolate)) {
790 end = str->length();
791 } else {
792 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
793 Object::ToInteger(isolate, position));
794 end = str->ToValidIndex(*position);
795 }
796
797 int start = end - search_string->length();
798 if (start < 0) return isolate->heap()->false_value();
799
800 str = String::Flatten(str);
801 search_string = String::Flatten(search_string);
802
803 DisallowHeapAllocation no_gc; // ensure vectors stay valid
804 String::FlatContent str_content = str->GetFlatContent();
805 String::FlatContent search_content = search_string->GetFlatContent();
806
807 if (str_content.IsOneByte() && search_content.IsOneByte()) {
808 Vector<const uint8_t> str_vector = str_content.ToOneByteVector();
809 Vector<const uint8_t> search_vector = search_content.ToOneByteVector();
810
811 return isolate->heap()->ToBoolean(memcmp(str_vector.start() + start,
812 search_vector.start(),
813 search_string->length()) == 0);
814 }
815
816 FlatStringReader str_reader(isolate, str);
817 FlatStringReader search_reader(isolate, search_string);
818
819 for (int i = 0; i < search_string->length(); i++) {
820 if (str_reader.Get(start + i) != search_reader.Get(i)) {
821 return isolate->heap()->false_value();
822 }
823 }
824 return isolate->heap()->true_value();
825 }
826
827 // ES6 section 21.1.3.7
828 // String.prototype.includes ( searchString [ , position ] )
829 BUILTIN(StringPrototypeIncludes) {
830 HandleScope handle_scope(isolate);
831 TO_THIS_STRING(str, "String.prototype.includes");
832
833 // Check if the search string is a regExp and fail if it is.
834 Handle<Object> search = args.atOrUndefined(isolate, 1);
835 Maybe<bool> is_reg_exp = RegExpUtils::IsRegExp(isolate, search);
836 if (is_reg_exp.IsNothing()) {
837 DCHECK(isolate->has_pending_exception());
838 return isolate->heap()->exception();
839 }
840 if (is_reg_exp.FromJust()) {
841 THROW_NEW_ERROR_RETURN_FAILURE(
842 isolate, NewTypeError(MessageTemplate::kFirstArgumentNotRegExp,
843 isolate->factory()->NewStringFromStaticChars(
844 "String.prototype.includes")));
845 }
846 Handle<String> search_string;
847 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
848 Object::ToString(isolate, search));
849 Handle<Object> position;
850 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
851 isolate, position,
852 Object::ToInteger(isolate, args.atOrUndefined(isolate, 2)));
853
854 uint32_t index = str->ToValidIndex(*position);
855 int index_in_str = String::IndexOf(isolate, str, search_string, index);
856 return *isolate->factory()->ToBoolean(index_in_str != -1);
857 }
858
859 void StringBuiltinsAssembler::StringIndexOf( 663 void StringBuiltinsAssembler::StringIndexOf(
860 Node* receiver, Node* instance_type, Node* search_string, 664 Node* receiver, Node* instance_type, Node* search_string,
861 Node* search_string_instance_type, Node* position, 665 Node* search_string_instance_type, Node* position,
862 std::function<void(Node*)> f_return) { 666 std::function<void(Node*)> f_return) {
863 CSA_ASSERT(this, IsString(receiver)); 667 CSA_ASSERT(this, IsString(receiver));
864 CSA_ASSERT(this, IsString(search_string)); 668 CSA_ASSERT(this, IsString(search_string));
865 CSA_ASSERT(this, TaggedIsSmi(position)); 669 CSA_ASSERT(this, TaggedIsSmi(position));
866 670
867 Label zero_length_needle(this), 671 Label zero_length_needle(this),
868 call_runtime_unchecked(this, Label::kDeferred), return_minus_1(this), 672 call_runtime_unchecked(this, Label::kDeferred), return_minus_1(this),
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
1058 862
1059 Bind(&call_runtime); 863 Bind(&call_runtime);
1060 { 864 {
1061 Comment("Call Runtime"); 865 Comment("Call Runtime");
1062 Node* result = CallRuntime(Runtime::kStringIndexOf, context, receiver, 866 Node* result = CallRuntime(Runtime::kStringIndexOf, context, receiver,
1063 search_string.value(), position.value()); 867 search_string.value(), position.value());
1064 arguments.PopAndReturn(result); 868 arguments.PopAndReturn(result);
1065 } 869 }
1066 } 870 }
1067 871
1068 // ES6 section 21.1.3.9
1069 // String.prototype.lastIndexOf ( searchString [ , position ] )
1070 BUILTIN(StringPrototypeLastIndexOf) {
1071 HandleScope handle_scope(isolate);
1072 return String::LastIndexOf(isolate, args.receiver(),
1073 args.atOrUndefined(isolate, 1),
1074 args.atOrUndefined(isolate, 2));
1075 }
1076
1077 // ES6 section 21.1.3.10 String.prototype.localeCompare ( that )
1078 //
1079 // This function is implementation specific. For now, we do not
1080 // do anything locale specific.
1081 // If internationalization is enabled, then i18n.js will override this function
1082 // and provide the proper functionality, so this is just a fallback.
1083 BUILTIN(StringPrototypeLocaleCompare) {
1084 HandleScope handle_scope(isolate);
1085 DCHECK_EQ(2, args.length());
1086
1087 TO_THIS_STRING(str1, "String.prototype.localeCompare");
1088 Handle<String> str2;
1089 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str2,
1090 Object::ToString(isolate, args.at(1)));
1091
1092 if (str1.is_identical_to(str2)) return Smi::kZero; // Equal.
1093 int str1_length = str1->length();
1094 int str2_length = str2->length();
1095
1096 // Decide trivial cases without flattening.
1097 if (str1_length == 0) {
1098 if (str2_length == 0) return Smi::kZero; // Equal.
1099 return Smi::FromInt(-str2_length);
1100 } else {
1101 if (str2_length == 0) return Smi::FromInt(str1_length);
1102 }
1103
1104 int end = str1_length < str2_length ? str1_length : str2_length;
1105
1106 // No need to flatten if we are going to find the answer on the first
1107 // character. At this point we know there is at least one character
1108 // in each string, due to the trivial case handling above.
1109 int d = str1->Get(0) - str2->Get(0);
1110 if (d != 0) return Smi::FromInt(d);
1111
1112 str1 = String::Flatten(str1);
1113 str2 = String::Flatten(str2);
1114
1115 DisallowHeapAllocation no_gc;
1116 String::FlatContent flat1 = str1->GetFlatContent();
1117 String::FlatContent flat2 = str2->GetFlatContent();
1118
1119 for (int i = 0; i < end; i++) {
1120 if (flat1.Get(i) != flat2.Get(i)) {
1121 return Smi::FromInt(flat1.Get(i) - flat2.Get(i));
1122 }
1123 }
1124
1125 return Smi::FromInt(str1_length - str2_length);
1126 }
1127
1128 // ES6 section 21.1.3.12 String.prototype.normalize ( [form] )
1129 //
1130 // Simply checks the argument is valid and returns the string itself.
1131 // If internationalization is enabled, then i18n.js will override this function
1132 // and provide the proper functionality, so this is just a fallback.
1133 BUILTIN(StringPrototypeNormalize) {
1134 HandleScope handle_scope(isolate);
1135 TO_THIS_STRING(string, "String.prototype.normalize");
1136
1137 Handle<Object> form_input = args.atOrUndefined(isolate, 1);
1138 if (form_input->IsUndefined(isolate)) return *string;
1139
1140 Handle<String> form;
1141 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, form,
1142 Object::ToString(isolate, form_input));
1143
1144 if (!(String::Equals(form,
1145 isolate->factory()->NewStringFromStaticChars("NFC")) ||
1146 String::Equals(form,
1147 isolate->factory()->NewStringFromStaticChars("NFD")) ||
1148 String::Equals(form,
1149 isolate->factory()->NewStringFromStaticChars("NFKC")) ||
1150 String::Equals(form,
1151 isolate->factory()->NewStringFromStaticChars("NFKD")))) {
1152 Handle<String> valid_forms =
1153 isolate->factory()->NewStringFromStaticChars("NFC, NFD, NFKC, NFKD");
1154 THROW_NEW_ERROR_RETURN_FAILURE(
1155 isolate,
1156 NewRangeError(MessageTemplate::kNormalizationForm, valid_forms));
1157 }
1158
1159 return *string;
1160 }
1161
1162 compiler::Node* StringBuiltinsAssembler::IsNullOrUndefined(Node* const value) { 872 compiler::Node* StringBuiltinsAssembler::IsNullOrUndefined(Node* const value) {
1163 return Word32Or(IsUndefined(value), IsNull(value)); 873 return Word32Or(IsUndefined(value), IsNull(value));
1164 } 874 }
1165 875
1166 void StringBuiltinsAssembler::RequireObjectCoercible(Node* const context, 876 void StringBuiltinsAssembler::RequireObjectCoercible(Node* const context,
1167 Node* const value, 877 Node* const value,
1168 const char* method_name) { 878 const char* method_name) {
1169 Label out(this), throw_exception(this, Label::kDeferred); 879 Label out(this), throw_exception(this, Label::kDeferred);
1170 Branch(IsNullOrUndefined(value), &throw_exception, &out); 880 Branch(IsNullOrUndefined(value), &throw_exception, &out);
1171 881
(...skipping 547 matching lines...) Expand 10 before | Expand all | Expand 10 after
1719 } 1429 }
1720 1430
1721 Bind(&out); 1431 Bind(&out);
1722 { 1432 {
1723 Node* result = 1433 Node* result =
1724 SubString(context, string, var_start.value(), var_end.value()); 1434 SubString(context, string, var_start.value(), var_end.value());
1725 Return(result); 1435 Return(result);
1726 } 1436 }
1727 } 1437 }
1728 1438
1729 BUILTIN(StringPrototypeStartsWith) {
1730 HandleScope handle_scope(isolate);
1731 TO_THIS_STRING(str, "String.prototype.startsWith");
1732
1733 // Check if the search string is a regExp and fail if it is.
1734 Handle<Object> search = args.atOrUndefined(isolate, 1);
1735 Maybe<bool> is_reg_exp = RegExpUtils::IsRegExp(isolate, search);
1736 if (is_reg_exp.IsNothing()) {
1737 DCHECK(isolate->has_pending_exception());
1738 return isolate->heap()->exception();
1739 }
1740 if (is_reg_exp.FromJust()) {
1741 THROW_NEW_ERROR_RETURN_FAILURE(
1742 isolate, NewTypeError(MessageTemplate::kFirstArgumentNotRegExp,
1743 isolate->factory()->NewStringFromStaticChars(
1744 "String.prototype.startsWith")));
1745 }
1746 Handle<String> search_string;
1747 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
1748 Object::ToString(isolate, search));
1749
1750 Handle<Object> position = args.atOrUndefined(isolate, 2);
1751 int start;
1752
1753 if (position->IsUndefined(isolate)) {
1754 start = 0;
1755 } else {
1756 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, position,
1757 Object::ToInteger(isolate, position));
1758 start = str->ToValidIndex(*position);
1759 }
1760
1761 if (start + search_string->length() > str->length()) {
1762 return isolate->heap()->false_value();
1763 }
1764
1765 FlatStringReader str_reader(isolate, String::Flatten(str));
1766 FlatStringReader search_reader(isolate, String::Flatten(search_string));
1767
1768 for (int i = 0; i < search_string->length(); i++) {
1769 if (str_reader.Get(start + i) != search_reader.Get(i)) {
1770 return isolate->heap()->false_value();
1771 }
1772 }
1773 return isolate->heap()->true_value();
1774 }
1775
1776 // ES6 section 21.1.3.25 String.prototype.toString () 1439 // ES6 section 21.1.3.25 String.prototype.toString ()
1777 TF_BUILTIN(StringPrototypeToString, CodeStubAssembler) { 1440 TF_BUILTIN(StringPrototypeToString, CodeStubAssembler) {
1778 Node* receiver = Parameter(0); 1441 Node* receiver = Parameter(0);
1779 Node* context = Parameter(3); 1442 Node* context = Parameter(3);
1780 1443
1781 Node* result = ToThisValue(context, receiver, PrimitiveType::kString, 1444 Node* result = ToThisValue(context, receiver, PrimitiveType::kString,
1782 "String.prototype.toString"); 1445 "String.prototype.toString");
1783 Return(result); 1446 Return(result);
1784 } 1447 }
1785 1448
1786 // ES6 section 21.1.3.27 String.prototype.trim ()
1787 BUILTIN(StringPrototypeTrim) {
1788 HandleScope scope(isolate);
1789 TO_THIS_STRING(string, "String.prototype.trim");
1790 return *String::Trim(string, String::kTrim);
1791 }
1792
1793 // Non-standard WebKit extension
1794 BUILTIN(StringPrototypeTrimLeft) {
1795 HandleScope scope(isolate);
1796 TO_THIS_STRING(string, "String.prototype.trimLeft");
1797 return *String::Trim(string, String::kTrimLeft);
1798 }
1799
1800 // Non-standard WebKit extension
1801 BUILTIN(StringPrototypeTrimRight) {
1802 HandleScope scope(isolate);
1803 TO_THIS_STRING(string, "String.prototype.trimRight");
1804 return *String::Trim(string, String::kTrimRight);
1805 }
1806
1807 // ES6 section 21.1.3.28 String.prototype.valueOf ( ) 1449 // ES6 section 21.1.3.28 String.prototype.valueOf ( )
1808 TF_BUILTIN(StringPrototypeValueOf, CodeStubAssembler) { 1450 TF_BUILTIN(StringPrototypeValueOf, CodeStubAssembler) {
1809 Node* receiver = Parameter(0); 1451 Node* receiver = Parameter(0);
1810 Node* context = Parameter(3); 1452 Node* context = Parameter(3);
1811 1453
1812 Node* result = ToThisValue(context, receiver, PrimitiveType::kString, 1454 Node* result = ToThisValue(context, receiver, PrimitiveType::kString,
1813 "String.prototype.valueOf"); 1455 "String.prototype.valueOf");
1814 Return(result); 1456 Return(result);
1815 } 1457 }
1816 1458
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
1962 { 1604 {
1963 // The {receiver} is not a valid JSGeneratorObject. 1605 // The {receiver} is not a valid JSGeneratorObject.
1964 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, 1606 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
1965 HeapConstant(factory()->NewStringFromAsciiChecked( 1607 HeapConstant(factory()->NewStringFromAsciiChecked(
1966 "String Iterator.prototype.next", TENURED)), 1608 "String Iterator.prototype.next", TENURED)),
1967 iterator); 1609 iterator);
1968 Unreachable(); 1610 Unreachable();
1969 } 1611 }
1970 } 1612 }
1971 1613
1972 namespace {
1973
1974 inline bool ToUpperOverflows(uc32 character) {
1975 // y with umlauts and the micro sign are the only characters that stop
1976 // fitting into one-byte when converting to uppercase.
1977 static const uc32 yuml_code = 0xff;
1978 static const uc32 micro_code = 0xb5;
1979 return (character == yuml_code || character == micro_code);
1980 }
1981
1982 template <class Converter>
1983 MUST_USE_RESULT static Object* ConvertCaseHelper(
1984 Isolate* isolate, String* string, SeqString* result, int result_length,
1985 unibrow::Mapping<Converter, 128>* mapping) {
1986 DisallowHeapAllocation no_gc;
1987 // We try this twice, once with the assumption that the result is no longer
1988 // than the input and, if that assumption breaks, again with the exact
1989 // length. This may not be pretty, but it is nicer than what was here before
1990 // and I hereby claim my vaffel-is.
1991 //
1992 // NOTE: This assumes that the upper/lower case of an ASCII
1993 // character is also ASCII. This is currently the case, but it
1994 // might break in the future if we implement more context and locale
1995 // dependent upper/lower conversions.
1996 bool has_changed_character = false;
1997
1998 // Convert all characters to upper case, assuming that they will fit
1999 // in the buffer
2000 StringCharacterStream stream(string);
2001 unibrow::uchar chars[Converter::kMaxWidth];
2002 // We can assume that the string is not empty
2003 uc32 current = stream.GetNext();
2004 bool ignore_overflow = Converter::kIsToLower || result->IsSeqTwoByteString();
2005 for (int i = 0; i < result_length;) {
2006 bool has_next = stream.HasMore();
2007 uc32 next = has_next ? stream.GetNext() : 0;
2008 int char_length = mapping->get(current, next, chars);
2009 if (char_length == 0) {
2010 // The case conversion of this character is the character itself.
2011 result->Set(i, current);
2012 i++;
2013 } else if (char_length == 1 &&
2014 (ignore_overflow || !ToUpperOverflows(current))) {
2015 // Common case: converting the letter resulted in one character.
2016 DCHECK(static_cast<uc32>(chars[0]) != current);
2017 result->Set(i, chars[0]);
2018 has_changed_character = true;
2019 i++;
2020 } else if (result_length == string->length()) {
2021 bool overflows = ToUpperOverflows(current);
2022 // We've assumed that the result would be as long as the
2023 // input but here is a character that converts to several
2024 // characters. No matter, we calculate the exact length
2025 // of the result and try the whole thing again.
2026 //
2027 // Note that this leaves room for optimization. We could just
2028 // memcpy what we already have to the result string. Also,
2029 // the result string is the last object allocated we could
2030 // "realloc" it and probably, in the vast majority of cases,
2031 // extend the existing string to be able to hold the full
2032 // result.
2033 int next_length = 0;
2034 if (has_next) {
2035 next_length = mapping->get(next, 0, chars);
2036 if (next_length == 0) next_length = 1;
2037 }
2038 int current_length = i + char_length + next_length;
2039 while (stream.HasMore()) {
2040 current = stream.GetNext();
2041 overflows |= ToUpperOverflows(current);
2042 // NOTE: we use 0 as the next character here because, while
2043 // the next character may affect what a character converts to,
2044 // it does not in any case affect the length of what it convert
2045 // to.
2046 int char_length = mapping->get(current, 0, chars);
2047 if (char_length == 0) char_length = 1;
2048 current_length += char_length;
2049 if (current_length > String::kMaxLength) {
2050 AllowHeapAllocation allocate_error_and_return;
2051 THROW_NEW_ERROR_RETURN_FAILURE(isolate,
2052 NewInvalidStringLengthError());
2053 }
2054 }
2055 // Try again with the real length. Return signed if we need
2056 // to allocate a two-byte string for to uppercase.
2057 return (overflows && !ignore_overflow) ? Smi::FromInt(-current_length)
2058 : Smi::FromInt(current_length);
2059 } else {
2060 for (int j = 0; j < char_length; j++) {
2061 result->Set(i, chars[j]);
2062 i++;
2063 }
2064 has_changed_character = true;
2065 }
2066 current = next;
2067 }
2068 if (has_changed_character) {
2069 return result;
2070 } else {
2071 // If we didn't actually change anything in doing the conversion
2072 // we simple return the result and let the converted string
2073 // become garbage; there is no reason to keep two identical strings
2074 // alive.
2075 return string;
2076 }
2077 }
2078
2079 template <class Converter>
2080 MUST_USE_RESULT static Object* ConvertCase(
2081 Handle<String> s, Isolate* isolate,
2082 unibrow::Mapping<Converter, 128>* mapping) {
2083 s = String::Flatten(s);
2084 int length = s->length();
2085 // Assume that the string is not empty; we need this assumption later
2086 if (length == 0) return *s;
2087
2088 // Simpler handling of ASCII strings.
2089 //
2090 // NOTE: This assumes that the upper/lower case of an ASCII
2091 // character is also ASCII. This is currently the case, but it
2092 // might break in the future if we implement more context and locale
2093 // dependent upper/lower conversions.
2094 if (s->IsOneByteRepresentationUnderneath()) {
2095 // Same length as input.
2096 Handle<SeqOneByteString> result =
2097 isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
2098 DisallowHeapAllocation no_gc;
2099 String::FlatContent flat_content = s->GetFlatContent();
2100 DCHECK(flat_content.IsFlat());
2101 bool has_changed_character = false;
2102 int index_to_first_unprocessed = FastAsciiConvert<Converter::kIsToLower>(
2103 reinterpret_cast<char*>(result->GetChars()),
2104 reinterpret_cast<const char*>(flat_content.ToOneByteVector().start()),
2105 length, &has_changed_character);
2106 // If not ASCII, we discard the result and take the 2 byte path.
2107 if (index_to_first_unprocessed == length)
2108 return has_changed_character ? *result : *s;
2109 }
2110
2111 Handle<SeqString> result; // Same length as input.
2112 if (s->IsOneByteRepresentation()) {
2113 result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked();
2114 } else {
2115 result = isolate->factory()->NewRawTwoByteString(length).ToHandleChecked();
2116 }
2117
2118 Object* answer = ConvertCaseHelper(isolate, *s, *result, length, mapping);
2119 if (answer->IsException(isolate) || answer->IsString()) return answer;
2120
2121 DCHECK(answer->IsSmi());
2122 length = Smi::cast(answer)->value();
2123 if (s->IsOneByteRepresentation() && length > 0) {
2124 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2125 isolate, result, isolate->factory()->NewRawOneByteString(length));
2126 } else {
2127 if (length < 0) length = -length;
2128 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2129 isolate, result, isolate->factory()->NewRawTwoByteString(length));
2130 }
2131 return ConvertCaseHelper(isolate, *s, *result, length, mapping);
2132 }
2133
2134 } // namespace
2135
2136 BUILTIN(StringPrototypeToLocaleLowerCase) {
2137 HandleScope scope(isolate);
2138 TO_THIS_STRING(string, "String.prototype.toLocaleLowerCase");
2139 return ConvertCase(string, isolate,
2140 isolate->runtime_state()->to_lower_mapping());
2141 }
2142
2143 BUILTIN(StringPrototypeToLocaleUpperCase) {
2144 HandleScope scope(isolate);
2145 TO_THIS_STRING(string, "String.prototype.toLocaleUpperCase");
2146 return ConvertCase(string, isolate,
2147 isolate->runtime_state()->to_upper_mapping());
2148 }
2149
2150 BUILTIN(StringPrototypeToLowerCase) {
2151 HandleScope scope(isolate);
2152 TO_THIS_STRING(string, "String.prototype.toLowerCase");
2153 return ConvertCase(string, isolate,
2154 isolate->runtime_state()->to_lower_mapping());
2155 }
2156
2157 BUILTIN(StringPrototypeToUpperCase) {
2158 HandleScope scope(isolate);
2159 TO_THIS_STRING(string, "String.prototype.toUpperCase");
2160 return ConvertCase(string, isolate,
2161 isolate->runtime_state()->to_upper_mapping());
2162 }
2163
2164 } // namespace internal 1614 } // namespace internal
2165 } // namespace v8 1615 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins-string.cc ('k') | src/builtins/builtins-symbol.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698