Home | History | Annotate | Download | only in include
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_UTIL_H_
      6 #define V8_UTIL_H_
      7 
      8 #include "v8.h"  // NOLINT(build/include)
      9 #include <assert.h>
     10 #include <map>
     11 #include <vector>
     12 
     13 /**
     14  * Support for Persistent containers.
     15  *
     16  * C++11 embedders can use STL containers with Global values,
     17  * but pre-C++11 does not support the required move semantic and hence
     18  * may want these container classes.
     19  */
     20 namespace v8 {
     21 
     22 typedef uintptr_t PersistentContainerValue;
     23 static const uintptr_t kPersistentContainerNotFound = 0;
     24 enum PersistentContainerCallbackType {
     25   kNotWeak,
     26   // These correspond to v8::WeakCallbackType
     27   kWeakWithParameter,
     28   kWeakWithInternalFields,
     29   kWeak = kWeakWithParameter  // For backwards compatibility.  Deprecate.
     30 };
     31 
     32 
     33 /**
     34  * A default trait implemenation for PersistentValueMap which uses std::map
     35  * as a backing map.
     36  *
     37  * Users will have to implement their own weak callbacks & dispose traits.
     38  */
     39 template<typename K, typename V>
     40 class StdMapTraits {
     41  public:
     42   // STL map & related:
     43   typedef std::map<K, PersistentContainerValue> Impl;
     44   typedef typename Impl::iterator Iterator;
     45 
     46   static bool Empty(Impl* impl) { return impl->empty(); }
     47   static size_t Size(Impl* impl) { return impl->size(); }
     48   static void Swap(Impl& a, Impl& b) { std::swap(a, b); }  // NOLINT
     49   static Iterator Begin(Impl* impl) { return impl->begin(); }
     50   static Iterator End(Impl* impl) { return impl->end(); }
     51   static K Key(Iterator it) { return it->first; }
     52   static PersistentContainerValue Value(Iterator it) { return it->second; }
     53   static PersistentContainerValue Set(Impl* impl, K key,
     54       PersistentContainerValue value) {
     55     std::pair<Iterator, bool> res = impl->insert(std::make_pair(key, value));
     56     PersistentContainerValue old_value = kPersistentContainerNotFound;
     57     if (!res.second) {
     58       old_value = res.first->second;
     59       res.first->second = value;
     60     }
     61     return old_value;
     62   }
     63   static PersistentContainerValue Get(Impl* impl, K key) {
     64     Iterator it = impl->find(key);
     65     if (it == impl->end()) return kPersistentContainerNotFound;
     66     return it->second;
     67   }
     68   static PersistentContainerValue Remove(Impl* impl, K key) {
     69     Iterator it = impl->find(key);
     70     if (it == impl->end()) return kPersistentContainerNotFound;
     71     PersistentContainerValue value = it->second;
     72     impl->erase(it);
     73     return value;
     74   }
     75 };
     76 
     77 
     78 /**
     79  * A default trait implementation for PersistentValueMap, which inherits
     80  * a std:map backing map from StdMapTraits and holds non-weak persistent
     81  * objects and has no special Dispose handling.
     82  *
     83  * You should not derive from this class, since MapType depends on the
     84  * surrounding class, and hence a subclass cannot simply inherit the methods.
     85  */
     86 template<typename K, typename V>
     87 class DefaultPersistentValueMapTraits : public StdMapTraits<K, V> {
     88  public:
     89   // Weak callback & friends:
     90   static const PersistentContainerCallbackType kCallbackType = kNotWeak;
     91   typedef PersistentValueMap<K, V, DefaultPersistentValueMapTraits<K, V> >
     92       MapType;
     93   typedef void WeakCallbackDataType;
     94 
     95   static WeakCallbackDataType* WeakCallbackParameter(
     96       MapType* map, const K& key, Local<V> value) {
     97     return NULL;
     98   }
     99   static MapType* MapFromWeakCallbackInfo(
    100       const WeakCallbackInfo<WeakCallbackDataType>& data) {
    101     return NULL;
    102   }
    103   static K KeyFromWeakCallbackInfo(
    104       const WeakCallbackInfo<WeakCallbackDataType>& data) {
    105     return K();
    106   }
    107   static void DisposeCallbackData(WeakCallbackDataType* data) { }
    108   static void Dispose(Isolate* isolate, Global<V> value, K key) {}
    109 };
    110 
    111 
    112 template <typename K, typename V>
    113 class DefaultGlobalMapTraits : public StdMapTraits<K, V> {
    114  private:
    115   template <typename T>
    116   struct RemovePointer;
    117 
    118  public:
    119   // Weak callback & friends:
    120   static const PersistentContainerCallbackType kCallbackType = kNotWeak;
    121   typedef GlobalValueMap<K, V, DefaultGlobalMapTraits<K, V> > MapType;
    122   typedef void WeakCallbackDataType;
    123 
    124   static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
    125                                                      Local<V> value) {
    126     return nullptr;
    127   }
    128   static MapType* MapFromWeakCallbackInfo(
    129       const WeakCallbackInfo<WeakCallbackDataType>& data) {
    130     return nullptr;
    131   }
    132   static K KeyFromWeakCallbackInfo(
    133       const WeakCallbackInfo<WeakCallbackDataType>& data) {
    134     return K();
    135   }
    136   static void DisposeCallbackData(WeakCallbackDataType* data) {}
    137   static void OnWeakCallback(
    138       const WeakCallbackInfo<WeakCallbackDataType>& data) {}
    139   static void Dispose(Isolate* isolate, Global<V> value, K key) {}
    140   // This is a second pass callback, so SetSecondPassCallback cannot be called.
    141   static void DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType>& data) {}
    142 
    143  private:
    144   template <typename T>
    145   struct RemovePointer<T*> {
    146     typedef T Type;
    147   };
    148 };
    149 
    150 
    151 /**
    152  * A map wrapper that allows using Global as a mapped value.
    153  * C++11 embedders don't need this class, as they can use Global
    154  * directly in std containers.
    155  *
    156  * The map relies on a backing map, whose type and accessors are described
    157  * by the Traits class. The backing map will handle values of type
    158  * PersistentContainerValue, with all conversion into and out of V8
    159  * handles being transparently handled by this class.
    160  */
    161 template <typename K, typename V, typename Traits>
    162 class PersistentValueMapBase {
    163  public:
    164   Isolate* GetIsolate() { return isolate_; }
    165 
    166   /**
    167    * Return size of the map.
    168    */
    169   size_t Size() { return Traits::Size(&impl_); }
    170 
    171   /**
    172    * Return whether the map holds weak persistents.
    173    */
    174   bool IsWeak() { return Traits::kCallbackType != kNotWeak; }
    175 
    176   /**
    177    * Get value stored in map.
    178    */
    179   Local<V> Get(const K& key) {
    180     return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, key)));
    181   }
    182 
    183   /**
    184    * Check whether a value is contained in the map.
    185    */
    186   bool Contains(const K& key) {
    187     return Traits::Get(&impl_, key) != kPersistentContainerNotFound;
    188   }
    189 
    190   /**
    191    * Get value stored in map and set it in returnValue.
    192    * Return true if a value was found.
    193    */
    194   bool SetReturnValue(const K& key,
    195       ReturnValue<Value> returnValue) {
    196     return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key));
    197   }
    198 
    199   /**
    200    * Call Isolate::SetReference with the given parent and the map value.
    201    */
    202   void SetReference(const K& key,
    203       const Persistent<Object>& parent) {
    204     GetIsolate()->SetReference(
    205       reinterpret_cast<internal::Object**>(parent.val_),
    206       reinterpret_cast<internal::Object**>(FromVal(Traits::Get(&impl_, key))));
    207   }
    208 
    209   /**
    210    * Call V8::RegisterExternallyReferencedObject with the map value for given
    211    * key.
    212    */
    213   void RegisterExternallyReferencedObject(K& key) {
    214     assert(Contains(key));
    215     V8::RegisterExternallyReferencedObject(
    216         reinterpret_cast<internal::Object**>(FromVal(Traits::Get(&impl_, key))),
    217         reinterpret_cast<internal::Isolate*>(GetIsolate()));
    218   }
    219 
    220   /**
    221    * Return value for key and remove it from the map.
    222    */
    223   Global<V> Remove(const K& key) {
    224     return Release(Traits::Remove(&impl_, key)).Pass();
    225   }
    226 
    227   /**
    228   * Traverses the map repeatedly,
    229   * in case side effects of disposal cause insertions.
    230   **/
    231   void Clear() {
    232     typedef typename Traits::Iterator It;
    233     HandleScope handle_scope(isolate_);
    234     // TODO(dcarney): figure out if this swap and loop is necessary.
    235     while (!Traits::Empty(&impl_)) {
    236       typename Traits::Impl impl;
    237       Traits::Swap(impl_, impl);
    238       for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
    239         Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
    240                         Traits::Key(i));
    241       }
    242     }
    243   }
    244 
    245   /**
    246    * Helper class for GetReference/SetWithReference. Do not use outside
    247    * that context.
    248    */
    249   class PersistentValueReference {
    250    public:
    251     PersistentValueReference() : value_(kPersistentContainerNotFound) { }
    252     PersistentValueReference(const PersistentValueReference& other)
    253         : value_(other.value_) { }
    254 
    255     Local<V> NewLocal(Isolate* isolate) const {
    256       return Local<V>::New(isolate, FromVal(value_));
    257     }
    258     bool IsEmpty() const {
    259       return value_ == kPersistentContainerNotFound;
    260     }
    261     template<typename T>
    262     bool SetReturnValue(ReturnValue<T> returnValue) {
    263       return SetReturnValueFromVal(&returnValue, value_);
    264     }
    265     void Reset() {
    266       value_ = kPersistentContainerNotFound;
    267     }
    268     void operator=(const PersistentValueReference& other) {
    269       value_ = other.value_;
    270     }
    271 
    272    private:
    273     friend class PersistentValueMapBase;
    274     friend class PersistentValueMap<K, V, Traits>;
    275     friend class GlobalValueMap<K, V, Traits>;
    276 
    277     explicit PersistentValueReference(PersistentContainerValue value)
    278         : value_(value) { }
    279 
    280     void operator=(PersistentContainerValue value) {
    281       value_ = value;
    282     }
    283 
    284     PersistentContainerValue value_;
    285   };
    286 
    287   /**
    288    * Get a reference to a map value. This enables fast, repeated access
    289    * to a value stored in the map while the map remains unchanged.
    290    *
    291    * Careful: This is potentially unsafe, so please use with care.
    292    * The value will become invalid if the value for this key changes
    293    * in the underlying map, as a result of Set or Remove for the same
    294    * key; as a result of the weak callback for the same key; or as a
    295    * result of calling Clear() or destruction of the map.
    296    */
    297   PersistentValueReference GetReference(const K& key) {
    298     return PersistentValueReference(Traits::Get(&impl_, key));
    299   }
    300 
    301  protected:
    302   explicit PersistentValueMapBase(Isolate* isolate) : isolate_(isolate) {}
    303 
    304   ~PersistentValueMapBase() { Clear(); }
    305 
    306   Isolate* isolate() { return isolate_; }
    307   typename Traits::Impl* impl() { return &impl_; }
    308 
    309   static V* FromVal(PersistentContainerValue v) {
    310     return reinterpret_cast<V*>(v);
    311   }
    312 
    313   static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
    314     V* v = persistent->val_;
    315     persistent->val_ = 0;
    316     return reinterpret_cast<PersistentContainerValue>(v);
    317   }
    318 
    319   static PersistentContainerValue Leak(Global<V>* persistent) {
    320     return reinterpret_cast<PersistentContainerValue>(persistent->val_);
    321   }
    322 
    323   /**
    324    * Return a container value as Global and make sure the weak
    325    * callback is properly disposed of. All remove functionality should go
    326    * through this.
    327    */
    328   static Global<V> Release(PersistentContainerValue v) {
    329     Global<V> p;
    330     p.val_ = FromVal(v);
    331     if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
    332       Traits::DisposeCallbackData(
    333           p.template ClearWeak<typename Traits::WeakCallbackDataType>());
    334     }
    335     return p.Pass();
    336   }
    337 
    338   void RemoveWeak(const K& key) {
    339     Global<V> p;
    340     p.val_ = FromVal(Traits::Remove(&impl_, key));
    341     p.Reset();
    342   }
    343 
    344  private:
    345   PersistentValueMapBase(PersistentValueMapBase&);
    346   void operator=(PersistentValueMapBase&);
    347 
    348   static bool SetReturnValueFromVal(ReturnValue<Value>* returnValue,
    349                                     PersistentContainerValue value) {
    350     bool hasValue = value != kPersistentContainerNotFound;
    351     if (hasValue) {
    352       returnValue->SetInternal(
    353           *reinterpret_cast<internal::Object**>(FromVal(value)));
    354     }
    355     return hasValue;
    356   }
    357 
    358   Isolate* isolate_;
    359   typename Traits::Impl impl_;
    360 };
    361 
    362 
    363 template <typename K, typename V, typename Traits>
    364 class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
    365  public:
    366   explicit PersistentValueMap(Isolate* isolate)
    367       : PersistentValueMapBase<K, V, Traits>(isolate) {}
    368 
    369   typedef
    370       typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
    371           PersistentValueReference;
    372 
    373   /**
    374    * Put value into map. Depending on Traits::kIsWeak, the value will be held
    375    * by the map strongly or weakly.
    376    * Returns old value as Global.
    377    */
    378   Global<V> Set(const K& key, Local<V> value) {
    379     Global<V> persistent(this->isolate(), value);
    380     return SetUnique(key, &persistent);
    381   }
    382 
    383   /**
    384    * Put value into map, like Set(const K&, Local<V>).
    385    */
    386   Global<V> Set(const K& key, Global<V> value) {
    387     return SetUnique(key, &value);
    388   }
    389 
    390   /**
    391    * Put the value into the map, and set the 'weak' callback when demanded
    392    * by the Traits class.
    393    */
    394   Global<V> SetUnique(const K& key, Global<V>* persistent) {
    395     if (Traits::kCallbackType != kNotWeak) {
    396       Local<V> value(Local<V>::New(this->isolate(), *persistent));
    397       persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
    398         Traits::WeakCallbackParameter(this, key, value), WeakCallback);
    399     }
    400     PersistentContainerValue old_value =
    401         Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
    402     return this->Release(old_value).Pass();
    403   }
    404 
    405   /**
    406    * Put a value into the map and update the reference.
    407    * Restrictions of GetReference apply here as well.
    408    */
    409   Global<V> Set(const K& key, Global<V> value,
    410                 PersistentValueReference* reference) {
    411     *reference = this->Leak(&value);
    412     return SetUnique(key, &value);
    413   }
    414 
    415  private:
    416   static void WeakCallback(
    417       const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
    418     if (Traits::kCallbackType != kNotWeak) {
    419       PersistentValueMap<K, V, Traits>* persistentValueMap =
    420           Traits::MapFromWeakCallbackInfo(data);
    421       K key = Traits::KeyFromWeakCallbackInfo(data);
    422       Traits::Dispose(data.GetIsolate(),
    423                       persistentValueMap->Remove(key).Pass(), key);
    424       Traits::DisposeCallbackData(data.GetParameter());
    425     }
    426   }
    427 };
    428 
    429 
    430 template <typename K, typename V, typename Traits>
    431 class GlobalValueMap : public PersistentValueMapBase<K, V, Traits> {
    432  public:
    433   explicit GlobalValueMap(Isolate* isolate)
    434       : PersistentValueMapBase<K, V, Traits>(isolate) {}
    435 
    436   typedef
    437       typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
    438           PersistentValueReference;
    439 
    440   /**
    441    * Put value into map. Depending on Traits::kIsWeak, the value will be held
    442    * by the map strongly or weakly.
    443    * Returns old value as Global.
    444    */
    445   Global<V> Set(const K& key, Local<V> value) {
    446     Global<V> persistent(this->isolate(), value);
    447     return SetUnique(key, &persistent);
    448   }
    449 
    450   /**
    451    * Put value into map, like Set(const K&, Local<V>).
    452    */
    453   Global<V> Set(const K& key, Global<V> value) {
    454     return SetUnique(key, &value);
    455   }
    456 
    457   /**
    458    * Put the value into the map, and set the 'weak' callback when demanded
    459    * by the Traits class.
    460    */
    461   Global<V> SetUnique(const K& key, Global<V>* persistent) {
    462     if (Traits::kCallbackType != kNotWeak) {
    463       WeakCallbackType callback_type =
    464           Traits::kCallbackType == kWeakWithInternalFields
    465               ? WeakCallbackType::kInternalFields
    466               : WeakCallbackType::kParameter;
    467       Local<V> value(Local<V>::New(this->isolate(), *persistent));
    468       persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
    469           Traits::WeakCallbackParameter(this, key, value), OnWeakCallback,
    470           callback_type);
    471     }
    472     PersistentContainerValue old_value =
    473         Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
    474     return this->Release(old_value).Pass();
    475   }
    476 
    477   /**
    478    * Put a value into the map and update the reference.
    479    * Restrictions of GetReference apply here as well.
    480    */
    481   Global<V> Set(const K& key, Global<V> value,
    482                 PersistentValueReference* reference) {
    483     *reference = this->Leak(&value);
    484     return SetUnique(key, &value);
    485   }
    486 
    487  private:
    488   static void OnWeakCallback(
    489       const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
    490     if (Traits::kCallbackType != kNotWeak) {
    491       auto map = Traits::MapFromWeakCallbackInfo(data);
    492       K key = Traits::KeyFromWeakCallbackInfo(data);
    493       map->RemoveWeak(key);
    494       Traits::OnWeakCallback(data);
    495       data.SetSecondPassCallback(SecondWeakCallback);
    496     }
    497   }
    498 
    499   static void SecondWeakCallback(
    500       const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
    501     Traits::DisposeWeak(data);
    502   }
    503 };
    504 
    505 
    506 /**
    507  * A map that uses Global as value and std::map as the backing
    508  * implementation. Persistents are held non-weak.
    509  *
    510  * C++11 embedders don't need this class, as they can use
    511  * Global directly in std containers.
    512  */
    513 template<typename K, typename V,
    514     typename Traits = DefaultPersistentValueMapTraits<K, V> >
    515 class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
    516  public:
    517   explicit StdPersistentValueMap(Isolate* isolate)
    518       : PersistentValueMap<K, V, Traits>(isolate) {}
    519 };
    520 
    521 
    522 /**
    523  * A map that uses Global as value and std::map as the backing
    524  * implementation. Globals are held non-weak.
    525  *
    526  * C++11 embedders don't need this class, as they can use
    527  * Global directly in std containers.
    528  */
    529 template <typename K, typename V,
    530           typename Traits = DefaultGlobalMapTraits<K, V> >
    531 class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
    532  public:
    533   explicit StdGlobalValueMap(Isolate* isolate)
    534       : GlobalValueMap<K, V, Traits>(isolate) {}
    535 };
    536 
    537 
    538 class DefaultPersistentValueVectorTraits {
    539  public:
    540   typedef std::vector<PersistentContainerValue> Impl;
    541 
    542   static void Append(Impl* impl, PersistentContainerValue value) {
    543     impl->push_back(value);
    544   }
    545   static bool IsEmpty(const Impl* impl) {
    546     return impl->empty();
    547   }
    548   static size_t Size(const Impl* impl) {
    549     return impl->size();
    550   }
    551   static PersistentContainerValue Get(const Impl* impl, size_t i) {
    552     return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
    553   }
    554   static void ReserveCapacity(Impl* impl, size_t capacity) {
    555     impl->reserve(capacity);
    556   }
    557   static void Clear(Impl* impl) {
    558     impl->clear();
    559   }
    560 };
    561 
    562 
    563 /**
    564  * A vector wrapper that safely stores Global values.
    565  * C++11 embedders don't need this class, as they can use Global
    566  * directly in std containers.
    567  *
    568  * This class relies on a backing vector implementation, whose type and methods
    569  * are described by the Traits class. The backing map will handle values of type
    570  * PersistentContainerValue, with all conversion into and out of V8
    571  * handles being transparently handled by this class.
    572  */
    573 template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
    574 class PersistentValueVector {
    575  public:
    576   explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
    577 
    578   ~PersistentValueVector() {
    579     Clear();
    580   }
    581 
    582   /**
    583    * Append a value to the vector.
    584    */
    585   void Append(Local<V> value) {
    586     Global<V> persistent(isolate_, value);
    587     Traits::Append(&impl_, ClearAndLeak(&persistent));
    588   }
    589 
    590   /**
    591    * Append a persistent's value to the vector.
    592    */
    593   void Append(Global<V> persistent) {
    594     Traits::Append(&impl_, ClearAndLeak(&persistent));
    595   }
    596 
    597   /**
    598    * Are there any values in the vector?
    599    */
    600   bool IsEmpty() const {
    601     return Traits::IsEmpty(&impl_);
    602   }
    603 
    604   /**
    605    * How many elements are in the vector?
    606    */
    607   size_t Size() const {
    608     return Traits::Size(&impl_);
    609   }
    610 
    611   /**
    612    * Retrieve the i-th value in the vector.
    613    */
    614   Local<V> Get(size_t index) const {
    615     return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
    616   }
    617 
    618   /**
    619    * Remove all elements from the vector.
    620    */
    621   void Clear() {
    622     size_t length = Traits::Size(&impl_);
    623     for (size_t i = 0; i < length; i++) {
    624       Global<V> p;
    625       p.val_ = FromVal(Traits::Get(&impl_, i));
    626     }
    627     Traits::Clear(&impl_);
    628   }
    629 
    630   /**
    631    * Reserve capacity in the vector.
    632    * (Efficiency gains depend on the backing implementation.)
    633    */
    634   void ReserveCapacity(size_t capacity) {
    635     Traits::ReserveCapacity(&impl_, capacity);
    636   }
    637 
    638  private:
    639   static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
    640     V* v = persistent->val_;
    641     persistent->val_ = 0;
    642     return reinterpret_cast<PersistentContainerValue>(v);
    643   }
    644 
    645   static V* FromVal(PersistentContainerValue v) {
    646     return reinterpret_cast<V*>(v);
    647   }
    648 
    649   Isolate* isolate_;
    650   typename Traits::Impl impl_;
    651 };
    652 
    653 }  // namespace v8
    654 
    655 #endif  // V8_UTIL_H
    656