v8  5.1.281 (node 6.17.1)
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" // 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;
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 OnWeakCallback(
137  const WeakCallbackInfo<WeakCallbackDataType>& data) {}
138  static void Dispose(Isolate* isolate, Global<V> value, K key) {}
139  // This is a second pass callback, so SetSecondPassCallback cannot be called.
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>
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  * Return value for key and remove it from the map.
210  */
211  Global<V> Remove(const K& key) {
212  return Release(Traits::Remove(&impl_, key)).Pass();
213  }
214 
215  /**
216  * Traverses the map repeatedly,
217  * in case side effects of disposal cause insertions.
218  **/
219  void Clear() {
220  typedef typename Traits::Iterator It;
221  HandleScope handle_scope(isolate_);
222  // TODO(dcarney): figure out if this swap and loop is necessary.
223  while (!Traits::Empty(&impl_)) {
224  typename Traits::Impl impl;
225  Traits::Swap(impl_, impl);
226  for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
227  Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
228  Traits::Key(i));
229  }
230  }
231  }
232 
233  /**
234  * Helper class for GetReference/SetWithReference. Do not use outside
235  * that context.
236  */
238  public:
239  PersistentValueReference() : value_(kPersistentContainerNotFound) { }
241  : value_(other.value_) { }
242 
243  Local<V> NewLocal(Isolate* isolate) const {
244  return Local<V>::New(isolate, FromVal(value_));
245  }
246  bool IsEmpty() const {
247  return value_ == kPersistentContainerNotFound;
248  }
249  template<typename T>
250  bool SetReturnValue(ReturnValue<T> returnValue) {
251  return SetReturnValueFromVal(&returnValue, value_);
252  }
253  void Reset() {
254  value_ = kPersistentContainerNotFound;
255  }
256  void operator=(const PersistentValueReference& other) {
257  value_ = other.value_;
258  }
259 
260  private:
262  friend class PersistentValueMap<K, V, Traits>;
263  friend class GlobalValueMap<K, V, Traits>;
264 
265  explicit PersistentValueReference(PersistentContainerValue value)
266  : value_(value) { }
267 
268  void operator=(PersistentContainerValue value) {
269  value_ = value;
270  }
271 
273  };
274 
275  /**
276  * Get a reference to a map value. This enables fast, repeated access
277  * to a value stored in the map while the map remains unchanged.
278  *
279  * Careful: This is potentially unsafe, so please use with care.
280  * The value will become invalid if the value for this key changes
281  * in the underlying map, as a result of Set or Remove for the same
282  * key; as a result of the weak callback for the same key; or as a
283  * result of calling Clear() or destruction of the map.
284  */
286  return PersistentValueReference(Traits::Get(&impl_, key));
287  }
288 
289  protected:
290  explicit PersistentValueMapBase(Isolate* isolate) : isolate_(isolate) {}
291 
293 
294  Isolate* isolate() { return isolate_; }
295  typename Traits::Impl* impl() { return &impl_; }
296 
298  return reinterpret_cast<V*>(v);
299  }
300 
302  V* v = persistent->val_;
303  persistent->val_ = 0;
304  return reinterpret_cast<PersistentContainerValue>(v);
305  }
306 
307  static PersistentContainerValue Leak(Global<V>* persistent) {
308  return reinterpret_cast<PersistentContainerValue>(persistent->val_);
309  }
310 
311  /**
312  * Return a container value as Global and make sure the weak
313  * callback is properly disposed of. All remove functionality should go
314  * through this.
315  */
317  Global<V> p;
318  p.val_ = FromVal(v);
319  if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
320  Traits::DisposeCallbackData(
321  p.template ClearWeak<typename Traits::WeakCallbackDataType>());
322  }
323  return p.Pass();
324  }
325 
326  void RemoveWeak(const K& key) {
327  Global<V> p;
328  p.val_ = FromVal(Traits::Remove(&impl_, key));
329  p.Reset();
330  }
331 
332  private:
333  PersistentValueMapBase(PersistentValueMapBase&);
334  void operator=(PersistentValueMapBase&);
335 
336  static bool SetReturnValueFromVal(ReturnValue<Value>* returnValue,
337  PersistentContainerValue value) {
338  bool hasValue = value != kPersistentContainerNotFound;
339  if (hasValue) {
340  returnValue->SetInternal(
341  *reinterpret_cast<internal::Object**>(FromVal(value)));
342  }
343  return hasValue;
344  }
345 
346  Isolate* isolate_;
347  typename Traits::Impl impl_;
348 };
349 
350 
351 template <typename K, typename V, typename Traits>
352 class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
353  public:
354  explicit PersistentValueMap(Isolate* isolate)
355  : PersistentValueMapBase<K, V, Traits>(isolate) {}
356 
357  typedef
358  typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
360 
361  /**
362  * Put value into map. Depending on Traits::kIsWeak, the value will be held
363  * by the map strongly or weakly.
364  * Returns old value as Global.
365  */
366  Global<V> Set(const K& key, Local<V> value) {
367  Global<V> persistent(this->isolate(), value);
368  return SetUnique(key, &persistent);
369  }
370 
371  /**
372  * Put value into map, like Set(const K&, Local<V>).
373  */
374  Global<V> Set(const K& key, Global<V> value) {
375  return SetUnique(key, &value);
376  }
377 
378  /**
379  * Put the value into the map, and set the 'weak' callback when demanded
380  * by the Traits class.
381  */
382  Global<V> SetUnique(const K& key, Global<V>* persistent) {
383  if (Traits::kCallbackType != kNotWeak) {
384  Local<V> value(Local<V>::New(this->isolate(), *persistent));
385  persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
386  Traits::WeakCallbackParameter(this, key, value), WeakCallback);
387  }
388  PersistentContainerValue old_value =
389  Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
390  return this->Release(old_value).Pass();
391  }
392 
393  /**
394  * Put a value into the map and update the reference.
395  * Restrictions of GetReference apply here as well.
396  */
397  Global<V> Set(const K& key, Global<V> value,
398  PersistentValueReference* reference) {
399  *reference = this->Leak(&value);
400  return SetUnique(key, &value);
401  }
402 
403  private:
404  static void WeakCallback(
405  const WeakCallbackData<V, typename Traits::WeakCallbackDataType>& data) {
406  if (Traits::kCallbackType != kNotWeak) {
407  PersistentValueMap<K, V, Traits>* persistentValueMap =
408  Traits::MapFromWeakCallbackData(data);
409  K key = Traits::KeyFromWeakCallbackData(data);
410  Traits::Dispose(data.GetIsolate(),
411  persistentValueMap->Remove(key).Pass(), key);
412  Traits::DisposeCallbackData(data.GetParameter());
413  }
414  }
415 };
416 
417 
418 template <typename K, typename V, typename Traits>
419 class GlobalValueMap : public PersistentValueMapBase<K, V, Traits> {
420  public:
421  explicit GlobalValueMap(Isolate* isolate)
422  : PersistentValueMapBase<K, V, Traits>(isolate) {}
423 
424  typedef
425  typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
427 
428  /**
429  * Put value into map. Depending on Traits::kIsWeak, the value will be held
430  * by the map strongly or weakly.
431  * Returns old value as Global.
432  */
433  Global<V> Set(const K& key, Local<V> value) {
434  Global<V> persistent(this->isolate(), value);
435  return SetUnique(key, &persistent);
436  }
437 
438  /**
439  * Put value into map, like Set(const K&, Local<V>).
440  */
441  Global<V> Set(const K& key, Global<V> value) {
442  return SetUnique(key, &value);
443  }
444 
445  /**
446  * Put the value into the map, and set the 'weak' callback when demanded
447  * by the Traits class.
448  */
449  Global<V> SetUnique(const K& key, Global<V>* persistent) {
450  if (Traits::kCallbackType != kNotWeak) {
451  WeakCallbackType callback_type =
452  Traits::kCallbackType == kWeakWithInternalFields
455  Local<V> value(Local<V>::New(this->isolate(), *persistent));
456  persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
457  Traits::WeakCallbackParameter(this, key, value), OnWeakCallback,
458  callback_type);
459  }
460  PersistentContainerValue old_value =
461  Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
462  return this->Release(old_value).Pass();
463  }
464 
465  /**
466  * Put a value into the map and update the reference.
467  * Restrictions of GetReference apply here as well.
468  */
469  Global<V> Set(const K& key, Global<V> value,
470  PersistentValueReference* reference) {
471  *reference = this->Leak(&value);
472  return SetUnique(key, &value);
473  }
474 
475  private:
476  static void OnWeakCallback(
477  const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
478  if (Traits::kCallbackType != kNotWeak) {
479  auto map = Traits::MapFromWeakCallbackInfo(data);
480  K key = Traits::KeyFromWeakCallbackInfo(data);
481  map->RemoveWeak(key);
482  Traits::OnWeakCallback(data);
483  data.SetSecondPassCallback(SecondWeakCallback);
484  }
485  }
486 
487  static void SecondWeakCallback(
488  const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
489  Traits::DisposeWeak(data);
490  }
491 };
492 
493 
494 /**
495  * A map that uses Global as value and std::map as the backing
496  * implementation. Persistents are held non-weak.
497  *
498  * C++11 embedders don't need this class, as they can use
499  * Global directly in std containers.
500  */
501 template<typename K, typename V,
502  typename Traits = DefaultPersistentValueMapTraits<K, V> >
503 class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
504  public:
505  explicit StdPersistentValueMap(Isolate* isolate)
506  : PersistentValueMap<K, V, Traits>(isolate) {}
507 };
508 
509 
510 /**
511  * A map that uses Global as value and std::map as the backing
512  * implementation. Globals are held non-weak.
513  *
514  * C++11 embedders don't need this class, as they can use
515  * Global directly in std containers.
516  */
517 template <typename K, typename V,
518  typename Traits = DefaultGlobalMapTraits<K, V> >
519 class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
520  public:
521  explicit StdGlobalValueMap(Isolate* isolate)
522  : GlobalValueMap<K, V, Traits>(isolate) {}
523 };
524 
525 
527  public:
528  typedef std::vector<PersistentContainerValue> Impl;
529 
530  static void Append(Impl* impl, PersistentContainerValue value) {
531  impl->push_back(value);
532  }
533  static bool IsEmpty(const Impl* impl) {
534  return impl->empty();
535  }
536  static size_t Size(const Impl* impl) {
537  return impl->size();
538  }
539  static PersistentContainerValue Get(const Impl* impl, size_t i) {
540  return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
541  }
542  static void ReserveCapacity(Impl* impl, size_t capacity) {
543  impl->reserve(capacity);
544  }
545  static void Clear(Impl* impl) {
546  impl->clear();
547  }
548 };
549 
550 
551 /**
552  * A vector wrapper that safely stores Global values.
553  * C++11 embedders don't need this class, as they can use Global
554  * directly in std containers.
555  *
556  * This class relies on a backing vector implementation, whose type and methods
557  * are described by the Traits class. The backing map will handle values of type
558  * PersistentContainerValue, with all conversion into and out of V8
559  * handles being transparently handled by this class.
560  */
561 template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
563  public:
564  explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
565 
567  Clear();
568  }
569 
570  /**
571  * Append a value to the vector.
572  */
573  void Append(Local<V> value) {
574  Global<V> persistent(isolate_, value);
575  Traits::Append(&impl_, ClearAndLeak(&persistent));
576  }
577 
578  /**
579  * Append a persistent's value to the vector.
580  */
581  void Append(Global<V> persistent) {
582  Traits::Append(&impl_, ClearAndLeak(&persistent));
583  }
584 
585  /**
586  * Are there any values in the vector?
587  */
588  bool IsEmpty() const {
589  return Traits::IsEmpty(&impl_);
590  }
591 
592  /**
593  * How many elements are in the vector?
594  */
595  size_t Size() const {
596  return Traits::Size(&impl_);
597  }
598 
599  /**
600  * Retrieve the i-th value in the vector.
601  */
602  Local<V> Get(size_t index) const {
603  return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
604  }
605 
606  /**
607  * Remove all elements from the vector.
608  */
609  void Clear() {
610  size_t length = Traits::Size(&impl_);
611  for (size_t i = 0; i < length; i++) {
612  Global<V> p;
613  p.val_ = FromVal(Traits::Get(&impl_, i));
614  }
615  Traits::Clear(&impl_);
616  }
617 
618  /**
619  * Reserve capacity in the vector.
620  * (Efficiency gains depend on the backing implementation.)
621  */
622  void ReserveCapacity(size_t capacity) {
623  Traits::ReserveCapacity(&impl_, capacity);
624  }
625 
626  private:
627  static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
628  V* v = persistent->val_;
629  persistent->val_ = 0;
630  return reinterpret_cast<PersistentContainerValue>(v);
631  }
632 
633  static V* FromVal(PersistentContainerValue v) {
634  return reinterpret_cast<V*>(v);
635  }
636 
637  Isolate* isolate_;
638  typename Traits::Impl impl_;
639 };
640 
641 } // namespace v8
642 
643 #endif // V8_UTIL_H