Viewing file: v8-util.h (20.17 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
#ifndef V8_UTIL_H_ #define V8_UTIL_H_
#include "v8.h" // NOLINT(build/include) #include <assert.h> #include <map> #include <vector>
/** * Support for Persistent containers. * * C++11 embedders can use STL containers with Global values, * but pre-C++11 does not support the required move semantic and hence * may want these container classes. */ namespace v8 {
typedef uintptr_t PersistentContainerValue; static const uintptr_t kPersistentContainerNotFound = 0; enum PersistentContainerCallbackType { kNotWeak, // These correspond to v8::WeakCallbackType kWeakWithParameter, kWeakWithInternalFields };
/** * A default trait implementation for PersistentValueMap which uses std::map * as a backing map. * * Users will have to implement their own weak callbacks & dispose traits. */ template<typename K, typename V> class StdMapTraits { public: // STL map & related: typedef std::map<K, PersistentContainerValue> Impl; typedef typename Impl::iterator Iterator;
static bool Empty(Impl* impl) { return impl->empty(); } static size_t Size(Impl* impl) { return impl->size(); } static void Swap(Impl& a, Impl& b) { std::swap(a, b); } // NOLINT static Iterator Begin(Impl* impl) { return impl->begin(); } static Iterator End(Impl* impl) { return impl->end(); } static K Key(Iterator it) { return it->first; } static PersistentContainerValue Value(Iterator it) { return it->second; } static PersistentContainerValue Set(Impl* impl, K key, PersistentContainerValue value) { std::pair<Iterator, bool> res = impl->insert(std::make_pair(key, value)); PersistentContainerValue old_value = kPersistentContainerNotFound; if (!res.second) { old_value = res.first->second; res.first->second = value; } return old_value; } static PersistentContainerValue Get(Impl* impl, K key) { Iterator it = impl->find(key); if (it == impl->end()) return kPersistentContainerNotFound; return it->second; } static PersistentContainerValue Remove(Impl* impl, K key) { Iterator it = impl->find(key); if (it == impl->end()) return kPersistentContainerNotFound; PersistentContainerValue value = it->second; impl->erase(it); return value; } };
/** * A default trait implementation for PersistentValueMap, which inherits * a std:map backing map from StdMapTraits and holds non-weak persistent * objects and has no special Dispose handling. * * You should not derive from this class, since MapType depends on the * surrounding class, and hence a subclass cannot simply inherit the methods. */ template<typename K, typename V> class DefaultPersistentValueMapTraits : public StdMapTraits<K, V> { public: // Weak callback & friends: static const PersistentContainerCallbackType kCallbackType = kNotWeak; typedef PersistentValueMap<K, V, DefaultPersistentValueMapTraits<K, V> > MapType; typedef void WeakCallbackDataType;
static WeakCallbackDataType* WeakCallbackParameter( MapType* map, const K& key, Local<V> value) { return nullptr; } static MapType* MapFromWeakCallbackInfo( const WeakCallbackInfo<WeakCallbackDataType>& data) { return nullptr; } static K KeyFromWeakCallbackInfo( const WeakCallbackInfo<WeakCallbackDataType>& data) { return K(); } static void DisposeCallbackData(WeakCallbackDataType* data) { } static void Dispose(Isolate* isolate, Global<V> value, K key) {} };
template <typename K, typename V> class DefaultGlobalMapTraits : public StdMapTraits<K, V> { private: template <typename T> struct RemovePointer;
public: // Weak callback & friends: static const PersistentContainerCallbackType kCallbackType = kNotWeak; typedef GlobalValueMap<K, V, DefaultGlobalMapTraits<K, V> > MapType; typedef void WeakCallbackDataType;
static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key, Local<V> value) { return nullptr; } static MapType* MapFromWeakCallbackInfo( const WeakCallbackInfo<WeakCallbackDataType>& data) { return nullptr; } static K KeyFromWeakCallbackInfo( const WeakCallbackInfo<WeakCallbackDataType>& data) { return K(); } static void DisposeCallbackData(WeakCallbackDataType* data) {} static void OnWeakCallback( const WeakCallbackInfo<WeakCallbackDataType>& data) {} static void Dispose(Isolate* isolate, Global<V> value, K key) {} // This is a second pass callback, so SetSecondPassCallback cannot be called. static void DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType>& data) {}
private: template <typename T> struct RemovePointer<T*> { typedef T Type; }; };
/** * A map wrapper that allows using Global as a mapped value. * C++11 embedders don't need this class, as they can use Global * directly in std containers. * * The map relies on a backing map, whose type and accessors are described * by the Traits class. The backing map will handle values of type * PersistentContainerValue, with all conversion into and out of V8 * handles being transparently handled by this class. */ template <typename K, typename V, typename Traits> class PersistentValueMapBase { public: Isolate* GetIsolate() { return isolate_; }
/** * Return size of the map. */ size_t Size() { return Traits::Size(&impl_); }
/** * Return whether the map holds weak persistents. */ bool IsWeak() { return Traits::kCallbackType != kNotWeak; }
/** * Get value stored in map. */ Local<V> Get(const K& key) { return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, key))); }
/** * Check whether a value is contained in the map. */ bool Contains(const K& key) { return Traits::Get(&impl_, key) != kPersistentContainerNotFound; }
/** * Get value stored in map and set it in returnValue. * Return true if a value was found. */ bool SetReturnValue(const K& key, ReturnValue<Value> returnValue) { return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key)); }
/** * Call V8::RegisterExternallyReferencedObject with the map value for given * key. */ V8_DEPRECATED( "Used TracedGlobal and EmbedderHeapTracer::RegisterEmbedderReference", inline void RegisterExternallyReferencedObject(K& key));
/** * Return value for key and remove it from the map. */ Global<V> Remove(const K& key) { return Release(Traits::Remove(&impl_, key)).Pass(); }
/** * Traverses the map repeatedly, * in case side effects of disposal cause insertions. **/ void Clear() { typedef typename Traits::Iterator It; HandleScope handle_scope(isolate_); // TODO(dcarney): figure out if this swap and loop is necessary. while (!Traits::Empty(&impl_)) { typename Traits::Impl impl; Traits::Swap(impl_, impl); for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) { Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(), Traits::Key(i)); } } }
/** * Helper class for GetReference/SetWithReference. Do not use outside * that context. */ class PersistentValueReference { public: PersistentValueReference() : value_(kPersistentContainerNotFound) { } PersistentValueReference(const PersistentValueReference& other) : value_(other.value_) { }
Local<V> NewLocal(Isolate* isolate) const { return Local<V>::New(isolate, FromVal(value_)); } bool IsEmpty() const { return value_ == kPersistentContainerNotFound; } template<typename T> bool SetReturnValue(ReturnValue<T> returnValue) { return SetReturnValueFromVal(&returnValue, value_); } void Reset() { value_ = kPersistentContainerNotFound; } void operator=(const PersistentValueReference& other) { value_ = other.value_; }
private: friend class PersistentValueMapBase; friend class PersistentValueMap<K, V, Traits>; friend class GlobalValueMap<K, V, Traits>;
explicit PersistentValueReference(PersistentContainerValue value) : value_(value) { }
void operator=(PersistentContainerValue value) { value_ = value; }
PersistentContainerValue value_; };
/** * Get a reference to a map value. This enables fast, repeated access * to a value stored in the map while the map remains unchanged. * * Careful: This is potentially unsafe, so please use with care. * The value will become invalid if the value for this key changes * in the underlying map, as a result of Set or Remove for the same * key; as a result of the weak callback for the same key; or as a * result of calling Clear() or destruction of the map. */ PersistentValueReference GetReference(const K& key) { return PersistentValueReference(Traits::Get(&impl_, key)); }
protected: explicit PersistentValueMapBase(Isolate* isolate) : isolate_(isolate), label_(nullptr) {} PersistentValueMapBase(Isolate* isolate, const char* label) : isolate_(isolate), label_(label) {}
~PersistentValueMapBase() { Clear(); }
Isolate* isolate() { return isolate_; } typename Traits::Impl* impl() { return &impl_; }
static V* FromVal(PersistentContainerValue v) { return reinterpret_cast<V*>(v); }
static PersistentContainerValue ClearAndLeak(Global<V>* persistent) { V* v = persistent->val_; persistent->val_ = nullptr; return reinterpret_cast<PersistentContainerValue>(v); }
static PersistentContainerValue Leak(Global<V>* persistent) { return reinterpret_cast<PersistentContainerValue>(persistent->val_); }
/** * Return a container value as Global and make sure the weak * callback is properly disposed of. All remove functionality should go * through this. */ static Global<V> Release(PersistentContainerValue v) { Global<V> p; p.val_ = FromVal(v); if (Traits::kCallbackType != kNotWeak && p.IsWeak()) { Traits::DisposeCallbackData( p.template ClearWeak<typename Traits::WeakCallbackDataType>()); } return p.Pass(); }
void RemoveWeak(const K& key) { Global<V> p; p.val_ = FromVal(Traits::Remove(&impl_, key)); p.Reset(); }
void AnnotateStrongRetainer(Global<V>* persistent) { persistent->AnnotateStrongRetainer(label_); }
private: PersistentValueMapBase(PersistentValueMapBase&); void operator=(PersistentValueMapBase&);
static bool SetReturnValueFromVal(ReturnValue<Value>* returnValue, PersistentContainerValue value) { bool hasValue = value != kPersistentContainerNotFound; if (hasValue) { returnValue->SetInternal( *reinterpret_cast<internal::Address*>(FromVal(value))); } return hasValue; }
Isolate* isolate_; typename Traits::Impl impl_; const char* label_; };
template <typename K, typename V, typename Traits> inline void PersistentValueMapBase<K, V, Traits>::RegisterExternallyReferencedObject( K& key) { assert(Contains(key)); V8::RegisterExternallyReferencedObject( reinterpret_cast<internal::Address*>(FromVal(Traits::Get(&impl_, key))), reinterpret_cast<internal::Isolate*>(GetIsolate())); }
template <typename K, typename V, typename Traits> class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> { public: explicit PersistentValueMap(Isolate* isolate) : PersistentValueMapBase<K, V, Traits>(isolate) {} PersistentValueMap(Isolate* isolate, const char* label) : PersistentValueMapBase<K, V, Traits>(isolate, label) {}
typedef typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference PersistentValueReference;
/** * Put value into map. Depending on Traits::kIsWeak, the value will be held * by the map strongly or weakly. * Returns old value as Global. */ Global<V> Set(const K& key, Local<V> value) { Global<V> persistent(this->isolate(), value); return SetUnique(key, &persistent); }
/** * Put value into map, like Set(const K&, Local<V>). */ Global<V> Set(const K& key, Global<V> value) { return SetUnique(key, &value); }
/** * Put the value into the map, and set the 'weak' callback when demanded * by the Traits class. */ Global<V> SetUnique(const K& key, Global<V>* persistent) { if (Traits::kCallbackType == kNotWeak) { this->AnnotateStrongRetainer(persistent); } else { WeakCallbackType callback_type = Traits::kCallbackType == kWeakWithInternalFields ? WeakCallbackType::kInternalFields : WeakCallbackType::kParameter; Local<V> value(Local<V>::New(this->isolate(), *persistent)); persistent->template SetWeak<typename Traits::WeakCallbackDataType>( Traits::WeakCallbackParameter(this, key, value), WeakCallback, callback_type); } PersistentContainerValue old_value = Traits::Set(this->impl(), key, this->ClearAndLeak(persistent)); return this->Release(old_value).Pass(); }
/** * Put a value into the map and update the reference. * Restrictions of GetReference apply here as well. */ Global<V> Set(const K& key, Global<V> value, PersistentValueReference* reference) { *reference = this->Leak(&value); return SetUnique(key, &value); }
private: static void WeakCallback( const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) { if (Traits::kCallbackType != kNotWeak) { PersistentValueMap<K, V, Traits>* persistentValueMap = Traits::MapFromWeakCallbackInfo(data); K key = Traits::KeyFromWeakCallbackInfo(data); Traits::Dispose(data.GetIsolate(), persistentValueMap->Remove(key).Pass(), key); Traits::DisposeCallbackData(data.GetParameter()); } } };
template <typename K, typename V, typename Traits> class GlobalValueMap : public PersistentValueMapBase<K, V, Traits> { public: explicit GlobalValueMap(Isolate* isolate) : PersistentValueMapBase<K, V, Traits>(isolate) {} GlobalValueMap(Isolate* isolate, const char* label) : PersistentValueMapBase<K, V, Traits>(isolate, label) {}
typedef typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference PersistentValueReference;
/** * Put value into map. Depending on Traits::kIsWeak, the value will be held * by the map strongly or weakly. * Returns old value as Global. */ Global<V> Set(const K& key, Local<V> value) { Global<V> persistent(this->isolate(), value); return SetUnique(key, &persistent); }
/** * Put value into map, like Set(const K&, Local<V>). */ Global<V> Set(const K& key, Global<V> value) { return SetUnique(key, &value); }
/** * Put the value into the map, and set the 'weak' callback when demanded * by the Traits class. */ Global<V> SetUnique(const K& key, Global<V>* persistent) { if (Traits::kCallbackType == kNotWeak) { this->AnnotateStrongRetainer(persistent); } else { WeakCallbackType callback_type = Traits::kCallbackType == kWeakWithInternalFields ? WeakCallbackType::kInternalFields : WeakCallbackType::kParameter; Local<V> value(Local<V>::New(this->isolate(), *persistent)); persistent->template SetWeak<typename Traits::WeakCallbackDataType>( Traits::WeakCallbackParameter(this, key, value), OnWeakCallback, callback_type); } PersistentContainerValue old_value = Traits::Set(this->impl(), key, this->ClearAndLeak(persistent)); return this->Release(old_value).Pass(); }
/** * Put a value into the map and update the reference. * Restrictions of GetReference apply here as well. */ Global<V> Set(const K& key, Global<V> value, PersistentValueReference* reference) { *reference = this->Leak(&value); return SetUnique(key, &value); }
private: static void OnWeakCallback( const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) { if (Traits::kCallbackType != kNotWeak) { auto map = Traits::MapFromWeakCallbackInfo(data); K key = Traits::KeyFromWeakCallbackInfo(data); map->RemoveWeak(key); Traits::OnWeakCallback(data); data.SetSecondPassCallback(SecondWeakCallback); } }
static void SecondWeakCallback( const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) { Traits::DisposeWeak(data); } };
/** * A map that uses Global as value and std::map as the backing * implementation. Persistents are held non-weak. * * C++11 embedders don't need this class, as they can use * Global directly in std containers. */ template<typename K, typename V, typename Traits = DefaultPersistentValueMapTraits<K, V> > class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> { public: explicit StdPersistentValueMap(Isolate* isolate) : PersistentValueMap<K, V, Traits>(isolate) {} };
/** * A map that uses Global as value and std::map as the backing * implementation. Globals are held non-weak. * * C++11 embedders don't need this class, as they can use * Global directly in std containers. */ template <typename K, typename V, typename Traits = DefaultGlobalMapTraits<K, V> > class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> { public: explicit StdGlobalValueMap(Isolate* isolate) : GlobalValueMap<K, V, Traits>(isolate) {} };
class DefaultPersistentValueVectorTraits { public: typedef std::vector<PersistentContainerValue> Impl;
static void Append(Impl* impl, PersistentContainerValue value) { impl->push_back(value); } static bool IsEmpty(const Impl* impl) { return impl->empty(); } static size_t Size(const Impl* impl) { return impl->size(); } static PersistentContainerValue Get(const Impl* impl, size_t i) { return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound; } static void ReserveCapacity(Impl* impl, size_t capacity) { impl->reserve(capacity); } static void Clear(Impl* impl) { impl->clear(); } };
/** * A vector wrapper that safely stores Global values. * C++11 embedders don't need this class, as they can use Global * directly in std containers. * * This class relies on a backing vector implementation, whose type and methods * are described by the Traits class. The backing map will handle values of type * PersistentContainerValue, with all conversion into and out of V8 * handles being transparently handled by this class. */ template<typename V, typename Traits = DefaultPersistentValueVectorTraits> class PersistentValueVector { public: explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
~PersistentValueVector() { Clear(); }
/** * Append a value to the vector. */ void Append(Local<V> value) { Global<V> persistent(isolate_, value); Traits::Append(&impl_, ClearAndLeak(&persistent)); }
/** * Append a persistent's value to the vector. */ void Append(Global<V> persistent) { Traits::Append(&impl_, ClearAndLeak(&persistent)); }
/** * Are there any values in the vector? */ bool IsEmpty() const { return Traits::IsEmpty(&impl_); }
/** * How many elements are in the vector? */ size_t Size() const { return Traits::Size(&impl_); }
/** * Retrieve the i-th value in the vector. */ Local<V> Get(size_t index) const { return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index))); }
/** * Remove all elements from the vector. */ void Clear() { size_t length = Traits::Size(&impl_); for (size_t i = 0; i < length; i++) { Global<V> p; p.val_ = FromVal(Traits::Get(&impl_, i)); } Traits::Clear(&impl_); }
/** * Reserve capacity in the vector. * (Efficiency gains depend on the backing implementation.) */ void ReserveCapacity(size_t capacity) { Traits::ReserveCapacity(&impl_, capacity); }
private: static PersistentContainerValue ClearAndLeak(Global<V>* persistent) { V* v = persistent->val_; persistent->val_ = nullptr; return reinterpret_cast<PersistentContainerValue>(v); }
static V* FromVal(PersistentContainerValue v) { return reinterpret_cast<V*>(v); }
Isolate* isolate_; typename Traits::Impl impl_; };
} // namespace v8
#endif // V8_UTIL_H
|