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: 2008 litl, LLC
4 : :
5 : : #ifndef GI_FUNCTION_H_
6 : : #define GI_FUNCTION_H_
7 : :
8 : : #include <config.h>
9 : :
10 : : #include <stdint.h>
11 : :
12 : : #include <memory> // for unique_ptr
13 : : #include <unordered_set>
14 : : #include <vector>
15 : :
16 : : #include <ffi.h>
17 : : #include <girepository.h>
18 : : #include <girffi.h> // for g_callable_info_get_closure_native_address
19 : : #include <glib-object.h>
20 : : #include <glib.h>
21 : :
22 : : #include <js/GCVector.h>
23 : : #include <js/RootingAPI.h>
24 : : #include <js/TypeDecls.h>
25 : : #include <js/Value.h>
26 : :
27 : : #include "gi/closure.h"
28 : : #include "gjs/jsapi-util.h"
29 : : #include "gjs/macros.h"
30 : :
31 : : namespace JS {
32 : : class CallArgs;
33 : : }
34 : :
35 : : typedef enum {
36 : : PARAM_NORMAL,
37 : : PARAM_SKIPPED,
38 : : PARAM_ARRAY,
39 : : PARAM_CALLBACK,
40 : : PARAM_UNKNOWN,
41 : : } GjsParamType;
42 : :
43 : : using GjsAutoGClosure =
44 : 248 : GjsAutoPointer<GClosure, GClosure, g_closure_unref, g_closure_ref>;
45 : :
46 : : struct GjsCallbackTrampoline : public Gjs::Closure {
47 : : GJS_JSAPI_RETURN_CONVENTION static GjsCallbackTrampoline* create(
48 : : JSContext* cx, JS::HandleObject callable, GICallableInfo* callable_info,
49 : : GIScopeType scope, bool has_scope_object, bool is_vfunc);
50 : :
51 : : ~GjsCallbackTrampoline();
52 : :
53 : 272 : void* closure() const {
54 : : #if GI_CHECK_VERSION(1, 71, 0)
55 : 272 : return g_callable_info_get_closure_native_address(m_info, m_closure);
56 : : #else
57 : : return m_closure;
58 : : #endif
59 : : }
60 : :
61 : 214 : ffi_closure* get_ffi_closure() const {
62 : 214 : return m_closure;
63 : : }
64 : :
65 : : void mark_forever();
66 : :
67 : : static void prepare_shutdown();
68 : :
69 : : private:
70 : : ffi_closure* create_closure();
71 : : GJS_JSAPI_RETURN_CONVENTION bool initialize();
72 : : GjsCallbackTrampoline(JSContext* cx, JS::HandleObject callable,
73 : : GICallableInfo* callable_info, GIScopeType scope,
74 : : bool has_scope_object, bool is_vfunc);
75 : :
76 : : void callback_closure(GIArgument** args, void* result);
77 : : GJS_JSAPI_RETURN_CONVENTION
78 : : bool callback_closure_inner(JSContext* cx, JS::HandleObject this_object,
79 : : GObject* gobject, JS::MutableHandleValue rval,
80 : : GIArgument** args, GITypeInfo* ret_type,
81 : : int n_args, int c_args_offset, void* result);
82 : : void warn_about_illegal_js_callback(const char* when, const char* reason,
83 : : bool dump_stack);
84 : :
85 : : static std::vector<GjsAutoGClosure> s_forever_closure_list;
86 : :
87 : : GjsAutoCallableInfo m_info;
88 : : ffi_closure* m_closure = nullptr;
89 : : std::unique_ptr<GjsParamType[]> m_param_types;
90 : : ffi_cif m_cif;
91 : :
92 : : GIScopeType m_scope : 3;
93 : : bool m_is_vfunc : 1;
94 : : };
95 : :
96 : : // Stack allocation only!
97 : : class GjsFunctionCallState {
98 : : GjsAutoCppPointer<GIArgument[]> m_in_cvalues;
99 : : GjsAutoCppPointer<GIArgument[]> m_out_cvalues;
100 : : GjsAutoCppPointer<GIArgument[]> m_inout_original_cvalues;
101 : :
102 : : public:
103 : : std::unordered_set<GIArgument*> ignore_release;
104 : : JS::RootedObject instance_object;
105 : : JS::RootedVector<JS::Value> return_values;
106 : : GjsAutoError local_error;
107 : : GICallableInfo* info;
108 : : uint8_t gi_argc = 0;
109 : : uint8_t processed_c_args = 0;
110 : : bool failed : 1;
111 : : bool can_throw_gerror : 1;
112 : : bool is_method : 1;
113 : :
114 : 50738 : GjsFunctionCallState(JSContext* cx, GICallableInfo* callable)
115 : 50738 : : instance_object(cx),
116 : 50738 : return_values(cx),
117 : 50738 : info(callable),
118 : 50738 : gi_argc(g_callable_info_get_n_args(callable)),
119 : 50738 : failed(false),
120 : 101476 : can_throw_gerror(g_callable_info_can_throw_gerror(callable)),
121 : 152214 : is_method(g_callable_info_is_method(callable)) {
122 : 50738 : int size = gi_argc + first_arg_offset();
123 [ + - ]: 50738 : m_in_cvalues = new GIArgument[size];
124 [ + - ]: 50738 : m_out_cvalues = new GIArgument[size];
125 [ + - ]: 50738 : m_inout_original_cvalues = new GIArgument[size];
126 : 50738 : }
127 : :
128 : : GjsFunctionCallState(const GjsFunctionCallState&) = delete;
129 : : GjsFunctionCallState& operator=(const GjsFunctionCallState&) = delete;
130 : :
131 [ + + ]: 479333 : constexpr int first_arg_offset() const { return is_method ? 2 : 1; }
132 : :
133 : : // The list always contains the return value, and the arguments
134 : 56542 : constexpr GIArgument* instance() {
135 [ + - ]: 56542 : return is_method ? &m_in_cvalues[1] : nullptr;
136 : : }
137 : :
138 : 130398 : constexpr GIArgument* return_value() { return &m_out_cvalues[0]; }
139 : :
140 : 112449 : constexpr GIArgument& in_cvalue(int index) const {
141 : 112449 : return m_in_cvalues[index + first_arg_offset()];
142 : : }
143 : :
144 : 113108 : constexpr GIArgument& out_cvalue(int index) const {
145 : 113108 : return m_out_cvalues[index + first_arg_offset()];
146 : : }
147 : :
148 : 102 : constexpr GIArgument& inout_original_cvalue(int index) const {
149 : 102 : return m_inout_original_cvalues[index + first_arg_offset()];
150 : : }
151 : :
152 : 130886 : constexpr bool did_throw_gerror() const {
153 [ + + + + ]: 130886 : return can_throw_gerror && local_error;
154 : : }
155 : :
156 [ + + + + ]: 29449 : constexpr bool call_completed() { return !failed && !did_throw_gerror(); }
157 : :
158 : 101468 : constexpr unsigned last_processed_index() {
159 : 101468 : return first_arg_offset() + processed_c_args;
160 : : }
161 : :
162 : 2 : [[nodiscard]] GjsAutoChar display_name() {
163 : 2 : GIBaseInfo* container = g_base_info_get_container(info); // !owned
164 [ + + ]: 2 : if (container) {
165 : : return g_strdup_printf(
166 : : "%s.%s.%s", g_base_info_get_namespace(container),
167 : 1 : g_base_info_get_name(container), g_base_info_get_name(info));
168 : : }
169 : : return g_strdup_printf("%s.%s", g_base_info_get_namespace(info),
170 : 1 : g_base_info_get_name(info));
171 : : }
172 : : };
173 : :
174 : : GJS_JSAPI_RETURN_CONVENTION
175 : : JSObject *gjs_define_function(JSContext *context,
176 : : JS::HandleObject in_object,
177 : : GType gtype,
178 : : GICallableInfo *info);
179 : :
180 : : GJS_JSAPI_RETURN_CONVENTION
181 : : bool gjs_invoke_constructor_from_c(JSContext* cx, GIFunctionInfo* info,
182 : : JS::HandleObject this_obj,
183 : : const JS::CallArgs& args,
184 : : GIArgument* rvalue);
185 : :
186 : : #endif // GI_FUNCTION_H_
|