• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
19 namespace v8 {
20 
21 typedef uintptr_t PersistentContainerValue;
22 static const uintptr_t kPersistentContainerNotFound = 0;
23 enum 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  */
38 template<typename K, typename V>
39 class StdMapTraits {
40  public:
41   // STL map & related:
42   typedef std::map<K, PersistentContainerValue> Impl;
43   typedef typename Impl::iterator Iterator;
44 
Empty(Impl * impl)45   static bool Empty(Impl* impl) { return impl->empty(); }
Size(Impl * impl)46   static size_t Size(Impl* impl) { return impl->size(); }
Swap(Impl & a,Impl & b)47   static void Swap(Impl& a, Impl& b) { std::swap(a, b); }  // NOLINT
Begin(Impl * impl)48   static Iterator Begin(Impl* impl) { return impl->begin(); }
End(Impl * impl)49   static Iterator End(Impl* impl) { return impl->end(); }
Key(Iterator it)50   static K Key(Iterator it) { return it->first; }
Value(Iterator it)51   static PersistentContainerValue Value(Iterator it) { return it->second; }
Set(Impl * impl,K key,PersistentContainerValue value)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   }
Get(Impl * impl,K key)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   }
Remove(Impl * impl,K key)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  */
85 template<typename K, typename V>
86 class 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 
WeakCallbackParameter(MapType * map,const K & key,Local<V> value)94   static WeakCallbackDataType* WeakCallbackParameter(
95       MapType* map, const K& key, Local<V> value) {
96     return NULL;
97   }
MapFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)98   static MapType* MapFromWeakCallbackInfo(
99       const WeakCallbackInfo<WeakCallbackDataType>& data) {
100     return NULL;
101   }
KeyFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)102   static K KeyFromWeakCallbackInfo(
103       const WeakCallbackInfo<WeakCallbackDataType>& data) {
104     return K();
105   }
DisposeCallbackData(WeakCallbackDataType * data)106   static void DisposeCallbackData(WeakCallbackDataType* data) { }
Dispose(Isolate * isolate,Global<V> value,K key)107   static void Dispose(Isolate* isolate, Global<V> value, K key) {}
108 };
109 
110 
111 template <typename K, typename V>
112 class 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 
WeakCallbackParameter(MapType * map,const K & key,Local<V> value)123   static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
124                                                      Local<V> value) {
125     return nullptr;
126   }
MapFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)127   static MapType* MapFromWeakCallbackInfo(
128       const WeakCallbackInfo<WeakCallbackDataType>& data) {
129     return nullptr;
130   }
KeyFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)131   static K KeyFromWeakCallbackInfo(
132       const WeakCallbackInfo<WeakCallbackDataType>& data) {
133     return K();
134   }
DisposeCallbackData(WeakCallbackDataType * data)135   static void DisposeCallbackData(WeakCallbackDataType* data) {}
OnWeakCallback(const WeakCallbackInfo<WeakCallbackDataType> & data)136   static void OnWeakCallback(
137       const WeakCallbackInfo<WeakCallbackDataType>& data) {}
Dispose(Isolate * isolate,Global<V> value,K key)138   static void Dispose(Isolate* isolate, Global<V> value, K key) {}
139   // This is a second pass callback, so SetSecondPassCallback cannot be called.
DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType> & data)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  */
160 template <typename K, typename V, typename Traits>
161 class 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 
362 template <typename K, typename V, typename Traits>
363 class 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 
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 
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  */
512 template<typename K, typename V,
513     typename Traits = DefaultPersistentValueMapTraits<K, V> >
514 class 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  */
528 template <typename K, typename V,
529           typename Traits = DefaultGlobalMapTraits<K, V> >
530 class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
531  public:
532   explicit StdGlobalValueMap(Isolate* isolate)
533       : GlobalValueMap<K, V, Traits>(isolate) {}
534 };
535 
536 
537 class 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  */
572 template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
573 class 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