v8  10.1.124 (node 18.2.0)
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 <assert.h>
9 
10 #include <map>
11 #include <vector>
12 
13 #include "v8-function-callback.h" // NOLINT(build/include_directory)
14 #include "v8-persistent-handle.h" // NOLINT(build/include_directory)
15 
16 /**
17  * Support for Persistent containers.
18  *
19  * C++11 embedders can use STL containers with Global values,
20  * but pre-C++11 does not support the required move semantic and hence
21  * may want these container classes.
22  */
23 namespace v8 {
24 
25 template <typename K, typename V, typename Traits>
26 class GlobalValueMap;
27 
28 typedef uintptr_t PersistentContainerValue;
29 static const uintptr_t kPersistentContainerNotFound = 0;
32  // These correspond to v8::WeakCallbackType
35 };
36 
37 /**
38  * A default trait implementation for PersistentValueMap which uses std::map
39  * as a backing map.
40  *
41  * Users will have to implement their own weak callbacks & dispose traits.
42  */
43 template<typename K, typename V>
44 class StdMapTraits {
45  public:
46  // STL map & related:
47  typedef std::map<K, PersistentContainerValue> Impl;
48  typedef typename Impl::iterator Iterator;
49 
50  static bool Empty(Impl* impl) { return impl->empty(); }
51  static size_t Size(Impl* impl) { return impl->size(); }
52  static void Swap(Impl& a, Impl& b) { std::swap(a, b); }
53  static Iterator Begin(Impl* impl) { return impl->begin(); }
54  static Iterator End(Impl* impl) { return impl->end(); }
55  static K Key(Iterator it) { return it->first; }
56  static PersistentContainerValue Value(Iterator it) { return it->second; }
57  static PersistentContainerValue Set(Impl* impl, K key,
59  std::pair<Iterator, bool> res = impl->insert(std::make_pair(key, value));
60  PersistentContainerValue old_value = kPersistentContainerNotFound;
61  if (!res.second) {
62  old_value = res.first->second;
63  res.first->second = value;
64  }
65  return old_value;
66  }
67  static PersistentContainerValue Get(Impl* impl, K key) {
68  Iterator it = impl->find(key);
69  if (it == impl->end()) return kPersistentContainerNotFound;
70  return it->second;
71  }
72  static PersistentContainerValue Remove(Impl* impl, K key) {
73  Iterator it = impl->find(key);
74  if (it == impl->end()) return kPersistentContainerNotFound;
75  PersistentContainerValue value = it->second;
76  impl->erase(it);
77  return value;
78  }
79 };
80 
81 
82 /**
83  * A default trait implementation for PersistentValueMap, which inherits
84  * a std:map backing map from StdMapTraits and holds non-weak persistent
85  * objects and has no special Dispose handling.
86  *
87  * You should not derive from this class, since MapType depends on the
88  * surrounding class, and hence a subclass cannot simply inherit the methods.
89  */
90 template<typename K, typename V>
92  public:
93  // Weak callback & friends:
95  typedef PersistentValueMap<K, V, DefaultPersistentValueMapTraits<K, V> >
97  typedef void WeakCallbackDataType;
98 
100  MapType* map, const K& key, Local<V> value) {
101  return nullptr;
102  }
104  const WeakCallbackInfo<WeakCallbackDataType>& data) {
105  return nullptr;
106  }
108  const WeakCallbackInfo<WeakCallbackDataType>& data) {
109  return K();
110  }
112  static void Dispose(Isolate* isolate, Global<V> value, K key) {}
113 };
114 
115 
116 template <typename K, typename V>
117 class DefaultGlobalMapTraits : public StdMapTraits<K, V> {
118  private:
119  template <typename T>
120  struct RemovePointer;
121 
122  public:
123  // Weak callback & friends:
125  typedef GlobalValueMap<K, V, DefaultGlobalMapTraits<K, V> > MapType;
126  typedef void WeakCallbackDataType;
127 
129  Local<V> value) {
130  return nullptr;
131  }
133  const WeakCallbackInfo<WeakCallbackDataType>& data) {
134  return nullptr;
135  }
137  const WeakCallbackInfo<WeakCallbackDataType>& data) {
138  return K();
139  }
141  static void OnWeakCallback(
142  const WeakCallbackInfo<WeakCallbackDataType>& data) {}
143  static void Dispose(Isolate* isolate, Global<V> value, K key) {}
144  // This is a second pass callback, so SetSecondPassCallback cannot be called.
145  static void DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType>& data) {}
146 
147  private:
148  template <typename T>
149  struct RemovePointer<T*> {
150  typedef T Type;
151  };
152 };
153 
154 
155 /**
156  * A map wrapper that allows using Global as a mapped value.
157  * C++11 embedders don't need this class, as they can use Global
158  * directly in std containers.
159  *
160  * The map relies on a backing map, whose type and accessors are described
161  * by the Traits class. The backing map will handle values of type
162  * PersistentContainerValue, with all conversion into and out of V8
163  * handles being transparently handled by this class.
164  */
165 template <typename K, typename V, typename Traits>
167  public:
168  Isolate* GetIsolate() { return isolate_; }
169 
170  /**
171  * Return size of the map.
172  */
173  size_t Size() { return Traits::Size(&impl_); }
174 
175  /**
176  * Return whether the map holds weak persistents.
177  */
178  bool IsWeak() { return Traits::kCallbackType != kNotWeak; }
179 
180  /**
181  * Get value stored in map.
182  */
183  Local<V> Get(const K& key) {
184  return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, key)));
185  }
186 
187  /**
188  * Check whether a value is contained in the map.
189  */
190  bool Contains(const K& key) {
191  return Traits::Get(&impl_, key) != kPersistentContainerNotFound;
192  }
193 
194  /**
195  * Get value stored in map and set it in returnValue.
196  * Return true if a value was found.
197  */
198  bool SetReturnValue(const K& key,
199  ReturnValue<Value> returnValue) {
200  return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key));
201  }
202 
203  /**
204  * Return value for key and remove it from the map.
205  */
206  Global<V> Remove(const K& key) {
207  return Release(Traits::Remove(&impl_, key)).Pass();
208  }
209 
210  /**
211  * Traverses the map repeatedly,
212  * in case side effects of disposal cause insertions.
213  **/
214  void Clear() {
215  typedef typename Traits::Iterator It;
216  HandleScope handle_scope(isolate_);
217  // TODO(dcarney): figure out if this swap and loop is necessary.
218  while (!Traits::Empty(&impl_)) {
219  typename Traits::Impl impl;
220  Traits::Swap(impl_, impl);
221  for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
222  Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
223  Traits::Key(i));
224  }
225  }
226  }
227 
228  /**
229  * Helper class for GetReference/SetWithReference. Do not use outside
230  * that context.
231  */
233  public:
234  PersistentValueReference() : value_(kPersistentContainerNotFound) { }
236  : value_(other.value_) { }
237 
238  Local<V> NewLocal(Isolate* isolate) const {
239  return Local<V>::New(isolate, FromVal(value_));
240  }
241  bool IsEmpty() const {
242  return value_ == kPersistentContainerNotFound;
243  }
244  template<typename T>
245  bool SetReturnValue(ReturnValue<T> returnValue) {
246  return SetReturnValueFromVal(&returnValue, value_);
247  }
248  void Reset() {
249  value_ = kPersistentContainerNotFound;
250  }
251  void operator=(const PersistentValueReference& other) {
252  value_ = other.value_;
253  }
254 
255  private:
257  friend class PersistentValueMap<K, V, Traits>;
258  friend class GlobalValueMap<K, V, Traits>;
259 
260  explicit PersistentValueReference(PersistentContainerValue value)
261  : value_(value) { }
262 
263  void operator=(PersistentContainerValue value) {
264  value_ = value;
265  }
266 
268  };
269 
270  /**
271  * Get a reference to a map value. This enables fast, repeated access
272  * to a value stored in the map while the map remains unchanged.
273  *
274  * Careful: This is potentially unsafe, so please use with care.
275  * The value will become invalid if the value for this key changes
276  * in the underlying map, as a result of Set or Remove for the same
277  * key; as a result of the weak callback for the same key; or as a
278  * result of calling Clear() or destruction of the map.
279  */
281  return PersistentValueReference(Traits::Get(&impl_, key));
282  }
283 
284  protected:
285  explicit PersistentValueMapBase(Isolate* isolate)
286  : isolate_(isolate), label_(nullptr) {}
287  PersistentValueMapBase(Isolate* isolate, const char* label)
288  : isolate_(isolate), label_(label) {}
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_ = nullptr;
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  void AnnotateStrongRetainer(Global<V>* persistent) {
331  persistent->AnnotateStrongRetainer(label_);
332  }
333 
334  private:
335  PersistentValueMapBase(PersistentValueMapBase&);
336  void operator=(PersistentValueMapBase&);
337 
338  static bool SetReturnValueFromVal(ReturnValue<Value>* returnValue,
339  PersistentContainerValue value) {
340  bool hasValue = value != kPersistentContainerNotFound;
341  if (hasValue) {
342  returnValue->SetInternal(
343  *reinterpret_cast<internal::Address*>(FromVal(value)));
344  }
345  return hasValue;
346  }
347 
348  Isolate* isolate_;
349  typename Traits::Impl impl_;
350  const char* label_;
351 };
352 
353 template <typename K, typename V, typename Traits>
354 class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
355  public:
356  explicit PersistentValueMap(Isolate* isolate)
357  : PersistentValueMapBase<K, V, Traits>(isolate) {}
358  PersistentValueMap(Isolate* isolate, const char* label)
359  : PersistentValueMapBase<K, V, Traits>(isolate, label) {}
360 
361  typedef
362  typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
364 
365  /**
366  * Put value into map. Depending on Traits::kIsWeak, the value will be held
367  * by the map strongly or weakly.
368  * Returns old value as Global.
369  */
370  Global<V> Set(const K& key, Local<V> value) {
371  Global<V> persistent(this->isolate(), value);
372  return SetUnique(key, &persistent);
373  }
374 
375  /**
376  * Put value into map, like Set(const K&, Local<V>).
377  */
378  Global<V> Set(const K& key, Global<V> value) {
379  return SetUnique(key, &value);
380  }
381 
382  /**
383  * Put the value into the map, and set the 'weak' callback when demanded
384  * by the Traits class.
385  */
386  Global<V> SetUnique(const K& key, Global<V>* persistent) {
387  if (Traits::kCallbackType == kNotWeak) {
388  this->AnnotateStrongRetainer(persistent);
389  } else {
390  WeakCallbackType callback_type =
391  Traits::kCallbackType == kWeakWithInternalFields
394  Local<V> value(Local<V>::New(this->isolate(), *persistent));
395  persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
396  Traits::WeakCallbackParameter(this, key, value), WeakCallback,
397  callback_type);
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  GlobalValueMap(Isolate* isolate, const char* label)
435  : PersistentValueMapBase<K, V, Traits>(isolate, label) {}
436 
437  typedef
438  typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
440 
441  /**
442  * Put value into map. Depending on Traits::kIsWeak, the value will be held
443  * by the map strongly or weakly.
444  * Returns old value as Global.
445  */
446  Global<V> Set(const K& key, Local<V> value) {
447  Global<V> persistent(this->isolate(), value);
448  return SetUnique(key, &persistent);
449  }
450 
451  /**
452  * Put value into map, like Set(const K&, Local<V>).
453  */
454  Global<V> Set(const K& key, Global<V> value) {
455  return SetUnique(key, &value);
456  }
457 
458  /**
459  * Put the value into the map, and set the 'weak' callback when demanded
460  * by the Traits class.
461  */
462  Global<V> SetUnique(const K& key, Global<V>* persistent) {
463  if (Traits::kCallbackType == kNotWeak) {
464  this->AnnotateStrongRetainer(persistent);
465  } else {
466  WeakCallbackType callback_type =
467  Traits::kCallbackType == kWeakWithInternalFields
470  Local<V> value(Local<V>::New(this->isolate(), *persistent));
471  persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
472  Traits::WeakCallbackParameter(this, key, value), OnWeakCallback,
473  callback_type);
474  }
475  PersistentContainerValue old_value =
476  Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
477  return this->Release(old_value).Pass();
478  }
479 
480  /**
481  * Put a value into the map and update the reference.
482  * Restrictions of GetReference apply here as well.
483  */
484  Global<V> Set(const K& key, Global<V> value,
485  PersistentValueReference* reference) {
486  *reference = this->Leak(&value);
487  return SetUnique(key, &value);
488  }
489 
490  private:
491  static void OnWeakCallback(
492  const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
493  if (Traits::kCallbackType != kNotWeak) {
494  auto map = Traits::MapFromWeakCallbackInfo(data);
495  K key = Traits::KeyFromWeakCallbackInfo(data);
496  map->RemoveWeak(key);
497  Traits::OnWeakCallback(data);
498  data.SetSecondPassCallback(SecondWeakCallback);
499  }
500  }
501 
502  static void SecondWeakCallback(
503  const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
504  Traits::DisposeWeak(data);
505  }
506 };
507 
508 
509 /**
510  * A map that uses Global as value and std::map as the backing
511  * implementation. Persistents are held non-weak.
512  *
513  * C++11 embedders don't need this class, as they can use
514  * Global directly in std containers.
515  */
516 template<typename K, typename V,
517  typename Traits = DefaultPersistentValueMapTraits<K, V> >
518 class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
519  public:
520  explicit StdPersistentValueMap(Isolate* isolate)
521  : PersistentValueMap<K, V, Traits>(isolate) {}
522 };
523 
524 
525 /**
526  * A map that uses Global as value and std::map as the backing
527  * implementation. Globals are held non-weak.
528  *
529  * C++11 embedders don't need this class, as they can use
530  * Global directly in std containers.
531  */
532 template <typename K, typename V,
533  typename Traits = DefaultGlobalMapTraits<K, V> >
534 class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
535  public:
536  explicit StdGlobalValueMap(Isolate* isolate)
537  : GlobalValueMap<K, V, Traits>(isolate) {}
538 };
539 
540 
542  public:
543  typedef std::vector<PersistentContainerValue> Impl;
544 
545  static void Append(Impl* impl, PersistentContainerValue value) {
546  impl->push_back(value);
547  }
548  static bool IsEmpty(const Impl* impl) {
549  return impl->empty();
550  }
551  static size_t Size(const Impl* impl) {
552  return impl->size();
553  }
554  static PersistentContainerValue Get(const Impl* impl, size_t i) {
555  return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
556  }
557  static void ReserveCapacity(Impl* impl, size_t capacity) {
558  impl->reserve(capacity);
559  }
560  static void Clear(Impl* impl) {
561  impl->clear();
562  }
563 };
564 
565 
566 /**
567  * A vector wrapper that safely stores Global values.
568  * C++11 embedders don't need this class, as they can use Global
569  * directly in std containers.
570  *
571  * This class relies on a backing vector implementation, whose type and methods
572  * are described by the Traits class. The backing map will handle values of type
573  * PersistentContainerValue, with all conversion into and out of V8
574  * handles being transparently handled by this class.
575  */
576 template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
578  public:
579  explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
580 
582  Clear();
583  }
584 
585  /**
586  * Append a value to the vector.
587  */
588  void Append(Local<V> value) {
589  Global<V> persistent(isolate_, value);
590  Traits::Append(&impl_, ClearAndLeak(&persistent));
591  }
592 
593  /**
594  * Append a persistent's value to the vector.
595  */
596  void Append(Global<V> persistent) {
597  Traits::Append(&impl_, ClearAndLeak(&persistent));
598  }
599 
600  /**
601  * Are there any values in the vector?
602  */
603  bool IsEmpty() const {
604  return Traits::IsEmpty(&impl_);
605  }
606 
607  /**
608  * How many elements are in the vector?
609  */
610  size_t Size() const {
611  return Traits::Size(&impl_);
612  }
613 
614  /**
615  * Retrieve the i-th value in the vector.
616  */
617  Local<V> Get(size_t index) const {
618  return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
619  }
620 
621  /**
622  * Remove all elements from the vector.
623  */
624  void Clear() {
625  size_t length = Traits::Size(&impl_);
626  for (size_t i = 0; i < length; i++) {
627  Global<V> p;
628  p.val_ = FromVal(Traits::Get(&impl_, i));
629  }
630  Traits::Clear(&impl_);
631  }
632 
633  /**
634  * Reserve capacity in the vector.
635  * (Efficiency gains depend on the backing implementation.)
636  */
637  void ReserveCapacity(size_t capacity) {
638  Traits::ReserveCapacity(&impl_, capacity);
639  }
640 
641  private:
642  static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
643  V* v = persistent->val_;
644  persistent->val_ = nullptr;
645  return reinterpret_cast<PersistentContainerValue>(v);
646  }
647 
648  static V* FromVal(PersistentContainerValue v) {
649  return reinterpret_cast<V*>(v);
650  }
651 
652  Isolate* isolate_;
653  typename Traits::Impl impl_;
654 };
655 
656 } // namespace v8
657 
658 #endif // V8_UTIL_H