File: function.h

package info (click to toggle)
gjs 1.86.0-3.1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,724 kB
  • sloc: cpp: 39,075; javascript: 30,720; ansic: 15,971; sh: 1,759; python: 772; xml: 135; makefile: 40
file content (176 lines) | stat: -rw-r--r-- 5,576 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
// SPDX-FileCopyrightText: 2008 litl, LLC

#ifndef GI_FUNCTION_H_
#define GI_FUNCTION_H_

#include <config.h>

#include <stdint.h>

#include <memory>  // for unique_ptr
#include <unordered_set>
#include <vector>

#include <ffi.h>
#include <girepository/girepository.h>
#include <glib-object.h>
#include <glib.h>

#include <js/GCVector.h>
#include <js/RootingAPI.h>
#include <js/TypeDecls.h>
#include <js/Value.h>
#include <mozilla/Maybe.h>

#include "gi/closure.h"
#include "gi/info.h"
#include "gjs/auto.h"
#include "gjs/gerror-result.h"
#include "gjs/macros.h"

namespace JS {
class CallArgs;
}

typedef enum {
    PARAM_NORMAL,
    PARAM_SKIPPED,
    PARAM_ARRAY,
    PARAM_CALLBACK,
    PARAM_UNKNOWN,
} GjsParamType;

struct GjsCallbackTrampoline : public Gjs::Closure {
    GJS_JSAPI_RETURN_CONVENTION
    static GjsCallbackTrampoline* create(JSContext*, JS::HandleObject callable,
                                         const GI::CallableInfo, GIScopeType,
                                         bool has_scope_object, bool is_vfunc);

    ~GjsCallbackTrampoline();

    void* closure() const { return m_info.closure_native_address(m_closure); }

    ffi_closure* get_ffi_closure() const {
        return m_closure;
    }

    void mark_forever();

    static void prepare_shutdown();

 private:
    ffi_closure* create_closure();
    GJS_JSAPI_RETURN_CONVENTION bool initialize();
    GjsCallbackTrampoline(JSContext*, JS::HandleObject callable,
                          const GI::CallableInfo, GIScopeType,
                          bool has_scope_object, bool is_vfunc);

    void callback_closure(GIArgument** args, void* result);
    GJS_JSAPI_RETURN_CONVENTION
    bool callback_closure_inner(JSContext* cx, JS::HandleObject this_object,
                                GObject* gobject, JS::MutableHandleValue rval,
                                GIArgument** args, const GI::TypeInfo ret_type,
                                unsigned n_args, unsigned c_args_offset,
                                void* result);
    void warn_about_illegal_js_callback(const char* when, const char* reason,
                                        bool dump_stack);

    static std::vector<Gjs::AutoGClosure> s_forever_closure_list;

    GI::AutoCallableInfo m_info;
    ffi_closure* m_closure = nullptr;
    std::unique_ptr<GjsParamType[]> m_param_types;
    ffi_cif m_cif;

    GIScopeType m_scope : 3;
    bool m_is_vfunc : 1;
};

// Stack allocation only!
class GjsFunctionCallState {
    Gjs::AutoCppPointer<GIArgument[]> m_in_cvalues;
    Gjs::AutoCppPointer<GIArgument[]> m_out_cvalues;
    Gjs::AutoCppPointer<GIArgument[]> m_inout_original_cvalues;

 public:
    std::unordered_set<GIArgument*> ignore_release;
    JS::RootedObject instance_object;
    JS::RootedVector<JS::Value> return_values;
    Gjs::AutoError local_error;
    const GI::CallableInfo info;
    uint8_t gi_argc = 0;
    uint8_t processed_c_args = 0;
    bool failed : 1;
    bool can_throw_gerror : 1;
    bool is_method : 1;

    GjsFunctionCallState(JSContext* cx, const GI::CallableInfo callable)
        : instance_object(cx),
          return_values(cx),
          info(callable),
          gi_argc(callable.n_args()),
          failed(false),
          can_throw_gerror(callable.can_throw_gerror()),
          is_method(callable.is_method()) {
        int size = gi_argc + first_arg_offset();
        m_in_cvalues = new GIArgument[size];
        m_out_cvalues = new GIArgument[size];
        m_inout_original_cvalues = new GIArgument[size];
    }

    GjsFunctionCallState(const GjsFunctionCallState&) = delete;
    GjsFunctionCallState& operator=(const GjsFunctionCallState&) = delete;

    constexpr int first_arg_offset() const { return is_method ? 2 : 1; }

    // The list always contains the return value, and the arguments
    constexpr GIArgument* instance() {
        return is_method ? &m_in_cvalues[1] : nullptr;
    }

    constexpr GIArgument* return_value() { return &m_out_cvalues[0]; }

    constexpr GIArgument& in_cvalue(int index) const {
        return m_in_cvalues[index + first_arg_offset()];
    }

    constexpr GIArgument& out_cvalue(int index) const {
        return m_out_cvalues[index + first_arg_offset()];
    }

    constexpr GIArgument& inout_original_cvalue(int index) const {
        return m_inout_original_cvalues[index + first_arg_offset()];
    }

    constexpr bool did_throw_gerror() const {
        return can_throw_gerror && local_error;
    }

    constexpr bool call_completed() { return !failed && !did_throw_gerror(); }

    constexpr unsigned last_processed_index() {
        return first_arg_offset() + processed_c_args;
    }

    [[nodiscard]] Gjs::AutoChar display_name() {
        mozilla::Maybe<const GI::BaseInfo> container = info.container();
        if (container) {
            return g_strdup_printf("%s.%s.%s", container->ns(),
                                   container->name(), info.name());
        }
        return g_strdup_printf("%s.%s", info.ns(), info.name());
    }
};

GJS_JSAPI_RETURN_CONVENTION
JSObject* gjs_define_function(JSContext*, JS::HandleObject in_object, GType,
                              const GI::CallableInfo);

GJS_JSAPI_RETURN_CONVENTION
bool gjs_invoke_constructor_from_c(JSContext*, const GI::FunctionInfo,
                                   JS::HandleObject this_obj,
                                   const JS::CallArgs&, GIArgument* rvalue);

#endif  // GI_FUNCTION_H_