Commit 38a48a48 authored by Ryan VanderMeulen's avatar Ryan VanderMeulen
Browse files

Backed out 4 changesets (bug 816784) for intermittent GC crashes.

Backed out changeset 9a553b9dc922 (bug 816784)
Backed out changeset ac4a48a831ce (bug 816784)
Backed out changeset e80197b11567 (bug 816784)
Backed out changeset 7e8f428a3edf (bug 816784)
parent 1750525a
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -9651,7 +9651,8 @@ public:
                                                                  : js::NukeWindowReferences);
        } else {
          // We only want to nuke wrappers for the chrome->content case
          js::NukeCrossCompartmentWrappers(cx, BrowserCompartmentMatcher(), cpt,
          js::NukeCrossCompartmentWrappers(cx, BrowserCompartmentMatcher(),
                                           js::SingleCompartment(cpt),
                                           win->IsInnerWindow() ? js::DontNukeWindowReferences
                                                                : js::NukeWindowReferences,
                                           js::NukeIncomingReferences);
+0 −2
Original line number Diff line number Diff line
@@ -231,8 +231,6 @@ var ignoreFunctions = {
    // The big hammers.
    "PR_GetCurrentThread" : true,
    "calloc" : true,

    "uint8 nsContentUtils::IsExpandedPrincipal(nsIPrincipal*)" : true,
};

function extraGCFunctions() {
+0 −1
Original line number Diff line number Diff line
@@ -87,7 +87,6 @@ class NurseryAwareHashMap
    using Lookup = typename MapType::Lookup;
    using Ptr = typename MapType::Ptr;
    using Range = typename MapType::Range;
    using Entry = typename MapType::Entry;

    explicit NurseryAwareHashMap(AllocPolicy a = AllocPolicy()) : map(a) {}

+2 −2
Original line number Diff line number Diff line
@@ -681,9 +681,9 @@ JSCompartment::traceOutgoingCrossCompartmentWrappers(JSTracer* trc)
    MOZ_ASSERT(JS::CurrentThreadIsHeapMajorCollecting());
    MOZ_ASSERT(!zone()->isCollectingFromAnyThread() || trc->runtime()->gc.isHeapCompacting());

    for (NonStringWrapperEnum e(this); !e.empty(); e.popFront()) {
        if (e.front().key().is<JSObject*>()) {
    for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
        Value v = e.front().value().unbarrieredGet();
        if (e.front().key().is<JSObject*>()) {
            ProxyObject* wrapper = &v.toObject().as<ProxyObject>();

            /*
+7 −195
Original line number Diff line number Diff line
@@ -184,11 +184,15 @@ class CrossCompartmentKey
        return wrapped.match(matcher);
    }

    // Valid for JSObject* and Debugger keys. Crashes immediately if used on a
    // JSString* key.
    JSCompartment* compartment() {
        struct GetCompartmentFunctor {
            JSCompartment* operator()(JSObject** tp) const { return (*tp)->compartment(); }
            JSCompartment* operator()(JSScript** tp) const { return (*tp)->compartment(); }
            JSCompartment* operator()(JSString** tp) const { return nullptr; }
            JSCompartment* operator()(JSString** tp) const {
                MOZ_CRASH("invalid ccw key"); return nullptr;
            }
        };
        return applyToWrapped(GetCompartmentFunctor());
    }
@@ -235,191 +239,9 @@ class CrossCompartmentKey
    WrappedType wrapped;
};

// The data structure for storing CCWs, which has a map per target compartment
// so we can access them easily. Note string CCWs are stored separately from the
// others because they have target compartment nullptr.
class WrapperMap
{
    static const size_t InitialInnerMapSize = 4;

    using InnerMap = NurseryAwareHashMap<CrossCompartmentKey,
                                         JS::Value,
                                         CrossCompartmentKey::Hasher,
                                         SystemAllocPolicy>;
    using OuterMap = GCHashMap<JSCompartment*,
                               InnerMap,
                               DefaultHasher<JSCompartment*>,
                               SystemAllocPolicy>;

    OuterMap map;

  public:
    class Enum
    {
      public:
        enum SkipStrings : bool {
            WithStrings = false,
            WithoutStrings = true
        };

      private:
        Enum(const Enum&) = delete;
        void operator=(const Enum&) = delete;

        void goToNext() {
            if (outer.isNothing())
                return;
            for (; !outer->empty(); outer->popFront()) {
                JSCompartment* c = outer->front().key();
                // Need to skip string at first, because the filter may not be
                // happy with a nullptr.
                if (!c && skipStrings)
                    continue;
                if (filter && !filter->match(c))
                    continue;
                InnerMap& m = outer->front().value();
                if (!m.empty()) {
                    if (inner.isSome())
                        inner.reset();
                    inner.emplace(m);
                    outer->popFront();
                    return;
                }
            }
        }

        mozilla::Maybe<OuterMap::Enum> outer;
        mozilla::Maybe<InnerMap::Enum> inner;
        const CompartmentFilter* filter;
        SkipStrings skipStrings;

      public:
        explicit Enum(WrapperMap& m, SkipStrings s = WithStrings) :
                filter(nullptr), skipStrings(s) {
            outer.emplace(m.map);
            goToNext();
        }

        Enum(WrapperMap& m, const CompartmentFilter& f, SkipStrings s = WithStrings) :
                filter(&f), skipStrings(s) {
            outer.emplace(m.map);
            goToNext();
        }

        Enum(WrapperMap& m, JSCompartment* target) {
            // Leave the outer map as nothing and only iterate the inner map we
            // find here.
            auto p = m.map.lookup(target);
            if (p)
                inner.emplace(p->value());
        }

        bool empty() const {
            return (outer.isNothing() || outer->empty()) &&
                   (inner.isNothing() || inner->empty());
        }

        InnerMap::Entry& front() const {
            MOZ_ASSERT(inner.isSome() && !inner->empty());
            return inner->front();
        }

        void popFront() {
            MOZ_ASSERT(!empty());
            if (!inner->empty()) {
                inner->popFront();
                if (!inner->empty())
                    return;
            }
            goToNext();
        }

        void removeFront() {
            MOZ_ASSERT(inner.isSome());
            inner->removeFront();
        }
    };

    class Ptr : public InnerMap::Ptr
    {
        friend class WrapperMap;

        InnerMap* map;

        Ptr() : InnerMap::Ptr(), map(nullptr) {}
        Ptr(const InnerMap::Ptr& p, InnerMap& m) : InnerMap::Ptr(p), map(&m) {}
    };

    MOZ_MUST_USE bool init(uint32_t len) { return map.init(len); }

    bool empty() {
        if (map.empty())
            return true;
        for (OuterMap::Enum e(map); !e.empty(); e.popFront()) {
            if (!e.front().value().empty())
                return false;
        }
        return true;
    }

    Ptr lookup(const CrossCompartmentKey& k) const {
        auto op = map.lookup(const_cast<CrossCompartmentKey&>(k).compartment());
        if (op) {
            auto ip = op->value().lookup(k);
            if (ip)
                return Ptr(ip, op->value());
        }
        return Ptr();
    }

    void remove(Ptr p) {
        if (p)
            p.map->remove(p);
    }

    MOZ_MUST_USE bool put(const CrossCompartmentKey& k, const JS::Value& v) {
        JSCompartment* c = const_cast<CrossCompartmentKey&>(k).compartment();
        MOZ_ASSERT(k.is<JSString*>() == !c);
        auto p = map.lookupForAdd(c);
        if (!p) {
            InnerMap m;
            if (!m.init(InitialInnerMapSize) || !map.add(p, c, mozilla::Move(m)))
                return false;
        }
        return p->value().put(k, v);
    }

    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
        size_t size = map.sizeOfExcludingThis(mallocSizeOf);
        for (OuterMap::Enum e(map); !e.empty(); e.popFront())
            size += e.front().value().sizeOfExcludingThis(mallocSizeOf);
        return size;
    }
    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) {
        size_t size = map.sizeOfIncludingThis(mallocSizeOf);
        for (OuterMap::Enum e(map); !e.empty(); e.popFront())
            size += e.front().value().sizeOfIncludingThis(mallocSizeOf);
        return size;
    }

    void sweepAfterMinorGC(JSTracer* trc) {
        for (OuterMap::Enum e(map); !e.empty(); e.popFront()) {
            InnerMap& m = e.front().value();
            m.sweepAfterMinorGC(trc);
            if (m.empty())
                e.removeFront();
        }
    }

    void sweep() {
        for (OuterMap::Enum e(map); !e.empty(); e.popFront()) {
            InnerMap& m = e.front().value();
            m.sweep();
            if (m.empty())
                e.removeFront();
        }
    }
};
using WrapperMap = NurseryAwareHashMap<CrossCompartmentKey, JS::Value,
                                       CrossCompartmentKey::Hasher, SystemAllocPolicy>;

// We must ensure that all newly allocated JSObjects get their metadata
// set. However, metadata builders may require the new object be in a sane
@@ -856,16 +678,6 @@ struct JSCompartment
        explicit WrapperEnum(JSCompartment* c) : js::WrapperMap::Enum(c->crossCompartmentWrappers) {}
    };

    struct NonStringWrapperEnum : public js::WrapperMap::Enum {
        explicit NonStringWrapperEnum(JSCompartment* c) : js::WrapperMap::Enum(c->crossCompartmentWrappers, WithoutStrings) {}
        explicit NonStringWrapperEnum(JSCompartment* c, const js::CompartmentFilter& f) : js::WrapperMap::Enum(c->crossCompartmentWrappers, f, WithoutStrings) {}
        explicit NonStringWrapperEnum(JSCompartment* c, JSCompartment* target) : js::WrapperMap::Enum(c->crossCompartmentWrappers, target) { MOZ_ASSERT(target); }
    };

    struct StringWrapperEnum : public js::WrapperMap::Enum {
        explicit StringWrapperEnum(JSCompartment* c) : js::WrapperMap::Enum(c->crossCompartmentWrappers, nullptr) {}
    };

    js::LexicalEnvironmentObject*
    getOrCreateNonSyntacticLexicalEnvironment(JSContext* cx, js::HandleObject enclosing);
    js::LexicalEnvironmentObject* getNonSyntacticLexicalEnvironment(JSObject* enclosing) const;
Loading