GCVariant.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef js_GCVariant_h
  6. #define js_GCVariant_h
  7. #include "mozilla/Variant.h"
  8. #include "js/GCPolicyAPI.h"
  9. #include "js/RootingAPI.h"
  10. #include "js/TracingAPI.h"
  11. namespace JS {
  12. // These template specializations allow Variant to be used inside GC wrappers.
  13. //
  14. // When matching on GC wrappers around Variants, matching should be done on
  15. // the wrapper itself. The matcher class's methods should take Handles or
  16. // MutableHandles. For example,
  17. //
  18. // struct MyMatcher
  19. // {
  20. // using ReturnType = const char*;
  21. // ReturnType match(HandleObject o) { return "object"; }
  22. // ReturnType match(HandleScript s) { return "script"; }
  23. // };
  24. //
  25. // Rooted<Variant<JSObject*, JSScript*>> v(cx, someScript);
  26. // MyMatcher mm;
  27. // v.match(mm);
  28. //
  29. // If you get compile errors about inability to upcast subclasses (e.g., from
  30. // NativeObject* to JSObject*) and are inside js/src, be sure to also include
  31. // "gc/Policy.h".
  32. namespace detail {
  33. template <typename... Ts>
  34. struct GCVariantImplementation;
  35. // The base case.
  36. template <typename T>
  37. struct GCVariantImplementation<T>
  38. {
  39. template <typename ConcreteVariant>
  40. static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
  41. T& thing = v->template as<T>();
  42. if (!mozilla::IsPointer<T>::value || thing)
  43. GCPolicy<T>::trace(trc, &thing, name);
  44. }
  45. template <typename Matcher, typename ConcreteVariant>
  46. static typename Matcher::ReturnType
  47. match(Matcher& matcher, Handle<ConcreteVariant> v) {
  48. const T& thing = v.get().template as<T>();
  49. return matcher.match(Handle<T>::fromMarkedLocation(&thing));
  50. }
  51. template <typename Matcher, typename ConcreteVariant>
  52. static typename Matcher::ReturnType
  53. match(Matcher& matcher, MutableHandle<ConcreteVariant> v) {
  54. T& thing = v.get().template as<T>();
  55. return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
  56. }
  57. };
  58. // The inductive case.
  59. template <typename T, typename... Ts>
  60. struct GCVariantImplementation<T, Ts...>
  61. {
  62. using Next = GCVariantImplementation<Ts...>;
  63. template <typename ConcreteVariant>
  64. static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
  65. if (v->template is<T>()) {
  66. T& thing = v->template as<T>();
  67. if (!mozilla::IsPointer<T>::value || thing)
  68. GCPolicy<T>::trace(trc, &thing, name);
  69. } else {
  70. Next::trace(trc, v, name);
  71. }
  72. }
  73. template <typename Matcher, typename ConcreteVariant>
  74. static typename Matcher::ReturnType
  75. match(Matcher& matcher, Handle<ConcreteVariant> v) {
  76. if (v.get().template is<T>()) {
  77. const T& thing = v.get().template as<T>();
  78. return matcher.match(Handle<T>::fromMarkedLocation(&thing));
  79. }
  80. return Next::match(matcher, v);
  81. }
  82. template <typename Matcher, typename ConcreteVariant>
  83. static typename Matcher::ReturnType
  84. match(Matcher& matcher, MutableHandle<ConcreteVariant> v) {
  85. if (v.get().template is<T>()) {
  86. T& thing = v.get().template as<T>();
  87. return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
  88. }
  89. return Next::match(matcher, v);
  90. }
  91. };
  92. } // namespace detail
  93. template <typename... Ts>
  94. struct GCPolicy<mozilla::Variant<Ts...>>
  95. {
  96. using Impl = detail::GCVariantImplementation<Ts...>;
  97. // Variants do not provide initial(). They do not have a default initial
  98. // value and one must be provided.
  99. static void trace(JSTracer* trc, mozilla::Variant<Ts...>* v, const char* name) {
  100. Impl::trace(trc, v, name);
  101. }
  102. };
  103. } // namespace JS
  104. namespace js {
  105. template <typename Outer, typename... Ts>
  106. class GCVariantOperations
  107. {
  108. using Impl = JS::detail::GCVariantImplementation<Ts...>;
  109. using Variant = mozilla::Variant<Ts...>;
  110. const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
  111. public:
  112. template <typename T>
  113. bool is() const {
  114. return variant().template is<T>();
  115. }
  116. template <typename T>
  117. JS::Handle<T> as() const {
  118. return Handle<T>::fromMarkedLocation(&variant().template as<T>());
  119. }
  120. template <typename Matcher>
  121. typename Matcher::ReturnType
  122. match(Matcher& matcher) const {
  123. return Impl::match(matcher, JS::Handle<Variant>::fromMarkedLocation(&variant()));
  124. }
  125. };
  126. template <typename Outer, typename... Ts>
  127. class MutableGCVariantOperations
  128. : public GCVariantOperations<Outer, Ts...>
  129. {
  130. using Impl = JS::detail::GCVariantImplementation<Ts...>;
  131. using Variant = mozilla::Variant<Ts...>;
  132. const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
  133. Variant& variant() { return static_cast<Outer*>(this)->get(); }
  134. public:
  135. template <typename T>
  136. JS::MutableHandle<T> as() {
  137. return JS::MutableHandle<T>::fromMarkedLocation(&variant().template as<T>());
  138. }
  139. template <typename Matcher>
  140. typename Matcher::ReturnType
  141. match(Matcher& matcher) {
  142. return Impl::match(matcher, JS::MutableHandle<Variant>::fromMarkedLocation(&variant()));
  143. }
  144. };
  145. template <typename... Ts>
  146. class RootedBase<mozilla::Variant<Ts...>>
  147. : public MutableGCVariantOperations<JS::Rooted<mozilla::Variant<Ts...>>, Ts...>
  148. { };
  149. template <typename... Ts>
  150. class MutableHandleBase<mozilla::Variant<Ts...>>
  151. : public MutableGCVariantOperations<JS::MutableHandle<mozilla::Variant<Ts...>>, Ts...>
  152. { };
  153. template <typename... Ts>
  154. class HandleBase<mozilla::Variant<Ts...>>
  155. : public GCVariantOperations<JS::Handle<mozilla::Variant<Ts...>>, Ts...>
  156. { };
  157. template <typename... Ts>
  158. class PersistentRootedBase<mozilla::Variant<Ts...>>
  159. : public MutableGCVariantOperations<JS::PersistentRooted<mozilla::Variant<Ts...>>, Ts...>
  160. { };
  161. } // namespace js
  162. #endif // js_GCVariant_h