Backed out changeset 3a0a2ffe803b (bug 1379461) for hazard failure
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 11 Jul 2017 12:59:09 +0200
changeset 368332 8dad48102b135b1f63008ceabe3469ab171920b0
parent 368331 3a0a2ffe803bb326d06ac070d1950ff0fda61146
child 368333 fd25d12ab9e7d5e8f8ca02d3ac7482aa039207ac
push id32162
push usercbook@mozilla.com
push dateWed, 12 Jul 2017 09:07:26 +0000
treeherdermozilla-central@09a4282d1172 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1379461
milestone56.0a1
backs out3a0a2ffe803bb326d06ac070d1950ff0fda61146
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 3a0a2ffe803b (bug 1379461) for hazard failure
js/ipc/WrapperOwner.cpp
js/ipc/WrapperOwner.h
js/public/Proxy.h
js/src/builtin/RegExp.cpp
js/src/jsapi.cpp
js/src/jsfriendapi.h
js/src/jswrapper.h
js/src/proxy/BaseProxyHandler.cpp
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/proxy/DeadObjectProxy.cpp
js/src/proxy/DeadObjectProxy.h
js/src/proxy/Proxy.cpp
js/src/proxy/Proxy.h
js/src/proxy/ScriptedProxyHandler.cpp
js/src/proxy/ScriptedProxyHandler.h
js/src/proxy/SecurityWrapper.cpp
js/src/proxy/Wrapper.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/RegExpShared.h
js/src/vm/RegExpStatics.cpp
js/src/vm/StructuredClone.cpp
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -124,52 +124,53 @@ class CPOWProxyHandler : public BaseProx
     virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
                                               AutoIdVector& props) const override;
     virtual bool hasInstance(JSContext* cx, HandleObject proxy,
                              MutableHandleValue v, bool* bp) const override;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject obj, js::ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject obj,
                          IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
-    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
+    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
+                                 MutableHandle<RegExpShared*> shared) const override;
     virtual void finalize(JSFreeOp* fop, JSObject* proxy) const override;
     virtual void objectMoved(JSObject* proxy, const JSObject* old) const override;
     virtual bool isCallable(JSObject* obj) const override;
     virtual bool isConstructor(JSObject* obj) const override;
     virtual bool getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const override;
     virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
                                         MutableHandleObject protop) const override;
 
     static const char family;
     static const CPOWProxyHandler singleton;
 };
 
 const char CPOWProxyHandler::family = 0;
 const CPOWProxyHandler CPOWProxyHandler::singleton;
 
-#define FORWARD(call, args, failRetVal)                                 \
+#define FORWARD(call, args)                                             \
     AUTO_PROFILER_LABEL(__func__, JS);                                  \
     WrapperOwner* owner = OwnerOf(proxy);                               \
     if (!owner->active()) {                                             \
         JS_ReportErrorASCII(cx, "cannot use a CPOW whose process is gone"); \
-        return failRetVal;                                              \
+        return false;                                                   \
     }                                                                   \
     if (!owner->allowMessage(cx)) {                                     \
-        return failRetVal;                                              \
+        return false;                                                   \
     }                                                                   \
     {                                                                   \
         CPOWTimer timer(cx);                                            \
         return owner->call args;                                        \
     }
 
 bool
 CPOWProxyHandler::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                         MutableHandle<PropertyDescriptor> desc) const
 {
-    FORWARD(getPropertyDescriptor, (cx, proxy, id, desc), false);
+    FORWARD(getPropertyDescriptor, (cx, proxy, id, desc));
 }
 
 bool
 WrapperOwner::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                     MutableHandle<PropertyDescriptor> desc)
 {
     ObjectId objId = idOf(proxy);
 
@@ -189,17 +190,17 @@ WrapperOwner::getPropertyDescriptor(JSCo
 
     return toDescriptor(cx, result, desc);
 }
 
 bool
 CPOWProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                            MutableHandle<PropertyDescriptor> desc) const
 {
-    FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc), false);
+    FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc));
 }
 
 bool
 WrapperOwner::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                        MutableHandle<PropertyDescriptor> desc)
 {
     ObjectId objId = idOf(proxy);
 
@@ -220,17 +221,17 @@ WrapperOwner::getOwnPropertyDescriptor(J
     return toDescriptor(cx, result, desc);
 }
 
 bool
 CPOWProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
                                  Handle<PropertyDescriptor> desc,
                                  ObjectOpResult& result) const
 {
-    FORWARD(defineProperty, (cx, proxy, id, desc, result), false);
+    FORWARD(defineProperty, (cx, proxy, id, desc, result));
 }
 
 bool
 WrapperOwner::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
                              Handle<PropertyDescriptor> desc,
                              ObjectOpResult& result)
 {
     ObjectId objId = idOf(proxy);
@@ -251,30 +252,30 @@ WrapperOwner::defineProperty(JSContext* 
 
     return ok(cx, status, result);
 }
 
 bool
 CPOWProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy,
                                   AutoIdVector& props) const
 {
-    FORWARD(ownPropertyKeys, (cx, proxy, props), false);
+    FORWARD(ownPropertyKeys, (cx, proxy, props));
 }
 
 bool
 WrapperOwner::ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props)
 {
     return getPropertyKeys(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
 }
 
 bool
 CPOWProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id,
                           ObjectOpResult& result) const
 {
-    FORWARD(delete_, (cx, proxy, id, result), false);
+    FORWARD(delete_, (cx, proxy, id, result));
 }
 
 bool
 WrapperOwner::delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result)
 {
     ObjectId objId = idOf(proxy);
 
     JSIDVariant idVar;
@@ -297,17 +298,17 @@ CPOWProxyHandler::enumerate(JSContext* c
     // call the base hook, that will use our implementation of getOwnEnumerablePropertyKeys
     // and follow the proto chain.
     return BaseProxyHandler::enumerate(cx, proxy);
 }
 
 bool
 CPOWProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
 {
-    FORWARD(has, (cx, proxy, id, bp), false);
+    FORWARD(has, (cx, proxy, id, bp));
 }
 
 bool
 WrapperOwner::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp)
 {
     ObjectId objId = idOf(proxy);
 
     JSIDVariant idVar;
@@ -321,17 +322,17 @@ WrapperOwner::has(JSContext* cx, HandleO
     LOG_STACK();
 
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
 {
-    FORWARD(hasOwn, (cx, proxy, id, bp), false);
+    FORWARD(hasOwn, (cx, proxy, id, bp));
 }
 
 bool
 WrapperOwner::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp)
 {
     ObjectId objId = idOf(proxy);
 
     JSIDVariant idVar;
@@ -346,30 +347,30 @@ WrapperOwner::hasOwn(JSContext* cx, Hand
 
     return !!ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
                       HandleId id, MutableHandleValue vp) const
 {
-    FORWARD(get, (cx, proxy, receiver, id, vp), false);
+    FORWARD(get, (cx, proxy, receiver, id, vp));
 }
 
 static bool
 CPOWDOMQI(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (!args.thisv().isObject() || !IsCPOW(&args.thisv().toObject())) {
         JS_ReportErrorASCII(cx, "bad this object passed to special QI");
         return false;
     }
 
     RootedObject proxy(cx, &args.thisv().toObject());
-    FORWARD(DOMQI, (cx, proxy, args), false);
+    FORWARD(DOMQI, (cx, proxy, args));
 }
 
 static bool
 CPOWToString(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject callee(cx, &args.callee());
     RootedValue cpowValue(cx);
@@ -377,17 +378,17 @@ CPOWToString(JSContext* cx, unsigned arg
         return false;
 
     if (!cpowValue.isObject() || !IsCPOW(&cpowValue.toObject())) {
         JS_ReportErrorASCII(cx, "CPOWToString called on an incompatible object");
         return false;
     }
 
     RootedObject proxy(cx, &cpowValue.toObject());
-    FORWARD(toString, (cx, proxy, args), false);
+    FORWARD(toString, (cx, proxy, args));
 }
 
 bool
 WrapperOwner::toString(JSContext* cx, HandleObject cpow, JS::CallArgs& args)
 {
     // Ask the other side to call its toString method. Update the callee so that
     // it points to the CPOW and not to the synthesized CPOWToString function.
     args.setCallee(ObjectValue(*cpow));
@@ -524,17 +525,17 @@ WrapperOwner::get(JSContext* cx, HandleO
 
     return true;
 }
 
 bool
 CPOWProxyHandler::set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
                       JS::HandleValue receiver, JS::ObjectOpResult& result) const
 {
-    FORWARD(set, (cx, proxy, id, v, receiver, result), false);
+    FORWARD(set, (cx, proxy, id, v, receiver, result));
 }
 
 bool
 WrapperOwner::set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
                   JS::HandleValue receiver, JS::ObjectOpResult& result)
 {
     ObjectId objId = idOf(proxy);
 
@@ -558,29 +559,29 @@ WrapperOwner::set(JSContext* cx, JS::Han
 
     return ok(cx, status, result);
 }
 
 bool
 CPOWProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
                                                AutoIdVector& props) const
 {
-    FORWARD(getOwnEnumerablePropertyKeys, (cx, proxy, props), false);
+    FORWARD(getOwnEnumerablePropertyKeys, (cx, proxy, props));
 }
 
 bool
 WrapperOwner::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props)
 {
     return getPropertyKeys(cx, proxy, JSITER_OWNONLY, props);
 }
 
 bool
 CPOWProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const
 {
-    FORWARD(preventExtensions, (cx, proxy, result), false);
+    FORWARD(preventExtensions, (cx, proxy, result));
 }
 
 bool
 WrapperOwner::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result)
 {
     ObjectId objId = idOf(proxy);
 
     ReturnStatus status;
@@ -590,17 +591,17 @@ WrapperOwner::preventExtensions(JSContex
     LOG_STACK();
 
     return ok(cx, status, result);
 }
 
 bool
 CPOWProxyHandler::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const
 {
-    FORWARD(isExtensible, (cx, proxy, extensible), false);
+    FORWARD(isExtensible, (cx, proxy, extensible));
 }
 
 bool
 WrapperOwner::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible)
 {
     ObjectId objId = idOf(proxy);
 
     ReturnStatus status;
@@ -610,23 +611,23 @@ WrapperOwner::isExtensible(JSContext* cx
     LOG_STACK();
 
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const
 {
-    FORWARD(callOrConstruct, (cx, proxy, args, false), false);
+    FORWARD(callOrConstruct, (cx, proxy, args, false));
 }
 
 bool
 CPOWProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
 {
-    FORWARD(callOrConstruct, (cx, proxy, args, true), false);
+    FORWARD(callOrConstruct, (cx, proxy, args, true));
 }
 
 bool
 WrapperOwner::callOrConstruct(JSContext* cx, HandleObject proxy, const CallArgs& args,
                               bool construct)
 {
     ObjectId objId = idOf(proxy);
 
@@ -699,17 +700,17 @@ WrapperOwner::callOrConstruct(JSContext*
         return false;
 
     return true;
 }
 
 bool
 CPOWProxyHandler::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp) const
 {
-    FORWARD(hasInstance, (cx, proxy, v, bp), false);
+    FORWARD(hasInstance, (cx, proxy, v, bp));
 }
 
 bool
 WrapperOwner::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp)
 {
     ObjectId objId = idOf(proxy);
 
     JSVariant vVar;
@@ -723,17 +724,17 @@ WrapperOwner::hasInstance(JSContext* cx,
     LOG_STACK();
 
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
 {
-    FORWARD(getBuiltinClass, (cx, proxy, cls), false);
+    FORWARD(getBuiltinClass, (cx, proxy, cls));
 }
 
 bool
 WrapperOwner::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls)
 {
     ObjectId objId = idOf(proxy);
 
     uint32_t classValue = uint32_t(ESClass::Other);
@@ -746,17 +747,17 @@ WrapperOwner::getBuiltinClass(JSContext*
 
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::isArray(JSContext* cx, HandleObject proxy,
                           IsArrayAnswer* answer) const
 {
-    FORWARD(isArray, (cx, proxy, answer), false);
+    FORWARD(isArray, (cx, proxy, answer));
 }
 
 bool
 WrapperOwner::isArray(JSContext* cx, HandleObject proxy, IsArrayAnswer* answer)
 {
     ObjectId objId = idOf(proxy);
 
     uint32_t ans;
@@ -797,17 +798,17 @@ WrapperOwner::className(JSContext* cx, H
     }
 
     return data->className.get();
 }
 
 bool
 CPOWProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const
 {
-    FORWARD(getPrototype, (cx, proxy, objp), false);
+    FORWARD(getPrototype, (cx, proxy, objp));
 }
 
 bool
 WrapperOwner::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject objp)
 {
     ObjectId objId = idOf(proxy);
 
     ObjectOrNullVariant val;
@@ -824,17 +825,17 @@ WrapperOwner::getPrototype(JSContext* cx
 
     return true;
 }
 
 bool
 CPOWProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
                                          MutableHandleObject objp) const
 {
-    FORWARD(getPrototypeIfOrdinary, (cx, proxy, isOrdinary, objp), false);
+    FORWARD(getPrototypeIfOrdinary, (cx, proxy, isOrdinary, objp));
 }
 
 bool
 WrapperOwner::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
                                      MutableHandleObject objp)
 {
     ObjectId objId = idOf(proxy);
 
@@ -848,45 +849,45 @@ WrapperOwner::getPrototypeIfOrdinary(JSC
     if (!ok(cx, status))
         return false;
 
     objp.set(fromObjectOrNullVariant(cx, val));
 
     return true;
 }
 
-RegExpShared*
-CPOWProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy) const
+bool
+CPOWProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy,
+                                  MutableHandle<RegExpShared*> shared) const
 {
-    FORWARD(regexp_toShared, (cx, proxy), nullptr);
+    FORWARD(regexp_toShared, (cx, proxy, shared));
 }
 
-RegExpShared*
-WrapperOwner::regexp_toShared(JSContext* cx, HandleObject proxy)
+bool
+WrapperOwner::regexp_toShared(JSContext* cx, HandleObject proxy, MutableHandle<RegExpShared*> shared)
 {
     ObjectId objId = idOf(proxy);
 
     ReturnStatus status;
     nsString source;
     unsigned flags = 0;
-    if (!SendRegExpToShared(objId, &status, &source, &flags)) {
-        MOZ_ALWAYS_FALSE(ipcfail(cx));
-        return nullptr;
-    }
+    if (!SendRegExpToShared(objId, &status, &source, &flags))
+        return ipcfail(cx);
+
     LOG_STACK();
 
     if (!ok(cx, status))
-        return nullptr;
+        return false;
 
     RootedObject regexp(cx);
     regexp = JS_NewUCRegExpObject(cx, source.get(), source.Length(), flags);
     if (!regexp)
-        return nullptr;
+        return false;
 
-    return js::RegExpToSharedNonInline(cx, regexp);
+    return js::RegExpToSharedNonInline(cx, regexp, shared);
 }
 
 void
 CPOWProxyHandler::finalize(JSFreeOp* fop, JSObject* proxy) const
 {
     AuxCPOWData* aux = AuxCPOWDataOf(proxy);
 
     OwnerOf(proxy)->drop(proxy);
@@ -1009,17 +1010,17 @@ InstanceOf(JSObject* proxy, const nsID* 
         return NS_ERROR_UNEXPECTED;
     return parent->instanceOf(proxy, id, bp);
 }
 
 bool
 DOMInstanceOf(JSContext* cx, JSObject* proxyArg, int prototypeID, int depth, bool* bp)
 {
     RootedObject proxy(cx, proxyArg);
-    FORWARD(domInstanceOf, (cx, proxy, prototypeID, depth, bp), false);
+    FORWARD(domInstanceOf, (cx, proxy, prototypeID, depth, bp));
 }
 
 } /* namespace jsipc */
 } /* namespace mozilla */
 
 nsresult
 WrapperOwner::instanceOf(JSObject* obj, const nsID* id, bool* bp)
 {
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -55,17 +55,18 @@ class WrapperOwner : public virtual Java
     bool hasInstance(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool* bp);
     bool getBuiltinClass(JSContext* cx, JS::HandleObject proxy, js::ESClass* cls);
     bool isArray(JSContext* cx, JS::HandleObject proxy, JS::IsArrayAnswer* answer);
     const char* className(JSContext* cx, JS::HandleObject proxy);
     bool getPrototype(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleObject protop);
     bool getPrototypeIfOrdinary(JSContext* cx, JS::HandleObject proxy, bool* isOrdinary,
                                 JS::MutableHandleObject protop);
 
-    js::RegExpShared* regexp_toShared(JSContext* cx, JS::HandleObject proxy);
+    bool regexp_toShared(JSContext* cx, JS::HandleObject proxy,
+                         js::MutableHandle<js::RegExpShared*> shared);
 
     nsresult instanceOf(JSObject* obj, const nsID* id, bool* bp);
 
     bool toString(JSContext* cx, JS::HandleObject callee, JS::CallArgs& args);
     bool DOMQI(JSContext* cx, JS::HandleObject callee, JS::CallArgs& args);
 
     /*
      * Check that |obj| is a DOM wrapper whose prototype chain contains
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -326,17 +326,18 @@ class JS_FRIEND_API(BaseProxyHandler)
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const;
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp) const;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy,
                                  ESClass* cls) const;
     virtual bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const;
     virtual const char* className(JSContext* cx, HandleObject proxy) const;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const;
-    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const;
+    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
+                                 MutableHandle<js::RegExpShared*> shared) const;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const;
     virtual void trace(JSTracer* trc, JSObject* proxy) const;
     virtual void finalize(JSFreeOp* fop, JSObject* proxy) const;
     virtual void objectMoved(JSObject* proxy, const JSObject* old) const;
 
     // Allow proxies, wrappers in particular, to specify callability at runtime.
     // Note: These do not take const JSObject*, but they do in spirit.
     //       We are not prepared to do this, as there's little const correctness
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -141,18 +141,18 @@ ExecuteRegExpImpl(JSContext* cx, RegExpS
 }
 
 /* Legacy ExecuteRegExp behavior is baked into the JSAPI. */
 bool
 js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, Handle<RegExpObject*> reobj,
                         HandleLinearString input, size_t* lastIndex, bool test,
                         MutableHandleValue rval)
 {
-    RootedRegExpShared shared(cx, RegExpObject::getShared(cx, reobj));
-    if (!shared)
+    RootedRegExpShared shared(cx);
+    if (!RegExpObject::getShared(cx, reobj, &shared))
         return false;
 
     ScopedMatchPairs matches(&cx->tempLifoAlloc());
 
     RegExpRunStatus status = ExecuteRegExpImpl(cx, res, &shared, input, *lastIndex,
                                                &matches, nullptr);
     if (status == RegExpRunStatus_Error)
         return false;
@@ -229,18 +229,18 @@ RegExpInitializeIgnoringLastIndex(JSCont
 
         /* Step 5. */
         if (!ParseRegExpFlags(cx, flagStr, &flags))
             return false;
     }
 
     if (sharedUse == UseRegExpShared) {
         /* Steps 7-8. */
-        RegExpShared* re = cx->zone()->regExps.get(cx, pattern, flags);
-        if (!re)
+        RootedRegExpShared re(cx);
+        if (!cx->zone()->regExps.get(cx, pattern, flags, &re))
             return false;
 
         /* Steps 9-12. */
         obj->initIgnoringLastIndex(pattern, flags);
 
         obj->setShared(*re);
     } else {
         /* Steps 7-8. */
@@ -335,22 +335,22 @@ regexp_compile_impl(JSContext* cx, const
         // don't assume |patternObj.is<RegExpObject>()|.  For the same reason,
         // don't reuse the RegExpShared below.
         RootedObject patternObj(cx, &patternValue.toObject());
 
         RootedAtom sourceAtom(cx);
         RegExpFlag flags;
         {
             // Step 3b.
-            RegExpShared* shared = RegExpToShared(cx, patternObj);
-            if (!shared)
+            RootedRegExpShared g(cx);
+            if (!RegExpToShared(cx, patternObj, &g))
                 return false;
 
-            sourceAtom = shared->getSource();
-            flags = shared->getFlags();
+            sourceAtom = g->getSource();
+            flags = g->getFlags();
         }
 
         // Step 5, minus lastIndex zeroing.
         regexp->initIgnoringLastIndex(sourceAtom, flags);
     } else {
         // Step 4.
         RootedValue P(cx, patternValue);
         RootedValue F(cx, args.get(1));
@@ -430,24 +430,24 @@ js::regexp_construct(JSContext* cx, unsi
         // don't assume |patternObj.is<RegExpObject>()|.  For the same reason,
         // don't reuse the RegExpShared below.
         RootedObject patternObj(cx, &patternValue.toObject());
 
         RootedAtom sourceAtom(cx);
         RegExpFlag flags;
         {
             // Step 4.a.
-            RegExpShared* shared = RegExpToShared(cx, patternObj);
-            if (!shared)
+            RootedRegExpShared g(cx);
+            if (!RegExpToShared(cx, patternObj, &g))
                 return false;
-            sourceAtom = shared->getSource();
+            sourceAtom = g->getSource();
 
             // Step 4.b.
             // Get original flags in all cases, to compare with passed flags.
-            flags = shared->getFlags();
+            flags = g->getFlags();
         }
 
         // Step 7.
         RootedObject proto(cx);
         if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
             return false;
 
         Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, GenericObject, proto));
@@ -894,18 +894,18 @@ ExecuteRegExp(JSContext* cx, HandleObjec
      * WARNING: Despite the presence of spec step comment numbers, this
      *          algorithm isn't consistent with any ES6 version, draft or
      *          otherwise.  YOU HAVE BEEN WARNED.
      */
 
     /* Steps 1-2 performed by the caller. */
     Rooted<RegExpObject*> reobj(cx, &regexp->as<RegExpObject>());
 
-    RootedRegExpShared re(cx, RegExpObject::getShared(cx, reobj));
-    if (!re)
+    RootedRegExpShared re(cx);
+    if (!RegExpObject::getShared(cx, reobj, &re))
         return RegExpRunStatus_Error;
 
     RegExpStatics* res;
     if (staticsUpdate == UpdateRegExpStatics) {
         res = GlobalObject::getRegExpStatics(cx, cx->global());
         if (!res)
             return RegExpRunStatus_Error;
     } else {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6267,30 +6267,30 @@ JS_ObjectIsRegExp(JSContext* cx, HandleO
 }
 
 JS_PUBLIC_API(unsigned)
 JS_GetRegExpFlags(JSContext* cx, HandleObject obj)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
 
-    RegExpShared* shared = RegExpToShared(cx, obj);
-    if (!shared)
+    RootedRegExpShared shared(cx);
+    if (!RegExpToShared(cx, obj, &shared))
         return false;
     return shared->getFlags();
 }
 
 JS_PUBLIC_API(JSString*)
 JS_GetRegExpSource(JSContext* cx, HandleObject obj)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
 
-    RegExpShared* shared = RegExpToShared(cx, obj);
-    if (!shared)
+    RootedRegExpShared shared(cx);
+    if (!RegExpToShared(cx, obj, &shared))
         return nullptr;
     return shared->getSource();
 }
 
 /************************************************************************/
 
 JS_PUBLIC_API(bool)
 JS_SetDefaultLocale(JSContext* cx, const char* locale)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1176,18 +1176,19 @@ CastToJSFreeOp(FreeOp* fop)
 extern JS_FRIEND_API(JSFlatString*)
 GetErrorTypeName(JSContext* cx, int16_t exnType);
 
 #ifdef JS_DEBUG
 extern JS_FRIEND_API(unsigned)
 GetEnterCompartmentDepth(JSContext* cx);
 #endif
 
-extern JS_FRIEND_API(RegExpShared*)
-RegExpToSharedNonInline(JSContext* cx, JS::HandleObject regexp);
+extern JS_FRIEND_API(bool)
+RegExpToSharedNonInline(JSContext* cx, JS::HandleObject regexp,
+                        JS::MutableHandle<RegExpShared*> shared);
 
 /* Implemented in CrossCompartmentWrapper.cpp. */
 typedef enum NukeReferencesToWindow {
     NukeWindowReferences,
     DontNukeWindowReferences
 } NukeReferencesToWindow;
 
 typedef enum NukeReferencesFromTarget {
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -111,17 +111,18 @@ class JS_FRIEND_API(Wrapper) : public Ba
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
                              bool* bp) const override;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject proxy,
                          JS::IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
                                    unsigned indent) const override;
-    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
+    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
+                                 MutableHandle<RegExpShared*> shared) const override;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
                                   MutableHandleValue vp) const override;
     virtual bool isCallable(JSObject* obj) const override;
     virtual bool isConstructor(JSObject* obj) const override;
     virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override;
 
   public:
     using BaseProxyHandler::Action;
@@ -205,17 +206,18 @@ class JS_FRIEND_API(CrossCompartmentWrap
                                               AutoIdVector& props) const override;
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const override;
     virtual bool hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v,
                              bool* bp) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper,
                                    unsigned indent) const override;
-    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
+    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
+                                 MutableHandle<RegExpShared*> shared) const override;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
 
     // Allocate CrossCompartmentWrappers in the nursery.
     virtual bool canNurseryAllocate() const override { return true; }
 
     static const CrossCompartmentWrapper singleton;
     static const CrossCompartmentWrapper singletonWithPrototype;
 };
@@ -302,17 +304,18 @@ class JS_FRIEND_API(SecurityWrapper) : p
     virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
                               ObjectOpResult& result) const override;
     virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override;
 
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const override;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject wrapper, JS::IsArrayAnswer* answer) const override;
-    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
+    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
+                                 MutableHandle<RegExpShared*> shared) const override;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
 
     // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded
     // against.
 
     virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
                        JS::HandleObject callable) const override;
     virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const override;
--- a/js/src/proxy/BaseProxyHandler.cpp
+++ b/js/src/proxy/BaseProxyHandler.cpp
@@ -320,18 +320,19 @@ BaseProxyHandler::fun_toString(JSContext
 {
     if (proxy->isCallable())
         return JS_NewStringCopyZ(cx, "function () {\n    [native code]\n}");
     RootedValue v(cx, ObjectValue(*proxy));
     ReportIsNotFunction(cx, v);
     return nullptr;
 }
 
-RegExpShared*
-BaseProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy) const
+bool
+BaseProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy,
+                                  MutableHandleRegExpShared shared) const
 {
     MOZ_CRASH("This should have been a wrapped regexp");
 }
 
 bool
 BaseProxyHandler::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const
 {
     vp.setUndefined();
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -458,31 +458,31 @@ CrossCompartmentWrapper::fun_toString(JS
         if (!str)
             return nullptr;
     }
     if (!cx->compartment()->wrap(cx, &str))
         return nullptr;
     return str;
 }
 
-RegExpShared*
-CrossCompartmentWrapper::regexp_toShared(JSContext* cx, HandleObject wrapper) const
+bool
+CrossCompartmentWrapper::regexp_toShared(JSContext* cx, HandleObject wrapper,
+                                         MutableHandleRegExpShared shared) const
 {
     RootedRegExpShared re(cx);
     {
         AutoCompartment call(cx, wrappedObject(wrapper));
-        re = Wrapper::regexp_toShared(cx, wrapper);
-        if (!re)
-            return nullptr;
+        if (!Wrapper::regexp_toShared(cx, wrapper, &re))
+            return false;
     }
 
     // Get an equivalent RegExpShared associated with the current compartment.
     RootedAtom source(cx, re->getSource());
     cx->markAtom(source);
-    return cx->zone()->regExps.get(cx, source, re->getFlags());
+    return cx->zone()->regExps.get(cx, source, re->getFlags(), shared);
 }
 
 bool
 CrossCompartmentWrapper::boxedValue_unbox(JSContext* cx, HandleObject wrapper, MutableHandleValue vp) const
 {
     PIERCE(cx, wrapper,
            NOTHING,
            Wrapper::boxedValue_unbox(cx, wrapper, vp),
--- a/js/src/proxy/DeadObjectProxy.cpp
+++ b/js/src/proxy/DeadObjectProxy.cpp
@@ -155,21 +155,22 @@ template <DeadProxyIsCallableIsConstruct
 JSString*
 DeadObjectProxy<CC>::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
 {
     ReportDead(cx);
     return nullptr;
 }
 
 template <DeadProxyIsCallableIsConstructorOption CC>
-RegExpShared*
-DeadObjectProxy<CC>::regexp_toShared(JSContext* cx, HandleObject proxy) const
+bool
+DeadObjectProxy<CC>::regexp_toShared(JSContext* cx, HandleObject proxy,
+                                     MutableHandle<RegExpShared*> shared) const
 {
     ReportDead(cx);
-    return nullptr;
+    return false;
 }
 
 template <>
 const char DeadObjectProxy<DeadProxyNotCallableNotConstructor>::family = 0;
 template <>
 const char DeadObjectProxy<DeadProxyNotCallableIsConstructor>::family = 0;
 template <>
 const char DeadObjectProxy<DeadProxyIsCallableNotConstructor>::family = 0;
--- a/js/src/proxy/DeadObjectProxy.h
+++ b/js/src/proxy/DeadObjectProxy.h
@@ -55,17 +55,18 @@ class DeadObjectProxy : public BaseProxy
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const override;
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
                              bool* bp) const override;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override;
-    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
+    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
+                                 MutableHandle<RegExpShared*> shared) const override;
 
     virtual bool isCallable(JSObject* obj) const override {
         return CC == DeadProxyIsCallableIsConstructor || CC == DeadProxyIsCallableNotConstructor;
     }
     virtual bool isConstructor(JSObject* obj) const override {
         return CC == DeadProxyIsCallableIsConstructor || CC == DeadProxyNotCallableIsConstructor;
     }
 
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -570,22 +570,22 @@ Proxy::fun_toString(JSContext* cx, Handl
     AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
                            BaseProxyHandler::GET, /* mayThrow = */ false);
     // Do the safe thing if the policy rejects.
     if (!policy.allowed())
         return handler->BaseProxyHandler::fun_toString(cx, proxy, indent);
     return handler->fun_toString(cx, proxy, indent);
 }
 
-RegExpShared*
-Proxy::regexp_toShared(JSContext* cx, HandleObject proxy)
+bool
+Proxy::regexp_toShared(JSContext* cx, HandleObject proxy, MutableHandleRegExpShared shared)
 {
     if (!CheckRecursionLimit(cx))
-        return nullptr;
-    return proxy->as<ProxyObject>().handler()->regexp_toShared(cx, proxy);
+        return false;
+    return proxy->as<ProxyObject>().handler()->regexp_toShared(cx, proxy, shared);
 }
 
 bool
 Proxy::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp)
 {
     if (!CheckRecursionLimit(cx))
         return false;
     return proxy->as<ProxyObject>().handler()->boxedValue_unbox(cx, proxy, vp);
--- a/js/src/proxy/Proxy.h
+++ b/js/src/proxy/Proxy.h
@@ -55,17 +55,18 @@ class Proxy
                                              AutoIdVector& props);
     static bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                            const CallArgs& args);
     static bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp);
     static bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls);
     static bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer);
     static const char* className(JSContext* cx, HandleObject proxy);
     static JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent);
-    static RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy);
+    static bool regexp_toShared(JSContext* cx, HandleObject proxy,
+                                MutableHandle<RegExpShared*> shared);
     static bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp);
 
     static bool watch(JSContext* cx, HandleObject proxy, HandleId id, HandleObject callable);
     static bool unwatch(JSContext* cx, HandleObject proxy, HandleId id);
 
     static bool getElements(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end,
                             ElementAdder* adder);
 
--- a/js/src/proxy/ScriptedProxyHandler.cpp
+++ b/js/src/proxy/ScriptedProxyHandler.cpp
@@ -1262,20 +1262,22 @@ ScriptedProxyHandler::className(JSContex
 JSString*
 ScriptedProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
 {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
                               js_Function_str, js_toString_str, "object");
     return nullptr;
 }
 
-RegExpShared*
-ScriptedProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy) const
+bool
+ScriptedProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy,
+                                      MutableHandleRegExpShared shared) const
 {
     MOZ_CRASH("Should not end up in ScriptedProxyHandler::regexp_toShared");
+    return false;
 }
 
 bool
 ScriptedProxyHandler::boxedValue_unbox(JSContext* cx, HandleObject proxy,
                                        MutableHandleValue vp) const
 {
     MOZ_CRASH("Should not end up in ScriptedProxyHandler::boxedValue_unbox");
     return false;
--- a/js/src/proxy/ScriptedProxyHandler.h
+++ b/js/src/proxy/ScriptedProxyHandler.h
@@ -64,17 +64,18 @@ class ScriptedProxyHandler : public Base
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
                              bool* bp) const override;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject proxy,
                          JS::IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
                                    unsigned indent) const override;
-    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
+    virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
+                                 MutableHandle<RegExpShared*> shared) const override;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
                                   MutableHandleValue vp) const override;
 
     virtual bool isCallable(JSObject* obj) const override;
     virtual bool isConstructor(JSObject* obj) const override;
 
     virtual bool isScripted() const override { return true; }
 
--- a/js/src/proxy/SecurityWrapper.cpp
+++ b/js/src/proxy/SecurityWrapper.cpp
@@ -82,20 +82,21 @@ bool
 SecurityWrapper<Base>::isArray(JSContext* cx, HandleObject obj, JS::IsArrayAnswer* answer) const
 {
     // This should ReportAccessDenied(cx), but bug 849730 disagrees.  :-(
     *answer = JS::IsArrayAnswer::NotArray;
     return true;
 }
 
 template <class Base>
-RegExpShared*
-SecurityWrapper<Base>::regexp_toShared(JSContext* cx, HandleObject obj) const
+bool
+SecurityWrapper<Base>::regexp_toShared(JSContext* cx, HandleObject obj,
+                                       MutableHandle<RegExpShared*> shared) const
 {
-    return Base::regexp_toShared(cx, obj);
+    return Base::regexp_toShared(cx, obj, shared);
 }
 
 template <class Base>
 bool
 SecurityWrapper<Base>::boxedValue_unbox(JSContext* cx, HandleObject obj, MutableHandleValue vp) const
 {
     vp.setUndefined();
     return true;
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -266,21 +266,21 @@ Wrapper::className(JSContext* cx, Handle
 JSString*
 Wrapper::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return fun_toStringHelper(cx, target, indent);
 }
 
-RegExpShared*
-Wrapper::regexp_toShared(JSContext* cx, HandleObject proxy) const
+bool
+Wrapper::regexp_toShared(JSContext* cx, HandleObject proxy, MutableHandleRegExpShared shared) const
 {
     RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return RegExpToShared(cx, target);
+    return RegExpToShared(cx, target, shared);
 }
 
 bool
 Wrapper::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const
 {
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return Unbox(cx, target, vp);
 }
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -111,23 +111,26 @@ VectorMatchPairs::allocOrExpandArray(siz
 
     pairs_ = &vec_[0];
     pairCount_ = pairCount;
     return true;
 }
 
 /* RegExpObject */
 
-/* static */ RegExpShared*
-RegExpObject::getShared(JSContext* cx, Handle<RegExpObject*> regexp)
+/* static */ bool
+RegExpObject::getShared(JSContext* cx, Handle<RegExpObject*> regexp,
+                        MutableHandleRegExpShared shared)
 {
-    if (regexp->hasShared())
-        return regexp->sharedRef();
+    if (regexp->hasShared()) {
+        shared.set(regexp->sharedRef());
+        return true;
+    }
 
-    return createShared(cx, regexp);
+    return createShared(cx, regexp, shared);
 }
 
 /* static */ bool
 RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask)
 {
   if (native == regexp_global) {
       *mask = GlobalFlag;
       return true;
@@ -262,27 +265,27 @@ RegExpObject::create(JSContext* cx, Hand
     if (!regexp)
         return nullptr;
 
     regexp->initAndZeroLastIndex(source, flags, cx);
 
     return regexp;
 }
 
-/* static */ RegExpShared*
-RegExpObject::createShared(JSContext* cx, Handle<RegExpObject*> regexp)
+/* static */ bool
+RegExpObject::createShared(JSContext* cx, Handle<RegExpObject*> regexp,
+                           MutableHandleRegExpShared shared)
 {
     MOZ_ASSERT(!regexp->hasShared());
     RootedAtom source(cx, regexp->getSource());
-    RegExpShared* shared = cx->zone()->regExps.get(cx, source, regexp->getFlags());
-    if (!shared)
-        return nullptr;
+    if (!cx->zone()->regExps.get(cx, source, regexp->getFlags(), shared))
+        return false;
 
     regexp->setShared(*shared);
-    return shared;
+    return true;
 }
 
 Shape*
 RegExpObject::assignInitialShape(JSContext* cx, Handle<RegExpObject*> self)
 {
     MOZ_ASSERT(self->empty());
 
     JS_STATIC_ASSERT(LAST_INDEX_SLOT == 0);
@@ -880,18 +883,18 @@ RegExpShared::dumpBytecode(JSContext* cx
 
     return true;
 }
 
 /* static */ bool
 RegExpObject::dumpBytecode(JSContext* cx, Handle<RegExpObject*> regexp,
                            bool match_only, HandleLinearString input)
 {
-    RootedRegExpShared shared(cx, getShared(cx, regexp));
-    if (!shared)
+    RootedRegExpShared shared(cx);
+    if (!getShared(cx, regexp, &shared))
         return false;
 
     return RegExpShared::dumpBytecode(cx, &shared, match_only, input);
 }
 #endif
 
 template <typename CharT>
 static MOZ_ALWAYS_INLINE bool
@@ -1281,45 +1284,49 @@ RegExpCompartment::sweep(JSRuntime* rt)
 
     if (optimizableRegExpInstanceShape_ &&
         IsAboutToBeFinalized(&optimizableRegExpInstanceShape_))
     {
         optimizableRegExpInstanceShape_.set(nullptr);
     }
 }
 
-RegExpShared*
-RegExpZone::get(JSContext* cx, HandleAtom source, RegExpFlag flags)
+bool
+RegExpZone::get(JSContext* cx, HandleAtom source, RegExpFlag flags,
+                MutableHandleRegExpShared result)
 {
     DependentAddPtr<Set> p(cx, set_, Key(source, flags));
-    if (p)
-        return *p;
+    if (p) {
+        result.set(*p);
+        return true;
+    }
 
     auto shared = Allocate<RegExpShared>(cx);
     if (!shared)
-        return nullptr;
+        return false;
 
     new (shared) RegExpShared(source, flags);
 
     if (!p.add(cx, set_, Key(source, flags), shared)) {
         ReportOutOfMemory(cx);
-        return nullptr;
+        return false;
     }
 
-    return shared;
+    result.set(shared);
+    return true;
 }
 
-RegExpShared*
-RegExpZone::get(JSContext* cx, HandleAtom atom, JSString* opt)
+bool
+RegExpZone::get(JSContext* cx, HandleAtom atom, JSString* opt, MutableHandleRegExpShared shared)
 {
     RegExpFlag flags = RegExpFlag(0);
     if (opt && !ParseRegExpFlags(cx, opt, &flags))
-        return nullptr;
+        return false;
 
-    return get(cx, atom, flags);
+    return get(cx, atom, flags, shared);
 }
 
 size_t
 RegExpZone::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     return set_.sizeOfExcludingThis(mallocSizeOf);
 }
 
@@ -1341,18 +1348,18 @@ js::CloneRegExpObject(JSContext* cx, JSO
         return nullptr;
     clone->initPrivate(nullptr);
 
     if (!EmptyShape::ensureInitialCustomShape<RegExpObject>(cx, clone))
         return nullptr;
 
     Rooted<JSAtom*> source(cx, regex->getSource());
 
-    RegExpShared* shared = RegExpObject::getShared(cx, regex);
-    if (!shared)
+    RootedRegExpShared shared(cx);
+    if (!RegExpObject::getShared(cx, regex, &shared))
         return nullptr;
 
     clone->initAndZeroLastIndex(source, shared->getFlags(), cx);
     clone->setShared(*shared);
 
     return clone;
 }
 
@@ -1481,20 +1488,20 @@ js::CloneScriptRegExpObject(JSContext* c
     RootedAtom source(cx, reobj.getSource());
     cx->markAtom(source);
 
     return RegExpObject::create(cx, source, reobj.getFlags(),
                                 nullptr, nullptr, cx->tempLifoAlloc(),
                                 TenuredObject);
 }
 
-JS_FRIEND_API(RegExpShared*)
-js::RegExpToSharedNonInline(JSContext* cx, HandleObject obj)
+JS_FRIEND_API(bool)
+js::RegExpToSharedNonInline(JSContext* cx, HandleObject obj, MutableHandleRegExpShared shared)
 {
-    return RegExpToShared(cx, obj);
+    return RegExpToShared(cx, obj, shared);
 }
 
 JS::ubi::Node::Size
 JS::ubi::Concrete<RegExpShared>::size(mozilla::MallocSizeOf mallocSizeOf) const
 {
     return js::gc::Arena::thingSize(gc::AllocKind::REGEXP_SHARED) +
         get().sizeOfExcludingThis(mallocSizeOf);
 }
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -138,17 +138,18 @@ class RegExpObject : public NativeObject
     bool ignoreCase() const { return getFlags() & IgnoreCaseFlag; }
     bool global() const     { return getFlags() & GlobalFlag; }
     bool multiline() const  { return getFlags() & MultilineFlag; }
     bool sticky() const     { return getFlags() & StickyFlag; }
     bool unicode() const    { return getFlags() & UnicodeFlag; }
 
     static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask);
 
-    static RegExpShared* getShared(JSContext* cx, Handle<RegExpObject*> regexp);
+    static MOZ_MUST_USE bool getShared(JSContext* cx, Handle<RegExpObject*> regexp,
+                                       MutableHandleRegExpShared shared);
 
     bool hasShared() {
         return !!sharedRef();
     }
 
     void setShared(RegExpShared& shared) {
         MOZ_ASSERT(!hasShared());
         sharedRef().init(&shared);
@@ -174,39 +175,40 @@ class RegExpObject : public NativeObject
                                           bool match_only, HandleLinearString input);
 #endif
 
   private:
     /*
      * Precondition: the syntax for |source| has already been validated.
      * Side effect: sets the private field.
      */
-    static RegExpShared* createShared(JSContext* cx, Handle<RegExpObject*> regexp);
+    static MOZ_MUST_USE bool createShared(JSContext* cx, Handle<RegExpObject*> regexp,
+                                          MutableHandleRegExpShared shared);
 
     /* Call setShared in preference to setPrivate. */
     void setPrivate(void* priv) = delete;
 };
 
 /*
  * Parse regexp flags. Report an error and return false if an invalid
  * sequence of flags is encountered (repeat/invalid flag).
  *
  * N.B. flagStr must be rooted.
  */
 bool
 ParseRegExpFlags(JSContext* cx, JSString* flagStr, RegExpFlag* flagsOut);
 
 /* Assuming GetBuiltinClass(obj) is ESClass::RegExp, return a RegExpShared for obj. */
-inline RegExpShared*
-RegExpToShared(JSContext* cx, HandleObject obj)
+inline bool
+RegExpToShared(JSContext* cx, HandleObject obj, MutableHandleRegExpShared shared)
 {
     if (obj->is<RegExpObject>())
-        return RegExpObject::getShared(cx, obj.as<RegExpObject>());
+        return RegExpObject::getShared(cx, obj.as<RegExpObject>(), shared);
 
-    return Proxy::regexp_toShared(cx, obj);
+    return Proxy::regexp_toShared(cx, obj, shared);
 }
 
 template<XDRMode mode>
 bool
 XDRScriptRegExpObject(XDRState<mode>* xdr, MutableHandle<RegExpObject*> objp);
 
 extern JSObject*
 CloneScriptRegExpObject(JSContext* cx, RegExpObject& re);
--- a/js/src/vm/RegExpShared.h
+++ b/js/src/vm/RegExpShared.h
@@ -268,20 +268,21 @@ class RegExpZone
     ~RegExpZone() {
         MOZ_ASSERT_IF(set_.initialized(), set_.empty());
     }
 
     bool init();
 
     bool empty() const { return set_.empty(); }
 
-    RegExpShared* get(JSContext* cx, HandleAtom source, RegExpFlag flags);
+    bool get(JSContext* cx, HandleAtom source, RegExpFlag flags, MutableHandleRegExpShared shared);
 
     /* Like 'get', but compile 'maybeOpt' (if non-null). */
-    RegExpShared* get(JSContext* cx, HandleAtom source, JSString* maybeOpt);
+    bool get(JSContext* cx, HandleAtom source, JSString* maybeOpt,
+             MutableHandleRegExpShared shared);
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
 class RegExpCompartment
 {
     /*
      * This is the template object where the result of re.exec() is based on,
--- a/js/src/vm/RegExpStatics.cpp
+++ b/js/src/vm/RegExpStatics.cpp
@@ -77,19 +77,19 @@ RegExpStatics::executeLazy(JSContext* cx
     if (!pendingLazyEvaluation)
         return true;
 
     MOZ_ASSERT(lazySource);
     MOZ_ASSERT(matchesInput);
     MOZ_ASSERT(lazyIndex != size_t(-1));
 
     /* Retrieve or create the RegExpShared in this zone. */
+    RootedRegExpShared shared(cx);
     RootedAtom source(cx, lazySource);
-    RootedRegExpShared shared(cx, cx->zone()->regExps.get(cx, source, lazyFlags));
-    if (!shared)
+    if (!cx->zone()->regExps.get(cx, source, lazyFlags, &shared))
         return false;
 
     /*
      * It is not necessary to call aboutToWrite(): evaluation of
      * implicit copies is safe.
      */
 
     /* Execute the full regular expression. */
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1484,18 +1484,18 @@ JSStructuredCloneWriter::startWrite(Hand
         if (backref)
             return true;
 
         ESClass cls;
         if (!GetBuiltinClass(context(), obj, &cls))
             return false;
 
         if (cls == ESClass::RegExp) {
-            RegExpShared* re = RegExpToShared(context(), obj);
-            if (!re)
+            RootedRegExpShared re(context());
+            if (!RegExpToShared(context(), obj, &re))
                 return false;
             return out.writePair(SCTAG_REGEXP_OBJECT, re->getFlags()) &&
                    writeString(SCTAG_STRING, re->getSource());
         } else if (cls == ESClass::Date) {
             RootedValue unboxed(context());
             if (!Unbox(context(), obj, &unboxed))
                 return false;
             return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(unboxed.toNumber());