1#include "include/pw.h"
2#include "src/pw_alloc.h"
3#include "src/pw_interfaces_internal.h"
4
5#include <libpussy/arena.h>
6#include <libpussy/mmarray.h>
7
8static Arena* arena = nullptr;
9
10void* _pw_arena_alloc_bytes(unsigned size, unsigned alignment)
11{
12 void* result = _arena_fit(arena, size, alignment);
13 if (!result) {
14 pw_panic("Out of memory\n");
15 }
16 return result;
17}
18
19PW_STRUCT(InterfaceInfo) {
20 char* name;
21 char** method_names;
22 unsigned num_methods;
23};
24
25static InterfaceInfo** registered_interfaces = nullptr;
26static unsigned num_registered_interfaces = 0;
27
28static char s_interface_not_registered[] = "Interface %u is not registered yet\n";
29#define pw_panic_interface_not_registered(interface_id) pw_panic(s_interface_not_registered, (interface_id));
30
31[[noreturn]]
32void _pw_panic_no_interface(uint16_t type_id, uint16_t interface_id)
33{
34 char* iname;
35 if (registered_interfaces) {
36 iname = registered_interfaces[interface_id]->name;
37 } else {
38 iname = "unknown";
39 }
40 pw_panic("Interface %s (%u) is not defined for %s\n", iname, interface_id, _pw_types[type_id]->name);
41}
42
43PwInterface_Generic* __pw_do_lookup_interface(PwType* type, uint16_t interface_id)
44{
45 PwInterface_Generic** iface = type->other_interfaces;
46 if (iface) {
47 PwInterface_Generic** iface_end = iface + type->num_other_interfaces;
48 do {
49 if ((*iface)->id == interface_id) {
50 return *iface;
51 }
52 iface++;
53 } while (iface < iface_end);
54 }
55 return nullptr;
56}
57
58void pw_destroy_compound(PwValuePtr value, _PwCompoundChain* tail)
59{
60 uint16_t type_id = value->type_id;
61
62 if (_pw_likely(type_id < PW_NUM_INTEGRAL_TYPES)) {
63 *value = PwNull();
64 return;
65 }
66
67 if (_pw_unlikely(_pw_on_chain(value, tail))) {
68 return;
69 }
70
71 PwMethod_Basic_decref* meth_decref;
72 pw_method(type_id, Basic, decref, &meth_decref);
73 PwFunc_Basic_decref fn_decref = meth_decref->func;
74 if (_pw_unlikely(fn_decref)) {
75 if (fn_decref(meth_decref, value)) {
76 // refcount is still above zero
77 // clean value holder but do not call destructor
78 *value = PwNull();
79 return;
80 }
81 }
82
83 PwMethod_Basic_destroy* meth_destroy;
84 pw_method(type_id, Basic, destroy, &meth_destroy);
85 PwFunc_Basic_destroy fn_destroy = meth_destroy->func;
86 if (_pw_unlikely(fn_destroy)) {
87 fn_destroy(meth_destroy, value, tail);
88 }
89 *value = PwNull();
90}
91
92
93#define builtin(name, ...) \
94 pw_hard_assert(PwInterfaceId_##name == pw_register_interface(#name, __VA_ARGS__))
95
96[[gnu::constructor]]
97void _pw_init_interfaces()
98{
99 if (registered_interfaces) {
100 return;
101 }
102
103 arena = create_arena(0);
104 registered_interfaces = mmarray_allocate(65536, 0, sizeof(InterfaceInfo*));
105
106 // register built-in interfaces
107
108# define X(name, ...) #name __VA_OPT__(,)
109 builtin(Basic, PW_BASIC_INTERFACE_METHODS, nullptr);
110 builtin(RandomAccess, PW_RANDOM_ACCESS_INTERFACE_METHODS, nullptr);
111 builtin(Reader, PW_READER_INTERFACE_METHODS, nullptr);
112 builtin(Writer, PW_WRITER_INTERFACE_METHODS, nullptr);
113 builtin(LineReader, PW_LINE_READER_INTERFACE_METHODS, nullptr);
114 builtin(Append, PW_APPEND_INTERFACE_METHODS, nullptr);
115 builtin(Fd, PW_FD_INTERFACE_METHODS, nullptr);
116# undef X
117}
118
119uint16_t pw_register_interface(char* name, ...)
120{
121 _pw_init_interfaces();
122 if (mmarray_grow(registered_interfaces, 1)) { /* no op, address not changed */ }
123
124 uint16_t interface_id = num_registered_interfaces++;
125 InterfaceInfo* iinfo = registered_interfaces[interface_id] = _pw_arena_alloc(1, InterfaceInfo);
126 iinfo->name = name;
127 iinfo->num_methods = 0;
128
129 va_list ap;
130 va_list temp_ap;
131 va_start(ap);
132
133 // count method names
134 va_copy(temp_ap, ap);
135 for(;;) {
136 char* method_name = va_arg(temp_ap, char*);
137 if (!method_name) {
138 break;
139 }
140 iinfo->num_methods++;
141 }
142 va_end(temp_ap);
143
144 // allocate array for method names
145 char** method_names = _pw_arena_alloc(iinfo->num_methods, char*);
146 iinfo->method_names = method_names;
147
148 // init method names
149 for (;;) {
150 char* method_name = va_arg(ap, char*);
151 if (!method_name) {
152 break;
153 }
154 *method_names++ = method_name;
155 }
156 va_end(ap);
157 return interface_id;
158}
159
160bool pw_interface_exists(uint16_t interface_id)
161{
162 return interface_id < num_registered_interfaces;
163}
164
165char* pw_get_interface_name(uint16_t interface_id)
166{
167 if (interface_id >= num_registered_interfaces) {
168 pw_panic_interface_not_registered(interface_id);
169 }
170 return registered_interfaces[interface_id]->name;
171}
172
173unsigned _pw_get_num_interface_methods(uint16_t interface_id)
174{
175 if (interface_id >= num_registered_interfaces) {
176 pw_panic_interface_not_registered(interface_id);
177 }
178 return registered_interfaces[interface_id]->num_methods;
179}
180
181
182static PwInterface_Generic* find_interface_definition(PwType* type, uint16_t interface_id)
183// helper for _pw_make_interface
184{
185 unsigned n = type->num_interface_definitions;
186 if (n) {
187 PwInterface_Generic** idef = type->interface_definitions;
188 PwInterface_Generic** idef_end = idef + n;
189 while (idef < idef_end) {
190 if ((*idef)->id == interface_id) {
191 return *idef;
192 }
193 idef++;
194 }
195 }
196 return nullptr;
197}
198
199PwInterface_Generic* _pw_make_interface(PwType* type, uint16_t interface_id)
200{
201 if (interface_id >= num_registered_interfaces) {
202 pw_panic_interface_not_registered(interface_id);
203 }
204
205 InterfaceInfo* iinfo = registered_interfaces[interface_id];
206
207 // allocate and initialize interface structure
208
209 unsigned memsize = sizeof(PwInterface_Generic) + iinfo->num_methods * sizeof(PwMethod_Generic);
210 PwInterface_Generic* interface = _pw_arena_alloc_bytes(memsize, alignof(PwInterface_Generic));
211 interface->id = interface_id;
212 interface->num_methods = iinfo->num_methods;
213 interface->name = iinfo->name;
214 interface->method_names = iinfo->method_names;
215 interface->type = type;
216
217 // make interface methods
218
219 PwMethod_Generic* method = interface->methods;
220 PwMethod_Generic* method_end = method + interface->num_methods;
221 unsigned method_index = 0;
222 while (method < method_end) {
223 method->func = nullptr;
224 method->super = nullptr;
225 method->self = nullptr;
226 method->struct_offset = 0;
227 method->type_id = 0;
228
229 // build MRO chain
230
231 PwMethod_Generic* sub_method = method; // current method in the chain
232 unsigned* struct_offset = type->struct_offsets;
233
234 PwInterface_Generic* idef = find_interface_definition(type, interface_id);
235
236 if (idef && idef->methods[method_index].func) {
237 // have func defined for this type
238 sub_method->func = idef->methods[method_index].func;
239 sub_method->self = interface;
240 sub_method->struct_offset = struct_offset? *struct_offset : 0;
241 sub_method->type_id = type->id;
242 }
243 struct_offset++;
244
245 PwType** base_type = type->base_types;
246 PwType** base_type_end = base_type + type->num_base_types;
247 while (base_type < base_type_end) {
248 PwType* t = *base_type;
249 idef = find_interface_definition(t, interface_id);
250
251 if (idef && idef->methods[method_index].func) {
252
253 // have super func
254
255 if (sub_method->func) {
256 // sub_method already initialized, allocate new one
257 PwMethod_Generic* super_method = _pw_arena_alloc(1, PwMethod_Generic);
258 super_method->super = nullptr;
259 sub_method->super = super_method;
260 sub_method = super_method;
261 }
262 // initialize current method
263 sub_method->func = idef->methods[method_index].func;
264 sub_method->self = _pw_lookup_interface_t(t, interface_id);
265 if (!sub_method->self) {
266 pw_panic("Interface %s must be initialized for %s\n", iinfo->name, t->name);
267 }
268 pw_hard_assert(sub_method->self->type->id == t->id);
269 sub_method->struct_offset = struct_offset? *struct_offset : 0;
270 sub_method->type_id = t->id;
271 }
272 base_type++;
273 struct_offset++;
274 }
275 method++;
276 method_index++;
277 }
278 return interface;
279}