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 V8::RegisterExternallyReferencedObject with the map value for given
    201    * key.
    202    */
    203   void RegisterExternallyReferencedObject(K& key) {
    204     assert(Contains(key));
    205     V8::RegisterExternallyReferencedObject(
    206         reinterpret_cast<internal::Object**>(FromVal(Traits::Get(&impl_, key))),
    207         reinterpret_cast<internal::Isolate*>(GetIsolate()));
    208   }
    209 
    210   /**
    211    * Return value for key and remove it from the map.
    212    */
    213   Global<V> Remove(const K& key) {
    214     return Release(Traits::Remove(&impl_, key)).Pass();
    215   }
    216 
    217   /**
    218   * Traverses the map repeatedly,
    219   * in case side effects of disposal cause insertions.
    220   **/
    221   void Clear() {
    222     typedef typename Traits::Iterator It;
    223     HandleScope handle_scope(isolate_);
    224     // TODO(dcarney): figure out if this swap and loop is necessary.
    225     while (!Traits::Empty(&impl_)) {
    226       typename Traits::Impl impl;
    227       Traits::Swap(impl_, impl);
    228       for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
    229         Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
    230                         Traits::Key(i));
    231       }
    232     }
    233   }
    234 
    235   /**
    236    * Helper class for GetReference/SetWithReference. Do not use outside
    237    * that context.
    238    */
    239   class PersistentValueReference {
    240    public:
    241     PersistentValueReference() : value_(kPersistentContainerNotFound) { }
    242     PersistentValueReference(const PersistentValueReference& other)
    243         : value_(other.value_) { }
    244 
    245     Local<V> NewLocal(Isolate* isolate) const {
    246       return Local<V>::New(isolate, FromVal(value_));
    247     }
    248     bool IsEmpty() const {
    249       return value_ == kPersistentContainerNotFound;
    250     }
    251     template<typename T>
    252     bool SetReturnValue(ReturnValue<T> returnValue) {
    253       return SetReturnValueFromVal(&returnValue, value_);
    254     }
    255     void Reset() {
    256       value_ = kPersistentContainerNotFound;
    257     }
    258     void operator=(const PersistentValueReference& other) {
    259       value_ = other.value_;
    260     }
    261 
    262    private:
    263     friend class PersistentValueMapBase;
    264     friend class PersistentValueMap<K, V, Traits>;
    265     friend class GlobalValueMap<K, V, Traits>;
    266 
    267     explicit PersistentValueReference(PersistentContainerValue value)
    268         : value_(value) { }
    269 
    270     void operator=(PersistentContainerValue value) {
    271       value_ = value;
    272     }
    273 
    274     PersistentContainerValue value_;
    275   };
    276 
    277   /**
    278    * Get a reference to a map value. This enables fast, repeated access
    279    * to a value stored in the map while the map remains unchanged.
    280    *
    281    * Careful: This is potentially unsafe, so please use with care.
    282    * The value will become invalid if the value for this key changes
    283    * in the underlying map, as a result of Set or Remove for the same
    284    * key; as a result of the weak callback for the same key; or as a
    285    * result of calling Clear() or destruction of the map.
    286    */
    287   PersistentValueReference GetReference(const K& key) {
    288     return PersistentValueReference(Traits::Get(&impl_, key));
    289   }
    290 
    291  protected:
    292   explicit PersistentValueMapBase(Isolate* isolate) : isolate_(isolate) {}
    293 
    294   ~PersistentValueMapBase() { Clear(); }
    295 
    296   Isolate* isolate() { return isolate_; }
    297   typename Traits::Impl* impl() { return &impl_; }
    298 
    299   static V* FromVal(PersistentContainerValue v) {
    300     return reinterpret_cast<V*>(v);
    301   }
    302 
    303   static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
    304     V* v = persistent->val_;
    305     persistent->val_ = 0;
    306     return reinterpret_cast<PersistentContainerValue>(v);
    307   }
    308 
    309   static PersistentContainerValue Leak(Global<V>* persistent) {
    310     return reinterpret_cast<PersistentContainerValue>(persistent->val_);
    311   }
    312 
    313   /**
    314    * Return a container value as Global and make sure the weak
    315    * callback is properly disposed of. All remove functionality should go
    316    * through this.
    317    */
    318   static Global<V> Release(PersistentContainerValue v) {
    319     Global<V> p;
    320     p.val_ = FromVal(v);
    321     if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
    322       Traits::DisposeCallbackData(
    323           p.template ClearWeak<typename Traits::WeakCallbackDataType>());
    324     }
    325     return p.Pass();
    326   }
    327 
    328   void RemoveWeak(const K& key) {
    329     Global<V> p;
    330     p.val_ = FromVal(Traits::Remove(&impl_, key));
    331     p.Reset();
    332   }
    333 
    334  private:
    335   PersistentValueMapBase(PersistentValueMapBase&);
    336   void operator=(PersistentValueMapBase&);
    337 
    338   static bool SetReturnValueFromVal(ReturnValue<Value>* returnValue,
    339                                     PersistentContainerValue value) {
    340     bool hasValue = value != kPersistentContainerNotFound;
    341     if (hasValue) {
    342       returnValue->SetInternal(
    343           *reinterpret_cast<internal::Object**>(FromVal(value)));
    344     }
    345     return hasValue;
    346   }
    347 
    348   Isolate* isolate_;
    349   typename Traits::Impl impl_;
    350 };
    351 
    352 
    353 template <typename K, typename V, typename Traits>
    354 class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
    355  public:
    356   explicit PersistentValueMap(Isolate* isolate)
    357       : PersistentValueMapBase<K, V, Traits>(isolate) {}
    358 
    359   typedef
    360       typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
    361           PersistentValueReference;
    362 
    363   /**
    364    * Put value into map. Depending on Traits::kIsWeak, the value will be held
    365    * by the map strongly or weakly.
    366    * Returns old value as Global.
    367    */
    368   Global<V> Set(const K& key, Local<V> value) {
    369     Global<V> persistent(this->isolate(), value);
    370     return SetUnique(key, &persistent);
    371   }
    372 
    373   /**
    374    * Put value into map, like Set(const K&, Local<V>).
    375    */
    376   Global<V> Set(const K& key, Global<V> value) {
    377     return SetUnique(key, &value);
    378   }
    379 
    380   /**
    381    * Put the value into the map, and set the 'weak' callback when demanded
    382    * by the Traits class.
    383    */
    384   Global<V> SetUnique(const K& key, Global<V>* persistent) {
    385     if (Traits::kCallbackType != kNotWeak) {
    386       WeakCallbackType callback_type =
    387           Traits::kCallbackType == kWeakWithInternalFields
    388               ? WeakCallbackType::kInternalFields
    389               : WeakCallbackType::kParameter;
    390       Local<V> value(Local<V>::New(this->isolate(), *persistent));
    391       persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
    392           Traits::WeakCallbackParameter(this, key, value), WeakCallback,
    393           callback_type);
    394     }
    395     PersistentContainerValue old_value =
    396         Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
    397     return this->Release(old_value).Pass();
    398   }
    399 
    400   /**
    401    * Put a value into the map and update the reference.
    402    * Restrictions of GetReference apply here as well.
    403    */
    404   Global<V> Set(const K& key, Global<V> value,
    405                 PersistentValueReference* reference) {
    406     *reference = this->Leak(&value);
    407     return SetUnique(key, &value);
    408   }
    409 
    410  private:
    411   static void WeakCallback(
    412       const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
    413     if (Traits::kCallbackType != kNotWeak) {
    414       PersistentValueMap<K, V, Traits>* persistentValueMap =
    415           Traits::MapFromWeakCallbackInfo(data);
    416       K key = Traits::KeyFromWeakCallbackInfo(data);
    417       Traits::Dispose(data.GetIsolate(),
    418                       persistentValueMap->Remove(key).Pass(), key);
    419       Traits::DisposeCallbackData(data.GetParameter());
    420     }
    421   }
    422 };
    423 
    424 
    425 template <typename K, typename V, typename Traits>
    426 class GlobalValueMap : public PersistentValueMapBase<K, V, Traits> {
    427  public:
    428   explicit GlobalValueMap(Isolate* isolate)
    429       : PersistentValueMapBase<K, V, Traits>(isolate) {}
    430 
    431   typedef
    432       typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
    433           PersistentValueReference;
    434 
    435   /**
    436    * Put value into map. Depending on Traits::kIsWeak, the value will be held
    437    * by the map strongly or weakly.
    438    * Returns old value as Global.
    439    */
    440   Global<V> Set(const K& key, Local<V> value) {
    441     Global<V> persistent(this->isolate(), value);
    442     return SetUnique(key, &persistent);
    443   }
    444 
    445   /**
    446    * Put value into map, like Set(const K&, Local<V>).
    447    */
    448   Global<V> Set(const K& key, Global<V> value) {
    449     return SetUnique(key, &value);
    450   }
    451 
    452   /**
    453    * Put the value into the map, and set the 'weak' callback when demanded
    454    * by the Traits class.
    455    */
    456   Global<V> SetUnique(const K& key, Global<V>* persistent) {
    457     if (Traits::kCallbackType != kNotWeak) {
    458       WeakCallbackType callback_type =
    459           Traits::kCallbackType == kWeakWithInternalFields
    460               ? WeakCallbackType::kInternalFields
    461               : WeakCallbackType::kParameter;
    462       Local<V> value(Local<V>::New(this->isolate(), *persistent));
    463       persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
    464           Traits::WeakCallbackParameter(this, key, value), OnWeakCallback,
    465           callback_type);
    466     }
    467     PersistentContainerValue old_value =
    468         Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
    469     return this->Release(old_value).Pass();
    470   }
    471 
    472   /**
    473    * Put a value into the map and update the reference.
    474    * Restrictions of GetReference apply here as well.
    475    */
    476   Global<V> Set(const K& key, Global<V> value,
    477                 PersistentValueReference* reference) {
    478     *reference = this->Leak(&value);
    479     return SetUnique(key, &value);
    480   }
    481 
    482  private:
    483   static void OnWeakCallback(
    484       const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
    485     if (Traits::kCallbackType != kNotWeak) {
    486       auto map = Traits::MapFromWeakCallbackInfo(data);
    487       K key = Traits::KeyFromWeakCallbackInfo(data);
    488       map->RemoveWeak(key);
    489       Traits::OnWeakCallback(data);
    490       data.SetSecondPassCallback(SecondWeakCallback);
    491     }
    492   }
    493 
    494   static void SecondWeakCallback(
    495       const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
    496     Traits::DisposeWeak(data);
    497   }
    498 };
    499 
    500 
    501 /**
    502  * A map that uses Global as value and std::map as the backing
    503  * implementation. Persistents are held non-weak.
    504  *
    505  * C++11 embedders don't need this class, as they can use
    506  * Global directly in std containers.
    507  */
    508 template<typename K, typename V,
    509     typename Traits = DefaultPersistentValueMapTraits<K, V> >
    510 class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
    511  public:
    512   explicit StdPersistentValueMap(Isolate* isolate)
    513       : PersistentValueMap<K, V, Traits>(isolate) {}
    514 };
    515 
    516 
    517 /**
    518  * A map that uses Global as value and std::map as the backing
    519  * implementation. Globals are held non-weak.
    520  *
    521  * C++11 embedders don't need this class, as they can use
    522  * Global directly in std containers.
    523  */
    524 template <typename K, typename V,
    525           typename Traits = DefaultGlobalMapTraits<K, V> >
    526 class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
    527  public:
    528   explicit StdGlobalValueMap(Isolate* isolate)
    529       : GlobalValueMap<K, V, Traits>(isolate) {}
    530 };
    531 
    532 
    533 class DefaultPersistentValueVectorTraits {
    534  public:
    535   typedef std::vector<PersistentContainerValue> Impl;
    536 
    537   static void Append(Impl* impl, PersistentContainerValue value) {
    538     impl->push_back(value);
    539   }
    540   static bool IsEmpty(const Impl* impl) {
    541     return impl->empty();
    542   }
    543   static size_t Size(const Impl* impl) {
    544     return impl->size();
    545   }
    546   static PersistentContainerValue Get(const Impl* impl, size_t i) {
    547     return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
    548   }
    549   static void ReserveCapacity(Impl* impl, size_t capacity) {
    550     impl->reserve(capacity);
    551   }
    552   static void Clear(Impl* impl) {
    553     impl->clear();
    554   }
    555 };
    556 
    557 
    558 /**
    559  * A vector wrapper that safely stores Global values.
    560  * C++11 embedders don't need this class, as they can use Global
    561  * directly in std containers.
    562  *
    563  * This class relies on a backing vector implementation, whose type and methods
    564  * are described by the Traits class. The backing map will handle values of type
    565  * PersistentContainerValue, with all conversion into and out of V8
    566  * handles being transparently handled by this class.
    567  */
    568 template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
    569 class PersistentValueVector {
    570  public:
    571   explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
    572 
    573   ~PersistentValueVector() {
    574     Clear();
    575   }
    576 
    577   /**
    578    * Append a value to the vector.
    579    */
    580   void Append(Local<V> value) {
    581     Global<V> persistent(isolate_, value);
    582     Traits::Append(&impl_, ClearAndLeak(&persistent));
    583   }
    584 
    585   /**
    586    * Append a persistent's value to the vector.
    587    */
    588   void Append(Global<V> persistent) {
    589     Traits::Append(&impl_, ClearAndLeak(&persistent));
    590   }
    591 
    592   /**
    593    * Are there any values in the vector?
    594    */
    595   bool IsEmpty() const {
    596     return Traits::IsEmpty(&impl_);
    597   }
    598 
    599   /**
    600    * How many elements are in the vector?
    601    */
    602   size_t Size() const {
    603     return Traits::Size(&impl_);
    604   }
    605 
    606   /**
    607    * Retrieve the i-th value in the vector.
    608    */
    609   Local<V> Get(size_t index) const {
    610     return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
    611   }
    612 
    613   /**
    614    * Remove all elements from the vector.
    615    */
    616   void Clear() {
    617     size_t length = Traits::Size(&impl_);
    618     for (size_t i = 0; i < length; i++) {
    619       Global<V> p;
    620       p.val_ = FromVal(Traits::Get(&impl_, i));
    621     }
    622     Traits::Clear(&impl_);
    623   }
    624 
    625   /**
    626    * Reserve capacity in the vector.
    627    * (Efficiency gains depend on the backing implementation.)
    628    */
    629   void ReserveCapacity(size_t capacity) {
    630     Traits::ReserveCapacity(&impl_, capacity);
    631   }
    632 
    633  private:
    634   static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
    635     V* v = persistent->val_;
    636     persistent->val_ = 0;
    637     return reinterpret_cast<PersistentContainerValue>(v);
    638   }
    639 
    640   static V* FromVal(PersistentContainerValue v) {
    641     return reinterpret_cast<V*>(v);
    642   }
    643 
    644   Isolate* isolate_;
    645   typename Traits::Impl impl_;
    646 };
    647 
    648 }  // namespace v8
    649 
    650 #endif  // V8_UTIL_H
    651