[builtins] Port RegExp MatchAll to Torque
Bug: v8:8976 Change-Id: Ibe20feb63b676f76b21dd8be7a9d1f3887af470a Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1816926 Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#63974}
This commit is contained in:
parent
628cc44a29
commit
74ade4a779
1
BUILD.gn
1
BUILD.gn
@ -1019,6 +1019,7 @@ torque_files = [
|
||||
"src/builtins/proxy.tq",
|
||||
"src/builtins/reflect.tq",
|
||||
"src/builtins/regexp-exec.tq",
|
||||
"src/builtins/regexp-match-all.tq",
|
||||
"src/builtins/regexp-match.tq",
|
||||
"src/builtins/regexp-replace.tq",
|
||||
"src/builtins/regexp-search.tq",
|
||||
|
@ -787,6 +787,8 @@ const PROXY_REVOCABLE_RESULT_MAP_INDEX: constexpr NativeContextSlot
|
||||
generates 'Context::PROXY_REVOCABLE_RESULT_MAP_INDEX';
|
||||
const REFLECT_APPLY_INDEX: constexpr NativeContextSlot
|
||||
generates 'Context::REFLECT_APPLY_INDEX';
|
||||
const REGEXP_FUNCTION_INDEX: constexpr NativeContextSlot
|
||||
generates 'Context::REGEXP_FUNCTION_INDEX';
|
||||
const REGEXP_LAST_MATCH_INFO_INDEX: constexpr NativeContextSlot
|
||||
generates 'Context::REGEXP_LAST_MATCH_INFO_INDEX';
|
||||
const INITIAL_STRING_ITERATOR_MAP_INDEX: constexpr NativeContextSlot
|
||||
|
@ -850,8 +850,6 @@ namespace internal {
|
||||
CPP(RegExpLeftContextGetter) \
|
||||
/* ES #sec-regexp.prototype.compile */ \
|
||||
TFJ(RegExpPrototypeCompile, 2, kReceiver, kPattern, kFlags) \
|
||||
/* https://tc39.github.io/proposal-string-matchall/ */ \
|
||||
TFJ(RegExpPrototypeMatchAll, 1, kReceiver, kString) \
|
||||
CPP(RegExpPrototypeToString) \
|
||||
CPP(RegExpRightContextGetter) \
|
||||
\
|
||||
|
@ -1824,128 +1824,11 @@ TNode<Object> RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
void RegExpMatchAllAssembler::Generate(TNode<Context> context,
|
||||
TNode<Context> native_context,
|
||||
TNode<Object> receiver,
|
||||
TNode<Object> maybe_string) {
|
||||
// 1. Let R be the this value.
|
||||
// 2. If Type(R) is not Object, throw a TypeError exception.
|
||||
ThrowIfNotJSReceiver(context, receiver,
|
||||
MessageTemplate::kIncompatibleMethodReceiver,
|
||||
"RegExp.prototype.@@matchAll");
|
||||
|
||||
// 3. Let S be ? ToString(O).
|
||||
TNode<String> string = ToString_Inline(context, maybe_string);
|
||||
|
||||
TVARIABLE(Object, var_matcher);
|
||||
TVARIABLE(BoolT, var_global);
|
||||
TVARIABLE(BoolT, var_unicode);
|
||||
Label create_iterator(this), if_fast_regexp(this),
|
||||
if_slow_regexp(this, Label::kDeferred);
|
||||
|
||||
// Strict, because following code uses the flags property.
|
||||
// TODO(jgruber): Handle slow flag accesses on the fast path and make this
|
||||
// permissive.
|
||||
BranchIfFastRegExp_Strict(context, CAST(receiver), &if_fast_regexp,
|
||||
&if_slow_regexp);
|
||||
|
||||
BIND(&if_fast_regexp);
|
||||
{
|
||||
TNode<JSRegExp> fast_regexp = CAST(receiver);
|
||||
TNode<Object> source =
|
||||
LoadObjectField(fast_regexp, JSRegExp::kSourceOffset);
|
||||
|
||||
// 4. Let C be ? SpeciesConstructor(R, %RegExp%).
|
||||
// 5. Let flags be ? ToString(? Get(R, "flags")).
|
||||
// 6. Let matcher be ? Construct(C, « R, flags »).
|
||||
TNode<String> flags = FlagsGetter(context, fast_regexp, true);
|
||||
var_matcher = RegExpCreate(context, native_context, source, flags);
|
||||
CSA_ASSERT(this,
|
||||
IsFastRegExpPermissive(context, CAST(var_matcher.value())));
|
||||
|
||||
// 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
|
||||
// 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
|
||||
FastStoreLastIndex(CAST(var_matcher.value()),
|
||||
FastLoadLastIndex(fast_regexp));
|
||||
|
||||
// 9. If flags contains "g", let global be true.
|
||||
// 10. Else, let global be false.
|
||||
var_global = FastFlagGetter(CAST(var_matcher.value()), JSRegExp::kGlobal);
|
||||
|
||||
// 11. If flags contains "u", let fullUnicode be true.
|
||||
// 12. Else, let fullUnicode be false.
|
||||
var_unicode = FastFlagGetter(CAST(var_matcher.value()), JSRegExp::kUnicode);
|
||||
Goto(&create_iterator);
|
||||
}
|
||||
|
||||
BIND(&if_slow_regexp);
|
||||
{
|
||||
// 4. Let C be ? SpeciesConstructor(R, %RegExp%).
|
||||
TNode<JSFunction> regexp_fun = CAST(
|
||||
LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX));
|
||||
TNode<JSReceiver> species_constructor =
|
||||
SpeciesConstructor(native_context, receiver, regexp_fun);
|
||||
|
||||
// 5. Let flags be ? ToString(? Get(R, "flags")).
|
||||
TNode<Object> flags =
|
||||
GetProperty(context, receiver, isolate()->factory()->flags_string());
|
||||
TNode<String> flags_string = ToString_Inline(context, flags);
|
||||
|
||||
// 6. Let matcher be ? Construct(C, « R, flags »).
|
||||
var_matcher =
|
||||
Construct(context, species_constructor, receiver, flags_string);
|
||||
|
||||
// 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
|
||||
TNode<Number> last_index =
|
||||
ToLength_Inline(context, SlowLoadLastIndex(context, receiver));
|
||||
|
||||
// 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
|
||||
SlowStoreLastIndex(context, var_matcher.value(), last_index);
|
||||
|
||||
// 9. If flags contains "g", let global be true.
|
||||
// 10. Else, let global be false.
|
||||
TNode<String> global_char_string = StringConstant("g");
|
||||
TNode<Smi> global_ix =
|
||||
CAST(CallBuiltin(Builtins::kStringIndexOf, context, flags_string,
|
||||
global_char_string, SmiZero()));
|
||||
var_global = SmiNotEqual(global_ix, SmiConstant(-1));
|
||||
|
||||
// 11. If flags contains "u", let fullUnicode be true.
|
||||
// 12. Else, let fullUnicode be false.
|
||||
TNode<String> unicode_char_string = StringConstant("u");
|
||||
TNode<Smi> unicode_ix =
|
||||
CAST(CallBuiltin(Builtins::kStringIndexOf, context, flags_string,
|
||||
unicode_char_string, SmiZero()));
|
||||
var_unicode = SmiNotEqual(unicode_ix, SmiConstant(-1));
|
||||
Goto(&create_iterator);
|
||||
}
|
||||
|
||||
BIND(&create_iterator);
|
||||
{
|
||||
{
|
||||
// UseCounter for matchAll with non-g RegExp.
|
||||
// https://crbug.com/v8/9551
|
||||
Label next(this);
|
||||
GotoIf(var_global.value(), &next);
|
||||
CallRuntime(Runtime::kIncrementUseCounter, context,
|
||||
SmiConstant(v8::Isolate::kRegExpMatchAllWithNonGlobalRegExp));
|
||||
Goto(&next);
|
||||
BIND(&next);
|
||||
}
|
||||
|
||||
// 13. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode).
|
||||
TNode<Object> iterator =
|
||||
CreateRegExpStringIterator(native_context, var_matcher.value(), string,
|
||||
var_global.value(), var_unicode.value());
|
||||
Return(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
// ES#sec-createregexpstringiterator
|
||||
// CreateRegExpStringIterator ( R, S, global, fullUnicode )
|
||||
TNode<Object> RegExpMatchAllAssembler::CreateRegExpStringIterator(
|
||||
TNode<Context> native_context, TNode<Object> regexp, TNode<String> string,
|
||||
TNode<BoolT> global, TNode<BoolT> full_unicode) {
|
||||
TNode<NativeContext> native_context, TNode<Object> regexp,
|
||||
TNode<String> string, TNode<BoolT> global, TNode<BoolT> full_unicode) {
|
||||
TNode<Map> map = CAST(LoadContextElement(
|
||||
native_context,
|
||||
Context::INITIAL_REGEXP_STRING_ITERATOR_PROTOTYPE_MAP_INDEX));
|
||||
@ -1985,16 +1868,6 @@ TNode<Object> RegExpMatchAllAssembler::CreateRegExpStringIterator(
|
||||
return iterator;
|
||||
}
|
||||
|
||||
// https://tc39.github.io/proposal-string-matchall/
|
||||
// RegExp.prototype [ @@matchAll ] ( string )
|
||||
TF_BUILTIN(RegExpPrototypeMatchAll, RegExpMatchAllAssembler) {
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<NativeContext> native_context = LoadNativeContext(context);
|
||||
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
|
||||
TNode<Object> maybe_string = CAST(Parameter(Descriptor::kString));
|
||||
Generate(context, native_context, receiver, maybe_string);
|
||||
}
|
||||
|
||||
// Generates the fast path for @@split. {regexp} is an unmodified, non-sticky
|
||||
// JSRegExp, {string} is a String, and {limit} is a Smi.
|
||||
TNode<JSArray> RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(
|
||||
|
@ -202,13 +202,11 @@ class RegExpMatchAllAssembler : public RegExpBuiltinsAssembler {
|
||||
explicit RegExpMatchAllAssembler(compiler::CodeAssemblerState* state)
|
||||
: RegExpBuiltinsAssembler(state) {}
|
||||
|
||||
TNode<Object> CreateRegExpStringIterator(TNode<Context> native_context,
|
||||
TNode<Object> CreateRegExpStringIterator(TNode<NativeContext> native_context,
|
||||
TNode<Object> regexp,
|
||||
TNode<String> string,
|
||||
TNode<BoolT> global,
|
||||
TNode<BoolT> full_unicode);
|
||||
void Generate(TNode<Context> context, TNode<Context> native_context,
|
||||
TNode<Object> receiver, TNode<Object> maybe_string);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -1550,8 +1550,8 @@ TF_BUILTIN(StringPrototypeMatchAll, StringBuiltinsAssembler) {
|
||||
// maybe_regexp is a fast regexp and receiver is a string.
|
||||
TNode<String> s = CAST(receiver);
|
||||
|
||||
RegExpMatchAllAssembler regexp_asm(state());
|
||||
regexp_asm.Generate(context, native_context, maybe_regexp, s);
|
||||
Return(
|
||||
RegExpPrototypeMatchAllImpl(context, native_context, maybe_regexp, s));
|
||||
};
|
||||
auto if_generic_call = [=](Node* fn) {
|
||||
Callable call_callable = CodeFactory::Call(isolate());
|
||||
|
120
src/builtins/regexp-match-all.tq
Normal file
120
src/builtins/regexp-match-all.tq
Normal file
@ -0,0 +1,120 @@
|
||||
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include 'src/builtins/builtins-regexp-gen.h'
|
||||
|
||||
namespace regexp {
|
||||
|
||||
extern transitioning macro RegExpBuiltinsAssembler::RegExpCreate(
|
||||
implicit context: Context)(Context, Object, String): Object;
|
||||
|
||||
extern transitioning macro
|
||||
RegExpMatchAllAssembler::CreateRegExpStringIterator(
|
||||
NativeContext, Object, String, bool, bool): JSAny;
|
||||
|
||||
const kRegExpMatchAllWithNonGlobalRegExp: constexpr int31
|
||||
generates 'v8::Isolate::kRegExpMatchAllWithNonGlobalRegExp';
|
||||
|
||||
@export
|
||||
transitioning macro RegExpPrototypeMatchAllImpl(implicit context: Context)(
|
||||
nativeContext: NativeContext, receiver: JSAny, string: JSAny): JSAny {
|
||||
// 1. Let R be the this value.
|
||||
// 2. If Type(R) is not Object, throw a TypeError exception.
|
||||
ThrowIfNotJSReceiver(
|
||||
receiver, kIncompatibleMethodReceiver, 'RegExp.prototype.@@matchAll');
|
||||
const receiver = UnsafeCast<JSReceiver>(receiver);
|
||||
|
||||
// 3. Let S be ? ToString(O).
|
||||
const string: String = ToString_Inline(context, string);
|
||||
|
||||
let matcher: Object;
|
||||
let global: bool;
|
||||
let unicode: bool;
|
||||
|
||||
// 'FastJSRegExp' uses the strict fast path check because following code
|
||||
// uses the flags property.
|
||||
// TODO(jgruber): Handle slow flag accesses on the fast path and make this
|
||||
// permissive.
|
||||
typeswitch (receiver) {
|
||||
case (fastRegExp: FastJSRegExp): {
|
||||
const source = fastRegExp.source;
|
||||
|
||||
// 4. Let C be ? SpeciesConstructor(R, %RegExp%).
|
||||
// 5. Let flags be ? ToString(? Get(R, "flags")).
|
||||
// 6. Let matcher be ? Construct(C, « R, flags »).
|
||||
const flags: String = FastFlagsGetter(fastRegExp);
|
||||
matcher = RegExpCreate(nativeContext, source, flags);
|
||||
const matcherRegExp = UnsafeCast<JSRegExp>(matcher);
|
||||
assert(IsFastRegExpPermissive(matcherRegExp));
|
||||
|
||||
// 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
|
||||
// 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
|
||||
const fastRegExp = UnsafeCast<FastJSRegExp>(receiver);
|
||||
FastStoreLastIndex(matcherRegExp, fastRegExp.lastIndex);
|
||||
|
||||
// 9. If flags contains "g", let global be true.
|
||||
// 10. Else, let global be false.
|
||||
global = FastFlagGetter(matcherRegExp, kGlobal);
|
||||
|
||||
// 11. If flags contains "u", let fullUnicode be true.
|
||||
// 12. Else, let fullUnicode be false.
|
||||
unicode = FastFlagGetter(matcherRegExp, kUnicode);
|
||||
}
|
||||
case (Object): {
|
||||
// 4. Let C be ? SpeciesConstructor(R, %RegExp%).
|
||||
const regexpFun =
|
||||
UnsafeCast<JSFunction>(nativeContext[REGEXP_FUNCTION_INDEX]);
|
||||
const speciesConstructor =
|
||||
UnsafeCast<Constructor>(SpeciesConstructor(receiver, regexpFun));
|
||||
|
||||
// 5. Let flags be ? ToString(? Get(R, "flags")).
|
||||
const flags = GetProperty(receiver, 'flags');
|
||||
const flagsString = ToString_Inline(context, flags);
|
||||
|
||||
// 6. Let matcher be ? Construct(C, « R, flags »).
|
||||
matcher = Construct(speciesConstructor, receiver, flagsString);
|
||||
|
||||
// 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
|
||||
const lastIndex: Number =
|
||||
ToLength_Inline(context, SlowLoadLastIndex(receiver));
|
||||
|
||||
// 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
|
||||
SlowStoreLastIndex(UnsafeCast<JSReceiver>(matcher), lastIndex);
|
||||
|
||||
// 9. If flags contains "g", let global be true.
|
||||
// 10. Else, let global be false.
|
||||
const globalCharString: String = StringConstant('g');
|
||||
const globalIndex: Smi =
|
||||
StringIndexOf(flagsString, globalCharString, 0);
|
||||
global = globalIndex != -1;
|
||||
|
||||
// 11. If flags contains "u", let fullUnicode be true.
|
||||
// 12. Else, let fullUnicode be false.
|
||||
const unicodeCharString = StringConstant('u');
|
||||
const unicodeIndex: Smi =
|
||||
StringIndexOf(flagsString, unicodeCharString, 0);
|
||||
unicode = unicodeIndex != -1;
|
||||
}
|
||||
}
|
||||
|
||||
// UseCounter for matchAll with non-g RegExp.
|
||||
// https://crbug.com/v8/9551
|
||||
if (!global) {
|
||||
IncrementUseCounter(
|
||||
context, SmiConstant(kRegExpMatchAllWithNonGlobalRegExp));
|
||||
}
|
||||
|
||||
// 13. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode).
|
||||
return CreateRegExpStringIterator(
|
||||
nativeContext, matcher, string, global, unicode);
|
||||
}
|
||||
|
||||
// https://tc39.github.io/proposal-string-matchall/
|
||||
// RegExp.prototype [ @@matchAll ] ( string )
|
||||
transitioning javascript builtin RegExpPrototypeMatchAll(
|
||||
js-implicit context: Context, receiver: JSAny)(string: JSAny): JSAny {
|
||||
const nativeContext: NativeContext = LoadNativeContext(context);
|
||||
return RegExpPrototypeMatchAllImpl(nativeContext, receiver, string);
|
||||
}
|
||||
}
|
@ -6,8 +6,6 @@
|
||||
|
||||
namespace regexp {
|
||||
|
||||
extern builtin
|
||||
StringIndexOf(implicit context: Context)(String, String, Smi): Smi;
|
||||
extern builtin
|
||||
SubString(implicit context: Context)(String, Smi, Smi): String;
|
||||
|
||||
|
@ -6,9 +6,6 @@
|
||||
|
||||
namespace regexp {
|
||||
|
||||
extern macro RegExpBuiltinsAssembler::FastLoadLastIndex(JSRegExp): Smi;
|
||||
extern macro RegExpBuiltinsAssembler::FastStoreLastIndex(JSRegExp, Smi): void;
|
||||
|
||||
transitioning macro
|
||||
RegExpPrototypeSearchBodyFast(implicit context: Context)(
|
||||
regexp: JSRegExp, string: String): JSAny {
|
||||
@ -41,10 +38,6 @@ namespace regexp {
|
||||
}
|
||||
}
|
||||
|
||||
extern transitioning macro RegExpBuiltinsAssembler::SlowLoadLastIndex(
|
||||
implicit context: Context)(JSAny): JSAny;
|
||||
extern transitioning macro RegExpBuiltinsAssembler::SlowStoreLastIndex(
|
||||
implicit context: Context)(JSAny, JSAny): void;
|
||||
extern macro RegExpBuiltinsAssembler::BranchIfFastRegExpResult(
|
||||
implicit context: Context)(Object): never labels IsUnmodified,
|
||||
IsModified;
|
||||
|
@ -161,4 +161,15 @@ namespace regexp {
|
||||
otherwise return SlowFlagsGetter(receiver);
|
||||
return FastFlagsGetter(fastRegexp);
|
||||
}
|
||||
|
||||
extern transitioning macro RegExpBuiltinsAssembler::SlowLoadLastIndex(
|
||||
implicit context: Context)(JSAny): JSAny;
|
||||
extern transitioning macro RegExpBuiltinsAssembler::SlowStoreLastIndex(
|
||||
implicit context: Context)(JSAny, JSAny): void;
|
||||
|
||||
extern macro RegExpBuiltinsAssembler::FastLoadLastIndex(JSRegExp): Smi;
|
||||
extern macro RegExpBuiltinsAssembler::FastStoreLastIndex(JSRegExp, Smi): void;
|
||||
|
||||
extern builtin
|
||||
StringIndexOf(implicit context: Context)(String, String, Smi): Smi;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user