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 "gi/info.h"
29 : : #include "gjs/auto.h"
30 : : #include "gjs/gerror-result.h"
31 : : #include "gjs/macros.h"
32 : :
33 : : namespace JS {
34 : : class CallArgs;
35 : : }
36 : :
37 : : typedef enum {
38 : : PARAM_NORMAL,
39 : : PARAM_SKIPPED,
40 : : PARAM_ARRAY,
41 : : PARAM_CALLBACK,
42 : : PARAM_UNKNOWN,
43 : : } GjsParamType;
44 : :
45 : : struct GjsCallbackTrampoline : public Gjs::Closure {
46 : : GJS_JSAPI_RETURN_CONVENTION static GjsCallbackTrampoline* create(
47 : : JSContext* cx, JS::HandleObject callable, GICallableInfo* callable_info,
48 : : GIScopeType scope, bool has_scope_object, bool is_vfunc);
49 : :
50 : : ~GjsCallbackTrampoline();
51 : :
52 : 315 : void* closure() const {
53 : 315 : return g_callable_info_get_closure_native_address(m_info, m_closure);
54 : : }
55 : :
56 : 250 : ffi_closure* get_ffi_closure() const {
57 : 250 : return m_closure;
58 : : }
59 : :
60 : : void mark_forever();
61 : :
62 : : static void prepare_shutdown();
63 : :
64 : : private:
65 : : ffi_closure* create_closure();
66 : : GJS_JSAPI_RETURN_CONVENTION bool initialize();
67 : : GjsCallbackTrampoline(JSContext* cx, JS::HandleObject callable,
68 : : GICallableInfo* callable_info, GIScopeType scope,
69 : : bool has_scope_object, bool is_vfunc);
70 : :
71 : : void callback_closure(GIArgument** args, void* result);
72 : : GJS_JSAPI_RETURN_CONVENTION
73 : : bool callback_closure_inner(JSContext* cx, JS::HandleObject this_object,
74 : : GObject* gobject, JS::MutableHandleValue rval,
75 : : GIArgument** args, GITypeInfo* ret_type,
76 : : int n_args, int c_args_offset, void* result);
77 : : void warn_about_illegal_js_callback(const char* when, const char* reason,
78 : : bool dump_stack);
79 : :
80 : : static std::vector<Gjs::AutoGClosure> s_forever_closure_list;
81 : :
82 : : GI::AutoCallableInfo m_info;
83 : : ffi_closure* m_closure = nullptr;
84 : : std::unique_ptr<GjsParamType[]> m_param_types;
85 : : ffi_cif m_cif;
86 : :
87 : : GIScopeType m_scope : 3;
88 : : bool m_is_vfunc : 1;
89 : : };
90 : :
91 : : // Stack allocation only!
92 : : class GjsFunctionCallState {
93 : : Gjs::AutoCppPointer<GIArgument[]> m_in_cvalues;
94 : : Gjs::AutoCppPointer<GIArgument[]> m_out_cvalues;
95 : : Gjs::AutoCppPointer<GIArgument[]> m_inout_original_cvalues;
96 : :
97 : : public:
98 : : std::unordered_set<GIArgument*> ignore_release;
99 : : JS::RootedObject instance_object;
100 : : JS::RootedVector<JS::Value> return_values;
101 : : Gjs::AutoError local_error;
102 : : GICallableInfo* info;
103 : : uint8_t gi_argc = 0;
104 : : uint8_t processed_c_args = 0;
105 : : bool failed : 1;
106 : : bool can_throw_gerror : 1;
107 : : bool is_method : 1;
108 : :
109 : 73430 : GjsFunctionCallState(JSContext* cx, GICallableInfo* callable)
110 : 73430 : : instance_object(cx),
111 : 73430 : return_values(cx),
112 : 73430 : info(callable),
113 : 73430 : gi_argc(g_callable_info_get_n_args(callable)),
114 : 73430 : failed(false),
115 : 146860 : can_throw_gerror(g_callable_info_can_throw_gerror(callable)),
116 : 220290 : is_method(g_callable_info_is_method(callable)) {
117 : 73430 : int size = gi_argc + first_arg_offset();
118 [ + - ]: 73430 : m_in_cvalues = new GIArgument[size];
119 [ + - ]: 73430 : m_out_cvalues = new GIArgument[size];
120 [ + - ]: 73430 : m_inout_original_cvalues = new GIArgument[size];
121 : 73430 : }
122 : :
123 : : GjsFunctionCallState(const GjsFunctionCallState&) = delete;
124 : : GjsFunctionCallState& operator=(const GjsFunctionCallState&) = delete;
125 : :
126 [ + + ]: 697835 : constexpr int first_arg_offset() const { return is_method ? 2 : 1; }
127 : :
128 : : // The list always contains the return value, and the arguments
129 : 80108 : constexpr GIArgument* instance() {
130 [ + - ]: 80108 : return is_method ? &m_in_cvalues[1] : nullptr;
131 : : }
132 : :
133 : 186345 : constexpr GIArgument* return_value() { return &m_out_cvalues[0]; }
134 : :
135 : 164873 : constexpr GIArgument& in_cvalue(int index) const {
136 : 164873 : return m_in_cvalues[index + first_arg_offset()];
137 : : }
138 : :
139 : 165688 : constexpr GIArgument& out_cvalue(int index) const {
140 : 165688 : return m_out_cvalues[index + first_arg_offset()];
141 : : }
142 : :
143 : 160 : constexpr GIArgument& inout_original_cvalue(int index) const {
144 : 160 : return m_inout_original_cvalues[index + first_arg_offset()];
145 : : }
146 : :
147 : 186943 : constexpr bool did_throw_gerror() const {
148 [ + + + + ]: 186943 : return can_throw_gerror && local_error;
149 : : }
150 : :
151 [ + + + + ]: 40276 : constexpr bool call_completed() { return !failed && !did_throw_gerror(); }
152 : :
153 : 146842 : constexpr unsigned last_processed_index() {
154 : 146842 : return first_arg_offset() + processed_c_args;
155 : : }
156 : :
157 : 3 : [[nodiscard]] Gjs::AutoChar display_name() {
158 : 3 : GIBaseInfo* container = g_base_info_get_container(info); // !owned
159 [ + + ]: 3 : if (container) {
160 : : return g_strdup_printf(
161 : : "%s.%s.%s", g_base_info_get_namespace(container),
162 : 1 : g_base_info_get_name(container), g_base_info_get_name(info));
163 : : }
164 : : return g_strdup_printf("%s.%s", g_base_info_get_namespace(info),
165 : 2 : g_base_info_get_name(info));
166 : : }
167 : : };
168 : :
169 : : GJS_JSAPI_RETURN_CONVENTION
170 : : JSObject *gjs_define_function(JSContext *context,
171 : : JS::HandleObject in_object,
172 : : GType gtype,
173 : : GICallableInfo *info);
174 : :
175 : : GJS_JSAPI_RETURN_CONVENTION
176 : : bool gjs_invoke_constructor_from_c(JSContext* cx, GIFunctionInfo* info,
177 : : JS::HandleObject this_obj,
178 : : const JS::CallArgs& args,
179 : : GIArgument* rvalue);
180 : :
181 : : #endif // GI_FUNCTION_H_
|