tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 8a6600bfda89f3a61f6309ed0f109728130d28d8
parent c4692f4209d521f00fac507337bfd7eba8d02227
Author: André Bargull <andre.bargull@gmail.com>
Date:   Mon, 20 Oct 2025 12:27:43 +0000

Bug 1991402 - Part 12: Convert RegExp getters. r=jandem

Differential Revision: https://phabricator.services.mozilla.com/D266604

Diffstat:
Mjs/src/builtin/RegExp.cpp | 17+++++++++--------
Mjs/src/builtin/RegExp.h | 2+-
Mjs/src/jit-test/tests/regexp/flag-getters.js | 20++++++++++++++++++++
Mjs/src/jit/CacheIR.cpp | 92+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mjs/src/jit/CacheIRGenerator.h | 6+++---
Mjs/src/jit/InlinableNatives.cpp | 8++++++++
Mjs/src/jit/InlinableNatives.h | 8++++++++
Mjs/src/vm/RegExpObject.cpp | 38--------------------------------------
Mjs/src/vm/RegExpObject.h | 2--
9 files changed, 97 insertions(+), 96 deletions(-)

diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp @@ -15,6 +15,7 @@ #include "frontend/FrontendContext.h" // AutoReportFrontendContext #include "frontend/TokenStream.h" #include "irregexp/RegExpAPI.h" +#include "jit/InlinableNatives.h" #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_NEWREGEXP_FLAGGED #include "js/PropertySpec.h" #include "js/RegExpFlags.h" // JS::RegExpFlag, JS::RegExpFlags @@ -964,15 +965,15 @@ bool js::regexp_unicodeSets(JSContext* cx, unsigned argc, JS::Value* vp) { const JSPropertySpec js::regexp_properties[] = { JS_SELF_HOSTED_GET("flags", "$RegExpFlagsGetter", 0), - JS_PSG("hasIndices", regexp_hasIndices, 0), - JS_PSG("global", regexp_global, 0), - JS_PSG("ignoreCase", regexp_ignoreCase, 0), - JS_PSG("multiline", regexp_multiline, 0), - JS_PSG("dotAll", regexp_dotAll, 0), + JS_INLINABLE_PSG("hasIndices", regexp_hasIndices, 0, RegExpHasIndices), + JS_INLINABLE_PSG("global", regexp_global, 0, RegExpGlobal), + JS_INLINABLE_PSG("ignoreCase", regexp_ignoreCase, 0, RegExpIgnoreCase), + JS_INLINABLE_PSG("multiline", regexp_multiline, 0, RegExpMultiline), + JS_INLINABLE_PSG("dotAll", regexp_dotAll, 0, RegExpDotAll), JS_PSG("source", regexp_source, 0), - JS_PSG("sticky", regexp_sticky, 0), - JS_PSG("unicode", regexp_unicode, 0), - JS_PSG("unicodeSets", regexp_unicodeSets, 0), + JS_INLINABLE_PSG("sticky", regexp_sticky, 0, RegExpSticky), + JS_INLINABLE_PSG("unicode", regexp_unicode, 0, RegExpUnicode), + JS_INLINABLE_PSG("unicodeSets", regexp_unicodeSets, 0, RegExpUnicodeSets), JS_PS_END, }; diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h @@ -164,7 +164,7 @@ extern const JSFunctionSpec regexp_static_methods[]; extern const JSPropertySpec regexp_properties[]; extern const JSFunctionSpec regexp_methods[]; -// Used in RegExpObject::isOriginalFlagGetter. +// Used in OptimizeRegExpPrototypeFuse::checkInvariant. [[nodiscard]] extern bool regexp_hasIndices(JSContext* cx, unsigned argc, JS::Value* vp); [[nodiscard]] extern bool regexp_global(JSContext* cx, unsigned argc, diff --git a/js/src/jit-test/tests/regexp/flag-getters.js b/js/src/jit-test/tests/regexp/flag-getters.js @@ -10,6 +10,16 @@ function testGlobal() { } for (let i = 0; i < 2; ++i) testGlobal(); +function testHasIndices() { + const xs = [/a/, /b/d]; + + for (let i = 0; i < 200; ++i) { + let x = xs[i & 1]; + assertEq(x.hasIndices, !!(i & 1)); + } +} +for (let i = 0; i < 2; ++i) testHasIndices(); + function testIgnoreCase() { const xs = [/a/, /b/i]; @@ -50,6 +60,16 @@ function testUnicode() { } for (let i = 0; i < 2; ++i) testUnicode(); +function testUnicodeSets() { + const xs = [/a/, /b/v]; + + for (let i = 0; i < 200; ++i) { + let x = xs[i & 1]; + assertEq(x.unicodeSets, !!(i & 1)); + } +} +for (let i = 0; i < 2; ++i) testUnicodeSets(); + function testSticky() { const xs = [/a/, /b/y]; diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp @@ -465,7 +465,6 @@ AttachDecision GetPropIRGenerator::tryAttachStub() { if (nameOrSymbol) { TRY_ATTACH(tryAttachObjectLength(obj, objId, id)); - TRY_ATTACH(tryAttachRegExp(obj, objId, id)); TRY_ATTACH(tryAttachNative(obj, objId, id, receiverId)); TRY_ATTACH(tryAttachModuleNamespace(obj, objId, id)); TRY_ATTACH(tryAttachWindowProxy(obj, objId, id)); @@ -2461,49 +2460,6 @@ AttachDecision GetPropIRGenerator::tryAttachInlinableNativeGetter( return nativeGen.tryAttachStub(); } -AttachDecision GetPropIRGenerator::tryAttachRegExp(HandleObject obj, - ObjOperandId objId, - HandleId id) { - if (!obj->is<RegExpObject>()) { - return AttachDecision::NoAction; - } - auto* regExp = &obj->as<RegExpObject>(); - - if (mode_ != ICState::Mode::Specialized) { - return AttachDecision::NoAction; - } - - // Receiver should be the object. - if (isSuper()) { - return AttachDecision::NoAction; - } - - NativeObject* holder = nullptr; - Maybe<PropertyInfo> prop; - NativeGetPropKind kind = - CanAttachNativeGetProp(cx_, obj, id, &holder, &prop, pc_); - if (kind != NativeGetPropKind::NativeGetter) { - return AttachDecision::NoAction; - } - - auto& fun = holder->getGetter(*prop)->as<JSFunction>(); - JS::RegExpFlags flags = JS::RegExpFlag::NoFlags; - if (!RegExpObject::isOriginalFlagGetter(fun.native(), &flags)) { - return AttachDecision::NoAction; - } - - maybeEmitIdGuard(id); - // Emit all the normal guards for calling this native, but specialize - // callNativeGetterResult. - emitCallGetterResultGuards(regExp, holder, id, *prop, objId); - - writer.regExpFlagResult(objId, flags.value()); - writer.returnFromIC(); - - trackAttached("GetProp.RegExpFlag"); - return AttachDecision::Attach; -} - AttachDecision GetPropIRGenerator::tryAttachFunction(HandleObject obj, ObjOperandId objId, HandleId id) { @@ -7745,6 +7701,38 @@ AttachDecision InlinableNativeIRGenerator::tryAttachHasClass( return AttachDecision::Attach; } +AttachDecision InlinableNativeIRGenerator::tryAttachRegExpFlag( + JS::RegExpFlags flags) { + // Expecting no arguments. + if (args_.length() != 0) { + return AttachDecision::NoAction; + } + + // Ensure |this| is a RegExpObject. + if (!thisval_.isObject() || !thisval_.toObject().is<RegExpObject>()) { + return AttachDecision::NoAction; + } + + auto* regExp = &thisval_.toObject().as<RegExpObject>(); + + // Initialize the input operand. + Int32OperandId argcId = initializeInputOperand(); + + // Guard callee is the native RegExp getter function. + ObjOperandId calleeId = emitNativeCalleeGuard(argcId); + + // Guard |this| is a RegExpObject. + ValOperandId thisValId = loadThis(calleeId); + ObjOperandId objId = writer.guardToObject(thisValId); + writer.guardShapeForClass(objId, regExp->shape()); + + writer.regExpFlagResult(objId, flags.value()); + writer.returnFromIC(); + + trackAttached("RegExpFlag"); + return AttachDecision::Attach; +} + // Returns whether the .lastIndex property is a non-negative int32 value and is // still writable. static bool HasOptimizableLastIndexSlot(RegExpObject* regexp, JSContext* cx) { @@ -13246,6 +13234,22 @@ AttachDecision InlinableNativeIRGenerator::tryAttachStub() { return tryAttachArrayIteratorPrototypeOptimizable(); // RegExp natives. + case InlinableNative::RegExpDotAll: + return tryAttachRegExpFlag(JS::RegExpFlag::DotAll); + case InlinableNative::RegExpGlobal: + return tryAttachRegExpFlag(JS::RegExpFlag::Global); + case InlinableNative::RegExpHasIndices: + return tryAttachRegExpFlag(JS::RegExpFlag::HasIndices); + case InlinableNative::RegExpIgnoreCase: + return tryAttachRegExpFlag(JS::RegExpFlag::IgnoreCase); + case InlinableNative::RegExpMultiline: + return tryAttachRegExpFlag(JS::RegExpFlag::Multiline); + case InlinableNative::RegExpSticky: + return tryAttachRegExpFlag(JS::RegExpFlag::Sticky); + case InlinableNative::RegExpUnicode: + return tryAttachRegExpFlag(JS::RegExpFlag::Unicode); + case InlinableNative::RegExpUnicodeSets: + return tryAttachRegExpFlag(JS::RegExpFlag::UnicodeSets); case InlinableNative::IsRegExpObject: return tryAttachHasClass(&RegExpObject::class_, /* isPossiblyWrapped = */ false); diff --git a/js/src/jit/CacheIRGenerator.h b/js/src/jit/CacheIRGenerator.h @@ -31,7 +31,8 @@ class JSFunction; namespace JS { struct XrayJitInfo; -} +class RegExpFlags; +} // namespace JS namespace js { @@ -176,8 +177,6 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator { ValOperandId receiverId); AttachDecision tryAttachObjectLength(HandleObject obj, ObjOperandId objId, HandleId id); - AttachDecision tryAttachRegExp(HandleObject obj, ObjOperandId objId, - HandleId id); AttachDecision tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId, HandleId id); AttachDecision tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, @@ -773,6 +772,7 @@ class MOZ_RAII InlinableNativeIRGenerator { AttachDecision tryAttachGuardToSharedArrayBuffer(); AttachDecision tryAttachHasClass(const JSClass* clasp, bool isPossiblyWrapped); + AttachDecision tryAttachRegExpFlag(JS::RegExpFlags flags); AttachDecision tryAttachRegExpMatcherSearcher(InlinableNative native); AttachDecision tryAttachRegExpSearcherLastLimit(); AttachDecision tryAttachRegExpHasCaptureGroups(); diff --git a/js/src/jit/InlinableNatives.cpp b/js/src/jit/InlinableNatives.cpp @@ -325,6 +325,14 @@ bool js::jit::CanInlineNativeCrossRealm(InlinableNative native) { case InlinableNative::NumberParseInt: case InlinableNative::NumberToString: case InlinableNative::ReflectGetPrototypeOf: + case InlinableNative::RegExpDotAll: + case InlinableNative::RegExpGlobal: + case InlinableNative::RegExpHasIndices: + case InlinableNative::RegExpIgnoreCase: + case InlinableNative::RegExpMultiline: + case InlinableNative::RegExpSticky: + case InlinableNative::RegExpUnicode: + case InlinableNative::RegExpUnicodeSets: case InlinableNative::SetConstructor: case InlinableNative::SetHas: case InlinableNative::SetDelete: diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h @@ -157,6 +157,14 @@ \ _(ReflectGetPrototypeOf) \ \ + _(RegExpDotAll) \ + _(RegExpGlobal) \ + _(RegExpHasIndices) \ + _(RegExpIgnoreCase) \ + _(RegExpMultiline) \ + _(RegExpSticky) \ + _(RegExpUnicode) \ + _(RegExpUnicodeSets) \ _(RegExpMatcher) \ _(RegExpSearcher) \ _(RegExpSearcherLastLimit) \ diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp @@ -117,44 +117,6 @@ RegExpShared* RegExpObject::getShared(JSContext* cx, return createShared(cx, regexp); } -/* static */ -bool RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlags* mask) { - if (native == regexp_hasIndices) { - *mask = RegExpFlag::HasIndices; - return true; - } - if (native == regexp_global) { - *mask = RegExpFlag::Global; - return true; - } - if (native == regexp_ignoreCase) { - *mask = RegExpFlag::IgnoreCase; - return true; - } - if (native == regexp_multiline) { - *mask = RegExpFlag::Multiline; - return true; - } - if (native == regexp_dotAll) { - *mask = RegExpFlag::DotAll; - return true; - } - if (native == regexp_sticky) { - *mask = RegExpFlag::Sticky; - return true; - } - if (native == regexp_unicode) { - *mask = RegExpFlag::Unicode; - return true; - } - if (native == regexp_unicodeSets) { - *mask = RegExpFlag::UnicodeSets; - return true; - } - - return false; -} - static const ClassSpec RegExpObjectClassSpec = { GenericCreateConstructor<js::regexp_construct, 2, gc::AllocKind::FUNCTION>, GenericCreatePrototype<RegExpObject>, diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h @@ -159,8 +159,6 @@ class RegExpObject : public NativeObject { return flags.global() || flags.sticky(); } - static bool isOriginalFlagGetter(JSNative native, JS::RegExpFlags* mask); - static RegExpShared* getShared(JSContext* cx, Handle<RegExpObject*> regexp); bool hasShared() const { return !getFixedSlot(SHARED_SLOT).isUndefined(); }