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 : 28082 : 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 : 559 : virtual GjsArgumentFlags flags() const {
69 : 559 : GjsArgumentFlags flags = GjsArgumentFlags::NONE;
70 [ - + ]: 559 : if (m_skip_in)
71 : 0 : flags |= GjsArgumentFlags::SKIP_IN;
72 : : else
73 : 559 : flags |= GjsArgumentFlags::ARG_IN;
74 [ + + ]: 559 : if (m_skip_out)
75 : 501 : flags |= GjsArgumentFlags::SKIP_OUT;
76 : : else
77 : 58 : flags |= GjsArgumentFlags::ARG_OUT;
78 : :
79 : 559 : 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 : 69767 : constexpr bool skip_in() const { return m_skip_in; }
91 : :
92 : 101917 : constexpr bool skip_out() const { return m_skip_out; }
93 : :
94 : : protected:
95 : 28497 : constexpr Argument() : m_skip_in(false), m_skip_out(false) {}
96 : :
97 : 0 : virtual const Arg::ReturnValue* as_return_value() const { return nullptr; }
98 : 0 : virtual const Arg::Instance* as_instance() const { return nullptr; }
99 : :
100 : 2659 : constexpr void set_instance_parameter() {
101 : 2659 : m_arg_name = "instance parameter";
102 : 2659 : m_skip_out = true;
103 : 2659 : }
104 : :
105 : 7503 : constexpr void set_return_value() { m_arg_name = "return value"; }
106 : :
107 : : bool invalid(JSContext*, const char* func = nullptr) const;
108 : :
109 : : const char* m_arg_name = nullptr;
110 : : bool m_skip_in : 1;
111 : : bool m_skip_out : 1;
112 : :
113 : : private:
114 : : friend struct ArgsCache;
115 : :
116 : : template <typename T, Arg::Kind ArgKind, typename... Args>
117 : : static GjsAutoCppPointer<T> make(uint8_t index, const char* name,
118 : : GITypeInfo* type_info, GITransfer transfer,
119 : : GjsArgumentFlags flags, Args&&... args);
120 : : };
121 : :
122 : : using ArgumentPtr = GjsAutoCppPointer<Argument>;
123 : :
124 : : // This is a trick to print out the sizes of the structs at compile time, in
125 : : // an error message:
126 : : // template <int s> struct Measure;
127 : : // Measure<sizeof(Argument)> arg_cache_size;
128 : :
129 : : #if defined(__x86_64__) && defined(__clang__) && !defined(_MSC_VER)
130 : : # define GJS_DO_ARGUMENTS_SIZE_CHECK 1
131 : : // This isn't meant to be comprehensive, but should trip on at least one CI job
132 : : // if sizeof(Gjs::Argument) is increased.
133 : : // Note that this check is not applicable for clang-cl builds, as Windows is
134 : : // an LLP64 system
135 : : static_assert(sizeof(Argument) <= 24,
136 : : "Think very hard before increasing the size of Gjs::Argument. "
137 : : "One is allocated for every argument to every introspected "
138 : : "function.");
139 : : #endif // x86-64 clang
140 : :
141 : : struct ArgsCache {
142 : : GJS_JSAPI_RETURN_CONVENTION
143 : : bool initialize(JSContext* cx, GICallableInfo* callable);
144 : :
145 : : // COMPAT: in C++20, use default initializers for these bitfields
146 : 9618 : ArgsCache() : m_is_method(false), m_has_return(false) {}
147 : :
148 : : constexpr bool initialized() { return m_args != nullptr; }
149 : : constexpr void clear() { m_args.reset(); }
150 : :
151 : : void build_arg(uint8_t gi_index, GIDirection, GIArgInfo*, GICallableInfo*,
152 : : bool* inc_counter_out);
153 : :
154 : : void build_return(GICallableInfo* callable, bool* inc_counter_out);
155 : :
156 : : void build_instance(GICallableInfo* callable);
157 : :
158 : : GType instance_type() const;
159 : : GITypeInfo* return_type() const;
160 : :
161 : : private:
162 : : void build_normal_in_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*,
163 : : GjsArgumentFlags);
164 : :
165 : : template <Arg::Kind ArgKind = Arg::Kind::NORMAL>
166 : : void build_interface_in_arg(uint8_t gi_index, GITypeInfo*, GIBaseInfo*,
167 : : GITransfer, const char* name, GjsArgumentFlags);
168 : :
169 : : template <typename T, Arg::Kind ArgKind = Arg::Kind::NORMAL,
170 : : typename... Args>
171 : : constexpr T* set_argument(uint8_t index, const char* name, GITypeInfo*,
172 : : GITransfer, GjsArgumentFlags flags,
173 : : Args&&... args);
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, GITransfer,
178 : : GjsArgumentFlags flags, Args&&... args);
179 : :
180 : : template <typename T, Arg::Kind ArgKind = Arg::Kind::NORMAL,
181 : : typename... Args>
182 : : constexpr T* set_argument_auto(Args&&... args);
183 : :
184 : : template <typename T, Arg::Kind ArgKind = Arg::Kind::NORMAL, typename Tuple,
185 : : typename... Args>
186 : : constexpr T* set_argument_auto(Tuple&& tuple, Args&&... args);
187 : :
188 : : template <Arg::Kind ArgKind = Arg::Kind::NORMAL>
189 : : void set_array_argument(GICallableInfo* callable, uint8_t gi_index,
190 : : GITypeInfo*, GIDirection, GIArgInfo*,
191 : : GjsArgumentFlags flags, int length_pos);
192 : :
193 : : template <typename T>
194 : : constexpr T* set_return(GITypeInfo*, GITransfer, GjsArgumentFlags);
195 : :
196 : : template <typename T>
197 : : constexpr T* set_instance(GITransfer,
198 : : GjsArgumentFlags flags = GjsArgumentFlags::NONE);
199 : :
200 : : constexpr void set_skip_all(uint8_t index, const char* name = nullptr);
201 : :
202 : : template <Arg::Kind ArgKind = Arg::Kind::NORMAL>
203 : 482959 : constexpr uint8_t arg_index(uint8_t index
204 : : [[maybe_unused]] = Argument::MAX_ARGS) const {
205 : : if constexpr (ArgKind == Arg::Kind::RETURN_VALUE)
206 : 116729 : return 0;
207 : : else if constexpr (ArgKind == Arg::Kind::INSTANCE)
208 [ + + ]: 106474 : return (m_has_return ? 1 : 0);
209 : : else if constexpr (ArgKind == Arg::Kind::NORMAL)
210 [ + + + + ]: 259756 : return (m_has_return ? 1 : 0) + (m_is_method ? 1 : 0) + index;
211 : : }
212 : :
213 : : template <Arg::Kind ArgKind = Arg::Kind::NORMAL>
214 : 482959 : constexpr ArgumentPtr& arg_get(uint8_t index = Argument::MAX_ARGS) const {
215 : 482959 : return m_args[arg_index<ArgKind>(index)];
216 : : }
217 : :
218 : : public:
219 : 223086 : constexpr Argument* argument(uint8_t index) const {
220 : 223086 : return arg_get(index).get();
221 : : }
222 : :
223 : 101156 : constexpr Argument* instance() const {
224 [ - + ]: 101156 : if (!m_is_method)
225 : 0 : return nullptr;
226 : :
227 : 101156 : return arg_get<Arg::Kind::INSTANCE>().get();
228 : : }
229 : :
230 : 184076 : constexpr Argument* return_value() const {
231 [ + + ]: 184076 : if (!m_has_return)
232 : 82353 : return nullptr;
233 : :
234 : 101723 : return arg_get<Arg::Kind::RETURN_VALUE>().get();
235 : : }
236 : :
237 : : private:
238 : : GjsAutoCppPointer<ArgumentPtr[]> m_args;
239 : :
240 : : bool m_is_method : 1;
241 : : bool m_has_return : 1;
242 : : };
243 : :
244 : : } // namespace Gjs
245 : :
246 : : #endif // GI_ARG_CACHE_H_
|