• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
Empty(Impl * impl)45    static bool Empty(Impl* impl) { return impl->empty(); }
Size(Impl * impl)46    static size_t Size(Impl* impl) { return impl->size(); }
Swap(Impl & a,Impl & b)47    static void Swap(Impl& a, Impl& b) { std::swap(a, b); }  // NOLINT
Begin(Impl * impl)48    static Iterator Begin(Impl* impl) { return impl->begin(); }
End(Impl * impl)49    static Iterator End(Impl* impl) { return impl->end(); }
Key(Iterator it)50    static K Key(Iterator it) { return it->first; }
Value(Iterator it)51    static PersistentContainerValue Value(Iterator it) { return it->second; }
Set(Impl * impl,K key,PersistentContainerValue value)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    }
Get(Impl * impl,K key)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    }
Remove(Impl * impl,K key)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  
WeakCallbackParameter(MapType * map,const K & key,Local<V> value)94    static WeakCallbackDataType* WeakCallbackParameter(
95        MapType* map, const K& key, Local<V> value) {
96      return NULL;
97    }
MapFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)98    static MapType* MapFromWeakCallbackInfo(
99        const WeakCallbackInfo<WeakCallbackDataType>& data) {
100      return NULL;
101    }
KeyFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)102    static K KeyFromWeakCallbackInfo(
103        const WeakCallbackInfo<WeakCallbackDataType>& data) {
104      return K();
105    }
DisposeCallbackData(WeakCallbackDataType * data)106    static void DisposeCallbackData(WeakCallbackDataType* data) { }
Dispose(Isolate * isolate,Global<V> value,K key)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  
WeakCallbackParameter(MapType * map,const K & key,Local<V> value)123    static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
124                                                       Local<V> value) {
125      return nullptr;
126    }
MapFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)127    static MapType* MapFromWeakCallbackInfo(
128        const WeakCallbackInfo<WeakCallbackDataType>& data) {
129      return nullptr;
130    }
KeyFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)131    static K KeyFromWeakCallbackInfo(
132        const WeakCallbackInfo<WeakCallbackDataType>& data) {
133      return K();
134    }
DisposeCallbackData(WeakCallbackDataType * data)135    static void DisposeCallbackData(WeakCallbackDataType* data) {}
OnWeakCallback(const WeakCallbackInfo<WeakCallbackDataType> & data)136    static void OnWeakCallback(
137        const WeakCallbackInfo<WeakCallbackDataType>& data) {}
Dispose(Isolate * isolate,Global<V> value,K key)138    static void Dispose(Isolate* isolate, Global<V> value, K key) {}
139    // This is a second pass callback, so SetSecondPassCallback cannot be called.
DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType> & data)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