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