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* 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
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   * 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
351template <typename K, typename V, typename Traits>
352class 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
418template <typename K, typename V, typename Traits>
419class 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 */
501template<typename K, typename V,
502    typename Traits = DefaultPersistentValueMapTraits<K, V> >
503class 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 */
517template <typename K, typename V,
518          typename Traits = DefaultGlobalMapTraits<K, V> >
519class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
520 public:
521  explicit StdGlobalValueMap(Isolate* isolate)
522      : GlobalValueMap<K, V, Traits>(isolate) {}
523};
524
525
526class 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 */
561template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
562class 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