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

#ifndef INCLUDE_V8_CPPGC_H_
#define INCLUDE_V8_CPPGC_H_

#include "cppgc/visitor.h"
9
#include "v8-internal.h"  // NOLINT(build/include_directory)
10 11 12 13
#include "v8.h"  // NOLINT(build/include_directory)

namespace v8 {

14
class Isolate;
15 16 17 18 19
template <typename T>
class JSMember;

namespace internal {

20 21
class JSMemberBaseExtractor;

22 23
// TODO(chromium:1056170): Provide implementation based on global handles.
class JSMemberBase {
24 25 26 27 28 29 30 31 32 33 34 35
 public:
  /**
   * Returns true if the reference is empty, i.e., has not been assigned
   * object.
   */
  bool IsEmpty() const { return val_ == kNullAddress; }

  /**
   * Clears the reference. IsEmpty() will return true after this call.
   */
  V8_INLINE void Reset();

36
 private:
37 38 39 40
  static internal::Address New(v8::Isolate* isolate, internal::Address* object,
                               internal::Address* slot);
  static void Delete(internal::Address* slot);

41 42
  JSMemberBase() = default;

43 44 45 46 47
  JSMemberBase(v8::Isolate* isolate, internal::Address* object)
      : val_(New(isolate, object, &this->val_)) {}

  internal::Address val_ = kNullAddress;

48 49
  template <typename T>
  friend class v8::JSMember;
50
  friend class v8::internal::JSMemberBaseExtractor;
51 52
};

53 54 55 56 57 58
void JSMemberBase::Reset() {
  if (IsEmpty()) return;
  Delete(reinterpret_cast<internal::Address*>(val_));
  val_ = kNullAddress;
}

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
}  // namespace internal

/**
 * A traced handle without destructor that clears the handle. The handle may
 * only be used in GarbageCollected objects and must be processed in a Trace()
 * method.
 *
 * TODO(chromium:1056170): Implementation.
 */
template <typename T>
class JSMember : public internal::JSMemberBase {
  static_assert(std::is_base_of<v8::Value, T>::value,
                "JSMember only supports references to v8::Value");

 public:
  JSMember() = default;

76 77 78 79 80
  template <typename U,
            typename = std::enable_if_t<std::is_base_of<T, U>::value>>
  JSMember(Isolate* isolate, Local<U> that)
      : internal::JSMemberBase(isolate, that.val_) {}

81
  // Heterogeneous construction.
82
  // TODO(chromium:1056170): Implementation.
83 84 85 86 87 88 89 90 91 92 93
  template <typename U,
            typename = std::enable_if_t<std::is_base_of<T, U>::value>>
  JSMember(const JSMember<U>& other) {}  // NOLINT
};

class JSVisitor : public cppgc::Visitor {
 public:
  explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {}

  template <typename T>
  void Trace(const JSMember<T>& ref) {
94
    if (ref.IsEmpty()) return;
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
    Visit(ref);
  }

 protected:
  using cppgc::Visitor::Visit;

  virtual void Visit(const internal::JSMemberBase& ref) {}
};

}  // namespace v8

namespace cppgc {

template <typename T>
struct TraceTrait<v8::JSMember<T>> {
  static void Trace(Visitor* visitor, const v8::JSMember<T>* self) {
    static_cast<v8::JSVisitor*>(visitor)->Trace(*self);
  }
};

}  // namespace cppgc

#endif  // INCLUDE_V8_CPPGC_H_