From b71db74ff57dd492c8472d0104953f638b97de0b Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 20 Feb 2014 18:24:09 -0800 Subject: [PATCH] Bug 973780 - Expose a wrapper for the internal WeakMap class outside of the engine. r=mccr8,terrence --- js/public/WeakMapPtr.h | 46 ++++++++++ js/src/jsapi-tests/testIntTypesABI.cpp | 1 + js/src/jsweakmap.h | 3 +- js/src/moz.build | 2 + js/src/vm/WeakMapPtr.cpp | 114 +++++++++++++++++++++++++ 5 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 js/public/WeakMapPtr.h create mode 100644 js/src/vm/WeakMapPtr.cpp diff --git a/js/public/WeakMapPtr.h b/js/public/WeakMapPtr.h new file mode 100644 index 000000000000..ffebd7a213e7 --- /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 +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 */ diff --git a/js/src/jsapi-tests/testIntTypesABI.cpp b/js/src/jsapi-tests/testIntTypesABI.cpp index ca851018bfb7..d2d9afc2d42b 100644 --- a/js/src/jsapi-tests/testIntTypesABI.cpp +++ b/js/src/jsapi-tests/testIntTypesABI.cpp @@ -37,6 +37,7 @@ #include "js/Utility.h" #include "js/Value.h" #include "js/Vector.h" +#include "js/WeakMapPtr.h" #include "jsapi-tests/tests.h" /* diff --git a/js/src/jsweakmap.h b/js/src/jsweakmap.h index 4b4c829beeed..804614ec3d43 100644 --- a/js/src/jsweakmap.h +++ b/js/src/jsweakmap.h @@ -85,7 +85,8 @@ class WeakMapBase { // 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); diff --git a/js/src/moz.build b/js/src/moz.build index 9ddfca91ab66..c75c58294402 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -88,6 +88,7 @@ EXPORTS.js += [ '../public/Utility.h', '../public/Value.h', '../public/Vector.h', + '../public/WeakMapPtr.h', ] UNIFIED_SOURCES += [ @@ -189,6 +190,7 @@ UNIFIED_SOURCES += [ 'vm/TypedArrayObject.cpp', 'vm/Unicode.cpp', 'vm/Value.cpp', + 'vm/WeakMapPtr.cpp', 'vm/Xdr.cpp', 'yarr/PageBlock.cpp', 'yarr/YarrCanonicalizeUCS2.cpp', diff --git a/js/src/vm/WeakMapPtr.cpp b/js/src/vm/WeakMapPtr.cpp new file mode 100644 index 000000000000..3b905a98db2e --- /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 +struct DataType +{ +}; + +template<> +struct DataType +{ + typedef EncapsulatedPtrObject Encapsulated; + static JSObject *NullValue() { return nullptr; } +}; + +template<> +struct DataType +{ + typedef EncapsulatedValue Encapsulated; + static JS::Value NullValue() { return JS::UndefinedValue(); } +}; + +template +struct Utils +{ + typedef typename DataType::Encapsulated KeyType; + typedef typename DataType::Encapsulated ValueType; + typedef WeakMap Type; + typedef Type* PtrType; + static PtrType cast(void *ptr) { return static_cast(ptr); } +}; + +} /* namespace */ + +template +void +JS::WeakMapPtr::destroy() +{ + MOZ_ASSERT(initialized()); + auto map = Utils::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 +bool +JS::WeakMapPtr::init(JSContext *cx) +{ + MOZ_ASSERT(!initialized()); + typename Utils::PtrType map = cx->runtime()->new_::Type>(cx); + if (!map || !map->init()) + return false; + ptr = map; + return true; +} + +template +void +JS::WeakMapPtr::trace(JSTracer *trc) +{ + MOZ_ASSERT(initialized()); + return Utils::cast(ptr)->trace(trc); +} + +template +V +JS::WeakMapPtr::lookup(const K &key) +{ + MOZ_ASSERT(initialized()); + typename Utils::Type::Ptr result = Utils::cast(ptr)->lookup(key); + if (!result) + return DataType::NullValue(); + return result->value(); +} + +template +bool +JS::WeakMapPtr::put(const K &key, const V &value) +{ + MOZ_ASSERT(initialized()); + return Utils::cast(ptr)->put(key, value); +} + +// +// Supported specializations of JS::WeakMap: +// + +template class JS::WeakMapPtr; + +#ifdef DEBUG +// Nobody's using this at the moment, but we want to make sure it compiles. +template class JS::WeakMapPtr; +#endif