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

Unified Diff: src/builtins/builtins-string-gen.cc

Issue 2870013004: [builtins] String.prototype.slice as a CSA builtin. (Closed)
Patch Set: REBASE. Created 3 years, 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/builtins/builtins-definitions.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/builtins/builtins-string-gen.cc
diff --git a/src/builtins/builtins-string-gen.cc b/src/builtins/builtins-string-gen.cc
index 5b457b7083b27fc469ff67dbf9a965da05fab93d..18fba261e8957c6a29e1c0ca305b0f0f45de1fc7 100644
--- a/src/builtins/builtins-string-gen.cc
+++ b/src/builtins/builtins-string-gen.cc
@@ -155,6 +155,41 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
return SmiLessThan(value, SmiConstant(0));
}
+ // substr and slice have a common way of handling the {start} argument.
+ void ConvertAndBoundsCheckStartArgument(Node* context, Variable* var_start,
+ Node* start, Node* string_length) {
+ Node* const start_int =
+ ToInteger(context, start, CodeStubAssembler::kTruncateMinusZero);
+ Node* const zero = SmiConstant(Smi::kZero);
+
+ Label done(this);
+ Label if_issmi(this), if_isheapnumber(this, Label::kDeferred);
+ Branch(TaggedIsSmi(start_int), &if_issmi, &if_isheapnumber);
+
+ BIND(&if_issmi);
+ {
+ var_start->Bind(
+ Select(SmiLessThan(start_int, zero),
+ [&] { return SmiMax(SmiAdd(string_length, start_int), zero); },
+ [&] { return start_int; }, MachineRepresentation::kTagged));
+ Goto(&done);
+ }
+
+ BIND(&if_isheapnumber);
+ {
+ // If {start} is a heap number, it is definitely out of bounds. If it is
+ // negative, {start} = max({string_length} + {start}),0) = 0'. If it is
+ // positive, set {start} to {string_length} which ultimately results in
+ // returning an empty string.
+ Node* const float_zero = Float64Constant(0.);
+ Node* const start_float = LoadHeapNumberValue(start_int);
+ var_start->Bind(SelectTaggedConstant(
+ Float64LessThan(start_float, float_zero), zero, string_length));
+ Goto(&done);
+ }
+ BIND(&done);
+ }
+
// Implements boilerplate logic for {match, split, replace, search} of the
// form:
//
@@ -1293,6 +1328,89 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
}
}
+// ES6 section 21.1.3.18 String.prototype.slice ( start, end )
+TF_BUILTIN(StringPrototypeSlice, StringBuiltinsAssembler) {
+ Label out(this);
+ VARIABLE(var_start, MachineRepresentation::kTagged);
+ VARIABLE(var_end, MachineRepresentation::kTagged);
+
+ const int kStart = 0;
+ const int kEnd = 1;
+ Node* argc =
+ ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
+ CodeStubArguments args(this, argc);
+ Node* const receiver = args.GetReceiver();
+ Node* const start =
+ args.GetOptionalArgumentValue(kStart, UndefinedConstant());
+ Node* const end = args.GetOptionalArgumentValue(kEnd, UndefinedConstant());
+ Node* const context = Parameter(BuiltinDescriptor::kContext);
+
+ Node* const smi_zero = SmiConstant(0);
+
+ // 1. Let O be ? RequireObjectCoercible(this value).
+ RequireObjectCoercible(context, receiver, "String.prototype.slice");
+
+ // 2. Let S be ? ToString(O).
+ Callable tostring_callable = CodeFactory::ToString(isolate());
+ Node* const subject_string = CallStub(tostring_callable, context, receiver);
+
+ // 3. Let len be the number of elements in S.
+ Node* const length = LoadStringLength(subject_string);
+
+ // Conversions and bounds-checks for {start}.
+ ConvertAndBoundsCheckStartArgument(context, &var_start, start, length);
+
+ // 5. If end is undefined, let intEnd be len;
+ var_end.Bind(length);
+ GotoIf(WordEqual(end, UndefinedConstant()), &out);
+
+ // else let intEnd be ? ToInteger(end).
+ Node* const end_int =
+ ToInteger(context, end, CodeStubAssembler::kTruncateMinusZero);
+
+ // 7. If intEnd < 0, let to be max(len + intEnd, 0);
+ // otherwise let to be min(intEnd, len).
+ Label if_issmi(this), if_isheapnumber(this, Label::kDeferred);
+ Branch(TaggedIsSmi(end_int), &if_issmi, &if_isheapnumber);
+
+ BIND(&if_issmi);
+ {
+ Node* const length_plus_end = SmiAdd(length, end_int);
+ var_end.Bind(Select(SmiLessThan(end_int, smi_zero),
+ [&] { return SmiMax(length_plus_end, smi_zero); },
+ [&] { return SmiMin(length, end_int); },
+ MachineRepresentation::kTagged));
+ Goto(&out);
+ }
+
+ BIND(&if_isheapnumber);
+ {
+ // If {end} is a heap number, it is definitely out of bounds. If it is
+ // negative, {int_end} = max({length} + {int_end}),0) = 0'. If it is
+ // positive, set {int_end} to {length} which ultimately results in
+ // returning an empty string.
+ Node* const float_zero = Float64Constant(0.);
+ Node* const end_float = LoadHeapNumberValue(end_int);
+ var_end.Bind(SelectTaggedConstant(Float64LessThan(end_float, float_zero),
+ smi_zero, length));
+ Goto(&out);
+ }
+
+ Label return_emptystring(this);
+ BIND(&out);
+ {
+ GotoIf(SmiLessThanOrEqual(var_end.value(), var_start.value()),
+ &return_emptystring);
+ Node* const result =
+ SubString(context, subject_string, var_start.value(), var_end.value(),
+ SubStringFlags::FROM_TO_ARE_BOUNDED);
+ args.PopAndReturn(result);
+ }
+
+ BIND(&return_emptystring);
+ args.PopAndReturn(EmptyStringConstant());
+}
+
// ES6 section 21.1.3.19 String.prototype.split ( separator, limit )
TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
Label out(this);
@@ -1397,8 +1515,8 @@ TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
}
// ES6 #sec-string.prototype.substr
-TF_BUILTIN(StringPrototypeSubstr, CodeStubAssembler) {
- Label out(this), handle_length(this);
+TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) {
+ Label out(this);
VARIABLE(var_start, MachineRepresentation::kTagged);
VARIABLE(var_length, MachineRepresentation::kTagged);
@@ -1417,94 +1535,62 @@ TF_BUILTIN(StringPrototypeSubstr, CodeStubAssembler) {
Node* const string_length = LoadStringLength(string);
// Conversions and bounds-checks for {start}.
- {
- Node* const start_int =
- ToInteger(context, start, CodeStubAssembler::kTruncateMinusZero);
-
- Label if_issmi(this), if_isheapnumber(this, Label::kDeferred);
- Branch(TaggedIsSmi(start_int), &if_issmi, &if_isheapnumber);
-
- BIND(&if_issmi);
- {
- Node* const length_plus_start = SmiAdd(string_length, start_int);
- var_start.Bind(Select(SmiLessThan(start_int, zero),
- [&] { return SmiMax(length_plus_start, zero); },
- [&] { return start_int; },
- MachineRepresentation::kTagged));
- Goto(&handle_length);
- }
-
- BIND(&if_isheapnumber);
- {
- // If {start} is a heap number, it is definitely out of bounds. If it is
- // negative, {start} = max({string_length} + {start}),0) = 0'. If it is
- // positive, set {start} to {string_length} which ultimately results in
- // returning an empty string.
- Node* const float_zero = Float64Constant(0.);
- Node* const start_float = LoadHeapNumberValue(start_int);
- var_start.Bind(SelectTaggedConstant(
- Float64LessThan(start_float, float_zero), zero, string_length));
- Goto(&handle_length);
- }
- }
+ ConvertAndBoundsCheckStartArgument(context, &var_start, start, string_length);
// Conversions and bounds-checks for {length}.
- BIND(&handle_length);
+ Label if_issmi(this), if_isheapnumber(this, Label::kDeferred);
+
+ // Default to {string_length} if {length} is undefined.
{
- Label if_issmi(this), if_isheapnumber(this, Label::kDeferred);
+ Label if_isundefined(this, Label::kDeferred), if_isnotundefined(this);
+ Branch(WordEqual(length, UndefinedConstant()), &if_isundefined,
+ &if_isnotundefined);
- // Default to {string_length} if {length} is undefined.
- {
- Label if_isundefined(this, Label::kDeferred), if_isnotundefined(this);
- Branch(WordEqual(length, UndefinedConstant()), &if_isundefined,
- &if_isnotundefined);
+ BIND(&if_isundefined);
+ var_length.Bind(string_length);
+ Goto(&if_issmi);
- BIND(&if_isundefined);
- var_length.Bind(string_length);
- Goto(&if_issmi);
+ BIND(&if_isnotundefined);
+ var_length.Bind(
+ ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero));
+ }
- BIND(&if_isnotundefined);
- var_length.Bind(
- ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero));
- }
+ Branch(TaggedIsSmi(var_length.value()), &if_issmi, &if_isheapnumber);
- Branch(TaggedIsSmi(var_length.value()), &if_issmi, &if_isheapnumber);
+ // Set {length} to min(max({length}, 0), {string_length} - {start}
+ BIND(&if_issmi);
+ {
+ Node* const positive_length = SmiMax(var_length.value(), zero);
- // Set {length} to min(max({length}, 0), {string_length} - {start}
- BIND(&if_issmi);
- {
- Node* const positive_length = SmiMax(var_length.value(), zero);
+ Node* const minimal_length = SmiSub(string_length, var_start.value());
+ var_length.Bind(SmiMin(positive_length, minimal_length));
- Node* const minimal_length = SmiSub(string_length, var_start.value());
- var_length.Bind(SmiMin(positive_length, minimal_length));
+ GotoIfNot(SmiLessThanOrEqual(var_length.value(), zero), &out);
+ Return(EmptyStringConstant());
+ }
- GotoIfNot(SmiLessThanOrEqual(var_length.value(), zero), &out);
- Return(EmptyStringConstant());
- }
+ BIND(&if_isheapnumber);
+ {
+ // If {length} is a heap number, it is definitely out of bounds. There are
+ // two cases according to the spec: if it is negative, "" is returned; if
+ // it is positive, then length is set to {string_length} - {start}.
- BIND(&if_isheapnumber);
- {
- // If {length} is a heap number, it is definitely out of bounds. There are
- // two cases according to the spec: if it is negative, "" is returned; if
- // it is positive, then length is set to {string_length} - {start}.
+ CSA_ASSERT(this, IsHeapNumberMap(LoadMap(var_length.value())));
- CSA_ASSERT(this, IsHeapNumberMap(LoadMap(var_length.value())));
+ Label if_isnegative(this), if_ispositive(this);
+ Node* const float_zero = Float64Constant(0.);
+ Node* const length_float = LoadHeapNumberValue(var_length.value());
+ Branch(Float64LessThan(length_float, float_zero), &if_isnegative,
+ &if_ispositive);
- Label if_isnegative(this), if_ispositive(this);
- Node* const float_zero = Float64Constant(0.);
- Node* const length_float = LoadHeapNumberValue(var_length.value());
- Branch(Float64LessThan(length_float, float_zero), &if_isnegative,
- &if_ispositive);
+ BIND(&if_isnegative);
+ Return(EmptyStringConstant());
- BIND(&if_isnegative);
+ BIND(&if_ispositive);
+ {
+ var_length.Bind(SmiSub(string_length, var_start.value()));
+ GotoIfNot(SmiLessThanOrEqual(var_length.value(), zero), &out);
Return(EmptyStringConstant());
-
- BIND(&if_ispositive);
- {
- var_length.Bind(SmiSub(string_length, var_start.value()));
- GotoIfNot(SmiLessThanOrEqual(var_length.value(), zero), &out);
- Return(EmptyStringConstant());
- }
}
}
« no previous file with comments | « src/builtins/builtins-definitions.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698