summaryrefslogtreecommitdiffstats
path: root/dom/base/nsWrapperCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/nsWrapperCache.cpp')
-rw-r--r--dom/base/nsWrapperCache.cpp149
1 files changed, 149 insertions, 0 deletions
diff --git a/dom/base/nsWrapperCache.cpp b/dom/base/nsWrapperCache.cpp
new file mode 100644
index 000000000..b91d86598
--- /dev/null
+++ b/dom/base/nsWrapperCache.cpp
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsWrapperCacheInlines.h"
+
+#include "js/Class.h"
+#include "js/Proxy.h"
+#include "mozilla/dom/DOMJSProxyHandler.h"
+#include "mozilla/CycleCollectedJSContext.h"
+#include "mozilla/HoldDropJSObjects.h"
+#include "nsCycleCollectionTraversalCallback.h"
+#include "nsCycleCollector.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+#ifdef DEBUG
+/* static */ bool
+nsWrapperCache::HasJSObjectMovedOp(JSObject* aWrapper)
+{
+ return js::HasObjectMovedOp(aWrapper);
+}
+#endif
+
+void
+nsWrapperCache::HoldJSObjects(void* aScriptObjectHolder,
+ nsScriptObjectTracer* aTracer)
+{
+ cyclecollector::HoldJSObjectsImpl(aScriptObjectHolder, aTracer);
+ if (mWrapper && !JS::ObjectIsTenured(mWrapper)) {
+ CycleCollectedJSContext::Get()->NurseryWrapperPreserved(mWrapper);
+ }
+}
+
+void
+nsWrapperCache::SetWrapperJSObject(JSObject* aWrapper)
+{
+ mWrapper = aWrapper;
+ UnsetWrapperFlags(kWrapperFlagsMask & ~WRAPPER_IS_NOT_DOM_BINDING);
+
+ if (aWrapper && !JS::ObjectIsTenured(aWrapper)) {
+ CycleCollectedJSContext::Get()->NurseryWrapperAdded(this);
+ }
+}
+
+void
+nsWrapperCache::ReleaseWrapper(void* aScriptObjectHolder)
+{
+ if (PreservingWrapper()) {
+ // PreserveWrapper puts new DOM bindings in the JS holders hash, but they
+ // can also be in the DOM expando hash, so we need to try to remove them
+ // from both here.
+ JSObject* obj = GetWrapperPreserveColor();
+ if (IsDOMBinding() && obj && js::IsProxy(obj)) {
+ DOMProxyHandler::ClearExternalRefsForWrapperRelease(obj);
+ }
+ SetPreservingWrapper(false);
+ cyclecollector::DropJSObjectsImpl(aScriptObjectHolder);
+ }
+}
+
+#ifdef DEBUG
+
+class DebugWrapperTraversalCallback : public nsCycleCollectionTraversalCallback
+{
+public:
+ explicit DebugWrapperTraversalCallback(JSObject* aWrapper)
+ : mFound(false)
+ , mWrapper(JS::GCCellPtr(aWrapper))
+ {
+ mFlags = WANT_ALL_TRACES;
+ }
+
+ NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt aRefCount,
+ const char* aObjName)
+ {
+ }
+ NS_IMETHOD_(void) DescribeGCedNode(bool aIsMarked,
+ const char* aObjName,
+ uint64_t aCompartmentAddress)
+ {
+ }
+
+ NS_IMETHOD_(void) NoteJSChild(const JS::GCCellPtr& aChild)
+ {
+ if (aChild == mWrapper) {
+ mFound = true;
+ }
+ }
+ NS_IMETHOD_(void) NoteXPCOMChild(nsISupports* aChild)
+ {
+ }
+ NS_IMETHOD_(void) NoteNativeChild(void* aChild,
+ nsCycleCollectionParticipant* aHelper)
+ {
+ }
+
+ NS_IMETHOD_(void) NoteNextEdgeName(const char* aName)
+ {
+ }
+
+ bool mFound;
+
+private:
+ JS::GCCellPtr mWrapper;
+};
+
+static void
+DebugWrapperTraceCallback(JS::GCCellPtr aPtr, const char* aName, void* aClosure)
+{
+ DebugWrapperTraversalCallback* callback =
+ static_cast<DebugWrapperTraversalCallback*>(aClosure);
+ if (aPtr.is<JSObject>()) {
+ callback->NoteJSChild(aPtr);
+ }
+}
+
+void
+nsWrapperCache::CheckCCWrapperTraversal(void* aScriptObjectHolder,
+ nsScriptObjectTracer* aTracer)
+{
+ JSObject* wrapper = GetWrapper();
+ if (!wrapper) {
+ return;
+ }
+
+ DebugWrapperTraversalCallback callback(wrapper);
+
+ // The CC traversal machinery cannot trigger GC; however, the analysis cannot
+ // see through the COM layer, so we use a suppression to help it.
+ JS::AutoSuppressGCAnalysis suppress;
+
+ aTracer->Traverse(aScriptObjectHolder, callback);
+ MOZ_ASSERT(callback.mFound,
+ "Cycle collection participant didn't traverse to preserved "
+ "wrapper! This will probably crash.");
+
+ callback.mFound = false;
+ aTracer->Trace(aScriptObjectHolder,
+ TraceCallbackFunc(DebugWrapperTraceCallback), &callback);
+ MOZ_ASSERT(callback.mFound,
+ "Cycle collection participant didn't trace preserved wrapper! "
+ "This will probably crash.");
+}
+
+#endif // DEBUG