Branch data Line data Source code
1 : : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 : : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
3 : : // SPDX-FileCopyrightText: 2013 Giovanni Campagna <scampa.giovanni@gmail.com>
4 : : // SPDX-FileCopyrightText: 2020 Marco Trevisan <marco.trevisan@canonical.com>
5 : :
6 : : #ifndef GI_ARG_CACHE_H_
7 : : #define GI_ARG_CACHE_H_
8 : :
9 : : #include <config.h>
10 : :
11 : : #include <stdint.h>
12 : :
13 : : #include <limits>
14 : :
15 : : #include <girepository.h>
16 : : #include <glib-object.h>
17 : :
18 : : #include <js/TypeDecls.h>
19 : :
20 : : #include "gi/arg.h"
21 : : #include "gjs/enum-utils.h"
22 : : #include "gjs/jsapi-util.h"
23 : : #include "gjs/macros.h"
24 : :
25 : : class GjsFunctionCallState;
26 : :
27 : : enum NotIntrospectableReason : uint8_t {
28 : : CALLBACK_OUT,
29 : : DESTROY_NOTIFY_NO_CALLBACK,
30 : : DESTROY_NOTIFY_NO_USER_DATA,
31 : : INTERFACE_TRANSFER_CONTAINER,
32 : : OUT_CALLER_ALLOCATES_NON_STRUCT,
33 : : UNREGISTERED_BOXED_WITH_TRANSFER,
34 : : UNREGISTERED_UNION,
35 : : UNSUPPORTED_TYPE,
36 : : LAST_REASON
37 : : };
38 : :
39 : : namespace Gjs {
40 : : namespace Arg {
41 : :
42 : : using ReturnValue = struct GenericOut;
43 : : struct Instance;
44 : :
45 : : enum class Kind {
46 : : NORMAL,
47 : : INSTANCE,
48 : : RETURN_VALUE,
49 : : };
50 : :
51 : : } // namespace Arg
52 : :
53 : : struct Argument {
54 : 32726 : virtual ~Argument() = default;
55 : :
56 : : GJS_JSAPI_RETURN_CONVENTION
57 : : virtual bool in(JSContext* cx, GjsFunctionCallState*,
58 : : GIArgument* in_argument, JS::HandleValue value);
59 : :
60 : : GJS_JSAPI_RETURN_CONVENTION
61 : : virtual bool out(JSContext* cx, GjsFunctionCallState*,
62 : : GIArgument* out_argument, JS::MutableHandleValue value);
63 : :
64 : : GJS_JSAPI_RETURN_CONVENTION
65 : : virtual bool release(JSContext* cx, GjsFunctionCallState*,
66 : : GIArgument* in_argument, GIArgument* out_argument);
67 : :
68 : 539 : virtual GjsArgumentFlags flags() const {
69 : 539 : GjsArgumentFlags flags = GjsArgumentFlags::NONE;
70 [ - + ]: 539 : if (m_skip_in)
71 : 0 : flags |= GjsArgumentFlags::SKIP_IN;
72 : : else
73 : 539 : flags |= GjsArgumentFlags::ARG_IN;
74 [ + + ]: 539 : if (m_skip_out)
75 : 507 : flags |= GjsArgumentFlags::SKIP_OUT;
76 : : else
77 : 32 : flags |= GjsArgumentFlags::ARG_OUT;
78 : :
79 : 539 : return flags;
80 : : }
81 : :
82 : : // Introspected functions can have up to 253 arguments. The callback
83 : : // closure or destroy notify parameter may have a value of 255 to indicate
84 : : // that it is absent.
85 : : static constexpr uint8_t MAX_ARGS = std::numeric_limits<uint8_t>::max() - 2;
86 : : static constexpr uint8_t ABSENT = std::numeric_limits<uint8_t>::max();
87 : :
88 : 8 : constexpr const char* arg_name() const { return m_arg_name; }
89 : :
90 : 73284 : constexpr bool skip_in() const { return m_skip_in; }
91 : :
92 : 107081 : constexpr bool skip_out() const { return m_skip_out; }
93 : :
94 : : protected:
95 : 33258 : constexpr Argument() : m_skip_in(false), m_skip_out(false) {}
96 : :
97 : 0 : virtual GITypeTag return_tag() const { return GI_TYPE_TAG_VOID; }
98 : 14376 : virtual const GITypeInfo* return_type() const { return nullptr; }
99 : 0 : virtual const Arg::Instance* as_instance() const { return nullptr; }
100 : :
101 : 3475 : constexpr void set_instance_parameter() {
102 : 3475 : m_arg_name = "instance parameter";
103 : 3475 : m_skip_out = true;
104 : 3475 : }
105 : :
106 : 8715 : constexpr void set_return_value() { m_arg_name = "return value"; }
107 : :
108 : : bool invalid(JSContext*, const char* func = nullptr) const;
109 : :
110 : : const char* m_arg_name = nullptr;
111 : : bool m_skip_in : 1;
112 : : bool m_skip_out : 1;
113 : :
114 : : private:
115 : : friend struct ArgsCache;
116 : :
117 : : template <typename T, Arg::Kind ArgKind, typename... Args>
118 : : static GjsAutoCppPointer<T> make(uint8_t index, const char* name,
119 : : GITypeInfo* type_info, GITransfer transfer,
120 : : GjsArgumentFlags flags, Args&&... args);
121 : : };
122 : :
123 : : using ArgumentPtr = GjsAutoCppPointer<Argument>;
124 : :
125 : : // This is a trick to print out the sizes of the structs at compile time, in
126 : : // an error message:
127 : : // template <int s> struct Measure;
128 : : // Measure<sizeof(Argument)> arg_cache_size;
129 : :
130 : : #if defined(__x86_64__) && defined(__clang__) && !defined(_MSC_VER)
131 : : # define GJS_DO_ARGUMENTS_SIZE_CHECK 1
132 : : // This isn't meant to be comprehensive, but should trip on at least one CI job
133 : : // if sizeof(Gjs::Argument) is increased.
134 : : // Note that this check is not applicable for clang-cl builds, as Windows is
135 : : // an LLP64 system
136 : : static_assert(sizeof(Argument) <= 24,
137 : : "Think very hard before increasing the size of Gjs::Argument. "
138 : : "One is allocated for every argument to every introspected "
139 : : "function.");
140 : : #endif // x86-64 clang
141 : :
142 : : struct ArgsCache {
143 : : GJS_JSAPI_RETURN_CONVENTION
144 : : bool initialize(JSContext* cx, GICallableInfo* callable);
145 : :
146 : : // COMPAT: in C++20, use default initializers for these bitfields
147 : 11030 : ArgsCache() : m_is_method(false), m_has_return(false) {}
148 : :
149 : : constexpr bool initialized() { return m_args != nullptr; }
150 : : constexpr void clear() { m_args.reset(); }
151 : :
152 : : void build_arg(uint8_t gi_index, GIDirection, GIArgInfo*, GICallableInfo*,
153 : : bool* inc_counter_out);
154 : :
155 : : void build_return(GICallableInfo* callable, bool* inc_counter_out);
156 : :
157 : : void build_instance(GICallableInfo* callable);
158 : :
159 : : GType instance_type() const;
160 : : GITypeTag return_tag() const;
161 : : GITypeInfo* return_type() const;
162 : :
163 : : private:
164 : : void build_normal_in_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*,
165 : : GjsArgumentFlags);
166 : : void build_normal_out_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*,
167 : : GjsArgumentFlags);
168 : : void build_normal_inout_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*,
169 : : GjsArgumentFlags);
170 : :
171 : : template <Arg::Kind ArgKind = Arg::Kind::NORMAL>
172 : : void build_interface_in_arg(uint8_t gi_index, GITypeInfo*, GIBaseInfo*,
173 : : GITransfer, const char* name, GjsArgumentFlags);
174 : :
175 : : template <typename T, Arg::Kind ArgKind = Arg::Kind::NORMAL,
176 : : typename... Args>
177 : : constexpr T* set_argument(uint8_t index, const char* name, GITypeInfo*,
178 : : GITransfer, GjsArgumentFlags flags,
179 : : Args&&... args);
180 : :
181 : : template <typename T, Arg::Kind ArgKind = Arg::Kind::NORMAL,
182 : : typename... Args>
183 : : constexpr T* set_argument(uint8_t index, const char* name, GITransfer,
184 : : GjsArgumentFlags flags, Args&&... args);
185 : :
186 : : template <typename T, Arg::Kind ArgKind = Arg::Kind::NORMAL,
187 : : typename... Args>
188 : : constexpr T* set_argument_auto(Args&&... args);
189 : :
190 : : template <typename T, Arg::Kind ArgKind = Arg::Kind::NORMAL, typename Tuple,
191 : : typename... Args>
192 : : constexpr T* set_argument_auto(Tuple&& tuple, Args&&... args);
193 : :
194 : : template <Arg::Kind ArgKind = Arg::Kind::NORMAL>
195 : : void set_array_argument(GICallableInfo* callable, uint8_t gi_index,
196 : : GITypeInfo*, GIDirection, GIArgInfo*,
197 : : GjsArgumentFlags flags, int length_pos);
198 : :
199 : : template <typename T>
200 : : constexpr T* set_return(GITypeInfo*, GITransfer, GjsArgumentFlags);
201 : :
202 : : template <typename T>
203 : : constexpr T* set_instance(GITransfer,
204 : : GjsArgumentFlags flags = GjsArgumentFlags::NONE);
205 : :
206 : : constexpr void set_skip_all(uint8_t index, const char* name = nullptr);
207 : :
208 : : template <Arg::Kind ArgKind = Arg::Kind::NORMAL>
209 : 551844 : constexpr uint8_t arg_index(uint8_t index
210 : : [[maybe_unused]] = Argument::MAX_ARGS) const {
211 : : if constexpr (ArgKind == Arg::Kind::RETURN_VALUE)
212 : 160244 : return 0;
213 : : else if constexpr (ArgKind == Arg::Kind::INSTANCE)
214 [ + + ]: 113413 : return (m_has_return ? 1 : 0);
215 : : else if constexpr (ArgKind == Arg::Kind::NORMAL)
216 [ + + + + ]: 278187 : return (m_has_return ? 1 : 0) + (m_is_method ? 1 : 0) + index;
217 : : }
218 : :
219 : : template <Arg::Kind ArgKind = Arg::Kind::NORMAL>
220 : 551844 : constexpr ArgumentPtr& arg_get(uint8_t index = Argument::MAX_ARGS) const {
221 : 551844 : return m_args[arg_index<ArgKind>(index)];
222 : : }
223 : :
224 : : public:
225 : 236051 : constexpr Argument* argument(uint8_t index) const {
226 : 236051 : return arg_get(index).get();
227 : : }
228 : :
229 : 106463 : constexpr Argument* instance() const {
230 [ - + ]: 106463 : if (!m_is_method)
231 : 0 : return nullptr;
232 : :
233 : 106463 : return arg_get<Arg::Kind::INSTANCE>().get();
234 : : }
235 : :
236 : 257889 : constexpr Argument* return_value() const {
237 [ + + ]: 257889 : if (!m_has_return)
238 : 115075 : return nullptr;
239 : :
240 : 142814 : return arg_get<Arg::Kind::RETURN_VALUE>().get();
241 : : }
242 : :
243 : : private:
244 : : GjsAutoCppPointer<ArgumentPtr[]> m_args;
245 : :
246 : : bool m_is_method : 1;
247 : : bool m_has_return : 1;
248 : : };
249 : :
250 : : } // namespace Gjs
251 : :
252 : : #endif // GI_ARG_CACHE_H_
|