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