summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/builtins-string-gen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/builtins/builtins-string-gen.cc')
-rw-r--r--deps/v8/src/builtins/builtins-string-gen.cc236
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,