Port some String builtins to Torque
StringPrototypeCharAt, StringPrototypeCharCodeAt, StringPrototypeCodePointAt Bug: v8:8996 Change-Id: I7faaec880801cfe244654a257dc98f67d4bc39ea Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1617807 Reviewed-by: Simon Zünd <szuend@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com> Cr-Commit-Position: refs/heads/master@{#61706}
This commit is contained in:
parent
19b8981303
commit
344473ca04
@ -761,6 +761,8 @@ type SlackTrackingMode constexpr 'SlackTrackingMode';
|
||||
type UnicodeEncoding constexpr 'UnicodeEncoding';
|
||||
const UTF16:
|
||||
constexpr UnicodeEncoding generates 'UnicodeEncoding::UTF16';
|
||||
const UTF32:
|
||||
constexpr UnicodeEncoding generates 'UnicodeEncoding::UTF32';
|
||||
|
||||
extern class Foreign extends HeapObject { foreign_address: RawPtr; }
|
||||
|
||||
@ -1075,6 +1077,7 @@ extern macro Int32TrueConstant(): bool;
|
||||
extern macro Int32FalseConstant(): bool;
|
||||
extern macro EmptyStringConstant(): EmptyString;
|
||||
extern macro LengthStringConstant(): String;
|
||||
extern macro NanConstant(): NaN;
|
||||
|
||||
const Hole: Hole = TheHoleConstant();
|
||||
const Null: Null = NullConstant();
|
||||
@ -1083,6 +1086,7 @@ const True: True = TrueConstant();
|
||||
const False: False = FalseConstant();
|
||||
const kEmptyString: EmptyString = EmptyStringConstant();
|
||||
const kLengthString: String = LengthStringConstant();
|
||||
const kNaN: NaN = NanConstant();
|
||||
|
||||
const true: constexpr bool generates 'true';
|
||||
const false: constexpr bool generates 'false';
|
||||
@ -1428,6 +1432,7 @@ extern runtime StringEqual(Context, String, String): Oddball;
|
||||
extern builtin StringLessThan(Context, String, String): Boolean;
|
||||
extern macro StringCharCodeAt(String, intptr): int32;
|
||||
extern runtime StringCompareSequence(Context, String, String, Number): Boolean;
|
||||
extern macro StringFromSingleCharCode(int32): String;
|
||||
|
||||
extern macro StrictEqual(Object, Object): Boolean;
|
||||
extern macro SmiLexicographicCompare(Smi, Smi): Smi;
|
||||
|
@ -943,12 +943,6 @@ namespace internal {
|
||||
CPP(StringFromCodePoint) \
|
||||
/* ES6 #sec-string.fromcharcode */ \
|
||||
TFJ(StringFromCharCode, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-string.prototype.charat */ \
|
||||
TFJ(StringPrototypeCharAt, 1, kReceiver, kPosition) \
|
||||
/* ES6 #sec-string.prototype.charcodeat */ \
|
||||
TFJ(StringPrototypeCharCodeAt, 1, kReceiver, kPosition) \
|
||||
/* ES6 #sec-string.prototype.codepointat */ \
|
||||
TFJ(StringPrototypeCodePointAt, 1, kReceiver, kPosition) \
|
||||
/* ES6 #sec-string.prototype.concat */ \
|
||||
TFJ(StringPrototypeConcat, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-string.prototype.includes */ \
|
||||
|
@ -325,29 +325,6 @@ TF_BUILTIN(SubString, StringBuiltinsAssembler) {
|
||||
Return(SubString(string, SmiUntag(from), SmiUntag(to)));
|
||||
}
|
||||
|
||||
void StringBuiltinsAssembler::GenerateStringAt(
|
||||
char const* method_name, TNode<Context> context, TNode<Object> receiver,
|
||||
TNode<Object> maybe_position, TNode<Object> default_return,
|
||||
const 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,
|
||||
@ -709,54 +686,6 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
|
||||
}
|
||||
}
|
||||
|
||||
// ES6 #sec-string.prototype.charat
|
||||
TF_BUILTIN(StringPrototypeCharAt, StringBuiltinsAssembler) {
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
|
||||
TNode<Object> maybe_position = CAST(Parameter(Descriptor::kPosition));
|
||||
|
||||
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 StringFromSingleCharCode(code);
|
||||
});
|
||||
}
|
||||
|
||||
// ES6 #sec-string.prototype.charcodeat
|
||||
TF_BUILTIN(StringPrototypeCharCodeAt, StringBuiltinsAssembler) {
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
|
||||
TNode<Object> maybe_position = CAST(Parameter(Descriptor::kPosition));
|
||||
|
||||
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 SmiFromInt32(value);
|
||||
});
|
||||
}
|
||||
|
||||
// ES6 #sec-string.prototype.codepointat
|
||||
TF_BUILTIN(StringPrototypeCodePointAt, StringBuiltinsAssembler) {
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
|
||||
TNode<Object> maybe_position = CAST(Parameter(Descriptor::kPosition));
|
||||
|
||||
GenerateStringAt("String.prototype.codePointAt", context, receiver,
|
||||
maybe_position, UndefinedConstant(),
|
||||
[this](TNode<String> receiver, TNode<IntPtrT> length,
|
||||
TNode<IntPtrT> index) {
|
||||
// This is always a call to a builtin from Javascript,
|
||||
// so we need to produce UTF32.
|
||||
Node* value = LoadSurrogatePairAt(receiver, length, index,
|
||||
UnicodeEncoding::UTF32);
|
||||
return SmiFromInt32(value);
|
||||
});
|
||||
}
|
||||
|
||||
// ES6 String.prototype.concat(...args)
|
||||
// ES6 #sec-string.prototype.concat
|
||||
TF_BUILTIN(StringPrototypeConcat, CodeStubAssembler) {
|
||||
|
@ -66,11 +66,6 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
||||
TNode<String> receiver, TNode<IntPtrT> length, TNode<IntPtrT> index)>
|
||||
StringAtAccessor;
|
||||
|
||||
void GenerateStringAt(const char* method_name, TNode<Context> context,
|
||||
TNode<Object> receiver, TNode<Object> maybe_position,
|
||||
TNode<Object> default_return,
|
||||
const StringAtAccessor& accessor);
|
||||
|
||||
void StringIndexOf(Node* const subject_string, Node* const search_string,
|
||||
Node* const position,
|
||||
const std::function<void(Node*)>& f_return);
|
||||
|
@ -50,4 +50,71 @@ namespace string {
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
transitioning macro GenerateStringAt(implicit context: Context)(
|
||||
receiver: Object, position: Object, methodName: constexpr string):
|
||||
never labels IfInBounds(String, intptr, intptr),
|
||||
IfOutOfBounds {
|
||||
// Check that {receiver} is coercible to Object and convert it to a String.
|
||||
const string: String = ToThisString(receiver, methodName);
|
||||
// Convert the {position} to a Smi and check that it's in bounds of
|
||||
// the {string}.
|
||||
const indexNumber: Number =
|
||||
ToInteger_Inline(context, position, kTruncateMinusZero);
|
||||
if (TaggedIsNotSmi(indexNumber)) goto IfOutOfBounds;
|
||||
const index: intptr = SmiUntag(UnsafeCast<Smi>(indexNumber));
|
||||
const length: intptr = string.length_intptr;
|
||||
if (Convert<uintptr>(index) >= Convert<uintptr>(length)) goto IfOutOfBounds;
|
||||
goto IfInBounds(string, index, length);
|
||||
}
|
||||
|
||||
// ES6 #sec-string.prototype.charat
|
||||
transitioning javascript builtin StringPrototypeCharAt(
|
||||
implicit context: Context)(receiver: Object, position: Object): Object {
|
||||
try {
|
||||
GenerateStringAt(receiver, position, 'String.prototype.charAt')
|
||||
otherwise IfInBounds, IfOutOfBounds;
|
||||
}
|
||||
label IfInBounds(string: String, index: intptr, length: intptr) {
|
||||
const code: int32 = StringCharCodeAt(string, index);
|
||||
return StringFromSingleCharCode(code);
|
||||
}
|
||||
label IfOutOfBounds {
|
||||
return kEmptyString;
|
||||
}
|
||||
}
|
||||
|
||||
// ES6 #sec-string.prototype.charcodeat
|
||||
transitioning javascript builtin StringPrototypeCharCodeAt(
|
||||
implicit context: Context)(receiver: Object, position: Object): Object {
|
||||
try {
|
||||
GenerateStringAt(receiver, position, 'String.prototype.charCodeAt')
|
||||
otherwise IfInBounds, IfOutOfBounds;
|
||||
}
|
||||
label IfInBounds(string: String, index: intptr, length: intptr) {
|
||||
const code: int32 = StringCharCodeAt(string, index);
|
||||
return Convert<Smi>(code);
|
||||
}
|
||||
label IfOutOfBounds {
|
||||
return kNaN;
|
||||
}
|
||||
}
|
||||
|
||||
// ES6 #sec-string.prototype.codepointat
|
||||
transitioning javascript builtin StringPrototypeCodePointAt(
|
||||
implicit context: Context)(receiver: Object, position: Object): Object {
|
||||
try {
|
||||
GenerateStringAt(receiver, position, 'String.prototype.codePointAt')
|
||||
otherwise IfInBounds, IfOutOfBounds;
|
||||
}
|
||||
label IfInBounds(string: String, index: intptr, length: intptr) {
|
||||
// This is always a call to a builtin from Javascript, so we need to
|
||||
// produce UTF32.
|
||||
const code: int32 = LoadSurrogatePairAt(string, length, index, UTF32);
|
||||
return Convert<Smi>(code);
|
||||
}
|
||||
label IfOutOfBounds {
|
||||
return Undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user