v8  4.5.103 (node 4.8.7)
V8 is Google's open source JavaScript engine
v8-util.h
Go to the documentation of this file.
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 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;
25  // These correspond to v8::WeakCallbackType
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 
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,
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  */
85 template<typename K, typename V>
87  public:
88  // Weak callback & friends:
92  typedef void WeakCallbackDataType;
93 
95  MapType* map, const K& key, Local<V> value) {
96  return NULL;
97  }
99  const WeakCallbackData<V, WeakCallbackDataType>& data) {
100  return NULL;
101  }
103  const WeakCallbackData<V, WeakCallbackDataType>& data) {
104  return K();
105  }
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:
121  typedef void WeakCallbackDataType;
122 
124  Local<V> value) {
125  return nullptr;
126  }
128  const WeakCallbackInfo<WeakCallbackDataType>& data) {
129  return nullptr;
130  }
132  const WeakCallbackInfo<WeakCallbackDataType>& data) {
133  return K();
134  }
136  static void Dispose(Isolate* isolate, Global<V> value, K key) {}
137  // This is a second pass callback, so SetSecondPassCallback cannot be called.
138  static void DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType>& data) {}
139 
140  private:
141  template <typename T>
142  struct RemovePointer<T*> {
143  typedef T Type;
144  };
145 };
146 
147 
148 /**
149  * A map wrapper that allows using Global as a mapped value.
150  * C++11 embedders don't need this class, as they can use Global
151  * directly in std containers.
152  *
153  * The map relies on a backing map, whose type and accessors are described
154  * by the Traits class. The backing map will handle values of type
155  * PersistentContainerValue, with all conversion into and out of V8
156  * handles being transparently handled by this class.
157  */
158 template <typename K, typename V, typename Traits>
160  public:
161  Isolate* GetIsolate() { return isolate_; }
162 
163  /**
164  * Return size of the map.
165  */
166  size_t Size() { return Traits::Size(&impl_); }
167 
168  /**
169  * Return whether the map holds weak persistents.
170  */
171  bool IsWeak() { return Traits::kCallbackType != kNotWeak; }
172 
173  /**
174  * Get value stored in map.
175  */
176  Local<V> Get(const K& key) {
177  return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, key)));
178  }
179 
180  /**
181  * Check whether a value is contained in the map.
182  */
183  bool Contains(const K& key) {
184  return Traits::Get(&impl_, key) != kPersistentContainerNotFound;
185  }
186 
187  /**
188  * Get value stored in map and set it in returnValue.
189  * Return true if a value was found.
190  */
191  bool SetReturnValue(const K& key,
192  ReturnValue<Value> returnValue) {
193  return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key));
194  }
195 
196  /**
197  * Call Isolate::SetReference with the given parent and the map value.
198  */
199  void SetReference(const K& key,
200  const Persistent<Object>& parent) {
201  GetIsolate()->SetReference(
202  reinterpret_cast<internal::Object**>(parent.val_),
203  reinterpret_cast<internal::Object**>(FromVal(Traits::Get(&impl_, key))));
204  }
205 
206  /**
207  * Return value for key and remove it from the map.
208  */
209  Global<V> Remove(const K& key) {
210  return Release(Traits::Remove(&impl_, key)).Pass();
211  }
212 
213  /**
214  * Traverses the map repeatedly,
215  * in case side effects of disposal cause insertions.
216  **/
217  void Clear() {
218  typedef typename Traits::Iterator It;
219  HandleScope handle_scope(isolate_);
220  // TODO(dcarney): figure out if this swap and loop is necessary.
221  while (!Traits::Empty(&impl_)) {
222  typename Traits::Impl impl;
223  Traits::Swap(impl_, impl);
224  for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
225  Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
226  Traits::Key(i));
227  }
228  }
229  }
230 
231  /**
232  * Helper class for GetReference/SetWithReference. Do not use outside
233  * that context.
234  */
236  public:
237  PersistentValueReference() : value_(kPersistentContainerNotFound) { }
239  : value_(other.value_) { }
240 
241  Local<V> NewLocal(Isolate* isolate) const {
242  return Local<V>::New(isolate, FromVal(value_));
243  }
244  bool IsEmpty() const {
245  return value_ == kPersistentContainerNotFound;
246  }
247  template<typename T>
248  bool SetReturnValue(ReturnValue<T> returnValue) {
249  return SetReturnValueFromVal(&returnValue, value_);
250  }
251  void Reset() {
252  value_ = kPersistentContainerNotFound;
253  }
254  void operator=(const PersistentValueReference& other) {
255  value_ = other.value_;
256  }
257 
258  private:
260  friend class PersistentValueMap<K, V, Traits>;
261  friend class GlobalValueMap<K, V, Traits>;
262 
263  explicit PersistentValueReference(PersistentContainerValue value)
264  : value_(value) { }
265 
266  void operator=(PersistentContainerValue value) {
267  value_ = value;
268  }
269 
271  };
272 
273  /**
274  * Get a reference to a map value. This enables fast, repeated access
275  * to a value stored in the map while the map remains unchanged.
276  *
277  * Careful: This is potentially unsafe, so please use with care.
278  * The value will become invalid if the value for this key changes
279  * in the underlying map, as a result of Set or Remove for the same
280  * key; as a result of the weak callback for the same key; or as a
281  * result of calling Clear() or destruction of the map.
282  */
284  return PersistentValueReference(Traits::Get(&impl_, key));
285  }
286 
287  protected:
288  explicit PersistentValueMapBase(Isolate* isolate) : isolate_(isolate) {}
289 
291 
292  Isolate* isolate() { return isolate_; }
293  typename Traits::Impl* impl() { return &impl_; }
294 
296  return reinterpret_cast<V*>(v);
297  }
298 
300  V* v = persistent->val_;
301  persistent->val_ = 0;
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  */
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  private:
331  PersistentValueMapBase(PersistentValueMapBase&);
332  void operator=(PersistentValueMapBase&);
333 
334  static bool SetReturnValueFromVal(ReturnValue<Value>* returnValue,
335  PersistentContainerValue value) {
336  bool hasValue = value != kPersistentContainerNotFound;
337  if (hasValue) {
338  returnValue->SetInternal(
339  *reinterpret_cast<internal::Object**>(FromVal(value)));
340  }
341  return hasValue;
342  }
343 
344  Isolate* isolate_;
345  typename Traits::Impl impl_;
346 };
347 
348 
349 template <typename K, typename V, typename Traits>
350 class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
351  public:
352  explicit PersistentValueMap(Isolate* isolate)
353  : PersistentValueMapBase<K, V, Traits>(isolate) {}
354 
355  typedef
356  typename PersistentValueMapBase<K, V, Traits>::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  Local<V> value(Local<V>::New(this->isolate(), *persistent));
383  persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
384  Traits::WeakCallbackParameter(this, key, value), WeakCallback);
385  }
386  PersistentContainerValue old_value =
387  Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
388  return this->Release(old_value).Pass();
389  }
390 
391  /**
392  * Put a value into the map and update the reference.
393  * Restrictions of GetReference apply here as well.
394  */
395  Global<V> Set(const K& key, Global<V> value,
396  PersistentValueReference* reference) {
397  *reference = this->Leak(&value);
398  return SetUnique(key, &value);
399  }
400 
401  private:
402  static void WeakCallback(
403  const WeakCallbackData<V, typename Traits::WeakCallbackDataType>& data) {
404  if (Traits::kCallbackType != kNotWeak) {
405  PersistentValueMap<K, V, Traits>* persistentValueMap =
406  Traits::MapFromWeakCallbackData(data);
407  K key = Traits::KeyFromWeakCallbackData(data);
408  Traits::Dispose(data.GetIsolate(),
409  persistentValueMap->Remove(key).Pass(), key);
410  Traits::DisposeCallbackData(data.GetParameter());
411  }
412  }
413 };
414 
415 
416 template <typename K, typename V, typename Traits>
417 class GlobalValueMap : public PersistentValueMapBase<K, V, Traits> {
418  public:
419  explicit GlobalValueMap(Isolate* isolate)
420  : PersistentValueMapBase<K, V, Traits>(isolate) {}
421 
422  typedef
423  typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
425 
426  /**
427  * Put value into map. Depending on Traits::kIsWeak, the value will be held
428  * by the map strongly or weakly.
429  * Returns old value as Global.
430  */
431  Global<V> Set(const K& key, Local<V> value) {
432  Global<V> persistent(this->isolate(), value);
433  return SetUnique(key, &persistent);
434  }
435 
436  /**
437  * Put value into map, like Set(const K&, Local<V>).
438  */
439  Global<V> Set(const K& key, Global<V> value) {
440  return SetUnique(key, &value);
441  }
442 
443  /**
444  * Put the value into the map, and set the 'weak' callback when demanded
445  * by the Traits class.
446  */
447  Global<V> SetUnique(const K& key, Global<V>* persistent) {
448  if (Traits::kCallbackType != kNotWeak) {
449  WeakCallbackType callback_type =
450  Traits::kCallbackType == kWeakWithInternalFields
453  Local<V> value(Local<V>::New(this->isolate(), *persistent));
454  persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
455  Traits::WeakCallbackParameter(this, key, value), FirstWeakCallback,
456  callback_type);
457  }
458  PersistentContainerValue old_value =
459  Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
460  return this->Release(old_value).Pass();
461  }
462 
463  /**
464  * Put a value into the map and update the reference.
465  * Restrictions of GetReference apply here as well.
466  */
467  Global<V> Set(const K& key, Global<V> value,
468  PersistentValueReference* reference) {
469  *reference = this->Leak(&value);
470  return SetUnique(key, &value);
471  }
472 
473  private:
474  static void FirstWeakCallback(
475  const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
476  if (Traits::kCallbackType != kNotWeak) {
477  auto map = Traits::MapFromWeakCallbackInfo(data);
478  K key = Traits::KeyFromWeakCallbackInfo(data);
479  map->RemoveWeak(key);
480  data.SetSecondPassCallback(SecondWeakCallback);
481  }
482  }
483 
484  static void SecondWeakCallback(
485  const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
486  Traits::DisposeWeak(data);
487  }
488 };
489 
490 
491 /**
492  * A map that uses Global as value and std::map as the backing
493  * implementation. Persistents are held non-weak.
494  *
495  * C++11 embedders don't need this class, as they can use
496  * Global directly in std containers.
497  */
498 template<typename K, typename V,
499  typename Traits = DefaultPersistentValueMapTraits<K, V> >
500 class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
501  public:
502  explicit StdPersistentValueMap(Isolate* isolate)
503  : PersistentValueMap<K, V, Traits>(isolate) {}
504 };
505 
506 
507 /**
508  * A map that uses Global as value and std::map as the backing
509  * implementation. Globals are held non-weak.
510  *
511  * C++11 embedders don't need this class, as they can use
512  * Global directly in std containers.
513  */
514 template <typename K, typename V,
515  typename Traits = DefaultGlobalMapTraits<K, V> >
516 class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
517  public:
518  explicit StdGlobalValueMap(Isolate* isolate)
519  : GlobalValueMap<K, V, Traits>(isolate) {}
520 };
521 
522 
524  public:
525  typedef std::vector<PersistentContainerValue> Impl;
526 
527  static void Append(Impl* impl, PersistentContainerValue value) {
528  impl->push_back(value);
529  }
530  static bool IsEmpty(const Impl* impl) {
531  return impl->empty();
532  }
533  static size_t Size(const Impl* impl) {
534  return impl->size();
535  }
536  static PersistentContainerValue Get(const Impl* impl, size_t i) {
537  return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
538  }
539  static void ReserveCapacity(Impl* impl, size_t capacity) {
540  impl->reserve(capacity);
541  }
542  static void Clear(Impl* impl) {
543  impl->clear();
544  }
545 };
546 
547 
548 /**
549  * A vector wrapper that safely stores Global values.
550  * C++11 embedders don't need this class, as they can use Global
551  * directly in std containers.
552  *
553  * This class relies on a backing vector implementation, whose type and methods
554  * are described by the Traits class. The backing map will handle values of type
555  * PersistentContainerValue, with all conversion into and out of V8
556  * handles being transparently handled by this class.
557  */
558 template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
560  public:
561  explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
562 
564  Clear();
565  }
566 
567  /**
568  * Append a value to the vector.
569  */
570  void Append(Local<V> value) {
571  Global<V> persistent(isolate_, value);
572  Traits::Append(&impl_, ClearAndLeak(&persistent));
573  }
574 
575  /**
576  * Append a persistent's value to the vector.
577  */
578  void Append(Global<V> persistent) {
579  Traits::Append(&impl_, ClearAndLeak(&persistent));
580  }
581 
582  /**
583  * Are there any values in the vector?
584  */
585  bool IsEmpty() const {
586  return Traits::IsEmpty(&impl_);
587  }
588 
589  /**
590  * How many elements are in the vector?
591  */
592  size_t Size() const {
593  return Traits::Size(&impl_);
594  }
595 
596  /**
597  * Retrieve the i-th value in the vector.
598  */
599  Local<V> Get(size_t index) const {
600  return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
601  }
602 
603  /**
604  * Remove all elements from the vector.
605  */
606  void Clear() {
607  size_t length = Traits::Size(&impl_);
608  for (size_t i = 0; i < length; i++) {
609  Global<V> p;
610  p.val_ = FromVal(Traits::Get(&impl_, i));
611  }
612  Traits::Clear(&impl_);
613  }
614 
615  /**
616  * Reserve capacity in the vector.
617  * (Efficiency gains depend on the backing implementation.)
618  */
619  void ReserveCapacity(size_t capacity) {
620  Traits::ReserveCapacity(&impl_, capacity);
621  }
622 
623  private:
624  static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
625  V* v = persistent->val_;
626  persistent->val_ = 0;
627  return reinterpret_cast<PersistentContainerValue>(v);
628  }
629 
630  static V* FromVal(PersistentContainerValue v) {
631  return reinterpret_cast<V*>(v);
632  }
633 
634  Isolate* isolate_;
635  typename Traits::Impl impl_;
636 };
637 
638 } // namespace v8
639 
640 #endif // V8_UTIL_H