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  */
23 namespace v8 {
24 
25 template <typename K, typename V, typename Traits>
26 class GlobalValueMap;
27 
28 typedef uintptr_t PersistentContainerValue;
29 static const uintptr_t kPersistentContainerNotFound = 0;
30 enum 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  */
43 template<typename K, typename V>
44 class StdMapTraits {
45  public:
46   // STL map & related:
47   typedef std::map<K, PersistentContainerValue> Impl;
48   typedef typename Impl::iterator Iterator;
49 
Empty(Impl * impl)50   static bool Empty(Impl* impl) { return impl->empty(); }
Size(Impl * impl)51   static size_t Size(Impl* impl) { return impl->size(); }
Swap(Impl & a,Impl & b)52   static void Swap(Impl& a, Impl& b) { std::swap(a, b); }
Begin(Impl * impl)53   static Iterator Begin(Impl* impl) { return impl->begin(); }
End(Impl * impl)54   static Iterator End(Impl* impl) { return impl->end(); }
Key(Iterator it)55   static K Key(Iterator it) { return it->first; }
Value(Iterator it)56   static PersistentContainerValue Value(Iterator it) { return it->second; }
Set(Impl * impl,K key,PersistentContainerValue value)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   }
Get(Impl * impl,K key)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   }
Remove(Impl * impl,K key)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  */
90 template<typename K, typename V>
91 class 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 
WeakCallbackParameter(MapType * map,const K & key,Local<V> value)99   static WeakCallbackDataType* WeakCallbackParameter(
100       MapType* map, const K& key, Local<V> value) {
101     return nullptr;
102   }
MapFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)103   static MapType* MapFromWeakCallbackInfo(
104       const WeakCallbackInfo<WeakCallbackDataType>& data) {
105     return nullptr;
106   }
KeyFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)107   static K KeyFromWeakCallbackInfo(
108       const WeakCallbackInfo<WeakCallbackDataType>& data) {
109     return K();
110   }
DisposeCallbackData(WeakCallbackDataType * data)111   static void DisposeCallbackData(WeakCallbackDataType* data) { }
Dispose(Isolate * isolate,Global<V> value,K key)112   static void Dispose(Isolate* isolate, Global<V> value, K key) {}
113 };
114 
115 
116 template <typename K, typename V>
117 class 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 
WeakCallbackParameter(MapType * map,const K & key,Local<V> value)128   static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
129                                                      Local<V> value) {
130     return nullptr;
131   }
MapFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)132   static MapType* MapFromWeakCallbackInfo(
133       const WeakCallbackInfo<WeakCallbackDataType>& data) {
134     return nullptr;
135   }
KeyFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)136   static K KeyFromWeakCallbackInfo(
137       const WeakCallbackInfo<WeakCallbackDataType>& data) {
138     return K();
139   }
DisposeCallbackData(WeakCallbackDataType * data)140   static void DisposeCallbackData(WeakCallbackDataType* data) {}
OnWeakCallback(const WeakCallbackInfo<WeakCallbackDataType> & data)141   static void OnWeakCallback(
142       const WeakCallbackInfo<WeakCallbackDataType>& data) {}
Dispose(Isolate * isolate,Global<V> value,K key)143   static void Dispose(Isolate* isolate, Global<V> value, K key) {}
144   // This is a second pass callback, so SetSecondPassCallback cannot be called.
DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType> & data)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  */
165 template <typename K, typename V, typename Traits>
166 class 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 
353 template <typename K, typename V, typename Traits>
354 class 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 
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   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  */
516 template<typename K, typename V,
517     typename Traits = DefaultPersistentValueMapTraits<K, V> >
518 class 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  */
532 template <typename K, typename V,
533           typename Traits = DefaultGlobalMapTraits<K, V> >
534 class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
535  public:
536   explicit StdGlobalValueMap(Isolate* isolate)
537       : GlobalValueMap<K, V, Traits>(isolate) {}
538 };
539 
540 
541 class 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  */
576 template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
577 class 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