Port StringPrototypeSubString to Torque
Bug: v8:8996 Change-Id: I63ae821086c42c14a317e866fb4f0f799f4c4f7c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1597555 Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com> Reviewed-by: Simon Zünd <szuend@chromium.org> Cr-Commit-Position: refs/heads/master@{#61360}
This commit is contained in:
parent
595c8e8efa
commit
47d32fef2b
2
BUILD.gn
2
BUILD.gn
@ -956,6 +956,7 @@ torque_files = [
|
||||
"src/builtins/string-iterator.tq",
|
||||
"src/builtins/string-repeat.tq",
|
||||
"src/builtins/string-startswith.tq",
|
||||
"src/builtins/string-substring.tq",
|
||||
"src/builtins/typed-array-createtypedarray.tq",
|
||||
"src/builtins/typed-array-every.tq",
|
||||
"src/builtins/typed-array-filter.tq",
|
||||
@ -1010,6 +1011,7 @@ torque_namespaces = [
|
||||
"string-html",
|
||||
"string-iterator",
|
||||
"string-repeat",
|
||||
"string-substring",
|
||||
"test",
|
||||
"typed-array",
|
||||
"typed-array-createtypedarray",
|
||||
|
@ -984,9 +984,6 @@ namespace internal {
|
||||
TFJ(StringPrototypeSplit, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-string.prototype.substr */ \
|
||||
TFJ(StringPrototypeSubstr, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-string.prototype.substring */ \
|
||||
TFJ(StringPrototypeSubstring, \
|
||||
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
TFJ(StringPrototypeTrim, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
TFJ(StringPrototypeTrimEnd, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
TFJ(StringPrototypeTrimStart, \
|
||||
|
@ -1920,56 +1920,6 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) {
|
||||
}
|
||||
}
|
||||
|
||||
TNode<Smi> StringBuiltinsAssembler::ToSmiBetweenZeroAnd(
|
||||
SloppyTNode<Context> context, SloppyTNode<Object> value,
|
||||
SloppyTNode<Smi> limit) {
|
||||
Label out(this);
|
||||
TVARIABLE(Smi, var_result);
|
||||
|
||||
TNode<Number> const value_int =
|
||||
ToInteger_Inline(context, value, CodeStubAssembler::kTruncateMinusZero);
|
||||
|
||||
Label if_issmi(this), if_isnotsmi(this, Label::kDeferred);
|
||||
Branch(TaggedIsSmi(value_int), &if_issmi, &if_isnotsmi);
|
||||
|
||||
BIND(&if_issmi);
|
||||
{
|
||||
TNode<Smi> value_smi = CAST(value_int);
|
||||
Label if_isinbounds(this), if_isoutofbounds(this, Label::kDeferred);
|
||||
Branch(SmiAbove(value_smi, limit), &if_isoutofbounds, &if_isinbounds);
|
||||
|
||||
BIND(&if_isinbounds);
|
||||
{
|
||||
var_result = CAST(value_int);
|
||||
Goto(&out);
|
||||
}
|
||||
|
||||
BIND(&if_isoutofbounds);
|
||||
{
|
||||
TNode<Smi> const zero = SmiConstant(0);
|
||||
var_result =
|
||||
SelectConstant<Smi>(SmiLessThan(value_smi, zero), zero, limit);
|
||||
Goto(&out);
|
||||
}
|
||||
}
|
||||
|
||||
BIND(&if_isnotsmi);
|
||||
{
|
||||
// {value} is a heap number - in this case, it is definitely out of bounds.
|
||||
TNode<HeapNumber> value_int_hn = CAST(value_int);
|
||||
|
||||
TNode<Float64T> const float_zero = Float64Constant(0.);
|
||||
TNode<Smi> const smi_zero = SmiConstant(0);
|
||||
TNode<Float64T> const value_float = LoadHeapNumberValue(value_int_hn);
|
||||
var_result = SelectConstant<Smi>(Float64LessThan(value_float, float_zero),
|
||||
smi_zero, limit);
|
||||
Goto(&out);
|
||||
}
|
||||
|
||||
BIND(&out);
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
TF_BUILTIN(StringSubstring, CodeStubAssembler) {
|
||||
TNode<String> string = CAST(Parameter(Descriptor::kString));
|
||||
TNode<IntPtrT> from = UncheckedCast<IntPtrT>(Parameter(Descriptor::kFrom));
|
||||
@ -1978,61 +1928,6 @@ TF_BUILTIN(StringSubstring, CodeStubAssembler) {
|
||||
Return(SubString(string, from, to));
|
||||
}
|
||||
|
||||
// ES6 #sec-string.prototype.substring
|
||||
TF_BUILTIN(StringPrototypeSubstring, StringBuiltinsAssembler) {
|
||||
const int kStartArg = 0;
|
||||
const int kEndArg = 1;
|
||||
|
||||
Node* const argc =
|
||||
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
|
||||
CodeStubArguments args(this, argc);
|
||||
|
||||
TNode<Object> receiver = args.GetReceiver();
|
||||
TNode<Object> start = args.GetOptionalArgumentValue(kStartArg);
|
||||
TNode<Object> end = args.GetOptionalArgumentValue(kEndArg);
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
|
||||
Label out(this);
|
||||
|
||||
TVARIABLE(Smi, var_start);
|
||||
TVARIABLE(Smi, var_end);
|
||||
|
||||
// Check that {receiver} is coercible to Object and convert it to a String.
|
||||
TNode<String> const string =
|
||||
ToThisString(context, receiver, "String.prototype.substring");
|
||||
|
||||
TNode<Smi> const length = LoadStringLengthAsSmi(string);
|
||||
|
||||
// Conversion and bounds-checks for {start}.
|
||||
var_start = ToSmiBetweenZeroAnd(context, start, length);
|
||||
|
||||
// Conversion and bounds-checks for {end}.
|
||||
{
|
||||
var_end = length;
|
||||
GotoIf(IsUndefined(end), &out);
|
||||
|
||||
var_end = ToSmiBetweenZeroAnd(context, end, length);
|
||||
|
||||
Label if_endislessthanstart(this);
|
||||
Branch(SmiLessThan(var_end.value(), var_start.value()),
|
||||
&if_endislessthanstart, &out);
|
||||
|
||||
BIND(&if_endislessthanstart);
|
||||
{
|
||||
TNode<Smi> const tmp = var_end.value();
|
||||
var_end = var_start.value();
|
||||
var_start = tmp;
|
||||
Goto(&out);
|
||||
}
|
||||
}
|
||||
|
||||
BIND(&out);
|
||||
{
|
||||
args.PopAndReturn(SubString(string, SmiUntag(var_start.value()),
|
||||
SmiUntag(var_end.value())));
|
||||
}
|
||||
}
|
||||
|
||||
// ES6 #sec-string.prototype.trim
|
||||
TF_BUILTIN(StringPrototypeTrim, StringTrimAssembler) {
|
||||
TNode<IntPtrT> argc =
|
||||
|
@ -64,10 +64,6 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
||||
void GenerateStringRelationalComparison(Node* context, Node* left,
|
||||
Node* right, Operation op);
|
||||
|
||||
TNode<Smi> ToSmiBetweenZeroAnd(SloppyTNode<Context> context,
|
||||
SloppyTNode<Object> value,
|
||||
SloppyTNode<Smi> limit);
|
||||
|
||||
typedef std::function<TNode<Object>(
|
||||
TNode<String> receiver, TNode<IntPtrT> length, TNode<IntPtrT> index)>
|
||||
StringAtAccessor;
|
||||
|
50
src/builtins/string-substring.tq
Normal file
50
src/builtins/string-substring.tq
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
namespace string_substring {
|
||||
|
||||
extern macro SubString(String, intptr, intptr): String;
|
||||
|
||||
transitioning macro ToSmiBetweenZeroAnd(implicit context: Context)(
|
||||
value: Object, limit: Smi): Smi {
|
||||
const valueInt: Number =
|
||||
ToInteger_Inline(context, value, kTruncateMinusZero);
|
||||
typeswitch (valueInt) {
|
||||
case (valueSmi: Smi): {
|
||||
if (SmiAbove(valueSmi, limit)) {
|
||||
return valueSmi < 0 ? 0 : limit;
|
||||
}
|
||||
return valueSmi;
|
||||
}
|
||||
// {value} is a heap number - in this case, it is definitely out of
|
||||
// bounds.
|
||||
case (hn: HeapNumber): {
|
||||
const valueFloat: float64 = LoadHeapNumberValue(hn);
|
||||
return valueFloat < 0. ? 0 : limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ES6 #sec-string.prototype.substring
|
||||
transitioning javascript builtin StringPrototypeSubstring(
|
||||
implicit context: Context)(receiver: Object, ...arguments): String {
|
||||
// Check that {receiver} is coercible to Object and convert it to a String.
|
||||
const string: String = ToThisString(receiver, 'String.prototype.substring');
|
||||
const length = string.length_smi;
|
||||
|
||||
// Conversion and bounds-checks for {start}.
|
||||
let start: Smi = ToSmiBetweenZeroAnd(arguments[0], length);
|
||||
|
||||
// Conversion and bounds-checks for {end}.
|
||||
let end: Smi = arguments[1] == Undefined ?
|
||||
length :
|
||||
ToSmiBetweenZeroAnd(arguments[1], length);
|
||||
if (end < start) {
|
||||
const tmp: Smi = end;
|
||||
end = start;
|
||||
start = tmp;
|
||||
}
|
||||
return SubString(string, SmiUntag(start), SmiUntag(end));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user