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 : static K Key(Iterator it) { return it->first; }
52 : static PersistentContainerValue Value(Iterator it) { return it->second; }
53 : static PersistentContainerValue Set(Impl* impl, K key,
54 : PersistentContainerValue value) {
55 : std::pair<Iterator, bool> res = impl->insert(std::make_pair(key, value));
56 : PersistentContainerValue old_value = kPersistentContainerNotFound;
57 : if (!res.second) {
58 : old_value = res.first->second;
59 : res.first->second = value;
60 : }
61 : return old_value;
62 : }
63 : static PersistentContainerValue Get(Impl* impl, K key) {
64 : Iterator it = impl->find(key);
65 : if (it == impl->end()) return kPersistentContainerNotFound;
66 : return it->second;
67 : }
68 : static PersistentContainerValue Remove(Impl* impl, K key) {
69 : Iterator it = impl->find(key);
70 : if (it == impl->end()) return kPersistentContainerNotFound;
71 : PersistentContainerValue value = it->second;
72 : impl->erase(it);
73 : 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 : Local<V> Get(const K& key) {
180 : 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 : Global<V> Remove(const K& key) {
224 : 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 : void Clear() {
232 : typedef typename Traits::Iterator It;
233 : HandleScope handle_scope(isolate_);
234 : // TODO(dcarney): figure out if this swap and loop is necessary.
235 : while (!Traits::Empty(&impl_)) {
236 : typename Traits::Impl impl;
237 : Traits::Swap(impl_, impl);
238 : for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
239 : Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
240 : Traits::Key(i));
241 : }
242 : }
243 : }
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 : 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 : : 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 : PersistentValueReference GetReference(const K& key) {
298 : return PersistentValueReference(Traits::Get(&impl_, key));
299 : }
300 :
301 : protected:
302 : explicit PersistentValueMapBase(Isolate* isolate) : isolate_(isolate) {}
303 :
304 : ~PersistentValueMapBase() { Clear(); }
305 :
306 : Isolate* isolate() { return isolate_; }
307 : typename Traits::Impl* impl() { return &impl_; }
308 :
309 : static V* FromVal(PersistentContainerValue v) {
310 : return reinterpret_cast<V*>(v);
311 : }
312 :
313 : static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
314 : V* v = persistent->val_;
315 : persistent->val_ = 0;
316 : return reinterpret_cast<PersistentContainerValue>(v);
317 : }
318 :
319 : static PersistentContainerValue Leak(Global<V>* persistent) {
320 : 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 : static Global<V> Release(PersistentContainerValue v) {
329 : Global<V> p;
330 : p.val_ = FromVal(v);
331 : if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
332 : Traits::DisposeCallbackData(
333 : p.template ClearWeak<typename Traits::WeakCallbackDataType>());
334 : }
335 : return p.Pass();
336 : }
337 :
338 : void RemoveWeak(const K& key) {
339 : Global<V> p;
340 : p.val_ = FromVal(Traits::Remove(&impl_, key));
341 : p.Reset();
342 : }
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 : 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 : Global<V> Set(const K& key, Local<V> value) {
379 : Global<V> persistent(this->isolate(), value);
380 : 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 : Global<V> SetUnique(const K& key, Global<V>* persistent) {
395 : if (Traits::kCallbackType != kNotWeak) {
396 : Local<V> value(Local<V>::New(this->isolate(), *persistent));
397 : persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
398 : Traits::WeakCallbackParameter(this, key, value), WeakCallback);
399 : }
400 : PersistentContainerValue old_value =
401 : Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
402 : return this->Release(old_value).Pass();
403 : }
404 :
405 : /**
406 : * Put a value into the map and update the reference.
407 : * Restrictions of GetReference apply here as well.
408 : */
409 : Global<V> Set(const K& key, Global<V> value,
410 : PersistentValueReference* reference) {
411 : *reference = this->Leak(&value);
412 : return SetUnique(key, &value);
413 : }
414 :
415 : private:
416 : static void WeakCallback(
417 : const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
418 : if (Traits::kCallbackType != kNotWeak) {
419 : PersistentValueMap<K, V, Traits>* persistentValueMap =
420 : Traits::MapFromWeakCallbackInfo(data);
421 : K key = Traits::KeyFromWeakCallbackInfo(data);
422 : Traits::Dispose(data.GetIsolate(),
423 : persistentValueMap->Remove(key).Pass(), key);
424 : Traits::DisposeCallbackData(data.GetParameter());
425 : }
426 : }
427 : };
428 :
429 :
430 : template <typename K, typename V, typename Traits>
431 : class GlobalValueMap : public PersistentValueMapBase<K, V, Traits> {
432 : public:
433 : explicit GlobalValueMap(Isolate* isolate)
434 : : PersistentValueMapBase<K, V, Traits>(isolate) {}
435 :
436 : typedef
437 : typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
438 : PersistentValueReference;
439 :
440 : /**
441 : * Put value into map. Depending on Traits::kIsWeak, the value will be held
442 : * by the map strongly or weakly.
443 : * Returns old value as Global.
444 : */
445 : Global<V> Set(const K& key, Local<V> value) {
446 : Global<V> persistent(this->isolate(), value);
447 : return SetUnique(key, &persistent);
448 : }
449 :
450 : /**
451 : * Put value into map, like Set(const K&, Local<V>).
452 : */
453 : Global<V> Set(const K& key, Global<V> value) {
454 : return SetUnique(key, &value);
455 : }
456 :
457 : /**
458 : * Put the value into the map, and set the 'weak' callback when demanded
459 : * by the Traits class.
460 : */
461 : Global<V> SetUnique(const K& key, Global<V>* persistent) {
462 : if (Traits::kCallbackType != kNotWeak) {
463 : WeakCallbackType callback_type =
464 : Traits::kCallbackType == kWeakWithInternalFields
465 : ? WeakCallbackType::kInternalFields
466 : : WeakCallbackType::kParameter;
467 : Local<V> value(Local<V>::New(this->isolate(), *persistent));
468 : persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
469 : Traits::WeakCallbackParameter(this, key, value), OnWeakCallback,
470 : callback_type);
471 : }
472 : PersistentContainerValue old_value =
473 : Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
474 : return this->Release(old_value).Pass();
475 : }
476 :
477 : /**
478 : * Put a value into the map and update the reference.
479 : * Restrictions of GetReference apply here as well.
480 : */
481 : Global<V> Set(const K& key, Global<V> value,
482 : PersistentValueReference* reference) {
483 : *reference = this->Leak(&value);
484 : return SetUnique(key, &value);
485 : }
486 :
487 : private:
488 : static void OnWeakCallback(
489 : const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
490 : if (Traits::kCallbackType != kNotWeak) {
491 : auto map = Traits::MapFromWeakCallbackInfo(data);
492 : K key = Traits::KeyFromWeakCallbackInfo(data);
493 : map->RemoveWeak(key);
494 : Traits::OnWeakCallback(data);
495 : data.SetSecondPassCallback(SecondWeakCallback);
496 : }
497 : }
498 :
499 : static void SecondWeakCallback(
500 : const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
501 : Traits::DisposeWeak(data);
502 : }
503 : };
504 :
505 :
506 : /**
507 : * A map that uses Global as value and std::map as the backing
508 : * implementation. Persistents are held non-weak.
509 : *
510 : * C++11 embedders don't need this class, as they can use
511 : * Global directly in std containers.
512 : */
513 : template<typename K, typename V,
514 : typename Traits = DefaultPersistentValueMapTraits<K, V> >
515 : class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
516 : public:
517 : explicit StdPersistentValueMap(Isolate* isolate)
518 : : PersistentValueMap<K, V, Traits>(isolate) {}
519 : };
520 :
521 :
522 : /**
523 : * A map that uses Global as value and std::map as the backing
524 : * implementation. Globals are held non-weak.
525 : *
526 : * C++11 embedders don't need this class, as they can use
527 : * Global directly in std containers.
528 : */
529 : template <typename K, typename V,
530 : typename Traits = DefaultGlobalMapTraits<K, V> >
531 : class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
532 : public:
533 : explicit StdGlobalValueMap(Isolate* isolate)
534 : : GlobalValueMap<K, V, Traits>(isolate) {}
535 : };
536 :
537 :
538 : class DefaultPersistentValueVectorTraits {
539 : public:
540 : typedef std::vector<PersistentContainerValue> Impl;
541 :
542 : static void Append(Impl* impl, PersistentContainerValue value) {
543 12142 : impl->push_back(value);
544 : }
545 : static bool IsEmpty(const Impl* impl) {
546 : return impl->empty();
547 : }
548 21396 : static size_t Size(const Impl* impl) {
549 : return impl->size();
550 : }
551 24296 : static PersistentContainerValue Get(const Impl* impl, size_t i) {
552 48592 : return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
553 : }
554 : static void ReserveCapacity(Impl* impl, size_t capacity) {
555 : impl->reserve(capacity);
556 : }
557 : static void Clear(Impl* impl) {
558 : impl->clear();
559 : }
560 : };
561 :
562 :
563 : /**
564 : * A vector wrapper that safely stores Global values.
565 : * C++11 embedders don't need this class, as they can use Global
566 : * directly in std containers.
567 : *
568 : * This class relies on a backing vector implementation, whose type and methods
569 : * are described by the Traits class. The backing map will handle values of type
570 : * PersistentContainerValue, with all conversion into and out of V8
571 : * handles being transparently handled by this class.
572 : */
573 : template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
574 : class PersistentValueVector {
575 : public:
576 4533 : explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
577 :
578 4533 : ~PersistentValueVector() {
579 4533 : Clear();
580 4533 : }
581 :
582 : /**
583 : * Append a value to the vector.
584 : */
585 12142 : void Append(Local<V> value) {
586 12142 : Global<V> persistent(isolate_, value);
587 12142 : Traits::Append(&impl_, ClearAndLeak(&persistent));
588 12142 : }
589 :
590 : /**
591 : * Append a persistent's value to the vector.
592 : */
593 : void Append(Global<V> persistent) {
594 : Traits::Append(&impl_, ClearAndLeak(&persistent));
595 : }
596 :
597 : /**
598 : * Are there any values in the vector?
599 : */
600 : bool IsEmpty() const {
601 : return Traits::IsEmpty(&impl_);
602 : }
603 :
604 : /**
605 : * How many elements are in the vector?
606 : */
607 : size_t Size() const {
608 : return Traits::Size(&impl_);
609 : }
610 :
611 : /**
612 : * Retrieve the i-th value in the vector.
613 : */
614 12160 : Local<V> Get(size_t index) const {
615 36480 : return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
616 : }
617 :
618 : /**
619 : * Remove all elements from the vector.
620 : */
621 4727 : void Clear() {
622 : size_t length = Traits::Size(&impl_);
623 16863 : for (size_t i = 0; i < length; i++) {
624 : Global<V> p;
625 12136 : p.val_ = FromVal(Traits::Get(&impl_, i));
626 : }
627 : Traits::Clear(&impl_);
628 4727 : }
629 :
630 : /**
631 : * Reserve capacity in the vector.
632 : * (Efficiency gains depend on the backing implementation.)
633 : */
634 : void ReserveCapacity(size_t capacity) {
635 : Traits::ReserveCapacity(&impl_, capacity);
636 : }
637 :
638 : private:
639 : static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
640 : V* v = persistent->val_;
641 : persistent->val_ = 0;
642 12142 : return reinterpret_cast<PersistentContainerValue>(v);
643 : }
644 :
645 : static V* FromVal(PersistentContainerValue v) {
646 24296 : return reinterpret_cast<V*>(v);
647 : }
648 :
649 : Isolate* isolate_;
650 : typename Traits::Impl impl_;
651 : };
652 :
653 : } // namespace v8
654 :
655 : #endif // V8_UTIL_H
|