Commit abfbe768 authored by Z Nguyen-Huu's avatar Z Nguyen-Huu Committed by Commit Bot

[builtins] Port some RegExp functions to Torque

RegExpPrototypeExecBodyWithoutResult, LoadLastIndex, StoreLastIndex.

Bug: v8:8976
Change-Id: I205d6a02c5a97e8c7e484bea3c9441b433197344
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1913330
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64967}
parent 2475c91b
......@@ -144,13 +144,6 @@ TNode<Object> RegExpBuiltinsAssembler::SlowLoadLastIndex(TNode<Context> context,
return GetProperty(context, regexp, isolate()->factory()->lastIndex_string());
}
TNode<Object> RegExpBuiltinsAssembler::LoadLastIndex(TNode<Context> context,
TNode<Object> regexp,
bool is_fastpath) {
return is_fastpath ? FastLoadLastIndex(CAST(regexp))
: SlowLoadLastIndex(context, regexp);
}
// The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified
// JSRegExp instance.
void RegExpBuiltinsAssembler::FastStoreLastIndex(TNode<JSRegExp> regexp,
......@@ -168,17 +161,6 @@ void RegExpBuiltinsAssembler::SlowStoreLastIndex(SloppyTNode<Context> context,
SetPropertyStrict(context, regexp, name, value);
}
void RegExpBuiltinsAssembler::StoreLastIndex(TNode<Context> context,
TNode<Object> regexp,
TNode<Number> value,
bool is_fastpath) {
if (is_fastpath) {
FastStoreLastIndex(CAST(regexp), CAST(value));
} else {
SlowStoreLastIndex(context, regexp, value);
}
}
TNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
TNode<Context> context, TNode<JSReceiver> maybe_regexp,
TNode<RegExpMatchInfo> match_info, TNode<String> string) {
......@@ -690,132 +672,6 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
return var_result.value();
}
// ES#sec-regexp.prototype.exec
// RegExp.prototype.exec ( string )
// Implements the core of RegExp.prototype.exec but without actually
// constructing the JSRegExpResult. Returns a fixed array containing match
// indices as returned by RegExpExecStub on successful match, and jumps to
// if_didnotmatch otherwise.
TNode<RegExpMatchInfo>
RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
TNode<Context> context, TNode<JSReceiver> maybe_regexp,
TNode<String> string, const bool is_fastpath, Label* if_didnotmatch) {
if (!is_fastpath) {
CallRuntime(Runtime::kIncrementUseCounter, context,
SmiConstant(v8::Isolate::kRegExpExecCalledOnSlowRegExp));
ThrowIfNotInstanceType(context, maybe_regexp, JS_REG_EXP_TYPE,
"RegExp.prototype.exec");
}
TNode<JSRegExp> regexp = CAST(maybe_regexp);
TVARIABLE(HeapObject, var_result);
Label out(this);
// Load lastIndex.
TVARIABLE(Number, var_lastindex);
{
TNode<Object> regexp_lastindex =
LoadLastIndex(context, regexp, is_fastpath);
if (is_fastpath) {
// ToLength on a positive smi is a nop and can be skipped.
CSA_ASSERT(this, TaggedIsPositiveSmi(regexp_lastindex));
var_lastindex = CAST(regexp_lastindex);
} else {
// Omit ToLength if lastindex is a non-negative smi.
Label call_tolength(this, Label::kDeferred), is_smi(this), next(this);
Branch(TaggedIsPositiveSmi(regexp_lastindex), &is_smi, &call_tolength);
BIND(&call_tolength);
var_lastindex = ToLength_Inline(context, regexp_lastindex);
Goto(&next);
BIND(&is_smi);
var_lastindex = CAST(regexp_lastindex);
Goto(&next);
BIND(&next);
}
}
// Check whether the regexp is global or sticky, which determines whether we
// update last index later on.
TNode<Smi> flags = CAST(LoadObjectField(regexp, JSRegExp::kFlagsOffset));
TNode<IntPtrT> is_global_or_sticky = WordAnd(
SmiUntag(flags), IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky));
TNode<BoolT> should_update_last_index =
WordNotEqual(is_global_or_sticky, IntPtrZero());
// Grab and possibly update last index.
Label run_exec(this);
{
Label if_doupdate(this), if_dontupdate(this);
Branch(should_update_last_index, &if_doupdate, &if_dontupdate);
BIND(&if_doupdate);
{
Label if_isoob(this, Label::kDeferred);
GotoIfNot(TaggedIsSmi(var_lastindex.value()), &if_isoob);
TNode<Smi> string_length = LoadStringLengthAsSmi(string);
GotoIfNot(SmiLessThanOrEqual(CAST(var_lastindex.value()), string_length),
&if_isoob);
Goto(&run_exec);
BIND(&if_isoob);
{
StoreLastIndex(context, regexp, SmiZero(), is_fastpath);
Goto(if_didnotmatch);
}
}
BIND(&if_dontupdate);
{
var_lastindex = SmiZero();
Goto(&run_exec);
}
}
TNode<HeapObject> match_indices;
Label successful_match(this);
BIND(&run_exec);
{
// Get last match info from the context.
TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<RegExpMatchInfo> last_match_info = CAST(LoadContextElement(
native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX));
// Call the exec stub.
match_indices = RegExpExecInternal(context, regexp, string,
var_lastindex.value(), last_match_info);
var_result = match_indices;
// {match_indices} is either null or the RegExpMatchInfo array.
// Return early if exec failed, possibly updating last index.
GotoIfNot(IsNull(match_indices), &successful_match);
GotoIfNot(should_update_last_index, if_didnotmatch);
StoreLastIndex(context, regexp, SmiZero(), is_fastpath);
Goto(if_didnotmatch);
}
BIND(&successful_match);
{
GotoIfNot(should_update_last_index, &out);
// Update the new last index from {match_indices}.
TNode<Smi> new_lastindex = CAST(UnsafeLoadFixedArrayElement(
CAST(match_indices), RegExpMatchInfo::kFirstCaptureIndex + 1));
StoreLastIndex(context, regexp, new_lastindex, is_fastpath);
Goto(&out);
}
BIND(&out);
return CAST(var_result.value());
}
TNode<BoolT> RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(
TNode<Context> context, TNode<Object> object, TNode<Map> map) {
Label out(this);
......@@ -1550,8 +1406,8 @@ TNode<Object> RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(
// On the fast path, grab the matching string from the raw match index
// array.
TNode<RegExpMatchInfo> match_indices =
RegExpPrototypeExecBodyWithoutResult(context, CAST(regexp), string,
true, &if_didnotmatch);
RegExpPrototypeExecBodyWithoutResultFast(context, CAST(regexp),
string, &if_didnotmatch);
Label dosubstring(this), donotsubstring(this);
Branch(var_atom.value(), &donotsubstring, &dosubstring);
......
......@@ -35,15 +35,11 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
return CAST(FastLoadLastIndexBeforeSmiCheck(regexp));
}
TNode<Object> SlowLoadLastIndex(TNode<Context> context, TNode<Object> regexp);
TNode<Object> LoadLastIndex(TNode<Context> context, TNode<Object> regexp,
bool is_fastpath);
void FastStoreLastIndex(TNode<JSRegExp> regexp, TNode<Smi> value);
void SlowStoreLastIndex(SloppyTNode<Context> context,
SloppyTNode<Object> regexp,
SloppyTNode<Object> value);
void StoreLastIndex(TNode<Context> context, TNode<Object> regexp,
TNode<Number> value, bool is_fastpath);
// Loads {var_string_start} and {var_string_end} with the corresponding
// offsets into the given {string_data}.
......@@ -65,10 +61,6 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
TNode<Context> context, TNode<JSReceiver> maybe_regexp,
TNode<RegExpMatchInfo> match_info, TNode<String> string);
TNode<RegExpMatchInfo> RegExpPrototypeExecBodyWithoutResult(
TNode<Context> context, TNode<JSReceiver> maybe_regexp,
TNode<String> string, const bool is_fastpath, Label* if_didnotmatch);
// Fast path check logic.
//
// Are you afraid? If not, you should be.
......
......@@ -77,8 +77,6 @@ extern macro HeapObjectToHeapNumber(HeapObject): HeapNumber
extern macro HeapObjectToSloppyArgumentsElements(HeapObject):
SloppyArgumentsElements
labels CastError;
extern macro HeapObjectToRegExpMatchInfo(HeapObject):
RegExpMatchInfo labels CastError;
extern macro TaggedToNumber(Object): Number
labels CastError;
......@@ -685,3 +683,9 @@ Cast<JSPromise>(o: HeapObject): JSPromise labels CastError {
if (IsJSPromise(o)) return %RawDownCast<JSPromise>(o);
goto CastError;
}
UnsafeCast<RegExpMatchInfo>(implicit context: Context)(o: Object):
RegExpMatchInfo {
assert(Is<FixedArray>(o));
return %RawDownCast<RegExpMatchInfo>(o);
}
......@@ -55,11 +55,87 @@ namespace regexp {
implicit context: Context)(JSReceiver, RegExpMatchInfo, String):
JSRegExpResult;
extern transitioning macro
RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
implicit context: Context)(JSReceiver, String, constexpr bool):
RegExpMatchInfo labels IfDidNotMatch;
const kGlobalOrSticky: constexpr int31
generates 'JSRegExp::kGlobal | JSRegExp::kSticky';
extern macro RegExpBuiltinsAssembler::RegExpExecInternal(
implicit context: Context)(JSRegExp, String, Number, RegExpMatchInfo):
HeapObject;
// ES#sec-regexp.prototype.exec
// RegExp.prototype.exec ( string )
// Implements the core of RegExp.prototype.exec but without actually
// constructing the JSRegExpResult. Returns a fixed array containing match
// indices as returned by RegExpExecStub on successful match, and jumps to
// IfDidNotMatch otherwise.
transitioning macro RegExpPrototypeExecBodyWithoutResult(implicit context:
Context)(
maybeRegexp: JSReceiver, string: String,
isFastPath: constexpr bool): RegExpMatchInfo labels IfDidNotMatch {
if (!isFastPath) {
IncrementUseCounter(context, SmiConstant(kRegExpExecCalledOnSlowRegExp));
if (!Is<JSRegExp>(maybeRegexp)) {
ThrowTypeError(
kIncompatibleMethodReceiver, 'RegExp.prototype.exec', maybeRegexp);
}
}
const regexp = UnsafeCast<JSRegExp>(maybeRegexp);
let lastIndex: Number;
const regexpLastIndex = LoadLastIndex(regexp, isFastPath);
if (isFastPath) {
// ToLength on a positive smi is a nop and can be skipped.
assert(TaggedIsPositiveSmi(regexpLastIndex));
lastIndex = UnsafeCast<Number>(regexpLastIndex);
} else {
// Omit ToLength if lastindex is a non-negative smi.
lastIndex = TaggedIsPositiveSmi(regexpLastIndex) ?
UnsafeCast<Number>(regexpLastIndex) :
ToLength_Inline(regexpLastIndex);
}
// Check whether the regexp is global or sticky, which determines whether we
// update last index later on.
const flags = UnsafeCast<Smi>(regexp.flags);
const isGlobalOrSticky: intptr =
SmiUntag(flags) & IntPtrConstant(kGlobalOrSticky);
const shouldUpdateLastIndex: bool = isGlobalOrSticky != 0;
// Grab and possibly update last index.
if (shouldUpdateLastIndex) {
if (!TaggedIsSmi(lastIndex) || (lastIndex > string.length_smi)) {
StoreLastIndex(regexp, SmiConstant(0), isFastPath);
goto IfDidNotMatch;
}
} else {
lastIndex = SmiConstant(0);
}
const lastMatchInfo: RegExpMatchInfo = GetRegExpLastMatchInfo();
const matchIndices =
RegExpExecInternal(regexp, string, lastIndex, lastMatchInfo);
// {match_indices} is either null or the RegExpMatchInfo array.
// Return early if exec failed, possibly updating last index.
if (matchIndices != Null) {
const matchIndicesRegExpMatchInfo =
UnsafeCast<RegExpMatchInfo>(matchIndices);
if (shouldUpdateLastIndex) {
// Update the new last index from {match_indices}.
const newLastIndex: Smi =
matchIndicesRegExpMatchInfo.GetEndOfCapture(0);
StoreLastIndex(regexp, newLastIndex, isFastPath);
}
return matchIndicesRegExpMatchInfo;
}
if (shouldUpdateLastIndex) {
StoreLastIndex(regexp, SmiConstant(0), isFastPath);
}
goto IfDidNotMatch;
}
@export
transitioning macro RegExpPrototypeExecBodyWithoutResultFast(
implicit context: Context)(regexp: JSRegExp, string: String):
RegExpMatchInfo labels IfDidNotMatch {
......@@ -224,6 +300,23 @@ namespace regexp {
extern macro RegExpBuiltinsAssembler::FastLoadLastIndex(JSRegExp): Smi;
extern macro RegExpBuiltinsAssembler::FastStoreLastIndex(JSRegExp, Smi): void;
@export
transitioning macro LoadLastIndex(implicit context: Context)(
regexp: JSAny, isFastPath: constexpr bool): JSAny {
return isFastPath ? FastLoadLastIndex(UnsafeCast<JSRegExp>(regexp)) :
SlowLoadLastIndex(regexp);
}
@export
transitioning macro StoreLastIndex(implicit context: Context)(
regexp: JSAny, value: Number, isFastPath: constexpr bool): void {
if (isFastPath) {
FastStoreLastIndex(UnsafeCast<JSRegExp>(regexp), UnsafeCast<Smi>(value));
} else {
SlowStoreLastIndex(regexp, value);
}
}
extern builtin
StringIndexOf(implicit context: Context)(String, String, Smi): Smi;
......@@ -240,6 +333,8 @@ namespace regexp {
generates 'v8::Isolate::kRegExpMatchIsFalseishOnJSRegExp';
const kRegExpPrototypeSourceGetter: constexpr UseCounterFeature
generates 'v8::Isolate::kRegExpPrototypeSourceGetter';
const kRegExpExecCalledOnSlowRegExp: constexpr UseCounterFeature
generates 'v8::Isolate::kRegExpExecCalledOnSlowRegExp';
// ES#sec-isregexp IsRegExp ( argument )
@export
......
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