123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658 |
- // 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 <assert.h>
- #include <map>
- #include <vector>
- #include "v8-function-callback.h" // NOLINT(build/include_directory)
- #include "v8-persistent-handle.h" // NOLINT(build/include_directory)
- /**
- * 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 {
- template <typename K, typename V, typename Traits>
- class GlobalValueMap;
- 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); }
- 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));
- }
- /**
- * 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>
- 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
|