• 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"
9 #include <map>
10 #include <vector>
11 
12 /**
13  * Support for Persistent containers.
14  *
15  * C++11 embedders can use STL containers with UniquePersistent 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   kWeak
26 };
27 
28 
29 /**
30  * A default trait implemenation for PersistentValueMap which uses std::map
31  * as a backing map.
32  *
33  * Users will have to implement their own weak callbacks & dispose traits.
34  */
35 template<typename K, typename V>
36 class StdMapTraits {
37  public:
38   // STL map & related:
39   typedef std::map<K, PersistentContainerValue> Impl;
40   typedef typename Impl::iterator Iterator;
41 
Empty(Impl * impl)42   static bool Empty(Impl* impl) { return impl->empty(); }
Size(Impl * impl)43   static size_t Size(Impl* impl) { return impl->size(); }
Swap(Impl & a,Impl & b)44   static void Swap(Impl& a, Impl& b) { std::swap(a, b); }  // NOLINT
Begin(Impl * impl)45   static Iterator Begin(Impl* impl) { return impl->begin(); }
End(Impl * impl)46   static Iterator End(Impl* impl) { return impl->end(); }
Key(Iterator it)47   static K Key(Iterator it) { return it->first; }
Value(Iterator it)48   static PersistentContainerValue Value(Iterator it) { return it->second; }
Set(Impl * impl,K key,PersistentContainerValue value)49   static PersistentContainerValue Set(Impl* impl, K key,
50       PersistentContainerValue value) {
51     std::pair<Iterator, bool> res = impl->insert(std::make_pair(key, value));
52     PersistentContainerValue old_value = kPersistentContainerNotFound;
53     if (!res.second) {
54       old_value = res.first->second;
55       res.first->second = value;
56     }
57     return old_value;
58   }
Get(Impl * impl,K key)59   static PersistentContainerValue Get(Impl* impl, K key) {
60     Iterator it = impl->find(key);
61     if (it == impl->end()) return kPersistentContainerNotFound;
62     return it->second;
63   }
Remove(Impl * impl,K key)64   static PersistentContainerValue Remove(Impl* impl, K key) {
65     Iterator it = impl->find(key);
66     if (it == impl->end()) return kPersistentContainerNotFound;
67     PersistentContainerValue value = it->second;
68     impl->erase(it);
69     return value;
70   }
71 };
72 
73 
74 /**
75  * A default trait implementation for PersistentValueMap, which inherits
76  * a std:map backing map from StdMapTraits and holds non-weak persistent
77  * objects and has no special Dispose handling.
78  *
79  * You should not derive from this class, since MapType depends on the
80  * surrounding class, and hence a subclass cannot simply inherit the methods.
81  */
82 template<typename K, typename V>
83 class DefaultPersistentValueMapTraits : public StdMapTraits<K, V> {
84  public:
85   // Weak callback & friends:
86   static const PersistentContainerCallbackType kCallbackType = kNotWeak;
87   typedef PersistentValueMap<K, V, DefaultPersistentValueMapTraits<K, V> >
88       MapType;
89   typedef void WeakCallbackDataType;
90 
WeakCallbackParameter(MapType * map,const K & key,Local<V> value)91   static WeakCallbackDataType* WeakCallbackParameter(
92       MapType* map, const K& key, Local<V> value) {
93     return NULL;
94   }
MapFromWeakCallbackData(const WeakCallbackData<V,WeakCallbackDataType> & data)95   static MapType* MapFromWeakCallbackData(
96           const WeakCallbackData<V, WeakCallbackDataType>& data) {
97     return NULL;
98   }
KeyFromWeakCallbackData(const WeakCallbackData<V,WeakCallbackDataType> & data)99   static K KeyFromWeakCallbackData(
100       const WeakCallbackData<V, WeakCallbackDataType>& data) {
101     return K();
102   }
DisposeCallbackData(WeakCallbackDataType * data)103   static void DisposeCallbackData(WeakCallbackDataType* data) { }
Dispose(Isolate * isolate,UniquePersistent<V> value,K key)104   static void Dispose(Isolate* isolate, UniquePersistent<V> value, K key) { }
105 };
106 
107 
108 /**
109  * A map wrapper that allows using UniquePersistent as a mapped value.
110  * C++11 embedders don't need this class, as they can use UniquePersistent
111  * directly in std containers.
112  *
113  * The map relies on a backing map, whose type and accessors are described
114  * by the Traits class. The backing map will handle values of type
115  * PersistentContainerValue, with all conversion into and out of V8
116  * handles being transparently handled by this class.
117  */
118 template<typename K, typename V, typename Traits>
119 class PersistentValueMap {
120  public:
PersistentValueMap(Isolate * isolate)121   explicit PersistentValueMap(Isolate* isolate) : isolate_(isolate) {}
122 
~PersistentValueMap()123   ~PersistentValueMap() { Clear(); }
124 
GetIsolate()125   Isolate* GetIsolate() { return isolate_; }
126 
127   /**
128    * Return size of the map.
129    */
Size()130   size_t Size() { return Traits::Size(&impl_); }
131 
132   /**
133    * Return whether the map holds weak persistents.
134    */
IsWeak()135   bool IsWeak() { return Traits::kCallbackType != kNotWeak; }
136 
137   /**
138    * Get value stored in map.
139    */
Get(const K & key)140   Local<V> Get(const K& key) {
141     return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, key)));
142   }
143 
144   /**
145    * Check whether a value is contained in the map.
146    */
Contains(const K & key)147   bool Contains(const K& key) {
148     return Traits::Get(&impl_, key) != kPersistentContainerNotFound;
149   }
150 
151   /**
152    * Get value stored in map and set it in returnValue.
153    * Return true if a value was found.
154    */
SetReturnValue(const K & key,ReturnValue<Value> returnValue)155   bool SetReturnValue(const K& key,
156       ReturnValue<Value> returnValue) {
157     return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key));
158   }
159 
160   /**
161    * Call Isolate::SetReference with the given parent and the map value.
162    */
SetReference(const K & key,const Persistent<Object> & parent)163   void SetReference(const K& key,
164       const Persistent<Object>& parent) {
165     GetIsolate()->SetReference(
166       reinterpret_cast<internal::Object**>(parent.val_),
167       reinterpret_cast<internal::Object**>(FromVal(Traits::Get(&impl_, key))));
168   }
169 
170   /**
171    * Put value into map. Depending on Traits::kIsWeak, the value will be held
172    * by the map strongly or weakly.
173    * Returns old value as UniquePersistent.
174    */
Set(const K & key,Local<V> value)175   UniquePersistent<V> Set(const K& key, Local<V> value) {
176     UniquePersistent<V> persistent(isolate_, value);
177     return SetUnique(key, &persistent);
178   }
179 
180   /**
181    * Put value into map, like Set(const K&, Local<V>).
182    */
Set(const K & key,UniquePersistent<V> value)183   UniquePersistent<V> Set(const K& key, UniquePersistent<V> value) {
184     return SetUnique(key, &value);
185   }
186 
187   /**
188    * Return value for key and remove it from the map.
189    */
Remove(const K & key)190   UniquePersistent<V> Remove(const K& key) {
191     return Release(Traits::Remove(&impl_, key)).Pass();
192   }
193 
194   /**
195   * Traverses the map repeatedly,
196   * in case side effects of disposal cause insertions.
197   **/
Clear()198   void Clear() {
199     typedef typename Traits::Iterator It;
200     HandleScope handle_scope(isolate_);
201     // TODO(dcarney): figure out if this swap and loop is necessary.
202     while (!Traits::Empty(&impl_)) {
203       typename Traits::Impl impl;
204       Traits::Swap(impl_, impl);
205       for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
206         Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
207                         Traits::Key(i));
208       }
209     }
210   }
211 
212   /**
213    * Helper class for GetReference/SetWithReference. Do not use outside
214    * that context.
215    */
216   class PersistentValueReference {
217    public:
PersistentValueReference()218     PersistentValueReference() : value_(kPersistentContainerNotFound) { }
PersistentValueReference(const PersistentValueReference & other)219     PersistentValueReference(const PersistentValueReference& other)
220         : value_(other.value_) { }
221 
NewLocal(Isolate * isolate)222     Local<V> NewLocal(Isolate* isolate) const {
223       return Local<V>::New(isolate, FromVal(value_));
224     }
IsEmpty()225     bool IsEmpty() const {
226       return value_ == kPersistentContainerNotFound;
227     }
228     template<typename T>
SetReturnValue(ReturnValue<T> returnValue)229     bool SetReturnValue(ReturnValue<T> returnValue) {
230       return SetReturnValueFromVal(&returnValue, value_);
231     }
Reset()232     void Reset() {
233       value_ = kPersistentContainerNotFound;
234     }
235     void operator=(const PersistentValueReference& other) {
236       value_ = other.value_;
237     }
238 
239    private:
240     friend class PersistentValueMap;
241 
PersistentValueReference(PersistentContainerValue value)242     explicit PersistentValueReference(PersistentContainerValue value)
243         : value_(value) { }
244 
245     void operator=(PersistentContainerValue value) {
246       value_ = value;
247     }
248 
249     PersistentContainerValue value_;
250   };
251 
252   /**
253    * Get a reference to a map value. This enables fast, repeated access
254    * to a value stored in the map while the map remains unchanged.
255    *
256    * Careful: This is potentially unsafe, so please use with care.
257    * The value will become invalid if the value for this key changes
258    * in the underlying map, as a result of Set or Remove for the same
259    * key; as a result of the weak callback for the same key; or as a
260    * result of calling Clear() or destruction of the map.
261    */
GetReference(const K & key)262   PersistentValueReference GetReference(const K& key) {
263     return PersistentValueReference(Traits::Get(&impl_, key));
264   }
265 
266   /**
267    * Put a value into the map and update the reference.
268    * Restrictions of GetReference apply here as well.
269    */
Set(const K & key,UniquePersistent<V> value,PersistentValueReference * reference)270   UniquePersistent<V> Set(const K& key, UniquePersistent<V> value,
271                           PersistentValueReference* reference) {
272     *reference = Leak(&value);
273     return SetUnique(key, &value);
274   }
275 
276  private:
277   PersistentValueMap(PersistentValueMap&);
278   void operator=(PersistentValueMap&);
279 
280   /**
281    * Put the value into the map, and set the 'weak' callback when demanded
282    * by the Traits class.
283    */
SetUnique(const K & key,UniquePersistent<V> * persistent)284   UniquePersistent<V> SetUnique(const K& key, UniquePersistent<V>* persistent) {
285     if (Traits::kCallbackType != kNotWeak) {
286       Local<V> value(Local<V>::New(isolate_, *persistent));
287       persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
288         Traits::WeakCallbackParameter(this, key, value), WeakCallback);
289     }
290     PersistentContainerValue old_value =
291         Traits::Set(&impl_, key, ClearAndLeak(persistent));
292     return Release(old_value).Pass();
293   }
294 
WeakCallback(const WeakCallbackData<V,typename Traits::WeakCallbackDataType> & data)295   static void WeakCallback(
296       const WeakCallbackData<V, typename Traits::WeakCallbackDataType>& data) {
297     if (Traits::kCallbackType != kNotWeak) {
298       PersistentValueMap<K, V, Traits>* persistentValueMap =
299           Traits::MapFromWeakCallbackData(data);
300       K key = Traits::KeyFromWeakCallbackData(data);
301       Traits::Dispose(data.GetIsolate(),
302                       persistentValueMap->Remove(key).Pass(), key);
303       Traits::DisposeCallbackData(data.GetParameter());
304     }
305   }
306 
FromVal(PersistentContainerValue v)307   static V* FromVal(PersistentContainerValue v) {
308     return reinterpret_cast<V*>(v);
309   }
310 
SetReturnValueFromVal(ReturnValue<Value> * returnValue,PersistentContainerValue value)311   static bool SetReturnValueFromVal(
312       ReturnValue<Value>* returnValue, PersistentContainerValue value) {
313     bool hasValue = value != kPersistentContainerNotFound;
314     if (hasValue) {
315       returnValue->SetInternal(
316           *reinterpret_cast<internal::Object**>(FromVal(value)));
317     }
318     return hasValue;
319   }
320 
ClearAndLeak(UniquePersistent<V> * persistent)321   static PersistentContainerValue ClearAndLeak(
322       UniquePersistent<V>* persistent) {
323     V* v = persistent->val_;
324     persistent->val_ = 0;
325     return reinterpret_cast<PersistentContainerValue>(v);
326   }
327 
Leak(UniquePersistent<V> * persistent)328   static PersistentContainerValue Leak(
329       UniquePersistent<V>* persistent) {
330     return reinterpret_cast<PersistentContainerValue>(persistent->val_);
331   }
332 
333   /**
334    * Return a container value as UniquePersistent and make sure the weak
335    * callback is properly disposed of. All remove functionality should go
336    * through this.
337    */
Release(PersistentContainerValue v)338   static UniquePersistent<V> Release(PersistentContainerValue v) {
339     UniquePersistent<V> p;
340     p.val_ = FromVal(v);
341     if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
342       Traits::DisposeCallbackData(
343           p.template ClearWeak<typename Traits::WeakCallbackDataType>());
344     }
345     return p.Pass();
346   }
347 
348   Isolate* isolate_;
349   typename Traits::Impl impl_;
350 };
351 
352 
353 /**
354  * A map that uses UniquePersistent as value and std::map as the backing
355  * implementation. Persistents are held non-weak.
356  *
357  * C++11 embedders don't need this class, as they can use
358  * UniquePersistent directly in std containers.
359  */
360 template<typename K, typename V,
361     typename Traits = DefaultPersistentValueMapTraits<K, V> >
362 class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
363  public:
StdPersistentValueMap(Isolate * isolate)364   explicit StdPersistentValueMap(Isolate* isolate)
365       : PersistentValueMap<K, V, Traits>(isolate) {}
366 };
367 
368 
369 class DefaultPersistentValueVectorTraits {
370  public:
371   typedef std::vector<PersistentContainerValue> Impl;
372 
Append(Impl * impl,PersistentContainerValue value)373   static void Append(Impl* impl, PersistentContainerValue value) {
374     impl->push_back(value);
375   }
IsEmpty(const Impl * impl)376   static bool IsEmpty(const Impl* impl) {
377     return impl->empty();
378   }
Size(const Impl * impl)379   static size_t Size(const Impl* impl) {
380     return impl->size();
381   }
Get(const Impl * impl,size_t i)382   static PersistentContainerValue Get(const Impl* impl, size_t i) {
383     return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
384   }
ReserveCapacity(Impl * impl,size_t capacity)385   static void ReserveCapacity(Impl* impl, size_t capacity) {
386     impl->reserve(capacity);
387   }
Clear(Impl * impl)388   static void Clear(Impl* impl) {
389     impl->clear();
390   }
391 };
392 
393 
394 /**
395  * A vector wrapper that safely stores UniquePersistent values.
396  * C++11 embedders don't need this class, as they can use UniquePersistent
397  * directly in std containers.
398  *
399  * This class relies on a backing vector implementation, whose type and methods
400  * are described by the Traits class. The backing map will handle values of type
401  * PersistentContainerValue, with all conversion into and out of V8
402  * handles being transparently handled by this class.
403  */
404 template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
405 class PersistentValueVector {
406  public:
PersistentValueVector(Isolate * isolate)407   explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
408 
~PersistentValueVector()409   ~PersistentValueVector() {
410     Clear();
411   }
412 
413   /**
414    * Append a value to the vector.
415    */
Append(Local<V> value)416   void Append(Local<V> value) {
417     UniquePersistent<V> persistent(isolate_, value);
418     Traits::Append(&impl_, ClearAndLeak(&persistent));
419   }
420 
421   /**
422    * Append a persistent's value to the vector.
423    */
Append(UniquePersistent<V> persistent)424   void Append(UniquePersistent<V> persistent) {
425     Traits::Append(&impl_, ClearAndLeak(&persistent));
426   }
427 
428   /**
429    * Are there any values in the vector?
430    */
IsEmpty()431   bool IsEmpty() const {
432     return Traits::IsEmpty(&impl_);
433   }
434 
435   /**
436    * How many elements are in the vector?
437    */
Size()438   size_t Size() const {
439     return Traits::Size(&impl_);
440   }
441 
442   /**
443    * Retrieve the i-th value in the vector.
444    */
Get(size_t index)445   Local<V> Get(size_t index) const {
446     return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
447   }
448 
449   /**
450    * Remove all elements from the vector.
451    */
Clear()452   void Clear() {
453     size_t length = Traits::Size(&impl_);
454     for (size_t i = 0; i < length; i++) {
455       UniquePersistent<V> p;
456       p.val_ = FromVal(Traits::Get(&impl_, i));
457     }
458     Traits::Clear(&impl_);
459   }
460 
461   /**
462    * Reserve capacity in the vector.
463    * (Efficiency gains depend on the backing implementation.)
464    */
ReserveCapacity(size_t capacity)465   void ReserveCapacity(size_t capacity) {
466     Traits::ReserveCapacity(&impl_, capacity);
467   }
468 
469  private:
ClearAndLeak(UniquePersistent<V> * persistent)470   static PersistentContainerValue ClearAndLeak(
471       UniquePersistent<V>* persistent) {
472     V* v = persistent->val_;
473     persistent->val_ = 0;
474     return reinterpret_cast<PersistentContainerValue>(v);
475   }
476 
FromVal(PersistentContainerValue v)477   static V* FromVal(PersistentContainerValue v) {
478     return reinterpret_cast<V*>(v);
479   }
480 
481   Isolate* isolate_;
482   typename Traits::Impl impl_;
483 };
484 
485 }  // namespace v8
486 
487 #endif  // V8_UTIL_H_
488