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; 24 enum PersistentContainerCallbackType { 25 kNotWeak, 26 // These correspond to v8::WeakCallbackType 27 kWeakWithParameter, 28 kWeakWithInternalFields 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 Empty(Impl * impl)44 static bool Empty(Impl* impl) { return impl->empty(); } Size(Impl * impl)45 static size_t Size(Impl* impl) { return impl->size(); } Swap(Impl & a,Impl & b)46 static void Swap(Impl& a, Impl& b) { std::swap(a, b); } // NOLINT Begin(Impl * impl)47 static Iterator Begin(Impl* impl) { return impl->begin(); } End(Impl * impl)48 static Iterator End(Impl* impl) { return impl->end(); } Key(Iterator it)49 static K Key(Iterator it) { return it->first; } Value(Iterator it)50 static PersistentContainerValue Value(Iterator it) { return it->second; } Set(Impl * impl,K key,PersistentContainerValue value)51 static PersistentContainerValue Set(Impl* impl, K key, 52 PersistentContainerValue value) { 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 } Get(Impl * impl,K key)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 } Remove(Impl * impl,K key)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> 85 class DefaultPersistentValueMapTraits : public StdMapTraits<K, V> { 86 public: 87 // Weak callback & friends: 88 static const PersistentContainerCallbackType kCallbackType = kNotWeak; 89 typedef PersistentValueMap<K, V, DefaultPersistentValueMapTraits<K, V> > 90 MapType; 91 typedef void WeakCallbackDataType; 92 WeakCallbackParameter(MapType * map,const K & key,Local<V> value)93 static WeakCallbackDataType* WeakCallbackParameter( 94 MapType* map, const K& key, Local<V> value) { 95 return nullptr; 96 } MapFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)97 static MapType* MapFromWeakCallbackInfo( 98 const WeakCallbackInfo<WeakCallbackDataType>& data) { 99 return nullptr; 100 } KeyFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)101 static K KeyFromWeakCallbackInfo( 102 const WeakCallbackInfo<WeakCallbackDataType>& data) { 103 return K(); 104 } DisposeCallbackData(WeakCallbackDataType * data)105 static void DisposeCallbackData(WeakCallbackDataType* data) { } Dispose(Isolate * isolate,Global<V> value,K key)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: 118 static const PersistentContainerCallbackType kCallbackType = kNotWeak; 119 typedef GlobalValueMap<K, V, DefaultGlobalMapTraits<K, V> > MapType; 120 typedef void WeakCallbackDataType; 121 WeakCallbackParameter(MapType * map,const K & key,Local<V> value)122 static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key, 123 Local<V> value) { 124 return nullptr; 125 } MapFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)126 static MapType* MapFromWeakCallbackInfo( 127 const WeakCallbackInfo<WeakCallbackDataType>& data) { 128 return nullptr; 129 } KeyFromWeakCallbackInfo(const WeakCallbackInfo<WeakCallbackDataType> & data)130 static K KeyFromWeakCallbackInfo( 131 const WeakCallbackInfo<WeakCallbackDataType>& data) { 132 return K(); 133 } DisposeCallbackData(WeakCallbackDataType * data)134 static void DisposeCallbackData(WeakCallbackDataType* data) {} OnWeakCallback(const WeakCallbackInfo<WeakCallbackDataType> & data)135 static void OnWeakCallback( 136 const WeakCallbackInfo<WeakCallbackDataType>& data) {} Dispose(Isolate * isolate,Global<V> value,K key)137 static void Dispose(Isolate* isolate, Global<V> value, K key) {} 138 // This is a second pass callback, so SetSecondPassCallback cannot be called. DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType> & data)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> 160 class PersistentValueMapBase { 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 */ 226 class PersistentValueReference { 227 public: 228 PersistentValueReference() : value_(kPersistentContainerNotFound) { } 229 PersistentValueReference(const PersistentValueReference& other) 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: 250 friend class PersistentValueMapBase; 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 261 PersistentContainerValue value_; 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 */ 274 PersistentValueReference GetReference(const K& key) { 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 284 ~PersistentValueMapBase() { Clear(); } 285 286 Isolate* isolate() { return isolate_; } 287 typename Traits::Impl* impl() { return &impl_; } 288 289 static V* FromVal(PersistentContainerValue v) { 290 return reinterpret_cast<V*>(v); 291 } 292 293 static PersistentContainerValue ClearAndLeak(Global<V>* persistent) { 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 */ 308 static Global<V> Release(PersistentContainerValue v) { 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 357 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 386 ? WeakCallbackType::kInternalFields 387 : WeakCallbackType::kParameter; 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 433 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 462 ? WeakCallbackType::kInternalFields 463 : WeakCallbackType::kParameter; 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 535 class DefaultPersistentValueVectorTraits { 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> 571 class PersistentValueVector { 572 public: 573 explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { } 574 575 ~PersistentValueVector() { 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 653