Bug 973780 - Expose a wrapper for the internal WeakMap class outside of the engine. r=mccr8,terrence

This commit is contained in:
Bobby Holley 2014-02-20 18:24:09 -08:00
parent e5c33da3e3
commit e07f769ce6
5 changed files with 165 additions and 1 deletions

46
js/public/WeakMapPtr.h Normal file
View File

@ -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 */

View File

@ -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"
/*

View File

@ -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);

View File

@ -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',

114
js/src/vm/WeakMapPtr.cpp Normal file
View File

@ -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