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:
Z Duong Nguyen-Huu 2019-05-20 08:49:41 -07:00 committed by Commit Bot
parent 19b8981303
commit 344473ca04
5 changed files with 72 additions and 82 deletions

View File

@ -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;

View File

@ -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 */ \

View File

@ -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) {

View File

@ -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);

View File

@ -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;
}
}
}