[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:
parent
e36eb3e947
commit
e3debe47cc
@ -1665,6 +1665,9 @@ extern macro ThrowTypeError(implicit context: Context)(
|
||||
extern transitioning runtime ThrowTypeErrorIfStrict(implicit context: Context)(
|
||||
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 ArrayCreate(implicit context: Context)(Number): JSArray;
|
||||
extern macro BuildAppendJSArray(
|
||||
|
@ -847,8 +847,6 @@ namespace internal {
|
||||
TFJ(RegExpPrototypeCompile, 2, kReceiver, kPattern, kFlags) \
|
||||
/* ES #sec-regexp.prototype.exec */ \
|
||||
TFJ(RegExpPrototypeExec, 1, kReceiver, kString) \
|
||||
/* ES #sec-get-regexp.prototype.flags */ \
|
||||
TFJ(RegExpPrototypeFlagsGetter, 0, kReceiver) \
|
||||
/* ES #sec-regexp.prototype-@@match */ \
|
||||
TFJ(RegExpPrototypeMatch, 1, kReceiver, kString) \
|
||||
/* https://tc39.github.io/proposal-string-matchall/ */ \
|
||||
|
@ -1459,11 +1459,11 @@ TF_BUILTIN(PromiseResolveTrampoline, PromiseBuiltinsAssembler) {
|
||||
// 1. Let C be the this value.
|
||||
Node* receiver = Parameter(Descriptor::kReceiver);
|
||||
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.
|
||||
ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
|
||||
"PromiseResolve");
|
||||
ThrowIfNotJSReceiver(context, CAST(receiver),
|
||||
MessageTemplate::kCalledOnNonObject, "PromiseResolve");
|
||||
|
||||
// 3. Return ? PromiseResolve(C, x).
|
||||
Return(CallBuiltin(Builtins::kPromiseResolve, context, receiver, value));
|
||||
@ -1767,10 +1767,11 @@ TF_BUILTIN(PromisePrototypeFinally, PromiseBuiltinsAssembler) {
|
||||
// 1. Let promise be the this value.
|
||||
Node* const receiver = Parameter(Descriptor::kReceiver);
|
||||
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.
|
||||
ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
|
||||
ThrowIfNotJSReceiver(context, CAST(receiver),
|
||||
MessageTemplate::kCalledOnNonObject,
|
||||
"Promise.prototype.finally");
|
||||
|
||||
// 3. Let C be ? SpeciesConstructor(promise, %Promise%).
|
||||
@ -2570,8 +2571,8 @@ TF_BUILTIN(PromiseRace, PromiseBuiltinsAssembler) {
|
||||
|
||||
Node* const receiver = Parameter(Descriptor::kReceiver);
|
||||
TNode<Context> const context = CAST(Parameter(Descriptor::kContext));
|
||||
ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
|
||||
"Promise.race");
|
||||
ThrowIfNotJSReceiver(context, CAST(receiver),
|
||||
MessageTemplate::kCalledOnNonObject, "Promise.race");
|
||||
|
||||
// Let promiseCapability be ? NewPromiseCapability(C).
|
||||
// Don't fire debugEvent so that forwarding the rejection through all does not
|
||||
|
@ -13,10 +13,10 @@ namespace internal {
|
||||
TF_BUILTIN(ReflectHas, CodeStubAssembler) {
|
||||
Node* target = Parameter(Descriptor::kTarget);
|
||||
Node* key = Parameter(Descriptor::kKey);
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
|
||||
ThrowIfNotJSReceiver(context, target, MessageTemplate::kCalledOnNonObject,
|
||||
"Reflect.has");
|
||||
ThrowIfNotJSReceiver(context, CAST(target),
|
||||
MessageTemplate::kCalledOnNonObject, "Reflect.has");
|
||||
|
||||
Return(CallBuiltin(Builtins::kHasProperty, context, target, key));
|
||||
}
|
||||
|
@ -893,34 +893,6 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpPrototypeExecBody(
|
||||
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(
|
||||
SloppyTNode<Context> context, SloppyTNode<Object> receiver) {
|
||||
TNode<Context> native_context = LoadNativeContext(context);
|
||||
@ -1211,8 +1183,8 @@ TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) {
|
||||
string));
|
||||
}
|
||||
|
||||
TNode<String> RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
|
||||
Node* const regexp,
|
||||
TNode<String> RegExpBuiltinsAssembler::FlagsGetter(TNode<Context> context,
|
||||
TNode<Object> regexp,
|
||||
bool is_fastpath) {
|
||||
Isolate* isolate = this->isolate();
|
||||
|
||||
@ -1225,9 +1197,9 @@ TNode<String> RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
|
||||
|
||||
if (is_fastpath) {
|
||||
// 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 =
|
||||
CAST(LoadObjectField(regexp, JSRegExp::kFlagsOffset));
|
||||
CAST(LoadObjectField(CAST(regexp), JSRegExp::kFlagsOffset));
|
||||
var_flags = SmiUntag(flags_smi);
|
||||
|
||||
#define CASE_FOR_FLAG(FLAG) \
|
||||
@ -1382,29 +1354,6 @@ Node* RegExpBuiltinsAssembler::RegExpInitialize(Node* const context,
|
||||
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
|
||||
// RegExp ( pattern, flags )
|
||||
TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
|
||||
@ -1562,7 +1511,7 @@ TF_BUILTIN(RegExpPrototypeCompile, RegExpBuiltinsAssembler) {
|
||||
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 =
|
||||
LoadObjectField(pattern, JSRegExp::kSourceOffset);
|
||||
|
||||
@ -1645,8 +1594,8 @@ TNode<BoolT> RegExpBuiltinsAssembler::FlagGetter(TNode<Context> context,
|
||||
}
|
||||
|
||||
// ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
|
||||
TNode<Object> RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
|
||||
Node* string) {
|
||||
TNode<Object> RegExpBuiltinsAssembler::RegExpExec(TNode<Context> context,
|
||||
Node* regexp, Node* string) {
|
||||
TVARIABLE(Object, var_result);
|
||||
Label out(this);
|
||||
|
||||
@ -2157,7 +2106,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast(
|
||||
}
|
||||
|
||||
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, IsString(string));
|
||||
|
||||
@ -2167,7 +2116,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow(
|
||||
|
||||
// Grab the initial value of last index.
|
||||
TNode<Object> const previous_last_index =
|
||||
SlowLoadLastIndex(CAST(context), CAST(regexp));
|
||||
SlowLoadLastIndex(context, CAST(regexp));
|
||||
|
||||
// Ensure last index is 0.
|
||||
{
|
||||
@ -2187,7 +2136,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow(
|
||||
{
|
||||
Label next(this), slow(this, Label::kDeferred);
|
||||
TNode<Object> const current_last_index =
|
||||
SlowLoadLastIndex(CAST(context), CAST(regexp));
|
||||
SlowLoadLastIndex(context, CAST(regexp));
|
||||
|
||||
BranchIfSameValue(current_last_index, previous_last_index, &next, &slow);
|
||||
|
||||
|
@ -84,10 +84,6 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
|
||||
TNode<String> string,
|
||||
const bool is_fastpath);
|
||||
|
||||
Node* ThrowIfNotJSReceiver(Node* context, Node* maybe_receiver,
|
||||
MessageTemplate msg_template,
|
||||
char const* method_name);
|
||||
|
||||
TNode<BoolT> IsReceiverInitialRegExpPrototype(SloppyTNode<Context> context,
|
||||
SloppyTNode<Object> receiver);
|
||||
|
||||
@ -153,8 +149,8 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
|
||||
void BranchIfFastRegExpResult(Node* const context, Node* const object,
|
||||
Label* if_isunmodified, Label* if_ismodified);
|
||||
|
||||
TNode<String> FlagsGetter(Node* const context, Node* const regexp,
|
||||
bool is_fastpath);
|
||||
TNode<String> FlagsGetter(TNode<Context> context, TNode<Object> regexp,
|
||||
const bool is_fastpath);
|
||||
|
||||
TNode<BoolT> FastFlagGetter(TNode<JSRegExp> regexp, JSRegExp::Flag flag);
|
||||
TNode<BoolT> FastFlagGetterGlobal(TNode<JSRegExp> regexp) {
|
||||
@ -171,7 +167,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
|
||||
Node* RegExpInitialize(Node* const context, Node* const regexp,
|
||||
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,
|
||||
SloppyTNode<Number> index,
|
||||
@ -190,7 +186,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
|
||||
void RegExpPrototypeSearchBodyFast(TNode<Context> context,
|
||||
TNode<JSRegExp> regexp,
|
||||
TNode<String> string);
|
||||
void RegExpPrototypeSearchBodySlow(Node* const context, Node* const regexp,
|
||||
void RegExpPrototypeSearchBodySlow(TNode<Context> context, Node* const regexp,
|
||||
Node* const string);
|
||||
|
||||
void RegExpPrototypeSplitBody(TNode<Context> context, TNode<JSRegExp> regexp,
|
||||
|
@ -130,4 +130,35 @@ namespace regexp {
|
||||
receiver, kUnicode, kRegExpPrototypeUnicodeGetter,
|
||||
'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);
|
||||
}
|
||||
}
|
||||
|
@ -6052,27 +6052,26 @@ Node* CodeStubAssembler::ThrowIfNotInstanceType(Node* context, Node* value,
|
||||
return var_value_map.value();
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::ThrowIfNotJSReceiver(Node* context, Node* value,
|
||||
MessageTemplate msg_template,
|
||||
const char* method_name) {
|
||||
Label out(this), throw_exception(this, Label::kDeferred);
|
||||
VARIABLE(var_value_map, MachineRepresentation::kTagged);
|
||||
void CodeStubAssembler::ThrowIfNotJSReceiver(TNode<Context> context,
|
||||
TNode<Object> value,
|
||||
MessageTemplate msg_template,
|
||||
const char* method_name) {
|
||||
Label done(this), throw_exception(this, Label::kDeferred);
|
||||
|
||||
GotoIf(TaggedIsSmi(value), &throw_exception);
|
||||
|
||||
// Load the instance type of the {value}.
|
||||
var_value_map.Bind(LoadMap(value));
|
||||
TNode<Uint16T> const value_instance_type =
|
||||
LoadMapInstanceType(var_value_map.value());
|
||||
TNode<Map> value_map = LoadMap(CAST(value));
|
||||
TNode<Uint16T> const value_instance_type = LoadMapInstanceType(value_map);
|
||||
|
||||
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.
|
||||
BIND(&throw_exception);
|
||||
ThrowTypeError(context, msg_template, method_name);
|
||||
ThrowTypeError(context, msg_template, StringConstant(method_name), value);
|
||||
|
||||
BIND(&out);
|
||||
return var_value_map.value();
|
||||
BIND(&done);
|
||||
}
|
||||
|
||||
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.
|
||||
ThrowIfNotJSReceiver(context, constructor,
|
||||
MessageTemplate::kConstructorNotReceiver);
|
||||
MessageTemplate::kConstructorNotReceiver, "");
|
||||
|
||||
// 5. Let S be ? Get(C, @@species).
|
||||
TNode<Object> species =
|
||||
|
@ -2321,10 +2321,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
InstanceType instance_type,
|
||||
char const* method_name);
|
||||
// Throws a TypeError for {method_name} if {value} is not a JSReceiver.
|
||||
// Returns the {value}'s map.
|
||||
Node* ThrowIfNotJSReceiver(Node* context, Node* value,
|
||||
MessageTemplate msg_template,
|
||||
const char* method_name = nullptr);
|
||||
void ThrowIfNotJSReceiver(TNode<Context> context, TNode<Object> value,
|
||||
MessageTemplate msg_template,
|
||||
const char* method_name);
|
||||
void ThrowIfNotCallable(TNode<Context> context, TNode<Object> value,
|
||||
const char* method_name);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user