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

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

Issue 2870013004: [builtins] String.prototype.slice as a CSA builtin. (Closed)
Patch Set: Flags for SubString. 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
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..a9b726af80bde86d9993053d1a4595bdb64c17c6 100644
--- a/src/builtins/builtins-string-gen.cc
+++ b/src/builtins/builtins-string-gen.cc
@@ -1293,6 +1293,123 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
}
}
+// ES6 section 21.1.3.18 String.prototype.slice ( start, end )
+TF_BUILTIN(StringPrototypeSlice, StringBuiltinsAssembler) {
+ Label handle_end(this), out(this);
+ VARIABLE(var_start, MachineRepresentation::kTagged);
+ VARIABLE(var_end, MachineRepresentation::kTagged);
+
+ Node* const receiver = Parameter(Descriptor::kReceiver);
+ Node* const start = Parameter(Descriptor::kStart);
+ Node* const end = Parameter(Descriptor::kEnd);
+ Node* const context = Parameter(Descriptor::kContext);
+
+ Node* const smi_zero = SmiConstant(0);
+
+ // 1. Let O be ? RequireObjectCoercible(this value).
+ RequireObjectCoercible(context, receiver, "String.prototype.slice");
+
+ // String and integer conversions.
+ // TODO(jgruber): The old implementation used Uint32Max instead of SmiMax -
jgruber 2017/05/11 08:57:40 Nit: This comment doesn't apply here.
mvstanton 2017/05/12 11:00:42 Done.
+ // but AFAIK there should not be a difference since arrays are capped at Smi
+ // lengths.
+
+ // 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}.
jgruber 2017/05/11 08:57:40 From a quick look this seems identical to arg hand
mvstanton 2017/05/12 11:00:42 Indeed, I made a utility method in the string code
+ {
+ // 4. Let intStart be ? ToInteger(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);
+
+ // 6. If intStart < 0, let from be max(len + intStart, 0);
+ // otherwise, let from be min(intStart, len).
+ BIND(&if_issmi);
+ {
+ Node* const length_plus_start = SmiAdd(length, start_int);
jgruber 2017/05/11 08:57:40 Nit: Just noticed that this could move into the Se
mvstanton 2017/05/12 11:00:42 Oh yeah! Done.
+ var_start.Bind(Select(SmiLessThan(start_int, smi_zero),
+ [&] { return SmiMax(length_plus_start, smi_zero); },
+ [&] { return SmiMin(start_int, length); },
+ MachineRepresentation::kTagged));
+ Goto(&handle_end);
+ }
+
+ 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), smi_zero, length));
+ Goto(&handle_end);
+ }
+ }
+
+ BIND(&handle_end);
+ {
+ // 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);
jgruber 2017/05/11 08:57:40 Same here.
mvstanton 2017/05/12 11:00:42 Done.
+ 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);
+ Return(result);
+ }
+
+ BIND(&return_emptystring);
+ Return(EmptyStringConstant());
+}
+
// ES6 section 21.1.3.19 String.prototype.split ( separator, limit )
TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
Label out(this);

Powered by Google App Engine
This is Rietveld 408576698