[builtins] Port RegExp StringIteratorNext to Torque
Bug: v8:8976 Change-Id: I3f13980ce49e1ca0f5caf5712c5181908054d649 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1834882 Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#64170}
This commit is contained in:
parent
cc5016e1b7
commit
25e551eff9
@ -1494,7 +1494,7 @@ transient type FastJSRegExpResult extends JSRegExpResult;
|
||||
@generateCppClass
|
||||
extern class JSRegExpStringIterator extends JSObject {
|
||||
// The [[IteratingRegExp]] internal property.
|
||||
iterating_reg_exp: JSAny;
|
||||
iterating_reg_exp: JSReceiver;
|
||||
// The [[IteratedString]] internal property.
|
||||
iterated_string: String;
|
||||
flags: Smi;
|
||||
@ -2303,6 +2303,14 @@ Cast<JSStringIterator>(o: HeapObject): JSStringIterator
|
||||
return HeapObjectToJSStringIterator(o) otherwise CastError;
|
||||
}
|
||||
|
||||
Cast<JSRegExpStringIterator>(o: HeapObject): JSRegExpStringIterator
|
||||
labels CastError {
|
||||
if (IsJSRegExpStringIterator(o)) {
|
||||
return %RawDownCast<JSRegExpStringIterator>(o);
|
||||
}
|
||||
goto CastError;
|
||||
}
|
||||
|
||||
Cast<JSTypedArray>(o: HeapObject): JSTypedArray
|
||||
labels CastError {
|
||||
if (IsJSTypedArray(o)) return %RawDownCast<JSTypedArray>(o);
|
||||
@ -3342,6 +3350,7 @@ extern macro IsFeedbackVector(HeapObject): bool;
|
||||
extern macro IsJSArray(HeapObject): bool;
|
||||
extern macro IsJSProxy(HeapObject): bool;
|
||||
extern macro IsJSRegExp(HeapObject): bool;
|
||||
extern macro IsJSRegExpStringIterator(HeapObject): bool;
|
||||
extern macro IsMap(HeapObject): bool;
|
||||
extern macro IsJSFunction(HeapObject): bool;
|
||||
extern macro IsJSObject(HeapObject): bool;
|
||||
|
@ -858,10 +858,6 @@ namespace internal {
|
||||
TFS(RegExpExecInternal, kRegExp, kString, kLastIndex, kMatchInfo) \
|
||||
ASM(RegExpInterpreterTrampoline, CCall) \
|
||||
\
|
||||
/* RegExp String Iterator */ \
|
||||
/* https://tc39.github.io/proposal-string-matchall/ */ \
|
||||
TFJ(RegExpStringIteratorPrototypeNext, 0, kReceiver) \
|
||||
\
|
||||
/* Set */ \
|
||||
TFJ(SetConstructor, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
TFJ(SetPrototypeHas, 1, kReceiver, kKey) \
|
||||
|
@ -2104,203 +2104,5 @@ TNode<JSArray> RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
class RegExpStringIteratorAssembler : public RegExpBuiltinsAssembler {
|
||||
public:
|
||||
explicit RegExpStringIteratorAssembler(compiler::CodeAssemblerState* state)
|
||||
: RegExpBuiltinsAssembler(state) {}
|
||||
|
||||
protected:
|
||||
TNode<Smi> LoadFlags(TNode<HeapObject> iterator) {
|
||||
return LoadObjectField<Smi>(iterator, JSRegExpStringIterator::kFlagsOffset);
|
||||
}
|
||||
|
||||
TNode<BoolT> HasDoneFlag(TNode<Smi> flags) {
|
||||
return UncheckedCast<BoolT>(
|
||||
IsSetSmi(flags, 1 << JSRegExpStringIterator::kDoneBit));
|
||||
}
|
||||
|
||||
TNode<BoolT> HasGlobalFlag(TNode<Smi> flags) {
|
||||
return UncheckedCast<BoolT>(
|
||||
IsSetSmi(flags, 1 << JSRegExpStringIterator::kGlobalBit));
|
||||
}
|
||||
|
||||
TNode<BoolT> HasUnicodeFlag(TNode<Smi> flags) {
|
||||
return UncheckedCast<BoolT>(
|
||||
IsSetSmi(flags, 1 << JSRegExpStringIterator::kUnicodeBit));
|
||||
}
|
||||
|
||||
void SetDoneFlag(TNode<HeapObject> iterator, TNode<Smi> flags) {
|
||||
TNode<Smi> new_flags =
|
||||
SmiOr(flags, SmiConstant(1 << JSRegExpStringIterator::kDoneBit));
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
iterator, JSRegExpStringIterator::kFlagsOffset, new_flags);
|
||||
}
|
||||
};
|
||||
|
||||
// https://tc39.github.io/proposal-string-matchall/
|
||||
// %RegExpStringIteratorPrototype%.next ( )
|
||||
TF_BUILTIN(RegExpStringIteratorPrototypeNext, RegExpStringIteratorAssembler) {
|
||||
const char* method_name = "%RegExpStringIterator%.prototype.next";
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<Object> maybe_receiver = CAST(Parameter(Descriptor::kReceiver));
|
||||
|
||||
Label if_match(this), if_no_match(this, Label::kDeferred),
|
||||
return_empty_done_result(this, Label::kDeferred);
|
||||
|
||||
// 1. Let O be the this value.
|
||||
// 2. If Type(O) is not Object, throw a TypeError exception.
|
||||
// 3. If O does not have all of the internal slots of a RegExp String Iterator
|
||||
// Object Instance (see 5.3), throw a TypeError exception.
|
||||
ThrowIfNotInstanceType(context, maybe_receiver,
|
||||
JS_REGEXP_STRING_ITERATOR_TYPE, method_name);
|
||||
TNode<HeapObject> receiver = CAST(maybe_receiver);
|
||||
|
||||
// 4. If O.[[Done]] is true, then
|
||||
// a. Return ! CreateIterResultObject(undefined, true).
|
||||
TNode<Smi> flags = LoadFlags(receiver);
|
||||
GotoIf(HasDoneFlag(flags), &return_empty_done_result);
|
||||
|
||||
// 5. Let R be O.[[IteratingRegExp]].
|
||||
TNode<JSReceiver> iterating_regexp = CAST(LoadObjectField(
|
||||
receiver, JSRegExpStringIterator::kIteratingRegExpOffset));
|
||||
|
||||
// For extra safety, also check the type in release mode.
|
||||
CSA_CHECK(this, IsJSReceiver(iterating_regexp));
|
||||
|
||||
// 6. Let S be O.[[IteratedString]].
|
||||
TNode<String> iterating_string = CAST(
|
||||
LoadObjectField(receiver, JSRegExpStringIterator::kIteratedStringOffset));
|
||||
|
||||
// 7. Let global be O.[[Global]].
|
||||
// See if_match.
|
||||
|
||||
// 8. Let fullUnicode be O.[[Unicode]].
|
||||
// See if_global.
|
||||
|
||||
// 9. Let match be ? RegExpExec(R, S).
|
||||
TVARIABLE(Object, var_match);
|
||||
TVARIABLE(BoolT, var_is_fast_regexp);
|
||||
{
|
||||
Label if_fast(this), if_slow(this, Label::kDeferred);
|
||||
BranchIfFastRegExp_Permissive(context, iterating_regexp, &if_fast,
|
||||
&if_slow);
|
||||
|
||||
BIND(&if_fast);
|
||||
{
|
||||
TNode<RegExpMatchInfo> match_indices =
|
||||
RegExpPrototypeExecBodyWithoutResult(
|
||||
context, iterating_regexp, iterating_string, &if_no_match, true);
|
||||
var_match = ConstructNewResultFromMatchInfo(
|
||||
context, iterating_regexp, match_indices, iterating_string);
|
||||
var_is_fast_regexp = Int32TrueConstant();
|
||||
Goto(&if_match);
|
||||
}
|
||||
|
||||
BIND(&if_slow);
|
||||
{
|
||||
var_match = RegExpExec(context, iterating_regexp, iterating_string);
|
||||
var_is_fast_regexp = Int32FalseConstant();
|
||||
Branch(IsNull(var_match.value()), &if_no_match, &if_match);
|
||||
}
|
||||
}
|
||||
|
||||
// 10. If match is null, then
|
||||
BIND(&if_no_match);
|
||||
{
|
||||
// a. Set O.[[Done]] to true.
|
||||
SetDoneFlag(receiver, flags);
|
||||
|
||||
// b. Return ! CreateIterResultObject(undefined, true).
|
||||
Goto(&return_empty_done_result);
|
||||
}
|
||||
// 11. Else,
|
||||
BIND(&if_match);
|
||||
{
|
||||
Label if_global(this), if_not_global(this, Label::kDeferred),
|
||||
return_result(this);
|
||||
|
||||
// a. If global is true,
|
||||
Branch(HasGlobalFlag(flags), &if_global, &if_not_global);
|
||||
BIND(&if_global);
|
||||
{
|
||||
Label if_fast(this), if_slow(this, Label::kDeferred);
|
||||
|
||||
// ii. If matchStr is the empty string,
|
||||
Branch(var_is_fast_regexp.value(), &if_fast, &if_slow);
|
||||
BIND(&if_fast);
|
||||
{
|
||||
// i. Let matchStr be ? ToString(? Get(match, "0")).
|
||||
CSA_ASSERT_BRANCH(this, [&](Label* ok, Label* not_ok) {
|
||||
BranchIfFastRegExpResult(context, var_match.value(), ok, not_ok);
|
||||
});
|
||||
CSA_ASSERT(this,
|
||||
SmiNotEqual(LoadFastJSArrayLength(CAST(var_match.value())),
|
||||
SmiZero()));
|
||||
TNode<FixedArray> result_fixed_array =
|
||||
CAST(LoadElements(CAST(var_match.value())));
|
||||
TNode<String> match_str =
|
||||
CAST(LoadFixedArrayElement(result_fixed_array, 0));
|
||||
|
||||
// When iterating_regexp is fast, we assume it stays fast even after
|
||||
// accessing the first match from the RegExp result.
|
||||
CSA_ASSERT(this, IsFastRegExpPermissive(context, iterating_regexp));
|
||||
GotoIfNot(IsEmptyString(match_str), &return_result);
|
||||
|
||||
// 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).
|
||||
TNode<Smi> this_index = FastLoadLastIndex(CAST(iterating_regexp));
|
||||
|
||||
// 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, fullUnicode).
|
||||
TNode<Smi> next_index = AdvanceStringIndexFast(
|
||||
iterating_string, this_index, HasUnicodeFlag(flags));
|
||||
|
||||
// 3. Perform ? Set(R, "lastIndex", nextIndex, true).
|
||||
FastStoreLastIndex(CAST(iterating_regexp), next_index);
|
||||
|
||||
// iii. Return ! CreateIterResultObject(match, false).
|
||||
Goto(&return_result);
|
||||
}
|
||||
BIND(&if_slow);
|
||||
{
|
||||
// i. Let matchStr be ? ToString(? Get(match, "0")).
|
||||
TNode<String> match_str = ToString_Inline(
|
||||
context, GetProperty(context, var_match.value(), SmiZero()));
|
||||
|
||||
GotoIfNot(IsEmptyString(match_str), &return_result);
|
||||
|
||||
// 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).
|
||||
TNode<Object> last_index = SlowLoadLastIndex(context, iterating_regexp);
|
||||
TNode<Number> this_index = ToLength_Inline(context, last_index);
|
||||
|
||||
// 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, fullUnicode).
|
||||
TNode<Number> next_index = AdvanceStringIndex(
|
||||
iterating_string, this_index, HasUnicodeFlag(flags), false);
|
||||
|
||||
// 3. Perform ? Set(R, "lastIndex", nextIndex, true).
|
||||
SlowStoreLastIndex(context, iterating_regexp, next_index);
|
||||
|
||||
// iii. Return ! CreateIterResultObject(match, false).
|
||||
Goto(&return_result);
|
||||
}
|
||||
}
|
||||
// b. Else,
|
||||
BIND(&if_not_global);
|
||||
{
|
||||
// i. Set O.[[Done]] to true.
|
||||
SetDoneFlag(receiver, flags);
|
||||
|
||||
// ii. Return ! CreateIterResultObject(match, false).
|
||||
Goto(&return_result);
|
||||
}
|
||||
BIND(&return_result);
|
||||
{
|
||||
Return(AllocateJSIteratorResult(context, var_match.value(),
|
||||
FalseConstant()));
|
||||
}
|
||||
}
|
||||
BIND(&return_empty_done_result);
|
||||
Return(
|
||||
AllocateJSIteratorResult(context, UndefinedConstant(), TrueConstant()));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -186,6 +186,11 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
|
||||
return CAST(AdvanceStringIndex(string, index, is_unicode, true));
|
||||
}
|
||||
|
||||
TNode<Smi> AdvanceStringIndexSlow(TNode<String> string, TNode<Number> index,
|
||||
TNode<BoolT> is_unicode) {
|
||||
return CAST(AdvanceStringIndex(string, index, is_unicode, false));
|
||||
}
|
||||
|
||||
TNode<Object> RegExpPrototypeMatchBody(TNode<Context> context,
|
||||
TNode<Object> regexp,
|
||||
TNode<String> const string,
|
||||
|
@ -107,4 +107,152 @@ namespace regexp {
|
||||
const nativeContext: NativeContext = LoadNativeContext(context);
|
||||
return RegExpPrototypeMatchAllImpl(nativeContext, receiver, string);
|
||||
}
|
||||
|
||||
const kJSRegExpStringIteratorDone:
|
||||
constexpr int31 generates '1 << JSRegExpStringIterator::kDoneBit';
|
||||
const kJSRegExpStringIteratorGlobal: constexpr int31
|
||||
generates '1 << JSRegExpStringIterator::kGlobalBit';
|
||||
const kJSRegExpStringIteratorUnicode: constexpr int31
|
||||
generates '1 << JSRegExpStringIterator::kUnicodeBit';
|
||||
|
||||
extern macro IsSetSmi(Smi, constexpr int31): bool;
|
||||
|
||||
macro HasDoneFlag(flags: Smi): bool {
|
||||
return IsSetSmi(flags, kJSRegExpStringIteratorDone);
|
||||
}
|
||||
|
||||
macro HasGlobalFlag(flags: Smi): bool {
|
||||
return IsSetSmi(flags, kJSRegExpStringIteratorGlobal);
|
||||
}
|
||||
|
||||
macro HasUnicodeFlag(flags: Smi): bool {
|
||||
return IsSetSmi(flags, kJSRegExpStringIteratorUnicode);
|
||||
}
|
||||
|
||||
macro SetDoneFlag(iterator: JSRegExpStringIterator, flags: Smi) {
|
||||
const newFlags: Smi = flags | kJSRegExpStringIteratorDone;
|
||||
iterator.flags = newFlags;
|
||||
}
|
||||
|
||||
extern macro RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
|
||||
implicit context: Context)(JSReceiver, RegExpMatchInfo, String):
|
||||
JSRegExpResult;
|
||||
|
||||
// https://tc39.github.io/proposal-string-matchall/
|
||||
// %RegExpStringIteratorPrototype%.next ( )
|
||||
transitioning javascript builtin RegExpStringIteratorPrototypeNext(
|
||||
js-implicit context: Context, receiver: JSAny)(): JSAny {
|
||||
// 1. Let O be the this value.
|
||||
// 2. If Type(O) is not Object, throw a TypeError exception.
|
||||
// 3. If O does not have all of the internal slots of a RegExp String
|
||||
// Iterator Object Instance (see 5.3), throw a TypeError exception.
|
||||
const methodName: constexpr string =
|
||||
'%RegExpStringIterator%.prototype.next';
|
||||
const receiver = Cast<JSRegExpStringIterator>(receiver) otherwise
|
||||
ThrowTypeError(kIncompatibleMethodReceiver, methodName, receiver);
|
||||
|
||||
try {
|
||||
// 4. If O.[[Done]] is true, then
|
||||
// a. Return ! CreateIterResultObject(undefined, true).
|
||||
const flags: Smi = receiver.flags;
|
||||
if (HasDoneFlag(flags)) goto ReturnEmptyDoneResult;
|
||||
|
||||
// 5. Let R be O.[[iteratingRegExp]].
|
||||
const iteratingRegExp: JSReceiver = receiver.iterating_reg_exp;
|
||||
|
||||
// 6. Let S be O.[[IteratedString]].
|
||||
const iteratingString: String = receiver.iterated_string;
|
||||
|
||||
// 7. Let global be O.[[Global]].
|
||||
// 8. Let fullUnicode be O.[[Unicode]].
|
||||
// 9. Let match be ? RegExpExec(R, S).
|
||||
let match: Object;
|
||||
let isFastRegExp: bool = false;
|
||||
try {
|
||||
if (IsFastRegExpPermissive(iteratingRegExp)) {
|
||||
const matchIndices: RegExpMatchInfo =
|
||||
RegExpPrototypeExecBodyWithoutResultFast(
|
||||
UnsafeCast<JSRegExp>(iteratingRegExp), iteratingString)
|
||||
otherwise IfNoMatch;
|
||||
match = ConstructNewResultFromMatchInfo(
|
||||
iteratingRegExp, matchIndices, iteratingString);
|
||||
isFastRegExp = true;
|
||||
} else {
|
||||
match = RegExpExec(context, iteratingRegExp, iteratingString);
|
||||
if (match == Null) {
|
||||
goto IfNoMatch;
|
||||
}
|
||||
}
|
||||
// 11. Else,
|
||||
// b. Else, handle non-global case first.
|
||||
if (!HasGlobalFlag(flags)) {
|
||||
// i. Set O.[[Done]] to true.
|
||||
SetDoneFlag(receiver, flags);
|
||||
|
||||
// ii. Return ! CreateIterResultObject(match, false).
|
||||
return AllocateJSIteratorResult(UnsafeCast<JSAny>(match), False);
|
||||
}
|
||||
// a. If global is true,
|
||||
assert(HasGlobalFlag(flags));
|
||||
if (isFastRegExp) {
|
||||
// i. Let matchStr be ? ToString(? Get(match, "0")).
|
||||
const match = UnsafeCast<FastJSRegExpResult>(match);
|
||||
const resultFixedArray = UnsafeCast<FixedArray>(match.elements);
|
||||
const matchStr = UnsafeCast<String>(resultFixedArray.objects[0]);
|
||||
|
||||
// When iterating_regexp is fast, we assume it stays fast even after
|
||||
// accessing the first match from the RegExp result.
|
||||
assert(IsFastRegExpPermissive(iteratingRegExp));
|
||||
const iteratingRegExp = UnsafeCast<JSRegExp>(iteratingRegExp);
|
||||
if (matchStr == kEmptyString) {
|
||||
// 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).
|
||||
const thisIndex: Smi = FastLoadLastIndex(iteratingRegExp);
|
||||
|
||||
// 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex,
|
||||
// fullUnicode).
|
||||
const nextIndex: Smi = AdvanceStringIndexFast(
|
||||
iteratingString, thisIndex, HasUnicodeFlag(flags));
|
||||
|
||||
// 3. Perform ? Set(R, "lastIndex", nextIndex, true).
|
||||
FastStoreLastIndex(iteratingRegExp, nextIndex);
|
||||
}
|
||||
|
||||
// iii. Return ! CreateIterResultObject(match, false).
|
||||
return AllocateJSIteratorResult(match, False);
|
||||
}
|
||||
assert(!isFastRegExp);
|
||||
// i. Let matchStr be ? ToString(? Get(match, "0")).
|
||||
const match = UnsafeCast<JSAny>(match);
|
||||
const matchStr =
|
||||
ToString_Inline(context, GetProperty(match, SmiConstant(0)));
|
||||
|
||||
if (matchStr == kEmptyString) {
|
||||
// 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).
|
||||
const lastIndex: JSAny = SlowLoadLastIndex(iteratingRegExp);
|
||||
const thisIndex: Number = ToLength_Inline(context, lastIndex);
|
||||
|
||||
// 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex,
|
||||
// fullUnicode).
|
||||
const nextIndex: Number = AdvanceStringIndexSlow(
|
||||
iteratingString, thisIndex, HasUnicodeFlag(flags));
|
||||
|
||||
// 3. Perform ? Set(R, "lastIndex", nextIndex, true).
|
||||
SlowStoreLastIndex(iteratingRegExp, nextIndex);
|
||||
}
|
||||
// iii. Return ! CreateIterResultObject(match, false).
|
||||
return AllocateJSIteratorResult(match, False);
|
||||
}
|
||||
// 10. If match is null, then
|
||||
label IfNoMatch {
|
||||
// a. Set O.[[Done]] to true.
|
||||
SetDoneFlag(receiver, flags);
|
||||
|
||||
// b. Return ! CreateIterResultObject(undefined, true).
|
||||
goto ReturnEmptyDoneResult;
|
||||
}
|
||||
}
|
||||
label ReturnEmptyDoneResult {
|
||||
return AllocateJSIteratorResult(Undefined, True);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,6 @@ namespace regexp {
|
||||
StringReplaceNonGlobalRegExpWithFunction(implicit context: Context)(
|
||||
String, JSRegExp, Callable): String;
|
||||
|
||||
extern macro
|
||||
RegExpBuiltinsAssembler::AdvanceStringIndexFast(String, Smi, bool): Smi;
|
||||
|
||||
transitioning macro RegExpReplaceCallableNoExplicitCaptures(implicit context:
|
||||
Context)(
|
||||
matchesElements: FixedArray, matchesLength: intptr, string: String,
|
||||
|
@ -172,4 +172,9 @@ namespace regexp {
|
||||
|
||||
extern builtin
|
||||
StringIndexOf(implicit context: Context)(String, String, Smi): Smi;
|
||||
|
||||
extern macro
|
||||
RegExpBuiltinsAssembler::AdvanceStringIndexFast(String, Smi, bool): Smi;
|
||||
extern macro
|
||||
RegExpBuiltinsAssembler::AdvanceStringIndexSlow(String, Number, bool): Smi;
|
||||
}
|
||||
|
@ -6300,6 +6300,11 @@ TNode<BoolT> CodeStubAssembler::IsJSStringIterator(
|
||||
return HasInstanceType(object, JS_STRING_ITERATOR_TYPE);
|
||||
}
|
||||
|
||||
TNode<BoolT> CodeStubAssembler::IsJSRegExpStringIterator(
|
||||
SloppyTNode<HeapObject> object) {
|
||||
return HasInstanceType(object, JS_REGEXP_STRING_ITERATOR_TYPE);
|
||||
}
|
||||
|
||||
TNode<BoolT> CodeStubAssembler::IsMap(SloppyTNode<HeapObject> map) {
|
||||
return IsMetaMap(LoadMap(map));
|
||||
}
|
||||
|
@ -2455,6 +2455,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
TNode<BoolT> IsJSPromise(SloppyTNode<HeapObject> object);
|
||||
TNode<BoolT> IsJSProxy(SloppyTNode<HeapObject> object);
|
||||
TNode<BoolT> IsJSStringIterator(SloppyTNode<HeapObject> object);
|
||||
TNode<BoolT> IsJSRegExpStringIterator(SloppyTNode<HeapObject> object);
|
||||
TNode<BoolT> IsJSReceiverInstanceType(SloppyTNode<Int32T> instance_type);
|
||||
TNode<BoolT> IsJSReceiverMap(SloppyTNode<Map> map);
|
||||
TNode<BoolT> IsJSReceiver(SloppyTNode<HeapObject> object);
|
||||
|
Loading…
Reference in New Issue
Block a user