diff options
Diffstat (limited to 'deps/v8/src/builtins/builtins-string-gen.cc')
-rw-r--r-- | deps/v8/src/builtins/builtins-string-gen.cc | 273 |
1 files changed, 154 insertions, 119 deletions
diff --git a/deps/v8/src/builtins/builtins-string-gen.cc b/deps/v8/src/builtins/builtins-string-gen.cc index c46a3fd35d..574f425a0a 100644 --- a/deps/v8/src/builtins/builtins-string-gen.cc +++ b/deps/v8/src/builtins/builtins-string-gen.cc @@ -39,11 +39,11 @@ Node* StringBuiltinsAssembler::DirectStringData(Node* string, BIND(&if_external); { // This is only valid for ExternalStrings where the resource data - // pointer is cached (i.e. no short external strings). - CSA_ASSERT( - this, Word32NotEqual(Word32And(string_instance_type, - Int32Constant(kShortExternalStringMask)), - Int32Constant(kShortExternalStringTag))); + // pointer is cached (i.e. no uncached external strings). + CSA_ASSERT(this, Word32NotEqual( + Word32And(string_instance_type, + Int32Constant(kUncachedExternalStringMask)), + Int32Constant(kUncachedExternalStringTag))); var_data.Bind(LoadObjectField(string, ExternalString::kResourceDataOffset, MachineType::Pointer())); Goto(&if_join); @@ -191,11 +191,11 @@ void StringBuiltinsAssembler::StringEqual_Core( // Check if both {lhs} and {rhs} are direct strings, and that in case of // ExternalStrings the data pointer is cached. - STATIC_ASSERT(kShortExternalStringTag != 0); + STATIC_ASSERT(kUncachedExternalStringTag != 0); STATIC_ASSERT(kIsIndirectStringTag != 0); int const kBothDirectStringMask = - kIsIndirectStringMask | kShortExternalStringMask | - ((kIsIndirectStringMask | kShortExternalStringMask) << 8); + kIsIndirectStringMask | kUncachedExternalStringMask | + ((kIsIndirectStringMask | kUncachedExternalStringMask) << 8); GotoIfNot(Word32Equal(Word32And(both_instance_types, Int32Constant(kBothDirectStringMask)), Int32Constant(0)), @@ -284,67 +284,31 @@ void StringBuiltinsAssembler::StringEqual_Loop( } } -void StringBuiltinsAssembler::Generate_StringAdd(StringAddFlags flags, - PretenureFlag pretenure_flag, - Node* context, Node* left, - Node* right) { - switch (flags) { - case STRING_ADD_CONVERT_LEFT: { - // TODO(danno): The ToString and JSReceiverToPrimitive below could be - // combined to avoid duplicate smi and instance type checks. - left = ToString(context, JSReceiverToPrimitive(context, left)); - Callable callable = CodeFactory::StringAdd( - isolate(), STRING_ADD_CHECK_NONE, pretenure_flag); - TailCallStub(callable, context, left, right); - break; - } - case STRING_ADD_CONVERT_RIGHT: { - // TODO(danno): The ToString and JSReceiverToPrimitive below could be - // combined to avoid duplicate smi and instance type checks. - right = ToString(context, JSReceiverToPrimitive(context, right)); - Callable callable = CodeFactory::StringAdd( - isolate(), STRING_ADD_CHECK_NONE, pretenure_flag); - TailCallStub(callable, context, left, right); - break; - } - case STRING_ADD_CHECK_NONE: { - CodeStubAssembler::AllocationFlag allocation_flags = - (pretenure_flag == TENURED) ? CodeStubAssembler::kPretenured - : CodeStubAssembler::kNone; - Return(StringAdd(context, CAST(left), CAST(right), allocation_flags)); - break; - } - } -} - -TF_BUILTIN(StringAdd_CheckNone_NotTenured, StringBuiltinsAssembler) { - Node* left = Parameter(Descriptor::kLeft); - Node* right = Parameter(Descriptor::kRight); +TF_BUILTIN(StringAdd_CheckNone, StringBuiltinsAssembler) { + TNode<String> left = CAST(Parameter(Descriptor::kLeft)); + TNode<String> right = CAST(Parameter(Descriptor::kRight)); Node* context = Parameter(Descriptor::kContext); - Generate_StringAdd(STRING_ADD_CHECK_NONE, NOT_TENURED, context, left, right); + Return(StringAdd(context, left, right)); } -TF_BUILTIN(StringAdd_CheckNone_Tenured, StringBuiltinsAssembler) { - Node* left = Parameter(Descriptor::kLeft); - Node* right = Parameter(Descriptor::kRight); +TF_BUILTIN(StringAdd_ConvertLeft, StringBuiltinsAssembler) { + TNode<Object> left = CAST(Parameter(Descriptor::kLeft)); + TNode<String> right = CAST(Parameter(Descriptor::kRight)); Node* context = Parameter(Descriptor::kContext); - Generate_StringAdd(STRING_ADD_CHECK_NONE, TENURED, context, left, right); + // TODO(danno): The ToString and JSReceiverToPrimitive below could be + // combined to avoid duplicate smi and instance type checks. + left = ToString(context, JSReceiverToPrimitive(context, left)); + TailCallBuiltin(Builtins::kStringAdd_CheckNone, context, left, right); } -TF_BUILTIN(StringAdd_ConvertLeft_NotTenured, StringBuiltinsAssembler) { - Node* left = Parameter(Descriptor::kLeft); - Node* right = Parameter(Descriptor::kRight); +TF_BUILTIN(StringAdd_ConvertRight, StringBuiltinsAssembler) { + TNode<String> left = CAST(Parameter(Descriptor::kLeft)); + TNode<Object> right = CAST(Parameter(Descriptor::kRight)); Node* context = Parameter(Descriptor::kContext); - Generate_StringAdd(STRING_ADD_CONVERT_LEFT, NOT_TENURED, context, left, - right); -} - -TF_BUILTIN(StringAdd_ConvertRight_NotTenured, StringBuiltinsAssembler) { - Node* left = Parameter(Descriptor::kLeft); - Node* right = Parameter(Descriptor::kRight); - Node* context = Parameter(Descriptor::kContext); - Generate_StringAdd(STRING_ADD_CONVERT_RIGHT, NOT_TENURED, context, left, - right); + // TODO(danno): The ToString and JSReceiverToPrimitive below could be + // combined to avoid duplicate smi and instance type checks. + right = ToString(context, JSReceiverToPrimitive(context, right)); + TailCallBuiltin(Builtins::kStringAdd_CheckNone, context, left, right); } TF_BUILTIN(SubString, StringBuiltinsAssembler) { @@ -354,12 +318,10 @@ TF_BUILTIN(SubString, StringBuiltinsAssembler) { Return(SubString(string, SmiUntag(from), SmiUntag(to))); } -void StringBuiltinsAssembler::GenerateStringAt(char const* method_name, - TNode<Context> context, - Node* receiver, - TNode<Object> maybe_position, - TNode<Object> default_return, - StringAtAccessor accessor) { +void StringBuiltinsAssembler::GenerateStringAt( + char const* method_name, TNode<Context> context, Node* receiver, + TNode<Object> maybe_position, TNode<Object> default_return, + const StringAtAccessor& accessor) { // Check that {receiver} is coercible to Object and convert it to a String. TNode<String> string = ToThisString(context, receiver, method_name); @@ -587,8 +549,9 @@ TF_BUILTIN(StringGreaterThanOrEqual, StringBuiltinsAssembler) { } TF_BUILTIN(StringCharAt, StringBuiltinsAssembler) { - Node* receiver = Parameter(Descriptor::kReceiver); - Node* position = Parameter(Descriptor::kPosition); + TNode<String> receiver = CAST(Parameter(Descriptor::kReceiver)); + TNode<IntPtrT> position = + UncheckedCast<IntPtrT>(Parameter(Descriptor::kPosition)); // Load the character code at the {position} from the {receiver}. TNode<Int32T> code = StringCharCodeAt(receiver, position); @@ -639,7 +602,6 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) { Node* context = Parameter(Descriptor::kContext); CodeStubArguments arguments(this, ChangeInt32ToIntPtr(argc)); - TNode<Smi> smi_argc = SmiTag(arguments.GetLength(INTPTR_PARAMETERS)); // Check if we have exactly one argument (plus the implicit receiver), i.e. // if the parent frame is not an arguments adaptor frame. Label if_oneargument(this), if_notoneargument(this); @@ -664,7 +626,7 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) { { Label two_byte(this); // Assume that the resulting string contains only one-byte characters. - Node* one_byte_result = AllocateSeqOneByteString(context, smi_argc); + Node* one_byte_result = AllocateSeqOneByteString(context, Unsigned(argc)); TVARIABLE(IntPtrT, var_max_index); var_max_index = IntPtrConstant(0); @@ -698,7 +660,7 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) { // At least one of the characters in the string requires a 16-bit // representation. Allocate a SeqTwoByteString to hold the resulting // string. - Node* two_byte_result = AllocateSeqTwoByteString(context, smi_argc); + Node* two_byte_result = AllocateSeqTwoByteString(context, Unsigned(argc)); // Copy the characters that have already been put in the 8-bit string into // their corresponding positions in the new 16-bit string. @@ -817,7 +779,7 @@ TF_BUILTIN(StringPrototypeConcat, CodeStubAssembler) { void StringBuiltinsAssembler::StringIndexOf( Node* const subject_string, Node* const search_string, Node* const position, - std::function<void(Node*)> f_return) { + const std::function<void(Node*)>& f_return) { CSA_ASSERT(this, IsString(subject_string)); CSA_ASSERT(this, IsString(search_string)); CSA_ASSERT(this, TaggedIsSmi(position)); @@ -1229,8 +1191,6 @@ TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) { TNode<Object> count = CAST(Parameter(Descriptor::kCount)); Node* const string = ToThisString(context, receiver, "String.prototype.repeat"); - Node* const is_stringempty = - SmiEqual(LoadStringLengthAsSmi(string), SmiConstant(0)); VARIABLE( var_count, MachineRepresentation::kTagged, @@ -1248,7 +1208,8 @@ TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) { TNode<Smi> smi_count = CAST(var_count.value()); GotoIf(SmiLessThan(smi_count, SmiConstant(0)), &invalid_count); GotoIf(SmiEqual(smi_count, SmiConstant(0)), &return_emptystring); - GotoIf(is_stringempty, &return_emptystring); + GotoIf(Word32Equal(LoadStringLengthAsWord32(string), Int32Constant(0)), + &return_emptystring); GotoIf(SmiGreaterThan(smi_count, SmiConstant(String::kMaxLength)), &invalid_string_length); Return(CallBuiltin(Builtins::kStringRepeat, context, string, smi_count)); @@ -1266,7 +1227,8 @@ TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) { &invalid_count); GotoIf(Float64LessThan(number_value, Float64Constant(0.0)), &invalid_count); - Branch(is_stringempty, &return_emptystring, &invalid_string_length); + Branch(Word32Equal(LoadStringLengthAsWord32(string), Int32Constant(0)), + &return_emptystring, &invalid_string_length); } } @@ -1311,9 +1273,6 @@ TF_BUILTIN(StringRepeat, StringBuiltinsAssembler) { VARIABLE(var_temp, MachineRepresentation::kTagged, string); TVARIABLE(Smi, var_count, count); - Callable stringadd_callable = - CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); - Label loop(this, {&var_count, &var_result, &var_temp}), return_result(this); Goto(&loop); BIND(&loop); @@ -1321,16 +1280,16 @@ TF_BUILTIN(StringRepeat, StringBuiltinsAssembler) { { Label next(this); GotoIfNot(SmiToInt32(SmiAnd(var_count.value(), SmiConstant(1))), &next); - var_result.Bind(CallStub(stringadd_callable, context, var_result.value(), - var_temp.value())); + var_result.Bind(CallBuiltin(Builtins::kStringAdd_CheckNone, context, + var_result.value(), var_temp.value())); Goto(&next); BIND(&next); } var_count = SmiShr(var_count.value(), 1); GotoIf(SmiEqual(var_count.value(), SmiConstant(0)), &return_result); - var_temp.Bind(CallStub(stringadd_callable, context, var_temp.value(), - var_temp.value())); + var_temp.Bind(CallBuiltin(Builtins::kStringAdd_CheckNone, context, + var_temp.value(), var_temp.value())); Goto(&loop); } @@ -1369,16 +1328,16 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) { TNode<String> const subject_string = ToString_Inline(context, receiver); TNode<String> const search_string = ToString_Inline(context, search); - TNode<Smi> const subject_length = LoadStringLengthAsSmi(subject_string); - TNode<Smi> const search_length = LoadStringLengthAsSmi(search_string); + TNode<IntPtrT> const subject_length = LoadStringLengthAsWord(subject_string); + TNode<IntPtrT> const search_length = LoadStringLengthAsWord(search_string); // Fast-path single-char {search}, long cons {receiver}, and simple string // {replace}. { Label next(this); - GotoIfNot(SmiEqual(search_length, SmiConstant(1)), &next); - GotoIfNot(SmiGreaterThan(subject_length, SmiConstant(0xFF)), &next); + GotoIfNot(WordEqual(search_length, IntPtrConstant(1)), &next); + GotoIfNot(IntPtrGreaterThan(subject_length, IntPtrConstant(0xFF)), &next); GotoIf(TaggedIsSmi(replace), &next); GotoIfNot(IsString(replace), &next); @@ -1430,10 +1389,8 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) { BIND(&next); } - TNode<Smi> const match_end_index = SmiAdd(match_start_index, search_length); - - Callable stringadd_callable = - CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); + TNode<Smi> const match_end_index = + SmiAdd(match_start_index, SmiFromIntPtr(search_length)); VARIABLE(var_result, MachineRepresentation::kTagged, EmptyStringConstant()); @@ -1465,8 +1422,8 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) { CallJS(call_callable, context, replace, UndefinedConstant(), search_string, match_start_index, subject_string); Node* const replacement_string = ToString_Inline(context, replacement); - var_result.Bind(CallStub(stringadd_callable, context, var_result.value(), - replacement_string)); + var_result.Bind(CallBuiltin(Builtins::kStringAdd_CheckNone, context, + var_result.value(), replacement_string)); Goto(&out); } @@ -1476,8 +1433,8 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) { Node* const replacement = GetSubstitution(context, subject_string, match_start_index, match_end_index, replace_string); - var_result.Bind( - CallStub(stringadd_callable, context, var_result.value(), replacement)); + var_result.Bind(CallBuiltin(Builtins::kStringAdd_CheckNone, context, + var_result.value(), replacement)); Goto(&out); } @@ -1485,9 +1442,9 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) { { Node* const suffix = CallBuiltin(Builtins::kStringSubstring, context, subject_string, - SmiUntag(match_end_index), SmiUntag(subject_length)); - Node* const result = - CallStub(stringadd_callable, context, var_result.value(), suffix); + SmiUntag(match_end_index), subject_length); + Node* const result = CallBuiltin(Builtins::kStringAdd_CheckNone, context, + var_result.value(), suffix); Return(result); } } @@ -1679,8 +1636,6 @@ class StringPadAssembler : public StringBuiltinsAssembler { SmiLessThanOrEqual(smi_max_length, SmiConstant(String::kMaxLength)), &invalid_string_length); - Callable stringadd_callable = - CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); CSA_ASSERT(this, SmiGreaterThan(smi_max_length, string_length)); TNode<Smi> const pad_length = SmiSub(smi_max_length, string_length); @@ -1717,19 +1672,20 @@ class StringPadAssembler : public StringBuiltinsAssembler { Node* const remainder_string = CallBuiltin( Builtins::kStringSubstring, context, var_fill_string.value(), IntPtrConstant(0), ChangeInt32ToIntPtr(remaining_word32)); - var_pad.Bind(CallStub(stringadd_callable, context, var_pad.value(), - remainder_string)); + var_pad.Bind(CallBuiltin(Builtins::kStringAdd_CheckNone, context, + var_pad.value(), remainder_string)); Goto(&return_result); } } BIND(&return_result); CSA_ASSERT(this, SmiEqual(pad_length, LoadStringLengthAsSmi(var_pad.value()))); - arguments.PopAndReturn(variant == kStart - ? CallStub(stringadd_callable, context, - var_pad.value(), receiver_string) - : CallStub(stringadd_callable, context, - receiver_string, var_pad.value())); + arguments.PopAndReturn( + variant == kStart + ? CallBuiltin(Builtins::kStringAdd_CheckNone, context, + var_pad.value(), receiver_string) + : CallBuiltin(Builtins::kStringAdd_CheckNone, context, + receiver_string, var_pad.value())); } BIND(&dont_pad); arguments.PopAndReturn(receiver_string); @@ -1844,7 +1800,7 @@ TNode<JSArray> StringBuiltinsAssembler::StringToArray( TNode<RawPtrT> string_data = UncheckedCast<RawPtrT>( to_direct.PointerToData(&fill_thehole_and_call_runtime)); TNode<IntPtrT> string_data_offset = to_direct.offset(); - TNode<Object> cache = LoadRoot(Heap::kSingleCharacterStringCacheRootIndex); + TNode<Object> cache = LoadRoot(RootIndex::kSingleCharacterStringCache); BuildFastLoop( IntPtrConstant(0), length, @@ -1876,7 +1832,7 @@ TNode<JSArray> StringBuiltinsAssembler::StringToArray( BIND(&fill_thehole_and_call_runtime); { FillFixedArrayWithValue(PACKED_ELEMENTS, elements, IntPtrConstant(0), - length, Heap::kTheHoleValueRootIndex); + length, RootIndex::kTheHoleValue); Goto(&call_runtime); } } @@ -2303,10 +2259,10 @@ void StringTrimAssembler::ScanForNonWhiteSpaceOrLineTerminator( BIND(&out); } -void StringTrimAssembler::BuildLoop(Variable* const var_index, Node* const end, - int increment, Label* const if_none_found, - Label* const out, - std::function<Node*(Node*)> get_character) { +void StringTrimAssembler::BuildLoop( + Variable* const var_index, Node* const end, int increment, + Label* const if_none_found, Label* const out, + const std::function<Node*(Node*)>& get_character) { Label loop(this, var_index); Goto(&loop); BIND(&loop); @@ -2403,14 +2359,14 @@ TF_BUILTIN(StringPrototypeIterator, CodeStubAssembler) { ToThisString(context, receiver, "String.prototype[Symbol.iterator]"); Node* native_context = LoadNativeContext(context); - Node* map = - LoadContextElement(native_context, Context::STRING_ITERATOR_MAP_INDEX); + Node* map = LoadContextElement(native_context, + Context::INITIAL_STRING_ITERATOR_MAP_INDEX); Node* iterator = Allocate(JSStringIterator::kSize); StoreMapNoWriteBarrier(iterator, map); StoreObjectFieldRoot(iterator, JSValue::kPropertiesOrHashOffset, - Heap::kEmptyFixedArrayRootIndex); + RootIndex::kEmptyFixedArray); StoreObjectFieldRoot(iterator, JSObject::kElementsOffset, - Heap::kEmptyFixedArrayRootIndex); + RootIndex::kEmptyFixedArray); StoreObjectFieldNoWriteBarrier(iterator, JSStringIterator::kStringOffset, string); Node* index = SmiConstant(0); @@ -2537,6 +2493,85 @@ TF_BUILTIN(StringIteratorPrototypeNext, StringBuiltinsAssembler) { } } +TNode<BoolT> StringBuiltinsAssembler::IsStringPrimitiveWithNoCustomIteration( + TNode<Object> object, TNode<Context> context) { + Label if_false(this, Label::kDeferred), exit(this); + TVARIABLE(BoolT, var_result); + + GotoIf(TaggedIsSmi(object), &if_false); + GotoIfNot(IsString(CAST(object)), &if_false); + + // Check that the String iterator hasn't been modified in a way that would + // affect iteration. + Node* protector_cell = LoadRoot(RootIndex::kStringIteratorProtector); + DCHECK(isolate()->heap()->string_iterator_protector()->IsPropertyCell()); + var_result = + WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset), + SmiConstant(Isolate::kProtectorValid)); + Goto(&exit); + + BIND(&if_false); + { + var_result = Int32FalseConstant(); + Goto(&exit); + } + + BIND(&exit); + return var_result.value(); +} + +TNode<JSArray> StringBuiltinsAssembler::StringToList(TNode<Context> context, + TNode<String> string) { + CSA_ASSERT(this, IsStringPrimitiveWithNoCustomIteration(string, context)); + const ElementsKind kind = PACKED_ELEMENTS; + const TNode<IntPtrT> length = LoadStringLengthAsWord(string); + + Node* const array_map = + LoadJSArrayElementsMap(kind, LoadNativeContext(context)); + Node* const array = AllocateJSArray(kind, array_map, length, SmiTag(length)); + Node* const elements = LoadElements(array); + + const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag; + TNode<IntPtrT> first_to_element_offset = + ElementOffsetFromIndex(IntPtrConstant(0), kind, INTPTR_PARAMETERS, 0); + VARIABLE( + var_offset, MachineType::PointerRepresentation(), + IntPtrAdd(first_to_element_offset, IntPtrConstant(first_element_offset))); + TVARIABLE(IntPtrT, var_position, IntPtrConstant(0)); + Label done(this), next_codepoint(this, {&var_position, &var_offset}); + + Goto(&next_codepoint); + + BIND(&next_codepoint); + { + // Loop condition. + GotoIfNot(IntPtrLessThan(var_position.value(), length), &done); + const UnicodeEncoding encoding = UnicodeEncoding::UTF16; + TNode<Int32T> ch = + LoadSurrogatePairAt(string, length, var_position.value(), encoding); + TNode<String> value = StringFromSingleCodePoint(ch, encoding); + + Store(elements, var_offset.value(), value); + + // Increment the position. + TNode<IntPtrT> ch_length = LoadStringLengthAsWord(value); + var_position = IntPtrAdd(var_position.value(), ch_length); + // Increment the array offset and continue the loop. + var_offset.Bind( + IntPtrAdd(var_offset.value(), IntPtrConstant(kPointerSize))); + Goto(&next_codepoint); + } + + BIND(&done); + return UncheckedCast<JSArray>(array); +} + +TF_BUILTIN(StringToList, StringBuiltinsAssembler) { + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<String> string = CAST(Parameter(Descriptor::kSource)); + Return(StringToList(context, string)); +} + // ----------------------------------------------------------------------------- // ES6 section B.2.3 Additional Properties of the String.prototype object |