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