diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 9004101e95..8294ca17dc 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -217,6 +217,10 @@ js::CreateRegExpMatchResult(JSContext* cx, RegExpShared& re, // Step 34b (reordered) // Set the |indices| property. if (hasIndices) { + fprintf(stderr, + "regexp indices store: arr=%p comp=%p zone=%p | indices=%p comp=%p zone=%p\n", + arr.get(), arr->compartment(), arr->zone(), + indices.get(), indices->compartment(), indices->zone()); arr->setSlot(3, ObjectValue(*indices)); } diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 3a0035a760..35d26a6778 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -859,8 +859,10 @@ class NativeObject : public ShapedObject // Check requirements on values stored to this object. MOZ_ALWAYS_INLINE void checkStoredValue(const Value& v) { - MOZ_ASSERT(IsObjectValueInCompartment(v, compartment())); - MOZ_ASSERT(AtomIsMarked(zoneFromAnyThread(), v)); + if (!IsObjectValueInCompartment(v, compartment())) + MOZ_CRASH("compartment mismatch"); + if (!AtomIsMarked(zoneFromAnyThread(), v)) + MOZ_CRASH("AtomIsMarked failed"); } MOZ_ALWAYS_INLINE void setSlot(uint32_t slot, const Value& value) { diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 57c58ff2eb..faba7b0510 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -1297,11 +1297,12 @@ RegExpShared::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) /* RegExpCompartment */ RegExpCompartment::RegExpCompartment(Zone* zone) - : optimizableRegExpPrototypeShape_(nullptr), + : perCompartment_(zone), + optimizableRegExpPrototypeShape_(nullptr), optimizableRegExpInstanceShape_(nullptr) { - for (auto& templateObj : matchResultTemplateObjects_) { - templateObj = nullptr; + { + MOZ_ALWAYS_TRUE(perCompartment_.init(4)); } } @@ -1311,9 +1312,30 @@ RegExpCompartment::~RegExpCompartment() } ArrayObject* -RegExpCompartment::createMatchResultTemplateObject(JSContext* cx, ResultTemplateKind kind) +RegExpCompartment::getOrCreateMatchResultTemplateObject(JSContext* cx, ResultTemplateKind kind) { - MOZ_ASSERT(!matchResultTemplateObjects_[kind]); + JSCompartment* comp = cx->compartment(); + + auto p = perCompartment_.lookupForAdd(comp); + if (!p) { + PerCompartmentData init; + if (!perCompartment_.add(p, comp, init)) + return nullptr; + } + + PerCompartmentData& data = p->value(); + if (data.matchResultTemplateObjects_[kind]) + return data.matchResultTemplateObjects_[kind]; + + return createMatchResultTemplateObject(cx, kind, data); +} + +ArrayObject* +RegExpCompartment::createMatchResultTemplateObject(JSContext* cx, + ResultTemplateKind kind, + PerCompartmentData& data) +{ + MOZ_ASSERT(!data.matchResultTemplateObjects_[kind]); /* Create template array object */ RootedArrayObject templateObject(cx, NewDenseUnallocatedArray(cx, RegExpObject::MaxPairCount, @@ -1337,8 +1359,8 @@ RegExpCompartment::createMatchResultTemplateObject(JSContext* cx, ResultTemplate return nullptr; } AddTypePropertyId(cx, templateObject, NameToId(cx->names().groups), TypeSet::AnyObjectType()); - matchResultTemplateObjects_[kind].set(templateObject); - return matchResultTemplateObjects_[kind]; + data.matchResultTemplateObjects_[kind].set(templateObject); + return data.matchResultTemplateObjects_[kind]; } /* Set dummy index property */ @@ -1377,9 +1399,8 @@ RegExpCompartment::createMatchResultTemplateObject(JSContext* cx, ResultTemplate AddTypePropertyId(cx, templateObject, NameToId(cx->names().indices), TypeSet::AnyObjectType()); } - matchResultTemplateObjects_[kind].set(templateObject); - - return matchResultTemplateObjects_[kind]; + data.matchResultTemplateObjects_[kind].set(templateObject); + return data.matchResultTemplateObjects_[kind]; } bool @@ -1397,22 +1418,21 @@ RegExpCompartment::init(JSContext* cx) void RegExpCompartment::sweep(JSRuntime* rt) { - for (auto& templateObject : matchResultTemplateObjects_) { - if (templateObject && IsAboutToBeFinalized(&templateObject)) { - templateObject.set(nullptr); - } - } + for (auto iter = perCompartment_.all(); !iter.empty(); iter.popFront()) { + PerCompartmentData& data = iter.front().value(); - if (optimizableRegExpPrototypeShape_ && - IsAboutToBeFinalized(&optimizableRegExpPrototypeShape_)) - { - optimizableRegExpPrototypeShape_.set(nullptr); - } + for (auto& templateObject : data.matchResultTemplateObjects_) { + if (templateObject && IsAboutToBeFinalized(&templateObject)) + templateObject.set(nullptr); + } - if (optimizableRegExpInstanceShape_ && - IsAboutToBeFinalized(&optimizableRegExpInstanceShape_)) - { - optimizableRegExpInstanceShape_.set(nullptr); + if (data.optimizableRegExpPrototypeShape_ && + IsAboutToBeFinalized(&data.optimizableRegExpPrototypeShape_)) + data.optimizableRegExpPrototypeShape_.set(nullptr); + + if (data.optimizableRegExpInstanceShape_ && + IsAboutToBeFinalized(&data.optimizableRegExpInstanceShape_)) + data.optimizableRegExpInstanceShape_.set(nullptr); } } diff --git a/js/src/vm/RegExpShared.h b/js/src/vm/RegExpShared.h index 941dca7f45..58ff907e8a 100644 --- a/js/src/vm/RegExpShared.h +++ b/js/src/vm/RegExpShared.h @@ -12,6 +12,7 @@ #ifndef vm_RegExpShared_h #define vm_RegExpShared_h +#include "js/GCHashTable.h" #include "mozilla/Assertions.h" #include "mozilla/MemoryReporting.h" @@ -22,6 +23,7 @@ #include "gc/Barrier.h" #include "gc/Heap.h" #include "gc/Marking.h" +#include "jsalloc.h" #include "js/UbiNode.h" #include "js/Vector.h" #include "irregexp/InfallibleVector.h" @@ -310,23 +312,31 @@ public: enum ResultTemplateKind { Normal, WithIndices, Indices, NumKinds }; private: - /* - * The template objects that the result of re.exec() is based on, if - * there is a result. These are used in CreateRegExpMatchResult. - * There are three template objects, each of which is an ArrayObject - * with some additional properties. We decide which to use based on - * the |hasIndices| (/d) flag. - * - * Normal: Has |index|, |input|, and |groups| properties. - * Used for the result object if |hasIndices| is not set. - * - * WithIndices: Has |index|, |input|, |groups|, and |indices| properties. - * Used for the result object if |hasIndices| is set. - * - * Indices: Has a |groups| property. If |hasIndices| is set, used - * for the |.indices| property of the result object. - */ - ReadBarriered matchResultTemplateObjects_[ResultTemplateKind::NumKinds]; + +struct PerCompartmentData { + ReadBarriered matchResultTemplateObjects_[NumKinds]; + ReadBarriered optimizableRegExpPrototypeShape_; + ReadBarriered optimizableRegExpInstanceShape_; + + PerCompartmentData() + : optimizableRegExpPrototypeShape_(nullptr), + optimizableRegExpInstanceShape_(nullptr) + { + for (auto& t : matchResultTemplateObjects_) + t = nullptr; + } + }; + + using PerCompartmentMap = + GCHashMap, + ZoneAllocPolicy>; + + PerCompartmentMap perCompartment_; // <-- add this + + ArrayObject* createMatchResultTemplateObject(JSContext* cx, + ResultTemplateKind kind, + PerCompartmentData& data); /* * The shape of RegExp.prototype object that satisfies following: @@ -349,19 +359,13 @@ private: */ ReadBarriered optimizableRegExpInstanceShape_; - ArrayObject* createMatchResultTemplateObject(JSContext* cx, ResultTemplateKind kind); - public: explicit RegExpCompartment(Zone* zone); void sweep(JSRuntime* rt); - /* Get or create template object used to base the result of .exec() on. */ - ArrayObject* getOrCreateMatchResultTemplateObject(JSContext* cx, ResultTemplateKind kind = ResultTemplateKind::Normal) { - if (matchResultTemplateObjects_[kind]) - return matchResultTemplateObjects_[kind]; - return createMatchResultTemplateObject(cx, kind); - } + ArrayObject* getOrCreateMatchResultTemplateObject(JSContext* cx, + ResultTemplateKind kind = Normal); Shape* getOptimizableRegExpPrototypeShape() { return optimizableRegExpPrototypeShape_;