[regexp] Stricter asserts in RegExpPrototypeExecBodyWithoutResult
Previously the fast path only asserted the correct instance types; but when reading lastIndex we additionally rely on a specific object shape. This is checked by HasInitialRegExpMap(). Bug: chromium:1024758 Change-Id: I0b401ffb246dd47153caf798446d8d41bc84bc8e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1924354 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Auto-Submit: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Sigurd Schneider <sigurds@chromium.org> Cr-Commit-Position: refs/heads/master@{#65071}
This commit is contained in:
parent
3c98a2a36a
commit
b5bdf0a8f4
@ -702,51 +702,6 @@ TNode<BoolT> RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
// We also return true if exec is undefined (and hence per spec)
|
||||
// the original {exec} will be used.
|
||||
TNode<BoolT> RegExpBuiltinsAssembler::IsFastRegExpWithOriginalExec(
|
||||
TNode<Context> context, TNode<JSRegExp> object) {
|
||||
CSA_ASSERT(this, TaggedIsNotSmi(object));
|
||||
Label out(this);
|
||||
Label check_last_index(this);
|
||||
TVARIABLE(BoolT, var_result);
|
||||
|
||||
#ifdef V8_ENABLE_FORCE_SLOW_PATH
|
||||
var_result = BoolConstant(false);
|
||||
GotoIfForceSlowPath(&out);
|
||||
#endif
|
||||
|
||||
TNode<BoolT> is_regexp = HasInstanceType(object, JS_REG_EXP_TYPE);
|
||||
|
||||
var_result = is_regexp;
|
||||
GotoIfNot(is_regexp, &out);
|
||||
|
||||
TNode<NativeContext> native_context = LoadNativeContext(context);
|
||||
TNode<Object> original_exec =
|
||||
LoadContextElement(native_context, Context::REGEXP_EXEC_FUNCTION_INDEX);
|
||||
|
||||
TNode<Object> regexp_exec =
|
||||
GetProperty(context, object, isolate()->factory()->exec_string());
|
||||
|
||||
TNode<BoolT> has_initialexec = TaggedEqual(regexp_exec, original_exec);
|
||||
var_result = has_initialexec;
|
||||
GotoIf(has_initialexec, &check_last_index);
|
||||
TNode<BoolT> is_undefined = IsUndefined(regexp_exec);
|
||||
var_result = is_undefined;
|
||||
GotoIfNot(is_undefined, &out);
|
||||
Goto(&check_last_index);
|
||||
|
||||
BIND(&check_last_index);
|
||||
// The smi check is required to omit ToLength(lastIndex) calls with possible
|
||||
// user-code execution on the fast path.
|
||||
TNode<Object> last_index = FastLoadLastIndexBeforeSmiCheck(object);
|
||||
var_result = TaggedIsPositiveSmi(last_index);
|
||||
Goto(&out);
|
||||
|
||||
BIND(&out);
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
TNode<BoolT> RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(
|
||||
TNode<Context> context, TNode<Object> object) {
|
||||
CSA_ASSERT(this, TaggedIsNotSmi(object));
|
||||
|
@ -115,10 +115,6 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
|
||||
TNode<BoolT> IsFastRegExpNoPrototype(TNode<Context> context,
|
||||
TNode<Object> object, TNode<Map> map);
|
||||
|
||||
// For debugging only. Uses a slow GetProperty call to fetch object.exec.
|
||||
TNode<BoolT> IsFastRegExpWithOriginalExec(TNode<Context> context,
|
||||
TNode<JSRegExp> object);
|
||||
|
||||
void BranchIfFastRegExpResult(const TNode<Context> context,
|
||||
const TNode<Object> object,
|
||||
Label* if_isunmodified, Label* if_ismodified);
|
||||
|
@ -57,8 +57,7 @@ namespace regexp {
|
||||
}
|
||||
case (Object): {
|
||||
// 4. Let C be ? SpeciesConstructor(R, %RegExp%).
|
||||
const regexpFun =
|
||||
UnsafeCast<JSFunction>(nativeContext[REGEXP_FUNCTION_INDEX]);
|
||||
const regexpFun = LoadRegExpFunction(nativeContext);
|
||||
const speciesConstructor =
|
||||
UnsafeCast<Constructor>(SpeciesConstructor(receiver, regexpFun));
|
||||
|
||||
|
@ -25,12 +25,8 @@ namespace regexp {
|
||||
return SelectBooleanConstant(matchIndices != Null);
|
||||
}
|
||||
|
||||
extern macro RegExpBuiltinsAssembler::IsFastRegExpWithOriginalExec(
|
||||
implicit context: Context)(JSRegExp): bool;
|
||||
|
||||
transitioning builtin RegExpPrototypeTestFast(implicit context: Context)(
|
||||
receiver: JSRegExp, string: String): Object {
|
||||
assert(IsFastRegExpWithOriginalExec(receiver));
|
||||
RegExpPrototypeExecBodyWithoutResultFast(receiver, string)
|
||||
otherwise return False;
|
||||
return True;
|
||||
|
@ -72,7 +72,9 @@ namespace regexp {
|
||||
Context)(
|
||||
maybeRegexp: JSReceiver, string: String,
|
||||
isFastPath: constexpr bool): RegExpMatchInfo labels IfDidNotMatch {
|
||||
if (!isFastPath) {
|
||||
if (isFastPath) {
|
||||
assert(HasInitialRegExpMap(maybeRegexp));
|
||||
} else {
|
||||
IncrementUseCounter(context, SmiConstant(kRegExpExecCalledOnSlowRegExp));
|
||||
if (!Is<JSRegExp>(maybeRegexp)) {
|
||||
ThrowTypeError(
|
||||
@ -153,11 +155,24 @@ namespace regexp {
|
||||
return ConstructNewResultFromMatchInfo(maybeRegexp, matchIndices, string);
|
||||
}
|
||||
|
||||
macro LoadRegExpFunction(implicit context: Context)(
|
||||
nativeContext: NativeContext): JSFunction {
|
||||
return UnsafeCast<JSFunction>(nativeContext[REGEXP_FUNCTION_INDEX]);
|
||||
}
|
||||
|
||||
// Note this doesn't guarantee const-ness of object properties, just
|
||||
// unchanged object layout.
|
||||
macro HasInitialRegExpMap(implicit context: Context)(o: HeapObject): bool {
|
||||
const nativeContext = LoadNativeContext(context);
|
||||
const function = LoadRegExpFunction(nativeContext);
|
||||
const initialMap = UnsafeCast<Map>(function.prototype_or_initial_map);
|
||||
return initialMap == o.map;
|
||||
}
|
||||
|
||||
macro IsReceiverInitialRegExpPrototype(implicit context:
|
||||
Context)(receiver: Object): bool {
|
||||
const nativeContext: NativeContext = LoadNativeContext(context);
|
||||
const regexpFun =
|
||||
UnsafeCast<JSFunction>(nativeContext[REGEXP_FUNCTION_INDEX]);
|
||||
const nativeContext = LoadNativeContext(context);
|
||||
const regexpFun = LoadRegExpFunction(nativeContext);
|
||||
const initialMap = UnsafeCast<Map>(regexpFun.prototype_or_initial_map);
|
||||
const initialPrototype: HeapObject = initialMap.prototype;
|
||||
return TaggedEqual(receiver, initialPrototype);
|
||||
@ -374,8 +389,7 @@ namespace regexp {
|
||||
@export
|
||||
transitioning macro RegExpCreate(implicit context: Context)(
|
||||
nativeContext: NativeContext, maybeString: JSAny, flags: String): JSAny {
|
||||
const regexpFun =
|
||||
UnsafeCast<JSFunction>(nativeContext[REGEXP_FUNCTION_INDEX]);
|
||||
const regexpFun = LoadRegExpFunction(nativeContext);
|
||||
const initialMap = UnsafeCast<Map>(regexpFun.prototype_or_initial_map);
|
||||
return RegExpCreate(initialMap, maybeString, flags);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user