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