v8  8.4.371 (node 14.15.5)
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_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;
26  // These correspond to v8::WeakCallbackType
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 
44  static bool Empty(Impl* impl) { return impl->empty(); }
45  static size_t Size(Impl* impl) { return impl->size(); }
46  static void Swap(Impl& a, Impl& b) { std::swap(a, b); } // NOLINT
47  static Iterator Begin(Impl* impl) { return impl->begin(); }
48  static Iterator End(Impl* impl) { return impl->end(); }
49  static K Key(Iterator it) { return it->first; }
50  static PersistentContainerValue Value(Iterator it) { return it->second; }
51  static PersistentContainerValue Set(Impl* impl, K key,
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  }
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  }
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>
86  public:
87  // Weak callback & friends:
91  typedef void WeakCallbackDataType;
92 
94  MapType* map, const K& key, Local<V> value) {
95  return nullptr;
96  }
99  return nullptr;
100  }
102  const WeakCallbackInfo<WeakCallbackDataType>& data) {
103  return K();
104  }
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:
120  typedef void WeakCallbackDataType;
121 
123  Local<V> value) {
124  return nullptr;
125  }
127  const WeakCallbackInfo<WeakCallbackDataType>& data) {
128  return nullptr;
129  }
131  const WeakCallbackInfo<WeakCallbackDataType>& data) {
132  return K();
133  }
135  static void OnWeakCallback(
136  const WeakCallbackInfo<WeakCallbackDataType>& data) {}
137  static void Dispose(Isolate* isolate, Global<V> value, K key) {}
138  // This is a second pass callback, so SetSecondPassCallback cannot be called.
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>
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  */
227  public:
228  PersistentValueReference() : value_(kPersistentContainerNotFound) { }
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:
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 
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  */
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 
285 
286  Isolate* isolate() { return isolate_; }
287  typename Traits::Impl* impl() { return &impl_; }
288 
290  return reinterpret_cast<V*>(v);
291  }
292 
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  */
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
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
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
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
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 
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>
572  public:
573  explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
574 
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