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