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 */
19namespace v8 {
20
21typedef uintptr_t PersistentContainerValue;
22static const uintptr_t kPersistentContainerNotFound = 0;
23enum 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 */
38template<typename K, typename V>
39class 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 */
85template<typename K, typename V>
86class DefaultPersistentValueMapTraits : public StdMapTraits<K, V> {
87 public:
88  // Weak callback & friends:
89  static const PersistentContainerCallbackType kCallbackType = kNotWeak;
90  typedef PersistentValueMap<K, V, DefaultPersistentValueMapTraits<K, V> >
91      MapType;
92  typedef void WeakCallbackDataType;
93
94  static WeakCallbackDataType* WeakCallbackParameter(
95      MapType* map, const K& key, Local<V> value) {
96    return NULL;
97  }
98  static MapType* MapFromWeakCallbackInfo(
99      const WeakCallbackInfo<WeakCallbackDataType>& data) {
100    return NULL;
101  }
102  static K KeyFromWeakCallbackInfo(
103      const WeakCallbackInfo<WeakCallbackDataType>& data) {
104    return K();
105  }
106  static void DisposeCallbackData(WeakCallbackDataType* data) { }
107  static void Dispose(Isolate* isolate, Global<V> value, K key) {}
108};
109
110
111template <typename K, typename V>
112class 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 */
160template <typename K, typename V, typename Traits>
161class 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
362template <typename K, typename V, typename Traits>
363class 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
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
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 */
512template<typename K, typename V,
513    typename Traits = DefaultPersistentValueMapTraits<K, V> >
514class 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 */
528template <typename K, typename V,
529          typename Traits = DefaultGlobalMapTraits<K, V> >
530class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
531 public:
532  explicit StdGlobalValueMap(Isolate* isolate)
533      : GlobalValueMap<K, V, Traits>(isolate) {}
534};
535
536
537class 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 */
572template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
573class 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