Bug 973780 - Expose a wrapper for the internal WeakMap class outside of the engine. r=mccr8,terrence
authorBobby Holley <bobbyholley@gmail.com>
Thu, 20 Feb 2014 18:24:09 -0800
changeset 170152 8db4d719f5f853db811be590f262acfc356cfb0f
parent 170151 c5953f75569b803a730ec277b1afca9ff9a6868f
child 170153 523e9ec89a9f02bc1b1b6e1d72733785e361bf08
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersmccr8, terrence
bugs973780
milestone30.0a1
Bug 973780 - Expose a wrapper for the internal WeakMap class outside of the engine. r=mccr8,terrence
js/public/WeakMapPtr.h
js/src/jsapi-tests/testIntTypesABI.cpp
js/src/jsweakmap.h
js/src/moz.build
js/src/vm/WeakMapPtr.cpp
new file mode 100644
--- /dev/null
+++ b/js/public/WeakMapPtr.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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/. */
+
+#ifndef js_WeakMapPtr_h
+#define js_WeakMapPtr_h
+
+#include "jspubtd.h"
+
+#include "js/TypeDecls.h"
+
+namespace JS {
+
+// A wrapper around the internal C++ representation of SpiderMonkey WeakMaps,
+// usable outside the engine.
+//
+// The supported template specializations are enumerated in WeakMapPtr.cpp. If
+// you want to use this class for a different key/value combination, add it to
+// the list and the compiler will generate the relevant machinery.
+template <typename K, typename V>
+class JS_PUBLIC_API(WeakMapPtr)
+{
+  public:
+    WeakMapPtr() : ptr(nullptr) {};
+    bool init(JSContext *cx);
+    bool initialized() { return ptr != nullptr; };
+    void destroy();
+    virtual ~WeakMapPtr() { MOZ_ASSERT(!initialized()); }
+    void trace(JSTracer *tracer);
+
+    V lookup(const K &key);
+    bool put(const K &key, const V &value);
+
+  private:
+    void *ptr;
+
+    // WeakMapPtr is neither copyable nor assignable.
+    WeakMapPtr(const WeakMapPtr &wmp) MOZ_DELETE;
+    WeakMapPtr &operator=(const WeakMapPtr &wmp) MOZ_DELETE;
+};
+
+} /* namespace JS */
+
+#endif  /* js_WeakMapPtr_h */
--- a/js/src/jsapi-tests/testIntTypesABI.cpp
+++ b/js/src/jsapi-tests/testIntTypesABI.cpp
@@ -32,16 +32,17 @@
 #include "js/RootingAPI.h"
 #include "js/SliceBudget.h"
 #include "js/StructuredClone.h"
 #include "js/Tracer.h"
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 #include "js/Value.h"
 #include "js/Vector.h"
+#include "js/WeakMapPtr.h"
 #include "jsapi-tests/tests.h"
 
 /*
  * Verify that our public (and intended to be public, versus being that way
  * because we haven't made them private yet) headers don't define
  * {u,}int{8,16,32,64} or JS{Ui,I}nt{8,16,32,64} types.  If any do, they will
  * assuredly conflict with a corresponding typedef below mapping to a *struct*.
  *
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -80,17 +80,18 @@ class WeakMapBase {
 
     // Remove entries whose keys are dead from all weak maps in a compartment marked as
     // live in this garbage collection.
     static void sweepCompartment(JSCompartment *c);
 
     // Trace all delayed weak map bindings. Used by the cycle collector.
     static void traceAllMappings(WeakMapTracer *tracer);
 
-    void check() { JS_ASSERT(next == WeakMapNotInList); }
+    bool isInList() { return next != WeakMapNotInList; }
+    void check() { JS_ASSERT(!isInList()); }
 
     // Remove everything from the weak map list for a compartment.
     static void resetCompartmentWeakMapList(JSCompartment *c);
 
     // Save the live weak map list for a compartment, appending the data to a vector.
     static bool saveCompartmentWeakMapList(JSCompartment *c, WeakMapVector &vector);
 
     // Restore live weak map lists for multiple compartments from a vector.
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -83,16 +83,17 @@ EXPORTS.js += [
     '../public/RootingAPI.h',
     '../public/SliceBudget.h',
     '../public/StructuredClone.h',
     '../public/Tracer.h',
     '../public/TypeDecls.h',
     '../public/Utility.h',
     '../public/Value.h',
     '../public/Vector.h',
+    '../public/WeakMapPtr.h',
 ]
 
 UNIFIED_SOURCES += [
     'assembler/jit/ExecutableAllocator.cpp',
     'builtin/Eval.cpp',
     'builtin/Intl.cpp',
     'builtin/MapObject.cpp',
     'builtin/Object.cpp',
@@ -184,16 +185,17 @@ UNIFIED_SOURCES += [
     'vm/Stack.cpp',
     'vm/String.cpp',
     'vm/StringBuffer.cpp',
     'vm/StructuredClone.cpp',
     'vm/ThreadPool.cpp',
     'vm/TypedArrayObject.cpp',
     'vm/Unicode.cpp',
     'vm/Value.cpp',
+    'vm/WeakMapPtr.cpp',
     'vm/Xdr.cpp',
     'yarr/PageBlock.cpp',
     'yarr/YarrCanonicalizeUCS2.cpp',
     'yarr/YarrInterpreter.cpp',
     'yarr/YarrPattern.cpp',
     'yarr/YarrSyntaxChecker.cpp',
 ]
 
new file mode 100644
--- /dev/null
+++ b/js/src/vm/WeakMapPtr.cpp
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 "js/WeakMapPtr.h"
+
+#include "jsweakmap.h"
+
+//
+// Machinery for the externally-linkable JS::WeakMapPtr, which wraps js::WeakMap
+// for a few public data types.
+//
+
+using namespace js;
+
+namespace {
+
+template<typename T>
+struct DataType
+{
+};
+
+template<>
+struct DataType<JSObject*>
+{
+    typedef EncapsulatedPtrObject Encapsulated;
+    static JSObject *NullValue() { return nullptr; }
+};
+
+template<>
+struct DataType<JS::Value>
+{
+    typedef EncapsulatedValue Encapsulated;
+    static JS::Value NullValue() { return JS::UndefinedValue(); }
+};
+
+template <typename K, typename V>
+struct Utils
+{
+    typedef typename DataType<K>::Encapsulated KeyType;
+    typedef typename DataType<V>::Encapsulated ValueType;
+    typedef WeakMap<KeyType, ValueType> Type;
+    typedef Type* PtrType;
+    static PtrType cast(void *ptr) { return static_cast<PtrType>(ptr); }
+};
+
+} /* namespace */
+
+template <typename K, typename V>
+void
+JS::WeakMapPtr<K, V>::destroy()
+{
+    MOZ_ASSERT(initialized());
+    auto map = Utils<K, V>::cast(ptr);
+    // If this destruction happens mid-GC, we might be in the compartment's list
+    // of known live weakmaps. If we are, remove ourselves before deleting.
+    if (map->isInList())
+        WeakMapBase::removeWeakMapFromList(map);
+    map->check();
+    js_delete(map);
+    ptr = nullptr;
+}
+
+template <typename K, typename V>
+bool
+JS::WeakMapPtr<K, V>::init(JSContext *cx)
+{
+    MOZ_ASSERT(!initialized());
+    typename Utils<K, V>::PtrType map = cx->runtime()->new_<typename Utils<K,V>::Type>(cx);
+    if (!map || !map->init())
+        return false;
+    ptr = map;
+    return true;
+}
+
+template <typename K, typename V>
+void
+JS::WeakMapPtr<K, V>::trace(JSTracer *trc)
+{
+    MOZ_ASSERT(initialized());
+    return Utils<K, V>::cast(ptr)->trace(trc);
+}
+
+template <typename K, typename V>
+V
+JS::WeakMapPtr<K, V>::lookup(const K &key)
+{
+    MOZ_ASSERT(initialized());
+    typename Utils<K, V>::Type::Ptr result = Utils<K, V>::cast(ptr)->lookup(key);
+    if (!result)
+        return DataType<V>::NullValue();
+    return result->value();
+}
+
+template <typename K, typename V>
+bool
+JS::WeakMapPtr<K, V>::put(const K &key, const V &value)
+{
+    MOZ_ASSERT(initialized());
+    return Utils<K, V>::cast(ptr)->put(key, value);
+}
+
+//
+// Supported specializations of JS::WeakMap:
+//
+
+template class JS::WeakMapPtr<JSObject*, JSObject*>;
+
+#ifdef DEBUG
+// Nobody's using this at the moment, but we want to make sure it compiles.
+template class JS::WeakMapPtr<JSObject*, JS::Value>;
+#endif