Chromium Code Reviews| 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); |