diff options
Diffstat (limited to 'deps/v8/src/builtins/builtins-string-gen.cc')
-rw-r--r-- | deps/v8/src/builtins/builtins-string-gen.cc | 236 |
1 files changed, 106 insertions, 130 deletions
diff --git a/deps/v8/src/builtins/builtins-string-gen.cc b/deps/v8/src/builtins/builtins-string-gen.cc index 9d86f3105b..195572de8e 100644 --- a/deps/v8/src/builtins/builtins-string-gen.cc +++ b/deps/v8/src/builtins/builtins-string-gen.cc @@ -126,8 +126,8 @@ Node* StringBuiltinsAssembler::PointerToStringDataAtIndex( void StringBuiltinsAssembler::ConvertAndBoundsCheckStartArgument( Node* context, Variable* var_start, Node* start, Node* string_length) { - TNode<Object> const start_int = - ToInteger(context, start, CodeStubAssembler::kTruncateMinusZero); + TNode<Object> const start_int = ToInteger_Inline( + CAST(context), CAST(start), CodeStubAssembler::kTruncateMinusZero); TNode<Smi> const zero = SmiConstant(0); Label done(this); @@ -319,6 +319,31 @@ void StringBuiltinsAssembler::StringEqual_Loop( } } +void StringBuiltinsAssembler::GenerateStringAt(char const* method_name, + TNode<Context> context, + Node* receiver, + TNode<Object> maybe_position, + TNode<Object> default_return, + StringAtAccessor accessor) { + // Check that {receiver} is coercible to Object and convert it to a String. + TNode<String> string = ToThisString(context, receiver, method_name); + + // Convert the {position} to a Smi and check that it's in bounds of the + // {string}. + Label if_outofbounds(this, Label::kDeferred); + TNode<Number> position = ToInteger_Inline( + context, maybe_position, CodeStubAssembler::kTruncateMinusZero); + GotoIfNot(TaggedIsSmi(position), &if_outofbounds); + TNode<IntPtrT> index = SmiUntag(CAST(position)); + TNode<IntPtrT> length = LoadStringLengthAsWord(string); + GotoIfNot(UintPtrLessThan(index, length), &if_outofbounds); + TNode<Object> result = accessor(string, length, index); + Return(result); + + BIND(&if_outofbounds); + Return(default_return); +} + void StringBuiltinsAssembler::GenerateStringRelationalComparison(Node* context, Node* left, Node* right, @@ -526,28 +551,43 @@ TF_BUILTIN(StringGreaterThanOrEqual, StringBuiltinsAssembler) { Operation::kGreaterThanOrEqual); } -TF_BUILTIN(StringCharAt, CodeStubAssembler) { +TF_BUILTIN(StringCharAt, StringBuiltinsAssembler) { Node* receiver = Parameter(Descriptor::kReceiver); Node* position = Parameter(Descriptor::kPosition); // Load the character code at the {position} from the {receiver}. - Node* code = StringCharCodeAt(receiver, position); + TNode<Int32T> code = StringCharCodeAt(receiver, position); // And return the single character string with only that {code} - Node* result = StringFromCharCode(code); + TNode<String> result = StringFromCharCode(code); Return(result); } -TF_BUILTIN(StringCharCodeAt, CodeStubAssembler) { +TF_BUILTIN(StringCharCodeAt, StringBuiltinsAssembler) { Node* receiver = Parameter(Descriptor::kReceiver); Node* position = Parameter(Descriptor::kPosition); // Load the character code at the {position} from the {receiver}. - Node* code = StringCharCodeAt(receiver, position); + TNode<Int32T> code = StringCharCodeAt(receiver, position); + + // And return it as TaggedSigned value. + // TODO(turbofan): Allow builtins to return values untagged. + TNode<Smi> result = SmiFromWord32(code); + Return(result); +} + +TF_BUILTIN(StringCodePointAt, StringBuiltinsAssembler) { + Node* receiver = Parameter(Descriptor::kReceiver); + Node* position = Parameter(Descriptor::kPosition); + // TODO(sigurds) Figure out if passing length as argument pays off. + TNode<IntPtrT> length = LoadStringLengthAsWord(receiver); + // Load the character code at the {position} from the {receiver}. + TNode<Int32T> code = + LoadSurrogatePairAt(receiver, length, position, UnicodeEncoding::UTF32); // And return it as TaggedSigned value. // TODO(turbofan): Allow builtins to return values untagged. - Node* result = SmiFromWord32(code); + TNode<Smi> result = SmiFromWord32(code); Return(result); } @@ -563,7 +603,7 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) { Node* context = Parameter(BuiltinDescriptor::kContext); CodeStubArguments arguments(this, ChangeInt32ToIntPtr(argc)); - TNode<Smi> smi_argc = SmiTag(arguments.GetLength()); + 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); @@ -577,7 +617,8 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) { // string on the fly otherwise. Node* code = arguments.AtIndex(0); Node* code32 = TruncateTaggedToWord32(context, code); - Node* code16 = Word32And(code32, Int32Constant(String::kMaxUtf16CodeUnit)); + TNode<Int32T> code16 = + Signed(Word32And(code32, Int32Constant(String::kMaxUtf16CodeUnit))); Node* result = StringFromCharCode(code16); arguments.PopAndReturn(result); } @@ -662,115 +703,49 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) { } // ES6 #sec-string.prototype.charat -TF_BUILTIN(StringPrototypeCharAt, CodeStubAssembler) { +TF_BUILTIN(StringPrototypeCharAt, StringBuiltinsAssembler) { + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); Node* receiver = Parameter(Descriptor::kReceiver); - Node* position = Parameter(Descriptor::kPosition); - Node* context = Parameter(Descriptor::kContext); - - // Check that {receiver} is coercible to Object and convert it to a String. - receiver = ToThisString(context, receiver, "String.prototype.charAt"); - - // Convert the {position} to a Smi and check that it's in bounds of the - // {receiver}. - { - Label return_emptystring(this, Label::kDeferred); - position = - ToInteger(context, position, CodeStubAssembler::kTruncateMinusZero); - GotoIfNot(TaggedIsSmi(position), &return_emptystring); - - // Determine the actual length of the {receiver} String. - TNode<Smi> receiver_length = LoadStringLengthAsSmi(receiver); - - // Return "" if the Smi {position} is outside the bounds of the {receiver}. - Label if_positioninbounds(this); - Branch(SmiAboveOrEqual(position, receiver_length), &return_emptystring, - &if_positioninbounds); - - BIND(&return_emptystring); - Return(EmptyStringConstant()); - - BIND(&if_positioninbounds); - } - - // Load the character code at the {position} from the {receiver}. - CSA_ASSERT(this, IntPtrLessThan(SmiUntag(position), - LoadStringLengthAsWord(receiver))); - CSA_ASSERT(this, - IntPtrGreaterThanOrEqual(SmiUntag(position), IntPtrConstant(0))); - Node* code = StringCharCodeAt(receiver, SmiUntag(position)); + TNode<Object> maybe_position = CAST(Parameter(Descriptor::kPosition)); - // And return the single character string with only that {code}. - Node* result = StringFromCharCode(code); - Return(result); + GenerateStringAt("String.prototype.charAt", context, receiver, maybe_position, + EmptyStringConstant(), + [this](TNode<String> string, TNode<IntPtrT> length, + TNode<IntPtrT> index) { + TNode<Int32T> code = StringCharCodeAt(string, index); + return StringFromCharCode(code); + }); } // ES6 #sec-string.prototype.charcodeat -TF_BUILTIN(StringPrototypeCharCodeAt, CodeStubAssembler) { +TF_BUILTIN(StringPrototypeCharCodeAt, StringBuiltinsAssembler) { + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); Node* receiver = Parameter(Descriptor::kReceiver); - Node* position = Parameter(Descriptor::kPosition); - Node* context = Parameter(Descriptor::kContext); - - // Check that {receiver} is coercible to Object and convert it to a String. - receiver = ToThisString(context, receiver, "String.prototype.charCodeAt"); - - // Convert the {position} to a Smi and check that it's in bounds of the - // {receiver}. - { - Label return_nan(this, Label::kDeferred); - position = - ToInteger(context, position, CodeStubAssembler::kTruncateMinusZero); - GotoIfNot(TaggedIsSmi(position), &return_nan); - - // Determine the actual length of the {receiver} String. - TNode<Smi> receiver_length = LoadStringLengthAsSmi(receiver); - - // Return NaN if the Smi {position} is outside the bounds of the {receiver}. - Label if_positioninbounds(this); - Branch(SmiAboveOrEqual(position, receiver_length), &return_nan, - &if_positioninbounds); + TNode<Object> maybe_position = CAST(Parameter(Descriptor::kPosition)); - BIND(&return_nan); - Return(NaNConstant()); - - BIND(&if_positioninbounds); - } - - // Load the character at the {position} from the {receiver}. - Node* value = StringCharCodeAt(receiver, SmiUntag(position)); - Node* result = SmiFromWord32(value); - Return(result); + GenerateStringAt("String.prototype.charCodeAt", context, receiver, + maybe_position, NanConstant(), + [this](TNode<String> receiver, TNode<IntPtrT> length, + TNode<IntPtrT> index) { + Node* value = StringCharCodeAt(receiver, index); + return SmiFromWord32(value); + }); } // ES6 #sec-string.prototype.codepointat TF_BUILTIN(StringPrototypeCodePointAt, StringBuiltinsAssembler) { - Node* context = Parameter(Descriptor::kContext); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); Node* receiver = Parameter(Descriptor::kReceiver); - Node* position = Parameter(Descriptor::kPosition); - - // Check that {receiver} is coercible to Object and convert it to a String. - receiver = ToThisString(context, receiver, "String.prototype.codePointAt"); - - // Convert the {position} to a Smi and check that it's in bounds of the - // {receiver}. - Label if_inbounds(this), if_outofbounds(this, Label::kDeferred); - position = - ToInteger(context, position, CodeStubAssembler::kTruncateMinusZero); - GotoIfNot(TaggedIsSmi(position), &if_outofbounds); - TNode<IntPtrT> untagged_position = SmiUntag(position); - TNode<IntPtrT> receiver_length = LoadStringLengthAsWord(receiver); - Branch(UintPtrLessThan(untagged_position, receiver_length), &if_inbounds, - &if_outofbounds); - - BIND(&if_inbounds); - { - Node* value = LoadSurrogatePairAt( - receiver, receiver_length, untagged_position, UnicodeEncoding::UTF32); - Node* result = SmiFromWord32(value); - Return(result); - } + TNode<Object> maybe_position = CAST(Parameter(Descriptor::kPosition)); - BIND(&if_outofbounds); - Return(UndefinedConstant()); + GenerateStringAt("String.prototype.codePointAt", context, receiver, + maybe_position, UndefinedConstant(), + [this](TNode<String> receiver, TNode<IntPtrT> length, + TNode<IntPtrT> index) { + Node* value = LoadSurrogatePairAt(receiver, length, index, + UnicodeEncoding::UTF32); + return SmiFromWord32(value); + }); } // ES6 String.prototype.concat(...args) @@ -999,7 +974,7 @@ void StringIncludesIndexOfAssembler::Generate(SearchVariant variant) { CodeStubArguments arguments(this, ChangeInt32ToIntPtr(argc)); Node* const receiver = arguments.GetReceiver(); // From now on use word-size argc value. - argc = arguments.GetLength(); + argc = arguments.GetLength(INTPTR_PARAMETERS); VARIABLE(var_search_string, MachineRepresentation::kTagged); VARIABLE(var_position, MachineRepresentation::kTagged); @@ -1217,16 +1192,17 @@ TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) { Label invalid_count(this), invalid_string_length(this), return_emptystring(this); - Node* const context = Parameter(Descriptor::kContext); + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); Node* const receiver = Parameter(Descriptor::kReceiver); - Node* const count = Parameter(Descriptor::kCount); + 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, - ToInteger(context, count, CodeStubAssembler::kTruncateMinusZero)); + VARIABLE( + var_count, MachineRepresentation::kTagged, + ToInteger_Inline(context, count, CodeStubAssembler::kTruncateMinusZero)); // Verifies a valid count and takes a fast path when the result will be an // empty string. @@ -1713,8 +1689,8 @@ TF_BUILTIN(StringPrototypeSlice, StringBuiltinsAssembler) { CodeStubArguments args(this, argc); Node* const receiver = args.GetReceiver(); Node* const start = args.GetOptionalArgumentValue(kStart); - Node* const end = args.GetOptionalArgumentValue(kEnd); - Node* const context = Parameter(BuiltinDescriptor::kContext); + TNode<Object> end = CAST(args.GetOptionalArgumentValue(kEnd)); + TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext)); TNode<Smi> const smi_zero = SmiConstant(0); @@ -1737,7 +1713,7 @@ TF_BUILTIN(StringPrototypeSlice, StringBuiltinsAssembler) { // else let intEnd be ? ToInteger(end). Node* const end_int = - ToInteger(context, end, CodeStubAssembler::kTruncateMinusZero); + ToInteger_Inline(context, end, CodeStubAssembler::kTruncateMinusZero); // 7. If intEnd < 0, let to be max(len + intEnd, 0); // otherwise let to be min(intEnd, len). @@ -1893,8 +1869,8 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) { Node* const receiver = args.GetReceiver(); Node* const start = args.GetOptionalArgumentValue(kStartArg); - Node* const length = args.GetOptionalArgumentValue(kLengthArg); - Node* const context = Parameter(BuiltinDescriptor::kContext); + TNode<Object> length = CAST(args.GetOptionalArgumentValue(kLengthArg)); + TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext)); Label out(this); @@ -1925,8 +1901,8 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) { Goto(&if_issmi); BIND(&if_isnotundefined); - var_length = - ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero); + var_length = ToInteger_Inline(context, length, + CodeStubAssembler::kTruncateMinusZero); } TVARIABLE(Smi, var_result_length); @@ -1984,7 +1960,7 @@ TNode<Smi> StringBuiltinsAssembler::ToSmiBetweenZeroAnd( TVARIABLE(Smi, var_result); TNode<Object> const value_int = - this->ToInteger(context, value, CodeStubAssembler::kTruncateMinusZero); + ToInteger_Inline(context, value, CodeStubAssembler::kTruncateMinusZero); Label if_issmi(this), if_isnotsmi(this, Label::kDeferred); Branch(TaggedIsSmi(value_int), &if_issmi, &if_isnotsmi); @@ -2296,14 +2272,14 @@ TF_BUILTIN(StringPrototypeIterator, CodeStubAssembler) { // Return the |word32| codepoint at {index}. Supports SeqStrings and // ExternalStrings. -TNode<Uint32T> StringBuiltinsAssembler::LoadSurrogatePairAt( +TNode<Int32T> StringBuiltinsAssembler::LoadSurrogatePairAt( SloppyTNode<String> string, SloppyTNode<IntPtrT> length, SloppyTNode<IntPtrT> index, UnicodeEncoding encoding) { Label handle_surrogate_pair(this), return_result(this); - TVARIABLE(Uint32T, var_result); - TVARIABLE(Uint32T, var_trail); + TVARIABLE(Int32T, var_result); + TVARIABLE(Int32T, var_trail); var_result = StringCharCodeAt(string, index); - var_trail = Unsigned(Int32Constant(0)); + var_trail = Int32Constant(0); GotoIf(Word32NotEqual(Word32And(var_result, Int32Constant(0xFC00)), Int32Constant(0xD800)), @@ -2318,8 +2294,8 @@ TNode<Uint32T> StringBuiltinsAssembler::LoadSurrogatePairAt( BIND(&handle_surrogate_pair); { - TNode<Uint32T> lead = var_result; - TNode<Uint32T> trail = var_trail; + TNode<Int32T> lead = var_result; + TNode<Int32T> trail = var_trail; // Check that this path is only taken if a surrogate pair is found CSA_SLOW_ASSERT(this, @@ -2331,7 +2307,7 @@ TNode<Uint32T> StringBuiltinsAssembler::LoadSurrogatePairAt( switch (encoding) { case UnicodeEncoding::UTF16: - var_result = Unsigned(Word32Or( + var_result = Signed(Word32Or( // Need to swap the order for big-endian platforms #if V8_TARGET_BIG_ENDIAN Word32Shl(lead, Int32Constant(16)), trail)); @@ -2347,8 +2323,8 @@ TNode<Uint32T> StringBuiltinsAssembler::LoadSurrogatePairAt( Int32Constant(0x10000 - (0xD800 << 10) - 0xDC00); // (lead << 10) + trail + SURROGATE_OFFSET - var_result = Unsigned(Int32Add(Word32Shl(lead, Int32Constant(10)), - Int32Add(trail, surrogate_offset))); + var_result = Signed(Int32Add(Word32Shl(lead, Int32Constant(10)), + Int32Add(trail, surrogate_offset))); break; } } @@ -2387,8 +2363,8 @@ TF_BUILTIN(StringIteratorPrototypeNext, StringBuiltinsAssembler) { BIND(&next_codepoint); { UnicodeEncoding encoding = UnicodeEncoding::UTF16; - Node* ch = LoadSurrogatePairAt(string, length, position, encoding); - Node* value = StringFromCodePoint(ch, encoding); + TNode<Int32T> ch = LoadSurrogatePairAt(string, length, position, encoding); + TNode<String> value = StringFromCodePoint(ch, encoding); var_value.Bind(value); TNode<IntPtrT> length = LoadStringLengthAsWord(value); StoreObjectFieldNoWriteBarrier(iterator, JSStringIterator::kNextIndexOffset, |