v8-util.h 19.5 KB
Newer Older
1
// Copyright 2014 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_UTIL_H_
#define V8_UTIL_H_

8
#include "v8.h"  // NOLINT(build/include)
9
#include <assert.h>
10
#include <map>
11
#include <vector>
12 13 14 15

/**
 * Support for Persistent containers.
 *
16
 * C++11 embedders can use STL containers with Global values,
17 18 19 20 21 22 23
 * but pre-C++11 does not support the required move semantic and hence
 * may want these container classes.
 */
namespace v8 {

typedef uintptr_t PersistentContainerValue;
static const uintptr_t kPersistentContainerNotFound = 0;
24 25
enum PersistentContainerCallbackType {
  kNotWeak,
26 27 28 29
  // These correspond to v8::WeakCallbackType
  kWeakWithParameter,
  kWeakWithInternalFields,
  kWeak = kWeakWithParameter  // For backwards compatibility.  Deprecate.
30
};
31

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

/**
 * A default trait implemenation for PersistentValueMap which uses std::map
 * as a backing map.
 *
 * Users will have to implement their own weak callbacks & dispose traits.
 */
template<typename K, typename V>
class StdMapTraits {
 public:
  // STL map & related:
  typedef std::map<K, PersistentContainerValue> Impl;
  typedef typename Impl::iterator Iterator;

  static bool Empty(Impl* impl) { return impl->empty(); }
  static size_t Size(Impl* impl) { return impl->size(); }
  static void Swap(Impl& a, Impl& b) { std::swap(a, b); }  // NOLINT
  static Iterator Begin(Impl* impl) { return impl->begin(); }
  static Iterator End(Impl* impl) { return impl->end(); }
  static K Key(Iterator it) { return it->first; }
  static PersistentContainerValue Value(Iterator it) { return it->second; }
  static PersistentContainerValue Set(Impl* impl, K key,
      PersistentContainerValue value) {
    std::pair<Iterator, bool> res = impl->insert(std::make_pair(key, value));
    PersistentContainerValue old_value = kPersistentContainerNotFound;
    if (!res.second) {
      old_value = res.first->second;
      res.first->second = value;
    }
    return old_value;
  }
  static PersistentContainerValue Get(Impl* impl, K key) {
    Iterator it = impl->find(key);
    if (it == impl->end()) return kPersistentContainerNotFound;
    return it->second;
  }
  static PersistentContainerValue Remove(Impl* impl, K key) {
    Iterator it = impl->find(key);
    if (it == impl->end()) return kPersistentContainerNotFound;
    PersistentContainerValue value = it->second;
    impl->erase(it);
    return value;
  }
};


/**
 * A default trait implementation for PersistentValueMap, which inherits
 * a std:map backing map from StdMapTraits and holds non-weak persistent
81
 * objects and has no special Dispose handling.
82
 *
83 84
 * You should not derive from this class, since MapType depends on the
 * 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 89
 public:
  // Weak callback & friends:
90 91 92
  static const PersistentContainerCallbackType kCallbackType = kNotWeak;
  typedef PersistentValueMap<K, V, DefaultPersistentValueMapTraits<K, V> >
      MapType;
93
  typedef void WeakCallbackDataType;
94

95
  static WeakCallbackDataType* WeakCallbackParameter(
96 97 98
      MapType* map, const K& key, Local<V> value) {
    return NULL;
  }
99 100
  static MapType* MapFromWeakCallbackInfo(
      const WeakCallbackInfo<WeakCallbackDataType>& data) {
101 102
    return NULL;
  }
103 104
  static K KeyFromWeakCallbackInfo(
      const WeakCallbackInfo<WeakCallbackDataType>& data) {
105 106 107
    return K();
  }
  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 115 116 117 118 119 120
 private:
  template <typename T>
  struct RemovePointer;

 public:
  // Weak callback & friends:
  static const PersistentContainerCallbackType kCallbackType = kNotWeak;
dcarney's avatar
dcarney committed
121 122
  typedef GlobalValueMap<K, V, DefaultGlobalMapTraits<K, V> > MapType;
  typedef void WeakCallbackDataType;
123

dcarney's avatar
dcarney committed
124
  static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
125 126
                                                     Local<V> value) {
    return nullptr;
127
  }
128
  static MapType* MapFromWeakCallbackInfo(
dcarney's avatar
dcarney committed
129
      const WeakCallbackInfo<WeakCallbackDataType>& data) {
130
    return nullptr;
131
  }
132
  static K KeyFromWeakCallbackInfo(
dcarney's avatar
dcarney committed
133
      const WeakCallbackInfo<WeakCallbackDataType>& data) {
134 135
    return K();
  }
dcarney's avatar
dcarney committed
136
  static void DisposeCallbackData(WeakCallbackDataType* data) {}
137 138
  static void OnWeakCallback(
      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.
dcarney's avatar
dcarney committed
141
  static void DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType>& data) {}
142 143 144 145 146 147 148 149 150

 private:
  template <typename T>
  struct RemovePointer<T*> {
    typedef T Type;
  };
};


151
/**
152 153
 * A map wrapper that allows using Global as a mapped value.
 * C++11 embedders don't need this class, as they can use Global
154 155 156 157 158 159 160
 * directly in std containers.
 *
 * The map relies on a backing map, whose type and accessors are described
 * by the Traits class. The backing map will handle values of type
 * PersistentContainerValue, with all conversion into and out of V8
 * handles being transparently handled by this class.
 */
161 162
template <typename K, typename V, typename Traits>
class PersistentValueMapBase {
163
 public:
164
  Isolate* GetIsolate() { return isolate_; }
165 166 167 168

  /**
   * Return size of the map.
   */
169
  size_t Size() { return Traits::Size(&impl_); }
170

171 172 173
  /**
   * Return whether the map holds weak persistents.
   */
174
  bool IsWeak() { return Traits::kCallbackType != kNotWeak; }
175

176 177 178
  /**
   * Get value stored in map.
   */
179
  Local<V> Get(const K& key) {
180 181 182 183 184 185
    return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, key)));
  }

  /**
   * Check whether a value is contained in the map.
   */
186
  bool Contains(const K& key) {
187
    return Traits::Get(&impl_, key) != kPersistentContainerNotFound;
188 189 190 191 192 193
  }

  /**
   * Get value stored in map and set it in returnValue.
   * Return true if a value was found.
   */
194
  bool SetReturnValue(const K& key,
195
      ReturnValue<Value> returnValue) {
196
    return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key));
197
  }
198 199 200 201

  /**
   * Call Isolate::SetReference with the given parent and the map value.
   */
202
  void SetReference(const K& key,
203
      const Persistent<Object>& parent) {
204 205 206 207 208
    GetIsolate()->SetReference(
      reinterpret_cast<internal::Object**>(parent.val_),
      reinterpret_cast<internal::Object**>(FromVal(Traits::Get(&impl_, key))));
  }

209
  /**
210 211
   * Call V8::RegisterExternallyReferencedObject with the map value for given
   * key.
212
   */
213
  void RegisterExternallyReferencedObject(K& key) {
214
    assert(Contains(key));
215 216 217
    V8::RegisterExternallyReferencedObject(
        reinterpret_cast<internal::Object**>(FromVal(Traits::Get(&impl_, key))),
        reinterpret_cast<internal::Isolate*>(GetIsolate()));
218 219
  }

220 221 222
  /**
   * Return value for key and remove it from the map.
   */
223
  Global<V> Remove(const K& key) {
224 225 226 227 228 229 230
    return Release(Traits::Remove(&impl_, key)).Pass();
  }

  /**
  * Traverses the map repeatedly,
  * in case side effects of disposal cause insertions.
  **/
231 232 233 234 235 236 237 238
  void Clear() {
    typedef typename Traits::Iterator It;
    HandleScope handle_scope(isolate_);
    // TODO(dcarney): figure out if this swap and loop is necessary.
    while (!Traits::Empty(&impl_)) {
      typename Traits::Impl impl;
      Traits::Swap(impl_, impl);
      for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
239 240
        Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
                        Traits::Key(i));
241 242 243
      }
    }
  }
244

245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
  /**
   * Helper class for GetReference/SetWithReference. Do not use outside
   * that context.
   */
  class PersistentValueReference {
   public:
    PersistentValueReference() : value_(kPersistentContainerNotFound) { }
    PersistentValueReference(const PersistentValueReference& other)
        : value_(other.value_) { }

    Local<V> NewLocal(Isolate* isolate) const {
      return Local<V>::New(isolate, FromVal(value_));
    }
    bool IsEmpty() const {
      return value_ == kPersistentContainerNotFound;
    }
    template<typename T>
    bool SetReturnValue(ReturnValue<T> returnValue) {
263
      return SetReturnValueFromVal(&returnValue, value_);
264 265 266 267 268 269 270 271 272
    }
    void Reset() {
      value_ = kPersistentContainerNotFound;
    }
    void operator=(const PersistentValueReference& other) {
      value_ = other.value_;
    }

   private:
273 274
    friend class PersistentValueMapBase;
    friend class PersistentValueMap<K, V, Traits>;
275
    friend class GlobalValueMap<K, V, Traits>;
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

    explicit PersistentValueReference(PersistentContainerValue value)
        : value_(value) { }

    void operator=(PersistentContainerValue value) {
      value_ = value;
    }

    PersistentContainerValue value_;
  };

  /**
   * Get a reference to a map value. This enables fast, repeated access
   * to a value stored in the map while the map remains unchanged.
   *
   * Careful: This is potentially unsafe, so please use with care.
   * The value will become invalid if the value for this key changes
   * in the underlying map, as a result of Set or Remove for the same
   * key; as a result of the weak callback for the same key; or as a
   * result of calling Clear() or destruction of the map.
   */
297
  PersistentValueReference GetReference(const K& key) {
298 299 300
    return PersistentValueReference(Traits::Get(&impl_, key));
  }

301 302 303 304 305 306 307 308 309 310 311 312
 protected:
  explicit PersistentValueMapBase(Isolate* isolate) : isolate_(isolate) {}

  ~PersistentValueMapBase() { Clear(); }

  Isolate* isolate() { return isolate_; }
  typename Traits::Impl* impl() { return &impl_; }

  static V* FromVal(PersistentContainerValue v) {
    return reinterpret_cast<V*>(v);
  }

313
  static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
314 315 316 317 318
    V* v = persistent->val_;
    persistent->val_ = 0;
    return reinterpret_cast<PersistentContainerValue>(v);
  }

319
  static PersistentContainerValue Leak(Global<V>* persistent) {
320 321 322
    return reinterpret_cast<PersistentContainerValue>(persistent->val_);
  }

323
  /**
324
   * Return a container value as Global and make sure the weak
325 326
   * callback is properly disposed of. All remove functionality should go
   * through this.
327
   */
328 329
  static Global<V> Release(PersistentContainerValue v) {
    Global<V> p;
330 331 332 333 334 335
    p.val_ = FromVal(v);
    if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
      Traits::DisposeCallbackData(
          p.template ClearWeak<typename Traits::WeakCallbackDataType>());
    }
    return p.Pass();
336 337
  }

dcarney's avatar
dcarney committed
338 339 340 341 342
  void RemoveWeak(const K& key) {
    Global<V> p;
    p.val_ = FromVal(Traits::Remove(&impl_, key));
    p.Reset();
  }
343

344
 private:
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
  PersistentValueMapBase(PersistentValueMapBase&);
  void operator=(PersistentValueMapBase&);

  static bool SetReturnValueFromVal(ReturnValue<Value>* returnValue,
                                    PersistentContainerValue value) {
    bool hasValue = value != kPersistentContainerNotFound;
    if (hasValue) {
      returnValue->SetInternal(
          *reinterpret_cast<internal::Object**>(FromVal(value)));
    }
    return hasValue;
  }

  Isolate* isolate_;
  typename Traits::Impl impl_;
};


template <typename K, typename V, typename Traits>
class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
 public:
  explicit PersistentValueMap(Isolate* isolate)
      : PersistentValueMapBase<K, V, Traits>(isolate) {}

  typedef
      typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
          PersistentValueReference;

  /**
   * Put value into map. Depending on Traits::kIsWeak, the value will be held
   * by the map strongly or weakly.
376
   * Returns old value as Global.
377
   */
378 379
  Global<V> Set(const K& key, Local<V> value) {
    Global<V> persistent(this->isolate(), value);
380 381 382 383 384 385
    return SetUnique(key, &persistent);
  }

  /**
   * Put value into map, like Set(const K&, Local<V>).
   */
386
  Global<V> Set(const K& key, Global<V> value) {
387 388
    return SetUnique(key, &value);
  }
389 390 391 392 393

  /**
   * Put the value into the map, and set the 'weak' callback when demanded
   * by the Traits class.
   */
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 402 403 404 405 406 407 408
        Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
    return this->Release(old_value).Pass();
  }

  /**
   * Put a value into the map and update the reference.
   * Restrictions of GetReference apply here as well.
   */
409 410
  Global<V> Set(const K& key, Global<V> value,
                PersistentValueReference* reference) {
411 412
    *reference = this->Leak(&value);
    return SetUnique(key, &value);
413 414
  }

415
 private:
416
  static void WeakCallback(
417
      const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
418 419
    if (Traits::kCallbackType != kNotWeak) {
      PersistentValueMap<K, V, Traits>* persistentValueMap =
420 421
          Traits::MapFromWeakCallbackInfo(data);
      K key = Traits::KeyFromWeakCallbackInfo(data);
422 423
      Traits::Dispose(data.GetIsolate(),
                      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 437 438 439 440 441 442
  typedef
      typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
          PersistentValueReference;

  /**
   * Put value into map. Depending on Traits::kIsWeak, the value will be held
   * by the map strongly or weakly.
443
   * Returns old value as Global.
444
   */
445 446
  Global<V> Set(const K& key, Local<V> value) {
    Global<V> persistent(this->isolate(), value);
447
    return SetUnique(key, &persistent);
448 449
  }

450 451 452
  /**
   * Put value into map, like Set(const K&, Local<V>).
   */
453
  Global<V> Set(const K& key, Global<V> value) {
454
    return SetUnique(key, &value);
455 456
  }

457
  /**
458 459
   * Put the value into the map, and set the 'weak' callback when demanded
   * by the Traits class.
460
   */
461
  Global<V> SetUnique(const K& key, Global<V>* persistent) {
462
    if (Traits::kCallbackType != kNotWeak) {
463 464 465 466
      WeakCallbackType callback_type =
          Traits::kCallbackType == kWeakWithInternalFields
              ? WeakCallbackType::kInternalFields
              : 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 473 474
    PersistentContainerValue old_value =
        Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
    return this->Release(old_value).Pass();
475 476
  }

477 478 479 480
  /**
   * Put a value into the map and update the reference.
   * Restrictions of GetReference apply here as well.
   */
481 482
  Global<V> Set(const K& key, Global<V> value,
                PersistentValueReference* reference) {
483 484 485 486 487
    *reference = this->Leak(&value);
    return SetUnique(key, &value);
  }

 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 500 501 502

  static void SecondWeakCallback(
      const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
    Traits::DisposeWeak(data);
  }
503 504
};

505 506

/**
507
 * A map that uses Global as value and std::map as the backing
508 509 510
 * implementation. Persistents are held non-weak.
 *
 * C++11 embedders don't need this class, as they can use
511
 * Global directly in std containers.
512 513 514 515 516 517 518 519 520
 */
template<typename K, typename V,
    typename Traits = DefaultPersistentValueMapTraits<K, V> >
class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
 public:
  explicit StdPersistentValueMap(Isolate* isolate)
      : PersistentValueMap<K, V, Traits>(isolate) {}
};

521

dcarney's avatar
dcarney committed
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
/**
 * A map that uses Global as value and std::map as the backing
 * implementation. Globals are held non-weak.
 *
 * C++11 embedders don't need this class, as they can use
 * Global directly in std containers.
 */
template <typename K, typename V,
          typename Traits = DefaultGlobalMapTraits<K, V> >
class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
 public:
  explicit StdGlobalValueMap(Isolate* isolate)
      : GlobalValueMap<K, V, Traits>(isolate) {}
};


538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
class DefaultPersistentValueVectorTraits {
 public:
  typedef std::vector<PersistentContainerValue> Impl;

  static void Append(Impl* impl, PersistentContainerValue value) {
    impl->push_back(value);
  }
  static bool IsEmpty(const Impl* impl) {
    return impl->empty();
  }
  static size_t Size(const Impl* impl) {
    return impl->size();
  }
  static PersistentContainerValue Get(const Impl* impl, size_t i) {
    return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
  }
  static void ReserveCapacity(Impl* impl, size_t capacity) {
    impl->reserve(capacity);
  }
  static void Clear(Impl* impl) {
    impl->clear();
  }
};


/**
564 565
 * A vector wrapper that safely stores Global values.
 * C++11 embedders don't need this class, as they can use Global
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
 * directly in std containers.
 *
 * This class relies on a backing vector implementation, whose type and methods
 * are described by the Traits class. The backing map will handle values of type
 * PersistentContainerValue, with all conversion into and out of V8
 * handles being transparently handled by this class.
 */
template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
class PersistentValueVector {
 public:
  explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }

  ~PersistentValueVector() {
    Clear();
  }

  /**
   * Append a value to the vector.
   */
  void Append(Local<V> value) {
586
    Global<V> persistent(isolate_, value);
587 588 589 590 591 592
    Traits::Append(&impl_, ClearAndLeak(&persistent));
  }

  /**
   * Append a persistent's value to the vector.
   */
593
  void Append(Global<V> persistent) {
594
    Traits::Append(&impl_, ClearAndLeak(&persistent));
595
  }
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623

  /**
   * Are there any values in the vector?
   */
  bool IsEmpty() const {
    return Traits::IsEmpty(&impl_);
  }

  /**
   * How many elements are in the vector?
   */
  size_t Size() const {
    return Traits::Size(&impl_);
  }

  /**
   * Retrieve the i-th value in the vector.
   */
  Local<V> Get(size_t index) const {
    return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
  }

  /**
   * Remove all elements from the vector.
   */
  void Clear() {
    size_t length = Traits::Size(&impl_);
    for (size_t i = 0; i < length; i++) {
624
      Global<V> p;
625 626 627 628 629 630 631 632 633 634 635 636 637 638
      p.val_ = FromVal(Traits::Get(&impl_, i));
    }
    Traits::Clear(&impl_);
  }

  /**
   * Reserve capacity in the vector.
   * (Efficiency gains depend on the backing implementation.)
   */
  void ReserveCapacity(size_t capacity) {
    Traits::ReserveCapacity(&impl_, capacity);
  }

 private:
639
  static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
640 641 642 643 644 645 646 647 648 649 650 651 652
    V* v = persistent->val_;
    persistent->val_ = 0;
    return reinterpret_cast<PersistentContainerValue>(v);
  }

  static V* FromVal(PersistentContainerValue v) {
    return reinterpret_cast<V*>(v);
  }

  Isolate* isolate_;
  typename Traits::Impl impl_;
};

653 654
}  // namespace v8

655
#endif  // V8_UTIL_H