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