[builtins] Port RegExp FlagsGetter to Torque

Bug: v8:8976
Change-Id: Id6449c0e2a473db7b1d3a1c143324d8810000374
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1773558
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63464}
This commit is contained in:
Z Nguyen-Huu 2019-08-29 15:24:21 -07:00 committed by Commit Bot
parent e36eb3e947
commit e3debe47cc
9 changed files with 74 additions and 98 deletions

View File

@ -1665,6 +1665,9 @@ extern macro ThrowTypeError(implicit context: Context)(
extern transitioning runtime ThrowTypeErrorIfStrict(implicit context: Context)( extern transitioning runtime ThrowTypeErrorIfStrict(implicit context: Context)(
Smi, Object, Object): void; Smi, Object, Object): void;
extern transitioning macro ThrowIfNotJSReceiver(implicit context: Context)(
JSAny, constexpr MessageTemplate, constexpr string): void;
extern macro ArraySpeciesCreate(Context, JSAny, Number): JSReceiver; extern macro ArraySpeciesCreate(Context, JSAny, Number): JSReceiver;
extern macro ArrayCreate(implicit context: Context)(Number): JSArray; extern macro ArrayCreate(implicit context: Context)(Number): JSArray;
extern macro BuildAppendJSArray( extern macro BuildAppendJSArray(

View File

@ -847,8 +847,6 @@ namespace internal {
TFJ(RegExpPrototypeCompile, 2, kReceiver, kPattern, kFlags) \ TFJ(RegExpPrototypeCompile, 2, kReceiver, kPattern, kFlags) \
/* ES #sec-regexp.prototype.exec */ \ /* ES #sec-regexp.prototype.exec */ \
TFJ(RegExpPrototypeExec, 1, kReceiver, kString) \ TFJ(RegExpPrototypeExec, 1, kReceiver, kString) \
/* ES #sec-get-regexp.prototype.flags */ \
TFJ(RegExpPrototypeFlagsGetter, 0, kReceiver) \
/* ES #sec-regexp.prototype-@@match */ \ /* ES #sec-regexp.prototype-@@match */ \
TFJ(RegExpPrototypeMatch, 1, kReceiver, kString) \ TFJ(RegExpPrototypeMatch, 1, kReceiver, kString) \
/* https://tc39.github.io/proposal-string-matchall/ */ \ /* https://tc39.github.io/proposal-string-matchall/ */ \

View File

@ -1459,11 +1459,11 @@ TF_BUILTIN(PromiseResolveTrampoline, PromiseBuiltinsAssembler) {
// 1. Let C be the this value. // 1. Let C be the this value.
Node* receiver = Parameter(Descriptor::kReceiver); Node* receiver = Parameter(Descriptor::kReceiver);
Node* value = Parameter(Descriptor::kValue); Node* value = Parameter(Descriptor::kValue);
Node* context = Parameter(Descriptor::kContext); TNode<Context> context = CAST(Parameter(Descriptor::kContext));
// 2. If Type(C) is not Object, throw a TypeError exception. // 2. If Type(C) is not Object, throw a TypeError exception.
ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject, ThrowIfNotJSReceiver(context, CAST(receiver),
"PromiseResolve"); MessageTemplate::kCalledOnNonObject, "PromiseResolve");
// 3. Return ? PromiseResolve(C, x). // 3. Return ? PromiseResolve(C, x).
Return(CallBuiltin(Builtins::kPromiseResolve, context, receiver, value)); Return(CallBuiltin(Builtins::kPromiseResolve, context, receiver, value));
@ -1767,10 +1767,11 @@ TF_BUILTIN(PromisePrototypeFinally, PromiseBuiltinsAssembler) {
// 1. Let promise be the this value. // 1. Let promise be the this value.
Node* const receiver = Parameter(Descriptor::kReceiver); Node* const receiver = Parameter(Descriptor::kReceiver);
Node* const on_finally = Parameter(Descriptor::kOnFinally); Node* const on_finally = Parameter(Descriptor::kOnFinally);
Node* const context = Parameter(Descriptor::kContext); TNode<Context> context = CAST(Parameter(Descriptor::kContext));
// 2. If Type(promise) is not Object, throw a TypeError exception. // 2. If Type(promise) is not Object, throw a TypeError exception.
ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject, ThrowIfNotJSReceiver(context, CAST(receiver),
MessageTemplate::kCalledOnNonObject,
"Promise.prototype.finally"); "Promise.prototype.finally");
// 3. Let C be ? SpeciesConstructor(promise, %Promise%). // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
@ -2570,8 +2571,8 @@ TF_BUILTIN(PromiseRace, PromiseBuiltinsAssembler) {
Node* const receiver = Parameter(Descriptor::kReceiver); Node* const receiver = Parameter(Descriptor::kReceiver);
TNode<Context> const context = CAST(Parameter(Descriptor::kContext)); TNode<Context> const context = CAST(Parameter(Descriptor::kContext));
ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject, ThrowIfNotJSReceiver(context, CAST(receiver),
"Promise.race"); MessageTemplate::kCalledOnNonObject, "Promise.race");
// Let promiseCapability be ? NewPromiseCapability(C). // Let promiseCapability be ? NewPromiseCapability(C).
// Don't fire debugEvent so that forwarding the rejection through all does not // Don't fire debugEvent so that forwarding the rejection through all does not

View File

@ -13,10 +13,10 @@ namespace internal {
TF_BUILTIN(ReflectHas, CodeStubAssembler) { TF_BUILTIN(ReflectHas, CodeStubAssembler) {
Node* target = Parameter(Descriptor::kTarget); Node* target = Parameter(Descriptor::kTarget);
Node* key = Parameter(Descriptor::kKey); Node* key = Parameter(Descriptor::kKey);
Node* context = Parameter(Descriptor::kContext); TNode<Context> context = CAST(Parameter(Descriptor::kContext));
ThrowIfNotJSReceiver(context, target, MessageTemplate::kCalledOnNonObject, ThrowIfNotJSReceiver(context, CAST(target),
"Reflect.has"); MessageTemplate::kCalledOnNonObject, "Reflect.has");
Return(CallBuiltin(Builtins::kHasProperty, context, target, key)); Return(CallBuiltin(Builtins::kHasProperty, context, target, key));
} }

View File

@ -893,34 +893,6 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpPrototypeExecBody(
return var_result.value(); return var_result.value();
} }
Node* RegExpBuiltinsAssembler::ThrowIfNotJSReceiver(
Node* context, Node* maybe_receiver, MessageTemplate msg_template,
char const* method_name) {
Label out(this), throw_exception(this, Label::kDeferred);
VARIABLE(var_value_map, MachineRepresentation::kTagged);
GotoIf(TaggedIsSmi(maybe_receiver), &throw_exception);
// Load the instance type of the {value}.
var_value_map.Bind(LoadMap(maybe_receiver));
TNode<Uint16T> const value_instance_type =
LoadMapInstanceType(var_value_map.value());
Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception);
// The {value} is not a compatible receiver for this method.
BIND(&throw_exception);
{
TNode<Object> const value_str =
CallBuiltin(Builtins::kToString, context, maybe_receiver);
ThrowTypeError(context, msg_template, StringConstant(method_name),
value_str);
}
BIND(&out);
return var_value_map.value();
}
TNode<BoolT> RegExpBuiltinsAssembler::IsReceiverInitialRegExpPrototype( TNode<BoolT> RegExpBuiltinsAssembler::IsReceiverInitialRegExpPrototype(
SloppyTNode<Context> context, SloppyTNode<Object> receiver) { SloppyTNode<Context> context, SloppyTNode<Object> receiver) {
TNode<Context> native_context = LoadNativeContext(context); TNode<Context> native_context = LoadNativeContext(context);
@ -1211,8 +1183,8 @@ TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) {
string)); string));
} }
TNode<String> RegExpBuiltinsAssembler::FlagsGetter(Node* const context, TNode<String> RegExpBuiltinsAssembler::FlagsGetter(TNode<Context> context,
Node* const regexp, TNode<Object> regexp,
bool is_fastpath) { bool is_fastpath) {
Isolate* isolate = this->isolate(); Isolate* isolate = this->isolate();
@ -1225,9 +1197,9 @@ TNode<String> RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
if (is_fastpath) { if (is_fastpath) {
// Refer to JSRegExp's flag property on the fast-path. // Refer to JSRegExp's flag property on the fast-path.
CSA_ASSERT(this, IsJSRegExp(regexp)); CSA_ASSERT(this, IsJSRegExp(CAST(regexp)));
TNode<Smi> const flags_smi = TNode<Smi> const flags_smi =
CAST(LoadObjectField(regexp, JSRegExp::kFlagsOffset)); CAST(LoadObjectField(CAST(regexp), JSRegExp::kFlagsOffset));
var_flags = SmiUntag(flags_smi); var_flags = SmiUntag(flags_smi);
#define CASE_FOR_FLAG(FLAG) \ #define CASE_FOR_FLAG(FLAG) \
@ -1382,29 +1354,6 @@ Node* RegExpBuiltinsAssembler::RegExpInitialize(Node* const context,
pattern, flags); pattern, flags);
} }
// ES #sec-get-regexp.prototype.flags
TF_BUILTIN(RegExpPrototypeFlagsGetter, RegExpBuiltinsAssembler) {
TNode<Object> maybe_receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
ThrowIfNotJSReceiver(context, maybe_receiver,
MessageTemplate::kRegExpNonObject,
"RegExp.prototype.flags");
TNode<JSReceiver> receiver = CAST(maybe_receiver);
// The check is strict because the following code relies on individual flag
// getters on the regexp prototype (e.g.: global, sticky, ...). We don't
// bother to check these individually.
Label if_isfastpath(this), if_isslowpath(this, Label::kDeferred);
BranchIfFastRegExp_Strict(context, receiver, &if_isfastpath, &if_isslowpath);
BIND(&if_isfastpath);
Return(FlagsGetter(context, receiver, true));
BIND(&if_isslowpath);
Return(FlagsGetter(context, receiver, false));
}
// ES#sec-regexp-pattern-flags // ES#sec-regexp-pattern-flags
// RegExp ( pattern, flags ) // RegExp ( pattern, flags )
TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) { TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
@ -1562,7 +1511,7 @@ TF_BUILTIN(RegExpPrototypeCompile, RegExpBuiltinsAssembler) {
BIND(&next); BIND(&next);
} }
TNode<String> const new_flags = FlagsGetter(context, pattern, true); TNode<String> const new_flags = FlagsGetter(context, CAST(pattern), true);
TNode<Object> const new_pattern = TNode<Object> const new_pattern =
LoadObjectField(pattern, JSRegExp::kSourceOffset); LoadObjectField(pattern, JSRegExp::kSourceOffset);
@ -1645,8 +1594,8 @@ TNode<BoolT> RegExpBuiltinsAssembler::FlagGetter(TNode<Context> context,
} }
// ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
TNode<Object> RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp, TNode<Object> RegExpBuiltinsAssembler::RegExpExec(TNode<Context> context,
Node* string) { Node* regexp, Node* string) {
TVARIABLE(Object, var_result); TVARIABLE(Object, var_result);
Label out(this); Label out(this);
@ -2157,7 +2106,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast(
} }
void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow( void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow(
Node* const context, Node* const regexp, Node* const string) { TNode<Context> context, Node* const regexp, Node* const string) {
CSA_ASSERT(this, IsJSReceiver(regexp)); CSA_ASSERT(this, IsJSReceiver(regexp));
CSA_ASSERT(this, IsString(string)); CSA_ASSERT(this, IsString(string));
@ -2167,7 +2116,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow(
// Grab the initial value of last index. // Grab the initial value of last index.
TNode<Object> const previous_last_index = TNode<Object> const previous_last_index =
SlowLoadLastIndex(CAST(context), CAST(regexp)); SlowLoadLastIndex(context, CAST(regexp));
// Ensure last index is 0. // Ensure last index is 0.
{ {
@ -2187,7 +2136,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow(
{ {
Label next(this), slow(this, Label::kDeferred); Label next(this), slow(this, Label::kDeferred);
TNode<Object> const current_last_index = TNode<Object> const current_last_index =
SlowLoadLastIndex(CAST(context), CAST(regexp)); SlowLoadLastIndex(context, CAST(regexp));
BranchIfSameValue(current_last_index, previous_last_index, &next, &slow); BranchIfSameValue(current_last_index, previous_last_index, &next, &slow);

View File

@ -84,10 +84,6 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
TNode<String> string, TNode<String> string,
const bool is_fastpath); const bool is_fastpath);
Node* ThrowIfNotJSReceiver(Node* context, Node* maybe_receiver,
MessageTemplate msg_template,
char const* method_name);
TNode<BoolT> IsReceiverInitialRegExpPrototype(SloppyTNode<Context> context, TNode<BoolT> IsReceiverInitialRegExpPrototype(SloppyTNode<Context> context,
SloppyTNode<Object> receiver); SloppyTNode<Object> receiver);
@ -153,8 +149,8 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
void BranchIfFastRegExpResult(Node* const context, Node* const object, void BranchIfFastRegExpResult(Node* const context, Node* const object,
Label* if_isunmodified, Label* if_ismodified); Label* if_isunmodified, Label* if_ismodified);
TNode<String> FlagsGetter(Node* const context, Node* const regexp, TNode<String> FlagsGetter(TNode<Context> context, TNode<Object> regexp,
bool is_fastpath); const bool is_fastpath);
TNode<BoolT> FastFlagGetter(TNode<JSRegExp> regexp, JSRegExp::Flag flag); TNode<BoolT> FastFlagGetter(TNode<JSRegExp> regexp, JSRegExp::Flag flag);
TNode<BoolT> FastFlagGetterGlobal(TNode<JSRegExp> regexp) { TNode<BoolT> FastFlagGetterGlobal(TNode<JSRegExp> regexp) {
@ -171,7 +167,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
Node* RegExpInitialize(Node* const context, Node* const regexp, Node* RegExpInitialize(Node* const context, Node* const regexp,
Node* const maybe_pattern, Node* const maybe_flags); Node* const maybe_pattern, Node* const maybe_flags);
TNode<Object> RegExpExec(Node* context, Node* regexp, Node* string); TNode<Object> RegExpExec(TNode<Context> context, Node* regexp, Node* string);
TNode<Number> AdvanceStringIndex(SloppyTNode<String> string, TNode<Number> AdvanceStringIndex(SloppyTNode<String> string,
SloppyTNode<Number> index, SloppyTNode<Number> index,
@ -190,7 +186,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
void RegExpPrototypeSearchBodyFast(TNode<Context> context, void RegExpPrototypeSearchBodyFast(TNode<Context> context,
TNode<JSRegExp> regexp, TNode<JSRegExp> regexp,
TNode<String> string); TNode<String> string);
void RegExpPrototypeSearchBodySlow(Node* const context, Node* const regexp, void RegExpPrototypeSearchBodySlow(TNode<Context> context, Node* const regexp,
Node* const string); Node* const string);
void RegExpPrototypeSplitBody(TNode<Context> context, TNode<JSRegExp> regexp, void RegExpPrototypeSplitBody(TNode<Context> context, TNode<JSRegExp> regexp,

View File

@ -130,4 +130,35 @@ namespace regexp {
receiver, kUnicode, kRegExpPrototypeUnicodeGetter, receiver, kUnicode, kRegExpPrototypeUnicodeGetter,
'RegExp.prototype.unicode'); 'RegExp.prototype.unicode');
} }
extern transitioning macro
RegExpBuiltinsAssembler::FlagsGetter(implicit context: Context)(
Object, constexpr bool): String;
transitioning macro
FastFlagsGetter(implicit context: Context)(receiver: FastJSRegExp): String {
return FlagsGetter(receiver, true);
}
transitioning macro SlowFlagsGetter(implicit context:
Context)(receiver: JSAny): String {
return FlagsGetter(receiver, false);
}
const kRegExpNonObject: constexpr MessageTemplate
generates 'MessageTemplate::kRegExpNonObject';
// ES #sec-get-regexp.prototype.flags
// TFJ(RegExpPrototypeFlagsGetter, 0, kReceiver) \
transitioning javascript builtin RegExpPrototypeFlagsGetter(
js-implicit context: Context, receiver: JSAny)(): String {
ThrowIfNotJSReceiver(receiver, kRegExpNonObject, 'RegExp.prototype.flags');
// The check is strict because the following code relies on individual flag
// getters on the regexp prototype (e.g.: global, sticky, ...). We don't
// bother to check these individually.
const fastRegexp = Cast<FastJSRegExp>(receiver)
otherwise return SlowFlagsGetter(receiver);
return FastFlagsGetter(fastRegexp);
}
} }

View File

@ -6052,27 +6052,26 @@ Node* CodeStubAssembler::ThrowIfNotInstanceType(Node* context, Node* value,
return var_value_map.value(); return var_value_map.value();
} }
Node* CodeStubAssembler::ThrowIfNotJSReceiver(Node* context, Node* value, void CodeStubAssembler::ThrowIfNotJSReceiver(TNode<Context> context,
MessageTemplate msg_template, TNode<Object> value,
const char* method_name) { MessageTemplate msg_template,
Label out(this), throw_exception(this, Label::kDeferred); const char* method_name) {
VARIABLE(var_value_map, MachineRepresentation::kTagged); Label done(this), throw_exception(this, Label::kDeferred);
GotoIf(TaggedIsSmi(value), &throw_exception); GotoIf(TaggedIsSmi(value), &throw_exception);
// Load the instance type of the {value}. // Load the instance type of the {value}.
var_value_map.Bind(LoadMap(value)); TNode<Map> value_map = LoadMap(CAST(value));
TNode<Uint16T> const value_instance_type = TNode<Uint16T> const value_instance_type = LoadMapInstanceType(value_map);
LoadMapInstanceType(var_value_map.value());
Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception); Branch(IsJSReceiverInstanceType(value_instance_type), &done,
&throw_exception);
// The {value} is not a compatible receiver for this method. // The {value} is not a compatible receiver for this method.
BIND(&throw_exception); BIND(&throw_exception);
ThrowTypeError(context, msg_template, method_name); ThrowTypeError(context, msg_template, StringConstant(method_name), value);
BIND(&out); BIND(&done);
return var_value_map.value();
} }
void CodeStubAssembler::ThrowIfNotCallable(TNode<Context> context, void CodeStubAssembler::ThrowIfNotCallable(TNode<Context> context,
@ -13008,7 +13007,7 @@ TNode<JSReceiver> CodeStubAssembler::SpeciesConstructor(
// 4. If Type(C) is not Object, throw a TypeError exception. // 4. If Type(C) is not Object, throw a TypeError exception.
ThrowIfNotJSReceiver(context, constructor, ThrowIfNotJSReceiver(context, constructor,
MessageTemplate::kConstructorNotReceiver); MessageTemplate::kConstructorNotReceiver, "");
// 5. Let S be ? Get(C, @@species). // 5. Let S be ? Get(C, @@species).
TNode<Object> species = TNode<Object> species =

View File

@ -2321,10 +2321,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
InstanceType instance_type, InstanceType instance_type,
char const* method_name); char const* method_name);
// Throws a TypeError for {method_name} if {value} is not a JSReceiver. // Throws a TypeError for {method_name} if {value} is not a JSReceiver.
// Returns the {value}'s map. void ThrowIfNotJSReceiver(TNode<Context> context, TNode<Object> value,
Node* ThrowIfNotJSReceiver(Node* context, Node* value, MessageTemplate msg_template,
MessageTemplate msg_template, const char* method_name);
const char* method_name = nullptr);
void ThrowIfNotCallable(TNode<Context> context, TNode<Object> value, void ThrowIfNotCallable(TNode<Context> context, TNode<Object> value,
const char* method_name); const char* method_name);