Commit 0c670bf6 authored by peterwmwong's avatar peterwmwong Committed by Commit Bot

[builtins] Port RegExpReplace TFS to Torque.

Bug: v8:8976
Change-Id: Ic903d353f05d0c16d4b735bbb1307ff6403fa72e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1559211Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Cr-Commit-Position: refs/heads/master@{#60782}
parent e88bd776
......@@ -16,6 +16,7 @@
#include 'src/objects/js-regexp-string-iterator.h'
#include 'src/objects/module.h'
#include 'src/objects/stack-frame-info.h'
#include 'src/builtins/builtins-regexp-gen.h'
type void;
type never;
......@@ -886,6 +887,15 @@ extern class JSRegExp extends JSObject {
flags: Smi | Undefined;
}
// Note: Although a condition for a FastJSRegExp is having a positive smi
// lastIndex (see RegExpBuiltinsAssembler::BranchIfFastRegExp), it is possible
// for this to change without transitioning the transient type. As a precaution,
// validate the lastIndex is positive smi when used in fast paths.
transient type FastJSRegExp extends JSRegExp;
extern operator '.global' macro
RegExpBuiltinsAssembler::FastFlagGetterGlobal(FastJSRegExp): bool;
extern class JSRegExpResult extends JSArray {
index: Object;
input: Object;
......@@ -1412,6 +1422,12 @@ Cast<JSArgumentsObjectWithLength>(implicit context: Context)(o: HeapObject):
}
}
Cast<FastJSRegExp>(implicit context: Context)(o: HeapObject): FastJSRegExp
labels CastError {
if (regexp::BranchIfFastRegExp(o)) return %RawDownCast<FastJSRegExp>(o);
goto CastError;
}
Cast<FastJSArray>(implicit context: Context)(o: HeapObject): FastJSArray
labels CastError {
const map: Map = o.map;
......@@ -1510,6 +1526,7 @@ extern macro Int32Constant(constexpr ElementsKind): ElementsKind;
extern macro IntPtrConstant(constexpr NativeContextSlot): NativeContextSlot;
extern macro IntPtrConstant(constexpr ContextSlot): ContextSlot;
extern macro IntPtrConstant(constexpr intptr): intptr;
extern macro SingleCharacterStringConstant(constexpr string): String;
extern macro BitcastWordToTaggedSigned(intptr): Smi;
extern macro BitcastWordToTaggedSigned(uintptr): Smi;
......
......@@ -942,7 +942,6 @@ namespace internal {
TFS(RegExpExecInternal, kRegExp, kString, kLastIndex, kMatchInfo) \
TFS(RegExpMatchFast, kReceiver, kPattern) \
TFS(RegExpPrototypeExecSlow, kReceiver, kString) \
TFS(RegExpReplace, kRegExp, kString, kReplaceValue) \
TFS(RegExpSearchFast, kReceiver, kPattern) \
TFS(RegExpSplit, kRegExp, kString, kLimit) \
\
......
......@@ -2971,77 +2971,6 @@ Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath(
return var_result.value();
}
// Helper that skips a few initial checks.
TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) {
TNode<JSRegExp> regexp = CAST(Parameter(Descriptor::kRegExp));
TNode<String> string = CAST(Parameter(Descriptor::kString));
TNode<Object> replace_value = CAST(Parameter(Descriptor::kReplaceValue));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
CSA_ASSERT(this, IsFastRegExp(context, regexp));
Label checkreplacestring(this), if_iscallable(this);
// 2. Is {replace_value} callable?
GotoIf(TaggedIsSmi(replace_value), &checkreplacestring);
Branch(IsCallableMap(LoadMap(CAST(replace_value))), &if_iscallable,
&checkreplacestring);
// 3. Does ToString({replace_value}) contain '$'?
BIND(&checkreplacestring);
{
Label runtime(this, Label::kDeferred);
TNode<String> replace_string = ToString_Inline(context, replace_value);
// ToString(replaceValue) could potentially change the shape of the RegExp
// object. Recheck that we are still on the fast path and bail to runtime
// otherwise.
{
Label next(this);
BranchIfFastRegExp(context, regexp, &next, &runtime);
BIND(&next);
}
TNode<String> dollar_string = HeapConstant(
isolate()->factory()->LookupSingleCharacterStringFromCode('$'));
TNode<Smi> dollar_ix =
CAST(CallBuiltin(Builtins::kStringIndexOf, context, replace_string,
dollar_string, SmiZero()));
GotoIfNot(SmiEqual(dollar_ix, SmiConstant(-1)), &runtime);
Return(
ReplaceSimpleStringFastPath(context, regexp, string, replace_string));
BIND(&runtime);
{
// Pass in replace_string (instead of replace_value) to avoid calling
// ToString(replace_value) twice.
Return(CallRuntime(Runtime::kRegExpReplaceRT, context, regexp, string,
replace_string));
}
}
// {regexp} is unmodified and {replace_value} is callable.
BIND(&if_iscallable);
{
Node* const replace_fn = replace_value;
// Check if the {regexp} is global.
Label if_isglobal(this), if_isnotglobal(this);
Node* const is_global = FastFlagGetter(regexp, JSRegExp::kGlobal);
Branch(is_global, &if_isglobal, &if_isnotglobal);
BIND(&if_isglobal);
Return(ReplaceGlobalCallableFastPath(context, regexp, string, replace_fn));
BIND(&if_isnotglobal);
Return(CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction,
context, string, regexp, replace_fn));
}
}
class RegExpStringIteratorAssembler : public RegExpBuiltinsAssembler {
public:
explicit RegExpStringIteratorAssembler(compiler::CodeAssemblerState* state)
......
......@@ -105,6 +105,9 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
Node* FlagsGetter(Node* const context, Node* const regexp, bool is_fastpath);
TNode<Int32T> FastFlagGetter(TNode<JSRegExp> regexp, JSRegExp::Flag flag);
TNode<BoolT> FastFlagGetterGlobal(TNode<JSRegExp> regexp) {
return ReinterpretCast<BoolT>(FastFlagGetter(regexp, JSRegExp::kGlobal));
}
TNode<Int32T> SlowFlagGetter(TNode<Context> context, TNode<Object> regexp,
JSRegExp::Flag flag);
TNode<Int32T> FlagGetter(TNode<Context> context, TNode<Object> regexp,
......
......@@ -2,12 +2,61 @@
// 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_replace {
extern transitioning builtin
RegExpReplace(implicit context: Context)(JSRegExp, String, Object): Object;
extern builtin
StringIndexOf(implicit context: Context)(String, String, Smi): Smi;
extern transitioning macro
RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath(
implicit context: Context)(JSRegExp, String, String): String;
extern transitioning macro
RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath(
implicit context: Context)(JSRegExp, String, Callable): String;
extern transitioning runtime
RegExpReplaceRT(Context, JSReceiver, String, Object): String;
extern transitioning runtime
StringReplaceNonGlobalRegExpWithFunction(implicit context: Context)(
String, JSRegExp, Callable): String;
transitioning builtin RegExpReplace(implicit context: Context)(
regexp: FastJSRegExp, string: String, replaceValue: Object): String {
// TODO(pwong): Remove assert when all callers (StringPrototypeReplace) are
// from Torque.
assert(Is<FastJSRegExp>(regexp));
// 2. Is {replace_value} callable?
typeswitch (replaceValue) {
case (replaceFn: Callable): {
return regexp.global ?
ReplaceGlobalCallableFastPath(regexp, string, replaceFn) :
StringReplaceNonGlobalRegExpWithFunction(string, regexp, replaceFn);
}
case (Object): {
const stableRegexp: JSRegExp = regexp;
const replaceString: String = ToString_Inline(context, replaceValue);
try {
// ToString(replaceValue) could potentially change the shape of the
// RegExp object. Recheck that we are still on the fast path and bail
// to runtime otherwise.
const fastRegexp = Cast<FastJSRegExp>(stableRegexp) otherwise Runtime;
if (StringIndexOf(
replaceString, SingleCharacterStringConstant('$'), 0) != -1) {
goto Runtime;
}
return ReplaceSimpleStringFastPath(fastRegexp, string, replaceString);
}
label Runtime deferred {
return RegExpReplaceRT(context, stableRegexp, string, replaceString);
}
}
}
}
transitioning javascript builtin RegExpPrototypeReplace(
context: Context, receiver: Object, ...arguments): Object {
......@@ -43,9 +92,11 @@ namespace regexp_replace {
const s = ToString_Inline(context, string);
// Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
if (regexp::BranchIfFastRegExp(context, rx)) {
return RegExpReplace(UnsafeCast<JSRegExp>(rx), s, replaceValue);
} else {
try {
const fastRx: FastJSRegExp = Cast<FastJSRegExp>(rx) otherwise Runtime;
return RegExpReplace(fastRx, s, replaceValue);
}
label Runtime deferred {
return RegExpReplaceRT(context, rx, s, replaceValue);
}
}
......
......@@ -6,7 +6,8 @@
namespace regexp {
extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp(Context, Object):
never labels IsFast, IsSlow;
extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp(
implicit context: Context)(HeapObject): never labels IsFast,
IsSlow;
}
......@@ -731,6 +731,13 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
Smi::FromInt(false_value));
}
TNode<String> SingleCharacterStringConstant(char const* single_char) {
DCHECK_EQ(strlen(single_char), 1);
return HeapConstant(
isolate()->factory()->LookupSingleCharacterStringFromCode(
single_char[0]));
}
TNode<Int32T> TruncateIntPtrToInt32(SloppyTNode<IntPtrT> value);
// Check a value for smi-ness
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment