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';
|
type UnicodeEncoding constexpr 'UnicodeEncoding';
|
||||||
const UTF16:
|
const UTF16:
|
||||||
constexpr UnicodeEncoding generates 'UnicodeEncoding::UTF16';
|
constexpr UnicodeEncoding generates 'UnicodeEncoding::UTF16';
|
||||||
|
const UTF32:
|
||||||
|
constexpr UnicodeEncoding generates 'UnicodeEncoding::UTF32';
|
||||||
|
|
||||||
extern class Foreign extends HeapObject { foreign_address: RawPtr; }
|
extern class Foreign extends HeapObject { foreign_address: RawPtr; }
|
||||||
|
|
||||||
@ -1075,6 +1077,7 @@ extern macro Int32TrueConstant(): bool;
|
|||||||
extern macro Int32FalseConstant(): bool;
|
extern macro Int32FalseConstant(): bool;
|
||||||
extern macro EmptyStringConstant(): EmptyString;
|
extern macro EmptyStringConstant(): EmptyString;
|
||||||
extern macro LengthStringConstant(): String;
|
extern macro LengthStringConstant(): String;
|
||||||
|
extern macro NanConstant(): NaN;
|
||||||
|
|
||||||
const Hole: Hole = TheHoleConstant();
|
const Hole: Hole = TheHoleConstant();
|
||||||
const Null: Null = NullConstant();
|
const Null: Null = NullConstant();
|
||||||
@ -1083,6 +1086,7 @@ const True: True = TrueConstant();
|
|||||||
const False: False = FalseConstant();
|
const False: False = FalseConstant();
|
||||||
const kEmptyString: EmptyString = EmptyStringConstant();
|
const kEmptyString: EmptyString = EmptyStringConstant();
|
||||||
const kLengthString: String = LengthStringConstant();
|
const kLengthString: String = LengthStringConstant();
|
||||||
|
const kNaN: NaN = NanConstant();
|
||||||
|
|
||||||
const true: constexpr bool generates 'true';
|
const true: constexpr bool generates 'true';
|
||||||
const false: constexpr bool generates 'false';
|
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 builtin StringLessThan(Context, String, String): Boolean;
|
||||||
extern macro StringCharCodeAt(String, intptr): int32;
|
extern macro StringCharCodeAt(String, intptr): int32;
|
||||||
extern runtime StringCompareSequence(Context, String, String, Number): Boolean;
|
extern runtime StringCompareSequence(Context, String, String, Number): Boolean;
|
||||||
|
extern macro StringFromSingleCharCode(int32): String;
|
||||||
|
|
||||||
extern macro StrictEqual(Object, Object): Boolean;
|
extern macro StrictEqual(Object, Object): Boolean;
|
||||||
extern macro SmiLexicographicCompare(Smi, Smi): Smi;
|
extern macro SmiLexicographicCompare(Smi, Smi): Smi;
|
||||||
|
@ -943,12 +943,6 @@ namespace internal {
|
|||||||
CPP(StringFromCodePoint) \
|
CPP(StringFromCodePoint) \
|
||||||
/* ES6 #sec-string.fromcharcode */ \
|
/* ES6 #sec-string.fromcharcode */ \
|
||||||
TFJ(StringFromCharCode, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
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 */ \
|
/* ES6 #sec-string.prototype.concat */ \
|
||||||
TFJ(StringPrototypeConcat, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
TFJ(StringPrototypeConcat, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||||
/* ES6 #sec-string.prototype.includes */ \
|
/* ES6 #sec-string.prototype.includes */ \
|
||||||
|
@ -325,29 +325,6 @@ TF_BUILTIN(SubString, StringBuiltinsAssembler) {
|
|||||||
Return(SubString(string, SmiUntag(from), SmiUntag(to)));
|
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,
|
void StringBuiltinsAssembler::GenerateStringRelationalComparison(Node* context,
|
||||||
Node* left,
|
Node* left,
|
||||||
Node* right,
|
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 String.prototype.concat(...args)
|
||||||
// ES6 #sec-string.prototype.concat
|
// ES6 #sec-string.prototype.concat
|
||||||
TF_BUILTIN(StringPrototypeConcat, CodeStubAssembler) {
|
TF_BUILTIN(StringPrototypeConcat, CodeStubAssembler) {
|
||||||
|
@ -66,11 +66,6 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
|||||||
TNode<String> receiver, TNode<IntPtrT> length, TNode<IntPtrT> index)>
|
TNode<String> receiver, TNode<IntPtrT> length, TNode<IntPtrT> index)>
|
||||||
StringAtAccessor;
|
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,
|
void StringIndexOf(Node* const subject_string, Node* const search_string,
|
||||||
Node* const position,
|
Node* const position,
|
||||||
const std::function<void(Node*)>& f_return);
|
const std::function<void(Node*)>& f_return);
|
||||||
|
@ -50,4 +50,71 @@ namespace string {
|
|||||||
|
|
||||||
return array;
|
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