Bug 1378740 - Share RegExpShareds across compartments within a zone. r=jonco
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 06 Jul 2017 16:40:39 +0200
changeset 367621 a47b92874b2b4a0cee64c11162f9899c810df745
parent 367620 650dc5fb7e7f2a4d3c5bef9543ed7abb69eef584
child 367622 42a708048bf711aa7bfb8f7f57bb15dcc7e6de92
push id92279
push userjandemooij@gmail.com
push dateThu, 06 Jul 2017 14:41:24 +0000
treeherdermozilla-inbound@a47b92874b2b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1378740
milestone56.0a1
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
Bug 1378740 - Share RegExpShareds across compartments within a zone. r=jonco
js/public/MemoryMetrics.h
js/src/builtin/RegExp.cpp
js/src/gc/Zone.cpp
js/src/gc/Zone.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/vm/MemoryMetrics.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/RegExpShared.h
js/src/vm/RegExpStatics.cpp
js/src/vm/TypeInference.cpp
js/xpconnect/src/XPCJSRuntime.cpp
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -644,16 +644,17 @@ struct ZoneStats
     macro(Other,   GCHeapUsed,  jitCodesGCHeap) \
     macro(Other,   GCHeapUsed,  objectGroupsGCHeap) \
     macro(Other,   MallocHeap,  objectGroupsMallocHeap) \
     macro(Other,   GCHeapUsed,  scopesGCHeap) \
     macro(Other,   MallocHeap,  scopesMallocHeap) \
     macro(Other,   GCHeapUsed,  regExpSharedsGCHeap) \
     macro(Other,   MallocHeap,  regExpSharedsMallocHeap) \
     macro(Other,   MallocHeap,  typePool) \
+    macro(Other,   MallocHeap,  regexpZone) \
     macro(Other,   MallocHeap,  jitZone) \
     macro(Other,   MallocHeap,  baselineStubsOptimized) \
     macro(Other,   MallocHeap,  cachedCFG) \
     macro(Other,   MallocHeap,  uniqueIdMap) \
     macro(Other,   MallocHeap,  shapeTables)
 
     ZoneStats()
       : FOR_EACH_SIZE(ZERO_SIZE)
@@ -765,17 +766,16 @@ struct CompartmentStats
     macro(Other,   MallocHeap, typeInferenceArrayTypeTables) \
     macro(Other,   MallocHeap, typeInferenceObjectTypeTables) \
     macro(Other,   MallocHeap, compartmentObject) \
     macro(Other,   MallocHeap, compartmentTables) \
     macro(Other,   MallocHeap, innerViewsTable) \
     macro(Other,   MallocHeap, lazyArrayBuffersTable) \
     macro(Other,   MallocHeap, objectMetadataTable) \
     macro(Other,   MallocHeap, crossCompartmentWrappersTable) \
-    macro(Other,   MallocHeap, regexpCompartment) \
     macro(Other,   MallocHeap, savedStacksSet) \
     macro(Other,   MallocHeap, varNamesSet) \
     macro(Other,   MallocHeap, nonSyntacticLexicalScopesTable) \
     macro(Other,   MallocHeap, templateLiteralMap) \
     macro(Other,   MallocHeap, jitCompartment) \
     macro(Other,   MallocHeap, privateData)
 
     CompartmentStats()
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -230,17 +230,17 @@ RegExpInitializeIgnoringLastIndex(JSCont
         /* Step 5. */
         if (!ParseRegExpFlags(cx, flagStr, &flags))
             return false;
     }
 
     if (sharedUse == UseRegExpShared) {
         /* Steps 7-8. */
         RootedRegExpShared re(cx);
-        if (!cx->compartment()->regExps.get(cx, pattern, flags, &re))
+        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. */
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -34,16 +34,17 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup*
     gcWeakMapList_(group),
     compartments_(),
     gcGrayRoots_(group),
     gcWeakRefs_(group),
     weakCaches_(group),
     gcWeakKeys_(group, SystemAllocPolicy(), rt->randomHashCodeScrambler()),
     gcSweepGroupEdges_(group),
     typeDescrObjects_(group, this),
+    regExps(this),
     markedAtoms_(group),
     atomCache_(group),
     externalStringCache_(group),
     usage(&rt->gc.usage),
     threshold(),
     gcDelayBytes(0),
     propertyTree_(group, this),
     baseShapes_(group, this),
@@ -88,17 +89,18 @@ Zone::~Zone()
 bool Zone::init(bool isSystemArg)
 {
     isSystem = isSystemArg;
     return uniqueIds().init() &&
            gcSweepGroupEdges().init() &&
            gcWeakKeys().init() &&
            typeDescrObjects().init() &&
            markedAtoms().init() &&
-           atomCache().init();
+           atomCache().init() &&
+           regExps.init();
 }
 
 void
 Zone::setNeedsIncrementalBarrier(bool needs)
 {
     MOZ_ASSERT_IF(needs && isAtomsZone(),
                   !runtimeFromActiveCooperatingThread()->hasHelperThreadZones());
     MOZ_ASSERT_IF(needs, canCollect());
@@ -339,16 +341,18 @@ Zone::nextZone() const
 {
     MOZ_ASSERT(isOnList());
     return listNext_;
 }
 
 void
 Zone::clearTables()
 {
+    MOZ_ASSERT(regExps.empty());
+
     if (baseShapes().initialized())
         baseShapes().clear();
     if (initialShapes().initialized())
         initialShapes().clear();
 }
 
 void
 Zone::fixupAfterMovingGC()
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -13,16 +13,17 @@
 #include "jscntxt.h"
 
 #include "ds/SplayTree.h"
 #include "gc/FindSCCs.h"
 #include "gc/GCRuntime.h"
 #include "js/GCHashTable.h"
 #include "js/TracingAPI.h"
 #include "vm/MallocProvider.h"
+#include "vm/RegExpShared.h"
 #include "vm/TypeInference.h"
 
 namespace js {
 
 namespace jit {
 class JitZone;
 } // namespace jit
 
@@ -173,16 +174,17 @@ struct Zone : public JS::shadow::Zone,
     }
 
     void findOutgoingEdges(js::gc::ZoneComponentFinder& finder);
 
     void discardJitCode(js::FreeOp* fop, bool discardBaselineCode = true);
 
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 size_t* typePool,
+                                size_t* regexpZone,
                                 size_t* jitZone,
                                 size_t* baselineStubsOptimized,
                                 size_t* cachedCFG,
                                 size_t* uniqueIdMap,
                                 size_t* shapeTables,
                                 size_t* atomsMarkBitmaps);
 
     // Iterate over all cells in the zone. See the definition of ZoneCellIter
@@ -391,16 +393,18 @@ struct Zone : public JS::shadow::Zone,
     // a free.
     js::gc::MemoryCounter<Zone> gcMallocCounter;
 
     // Counter of JIT code executable memory for GC scheduling. Also imprecise,
     // since wasm can generate code that outlives a zone.
     js::gc::MemoryCounter<Zone> jitCodeCounter;
 
   public:
+    js::RegExpZone regExps;
+
     JS::WeakCache<TypeDescrObjectSet>& typeDescrObjects() { return typeDescrObjects_.ref(); }
 
     bool addTypeDescrObject(JSContext* cx, HandleObject obj);
 
     bool triggerGCForTooMuchMalloc() {
         JSRuntime* rt = runtimeFromAnyThread();
 
         if (CurrentThreadCanAccessRuntime(rt))
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -149,19 +149,16 @@ JSCompartment::init(JSContext* maybecx)
     JS::ResetTimeZone();
 
     if (!crossCompartmentWrappers.init(0)) {
         if (maybecx)
             ReportOutOfMemory(maybecx);
         return false;
     }
 
-    if (!regExps.init(maybecx))
-        return false;
-
     enumerators = NativeIterator::allocateSentinel(maybecx);
     if (!enumerators)
         return false;
 
     if (!savedStacks_.init() || !varNames_.init() || !templateLiteralMap_.init()) {
         if (maybecx)
             ReportOutOfMemory(maybecx);
         return false;
@@ -1083,17 +1080,16 @@ JSCompartment::clearTables()
 
     // No scripts should have run in this compartment. This is used when
     // merging a compartment that has been used off thread into another
     // compartment and zone.
     MOZ_ASSERT(crossCompartmentWrappers.empty());
     MOZ_ASSERT(!jitCompartment_);
     MOZ_ASSERT(!debugEnvs);
     MOZ_ASSERT(enumerators->next() == enumerators);
-    MOZ_ASSERT(regExps.empty());
     MOZ_ASSERT(templateLiteralMap_.empty());
 
     objectGroups.clearTables();
     if (savedStacks_.initialized())
         savedStacks_.clear();
     if (varNames_.initialized())
         varNames_.clear();
 }
@@ -1364,17 +1360,16 @@ JSCompartment::addSizeOfIncludingThis(mo
                                       size_t* tiArrayTypeTables,
                                       size_t* tiObjectTypeTables,
                                       size_t* compartmentObject,
                                       size_t* compartmentTables,
                                       size_t* innerViewsArg,
                                       size_t* lazyArrayBuffersArg,
                                       size_t* objectMetadataTablesArg,
                                       size_t* crossCompartmentWrappersArg,
-                                      size_t* regexpCompartment,
                                       size_t* savedStacksSet,
                                       size_t* varNamesSet,
                                       size_t* nonSyntacticLexicalEnvironmentsArg,
                                       size_t* templateLiteralMap,
                                       size_t* jitCompartment,
                                       size_t* privateData)
 {
     *compartmentObject += mallocSizeOf(this);
@@ -1383,17 +1378,16 @@ JSCompartment::addSizeOfIncludingThis(mo
                                         compartmentTables);
     wasm.addSizeOfExcludingThis(mallocSizeOf, compartmentTables);
     *innerViewsArg += innerViews.sizeOfExcludingThis(mallocSizeOf);
     if (lazyArrayBuffers)
         *lazyArrayBuffersArg += lazyArrayBuffers->sizeOfIncludingThis(mallocSizeOf);
     if (objectMetadataTable)
         *objectMetadataTablesArg += objectMetadataTable->sizeOfIncludingThis(mallocSizeOf);
     *crossCompartmentWrappersArg += crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf);
-    *regexpCompartment += regExps.sizeOfExcludingThis(mallocSizeOf);
     *savedStacksSet += savedStacks_.sizeOfExcludingThis(mallocSizeOf);
     *varNamesSet += varNames_.sizeOfExcludingThis(mallocSizeOf);
     if (nonSyntacticLexicalEnvironments_)
         *nonSyntacticLexicalEnvironmentsArg +=
             nonSyntacticLexicalEnvironments_->sizeOfIncludingThis(mallocSizeOf);
     *templateLiteralMap += templateLiteralMap_.sizeOfExcludingThis(mallocSizeOf);
     if (jitCompartment_)
         *jitCompartment += jitCompartment_->sizeOfIncludingThis(mallocSizeOf);
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -731,17 +731,16 @@ struct JSCompartment
                                 size_t* tiArrayTypeTables,
                                 size_t* tiObjectTypeTables,
                                 size_t* compartmentObject,
                                 size_t* compartmentTables,
                                 size_t* innerViews,
                                 size_t* lazyArrayBuffers,
                                 size_t* objectMetadataTables,
                                 size_t* crossCompartmentWrappers,
-                                size_t* regexpCompartment,
                                 size_t* savedStacksSet,
                                 size_t* varNamesSet,
                                 size_t* nonSyntacticLexicalScopes,
                                 size_t* templateLiteralMap,
                                 size_t* jitCompartment,
                                 size_t* privateData);
 
     // Object group tables and other state in the compartment.
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -472,17 +472,17 @@ CrossCompartmentWrapper::regexp_toShared
         AutoCompartment call(cx, wrappedObject(wrapper));
         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->compartment()->regExps.get(cx, source, re->getFlags(), shared);
+    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/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -318,16 +318,17 @@ StatsZoneCallback(JSRuntime* rt, void* d
     ZoneStats& zStats = rtStats->zoneStatsVector.back();
     if (!zStats.initStrings(rt))
         MOZ_CRASH("oom");
     rtStats->initExtraZoneStats(zone, &zStats);
     rtStats->currZoneStats = &zStats;
 
     zone->addSizeOfIncludingThis(rtStats->mallocSizeOf_,
                                  &zStats.typePool,
+                                 &zStats.regexpZone,
                                  &zStats.jitZone,
                                  &zStats.baselineStubsOptimized,
                                  &zStats.cachedCFG,
                                  &zStats.uniqueIdMap,
                                  &zStats.shapeTables,
                                  &rtStats->runtime.atomsMarkBitmaps);
 }
 
@@ -352,17 +353,16 @@ StatsCompartmentCallback(JSContext* cx, 
                                         &cStats.typeInferenceArrayTypeTables,
                                         &cStats.typeInferenceObjectTypeTables,
                                         &cStats.compartmentObject,
                                         &cStats.compartmentTables,
                                         &cStats.innerViewsTable,
                                         &cStats.lazyArrayBuffersTable,
                                         &cStats.objectMetadataTable,
                                         &cStats.crossCompartmentWrappersTable,
-                                        &cStats.regexpCompartment,
                                         &cStats.savedStacksSet,
                                         &cStats.varNamesSet,
                                         &cStats.nonSyntacticLexicalScopesTable,
                                         &cStats.templateLiteralMap,
                                         &cStats.jitCompartment,
                                         &cStats.privateData);
 }
 
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -276,17 +276,17 @@ RegExpObject::create(JSContext* cx, Hand
 }
 
 /* static */ bool
 RegExpObject::createShared(JSContext* cx, Handle<RegExpObject*> regexp,
                            MutableHandleRegExpShared shared)
 {
     MOZ_ASSERT(!regexp->hasShared());
     RootedAtom source(cx, regexp->getSource());
-    if (!cx->compartment()->regExps.get(cx, source, regexp->getFlags(), shared))
+    if (!cx->zone()->regExps.get(cx, source, regexp->getFlags(), shared))
         return false;
 
     regexp->setShared(*shared);
     return true;
 }
 
 Shape*
 RegExpObject::assignInitialShape(JSContext* cx, Handle<RegExpObject*> self)
@@ -1189,27 +1189,21 @@ RegExpShared::sizeOfExcludingThis(mozill
         n += mallocSizeOf(tables[i]);
 
     return n;
 }
 
 /* RegExpCompartment */
 
 RegExpCompartment::RegExpCompartment(Zone* zone)
-  : set_(zone, zone->runtimeFromActiveCooperatingThread()),
-    matchResultTemplateObject_(nullptr),
+  : matchResultTemplateObject_(nullptr),
     optimizableRegExpPrototypeShape_(nullptr),
     optimizableRegExpInstanceShape_(nullptr)
 {}
 
-RegExpCompartment::~RegExpCompartment()
-{
-    MOZ_ASSERT_IF(set_.initialized(), set_.empty());
-}
-
 ArrayObject*
 RegExpCompartment::createMatchResultTemplateObject(JSContext* cx)
 {
     MOZ_ASSERT(!matchResultTemplateObject_);
 
     /* Create template array object */
     RootedArrayObject templateObject(cx, NewDenseUnallocatedArray(cx, RegExpObject::MaxPairCount,
                                                                   nullptr, TenuredObject));
@@ -1252,23 +1246,20 @@ RegExpCompartment::createMatchResultTemp
     AddTypePropertyId(cx, templateObject, JSID_VOID, TypeSet::UndefinedType());
 
     matchResultTemplateObject_.set(templateObject);
 
     return matchResultTemplateObject_;
 }
 
 bool
-RegExpCompartment::init(JSContext* cx)
+RegExpZone::init()
 {
-    if (!set_.init(0)) {
-        if (cx)
-            ReportOutOfMemory(cx);
+    if (!set_.init(0))
         return false;
-    }
 
     return true;
 }
 
 void
 RegExpCompartment::sweep(JSRuntime* rt)
 {
     if (matchResultTemplateObject_ &&
@@ -1286,18 +1277,18 @@ RegExpCompartment::sweep(JSRuntime* rt)
     if (optimizableRegExpInstanceShape_ &&
         IsAboutToBeFinalized(&optimizableRegExpInstanceShape_))
     {
         optimizableRegExpInstanceShape_.set(nullptr);
     }
 }
 
 bool
-RegExpCompartment::get(JSContext* cx, HandleAtom source, RegExpFlag flags,
-                       MutableHandleRegExpShared result)
+RegExpZone::get(JSContext* cx, HandleAtom source, RegExpFlag flags,
+                MutableHandleRegExpShared result)
 {
     DependentAddPtr<Set> p(cx, set_, Key(source, flags));
     if (p) {
         result.set(*p);
         return true;
     }
 
     auto shared = Allocate<RegExpShared>(cx);
@@ -1311,32 +1302,35 @@ RegExpCompartment::get(JSContext* cx, Ha
         return false;
     }
 
     result.set(shared);
     return true;
 }
 
 bool
-RegExpCompartment::get(JSContext* cx, HandleAtom atom, JSString* opt,
-                       MutableHandleRegExpShared shared)
+RegExpZone::get(JSContext* cx, HandleAtom atom, JSString* opt, MutableHandleRegExpShared shared)
 {
     RegExpFlag flags = RegExpFlag(0);
     if (opt && !ParseRegExpFlags(cx, opt, &flags))
         return false;
 
     return get(cx, atom, flags, shared);
 }
 
 size_t
-RegExpCompartment::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
+RegExpZone::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     return set_.sizeOfExcludingThis(mallocSizeOf);
 }
 
+RegExpZone::RegExpZone(Zone* zone)
+  : set_(zone, zone->runtimeFromActiveCooperatingThread())
+{}
+
 /* Functions */
 
 JSObject*
 js::CloneRegExpObject(JSContext* cx, JSObject* obj_)
 {
     Rooted<RegExpObject*> regex(cx, &obj_->as<RegExpObject>());
 
     // Unlike RegExpAlloc, all clones must use |regex|'s group.
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -29,18 +29,18 @@ namespace JS { struct Zone; }
  *
  * There are several engine concepts associated with a single logical regexp:
  *
  *   RegExpObject:
  *     The JS-visible object whose .[[Class]] equals "RegExp".
  *   RegExpShared:
  *     The compiled representation of the regexp (lazily created, cleared
  *     during some forms of GC).
- *   RegExpCompartment:
- *     Owns all RegExpShared instances in a compartment.
+ *   RegExpZone:
+ *     Owns all RegExpShared instances in a zone.
  */
 namespace js {
 
 struct MatchPair;
 class MatchPairs;
 class RegExpStatics;
 
 namespace frontend { class TokenStream; }
--- a/js/src/vm/RegExpShared.h
+++ b/js/src/vm/RegExpShared.h
@@ -14,20 +14,22 @@
 
 #include "mozilla/Assertions.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "jsalloc.h"
 #include "jsatom.h"
 
 #include "builtin/SelfHostingDefines.h"
+#include "gc/Barrier.h"
 #include "gc/Heap.h"
 #include "gc/Marking.h"
 #include "js/UbiNode.h"
 #include "js/Vector.h"
+#include "vm/ArrayObject.h"
 
 struct JSContext;
 
 namespace js {
 
 class ArrayObject;
 class MatchPairs;
 class RegExpCompartment;
@@ -90,18 +92,18 @@ class RegExpShared : public gc::TenuredC
     };
 
     enum ForceByteCodeEnum {
         DontForceByteCode,
         ForceByteCode
     };
 
   private:
-    friend class RegExpCompartment;
     friend class RegExpStatics;
+    friend class RegExpZone;
 
     struct RegExpCompilation
     {
         ReadBarriered<jit::JitCode*> jitCode;
         uint8_t* byteCode;
 
         RegExpCompilation() : byteCode(nullptr) {}
 
@@ -222,17 +224,17 @@ class RegExpShared : public gc::TenuredC
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
 #ifdef DEBUG
     static bool dumpBytecode(JSContext* cx, MutableHandleRegExpShared res, bool match_only,
                              HandleLinearString input);
 #endif
 };
 
-class RegExpCompartment
+class RegExpZone
 {
     struct Key {
         JSAtom* atom;
         uint16_t flag;
 
         Key() {}
         Key(JSAtom* atom, RegExpFlag flag)
           : atom(atom), flag(flag)
@@ -247,22 +249,44 @@ class RegExpCompartment
             return DefaultHasher<JSAtom*>::hash(l.atom) ^ (l.flag << 1);
         }
         static bool match(Key l, Key r) {
             return l.atom == r.atom && l.flag == r.flag;
         }
     };
 
     /*
-     * The set of all RegExpShareds in the compartment. On every GC, every
-     * RegExpShared that was not marked is deleted and removed from the set.
+     * The set of all RegExpShareds in the zone. On every GC, every RegExpShared
+     * that was not marked is deleted and removed from the set.
      */
     using Set = JS::WeakCache<JS::GCHashSet<ReadBarriered<RegExpShared*>, Key, RuntimeAllocPolicy>>;
     Set set_;
 
+  public:
+    explicit RegExpZone(Zone* zone);
+
+    ~RegExpZone() {
+        MOZ_ASSERT_IF(set_.initialized(), set_.empty());
+    }
+
+    bool init();
+
+    bool empty() const { return set_.empty(); }
+
+    bool get(JSContext* cx, HandleAtom source, RegExpFlag flags, MutableHandleRegExpShared shared);
+
+    /* Like 'get', but compile 'maybeOpt' (if non-null). */
+    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,
      * if there is a result. This is used in CreateRegExpMatchResult to set
      * the input/index properties faster.
      */
     ReadBarriered<ArrayObject*> matchResultTemplateObject_;
 
     /*
@@ -285,29 +309,19 @@ class RegExpCompartment
      *   * prototype is RegExp.prototype
      */
     ReadBarriered<Shape*> optimizableRegExpInstanceShape_;
 
     ArrayObject* createMatchResultTemplateObject(JSContext* cx);
 
   public:
     explicit RegExpCompartment(Zone* zone);
-    ~RegExpCompartment();
 
-    bool init(JSContext* cx);
     void sweep(JSRuntime* rt);
 
-    bool empty() { return set_.empty(); }
-
-    bool get(JSContext* cx, HandleAtom source, RegExpFlag flags, MutableHandleRegExpShared shared);
-
-    /* Like 'get', but compile 'maybeOpt' (if non-null). */
-    bool get(JSContext* cx, HandleAtom source, JSString* maybeOpt,
-             MutableHandleRegExpShared shared);
-
     /* Get or create template object used to base the result of .exec() on. */
     ArrayObject* getOrCreateMatchResultTemplateObject(JSContext* cx) {
         if (matchResultTemplateObject_)
             return matchResultTemplateObject_;
         return createMatchResultTemplateObject(cx);
     }
 
     Shape* getOptimizableRegExpPrototypeShape() {
@@ -324,18 +338,16 @@ class RegExpCompartment
     }
 
     static size_t offsetOfOptimizableRegExpPrototypeShape() {
         return offsetof(RegExpCompartment, optimizableRegExpPrototypeShape_);
     }
     static size_t offsetOfOptimizableRegExpInstanceShape() {
         return offsetof(RegExpCompartment, optimizableRegExpInstanceShape_);
     }
-
-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
 } /* namespace js */
 
 namespace JS {
 namespace ubi {
 
 template <>
--- a/js/src/vm/RegExpStatics.cpp
+++ b/js/src/vm/RegExpStatics.cpp
@@ -76,20 +76,20 @@ 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 compartment. */
+    /* Retrieve or create the RegExpShared in this zone. */
     RootedRegExpShared shared(cx);
     RootedAtom source(cx, lazySource);
-    if (!cx->compartment()->regExps.get(cx, source, lazyFlags, &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/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -4485,24 +4485,26 @@ void
 TypeScript::destroy()
 {
     js_delete(this);
 }
 
 void
 Zone::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                              size_t* typePool,
+                             size_t* regexpZone,
                              size_t* jitZone,
                              size_t* baselineStubsOptimized,
                              size_t* cachedCFG,
                              size_t* uniqueIdMap,
                              size_t* shapeTables,
                              size_t* atomsMarkBitmaps)
 {
     *typePool += types.typeLifoAlloc().sizeOfExcludingThis(mallocSizeOf);
+    *regexpZone += regExps.sizeOfExcludingThis(mallocSizeOf);
     if (jitZone_)
         jitZone_->addSizeOfIncludingThis(mallocSizeOf, jitZone, baselineStubsOptimized, cachedCFG);
     *uniqueIdMap += uniqueIds().sizeOfExcludingThis(mallocSizeOf);
     *shapeTables += baseShapes().sizeOfExcludingThis(mallocSizeOf)
                   + initialShapes().sizeOfExcludingThis(mallocSizeOf);
     *atomsMarkBitmaps += markedAtoms().sizeOfExcludingThis(mallocSizeOf);
 }
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1395,16 +1395,20 @@ ReportZoneStats(const JS::ZoneStats& zSt
     ZCREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("regexp-shareds/malloc-heap"),
         zStats.regExpSharedsMallocHeap,
         "Shared compiled regexp data.");
 
     ZCREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("type-pool"),
         zStats.typePool,
         "Type sets and related data.");
 
+    ZCREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("regexp-zone"),
+        zStats.regexpZone,
+        "The regexp zone and regexp data.");
+
     ZCREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("jit-zone"),
         zStats.jitZone,
         "The JIT zone.");
 
     ZCREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("baseline/optimized-stubs"),
         zStats.baselineStubsOptimized,
         "The Baseline JIT's optimized IC stubs (excluding code).");
 
@@ -1793,20 +1797,16 @@ ReportCompartmentStats(const JS::Compart
     ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("object-metadata"),
         cStats.objectMetadataTable,
         "The table used by debugging tools for tracking object metadata");
 
     ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("cross-compartment-wrapper-table"),
         cStats.crossCompartmentWrappersTable,
         "The cross-compartment wrapper table.");
 
-    ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("regexp-compartment"),
-        cStats.regexpCompartment,
-        "The regexp compartment and regexp data.");
-
     ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("saved-stacks-set"),
         cStats.savedStacksSet,
         "The saved stacks set.");
 
     ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("non-syntactic-lexical-scopes-table"),
         cStats.nonSyntacticLexicalScopesTable,
         "The non-syntactic lexical scopes table.");