[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:
Z Nguyen-Huu 2019-09-25 12:59:04 -07:00 committed by Commit Bot
parent 628cc44a29
commit 74ade4a779
10 changed files with 139 additions and 145 deletions

View File

@ -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",

View File

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

View File

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

View File

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

View File

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

View File

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

View 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);
}
}

View File

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

View File

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

View File

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