2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
38 shared_var pointer_t
*optimizer_fn
;
40 static struct tree modules
;
41 rwlock_decl(modules_mutex
);
43 struct module_function
{
44 struct tree_entry entry
;
47 struct function_designator fd
;
51 struct tree_entry entry
;
52 struct tree functions
;
53 struct module_designator md
;
56 static pointer_t
module_create_optimizer_reference(struct module
*m
, struct function_designator
*fd
)
59 ajla_flat_option_t program
;
60 int_default_t path_idx
;
61 struct data
*filename
;
63 struct data
*nesting_path
;
68 program
= m
->md
.program
;
70 path_idx
= m
->md
.path_idx
;
71 if (path_idx
< 0 || (uint_default_t
)path_idx
!= m
->md
.path_idx
) {
72 return pointer_error(error_ajla(EC_ASYNC
, AJLA_ERROR_SIZE_OVERFLOW
), NULL
, NULL pass_file_line
);
75 filename
= array_from_flat_mem(type_get_fixed(0, true), cast_ptr(const char *, m
->md
.path
), m
->md
.path_len
, &err
);
76 if (unlikely(!filename
)) {
77 return pointer_error(err
, NULL
, NULL pass_file_line
);
80 np
= mem_alloc_array_mayfail(mem_alloc_mayfail
, int_default_t
*, 0, 0, fd
->n_entries
, sizeof(int_default_t
), &err
);
82 data_dereference(filename
);
83 return pointer_error(err
, NULL
, NULL pass_file_line
);
85 for (i
= 0; i
< fd
->n_entries
; i
++) {
86 int_default_t e
= (int_default_t
)fd
->entries
[i
];
87 if (unlikely(e
< 0) || unlikely(e
!= fd
->entries
[i
])) {
88 data_dereference(filename
);
90 return pointer_error(error_ajla(EC_ASYNC
, AJLA_ERROR_SIZE_OVERFLOW
), NULL
, NULL pass_file_line
);
94 nesting_path
= array_from_flat_mem(type_get_int(INT_DEFAULT_N
), cast_ptr(const char *, np
), fd
->n_entries
, &err
);
96 if (unlikely(!nesting_path
)) {
97 data_dereference(filename
);
98 return pointer_error(err
, NULL
, NULL pass_file_line
);
101 fn_ref
= data_alloc_function_reference_mayfail(4, &err pass_file_line
);
102 if (unlikely(!fn_ref
)) {
103 data_dereference(filename
);
104 data_dereference(nesting_path
);
105 return pointer_error(err
, NULL
, NULL pass_file_line
);
107 da(fn_ref
,function_reference
)->is_indirect
= false;
108 da(fn_ref
,function_reference
)->u
.direct
= optimizer_fn
;
110 data_fill_function_reference_flat(fn_ref
, 0, type_get_int(INT_DEFAULT_N
), cast_ptr(unsigned char *, &path_idx
));
111 data_fill_function_reference(fn_ref
, 1, pointer_data(filename
));
112 data_fill_function_reference_flat(fn_ref
, 2, type_get_flat_option(), cast_ptr(unsigned char *, &program
));
113 data_fill_function_reference(fn_ref
, 3, pointer_data(nesting_path
));
115 if (unlikely(!thunk_alloc_function_call(pointer_data(fn_ref
), 1, &result
, &err
))) {
116 data_dereference(fn_ref
);
117 return pointer_error(err
, NULL
, NULL pass_file_line
);
120 return pointer_thunk(result
);
123 static bool module_function_init(struct module
*m
, struct module_function
*mf
, ajla_error_t attr_unused
*mayfail
)
126 union internal_arg ia
[3];
127 if (m
->md
.path_idx
> 0) {
128 optr
= module_create_optimizer_reference(m
, &mf
->fd
);
129 ia
[0].ptr
= &mf
->optimizer
;
132 ptr
= function_build_internal_thunk(pcode_build_function_from_array
, 3, ia
);
136 optr
= function_build_internal_thunk(pcode_array_from_builtin
, 2, ia
);
137 ptr
= function_build_internal_thunk(pcode_build_function_from_builtin
, 2, ia
);
140 mf
->optimizer
= optr
;
144 static int function_test(const struct tree_entry
*e
, uintptr_t id
)
146 const struct function_designator
*fd
= cast_cpp(const struct function_designator
*, num_to_ptr(id
));
147 const struct module_function
*mf
= get_struct(e
, struct module_function
, entry
);
148 return function_designator_compare(&mf
->fd
, fd
);
151 static struct module_function
*module_find_function(struct module
*m
, const struct function_designator
*fd
, bool create
, ajla_error_t
*mayfail
)
153 struct tree_insert_position ins
;
154 struct tree_entry
*e
;
155 struct module_function
*mf
;
157 e
= tree_find_for_insert(&m
->functions
, function_test
, ptr_to_num(fd
), &ins
);
159 return get_struct(e
, struct module_function
, entry
);
164 mf
= struct_alloc_array_mayfail(mem_alloc_mayfail
, struct module_function
, fd
.entries
, fd
->n_entries
, mayfail
);
168 mf
->fd
.n_entries
= fd
->n_entries
;
169 memcpy(mf
->fd
.entries
, fd
->entries
, fd
->n_entries
* sizeof(fd
->entries
[0]));
171 if (unlikely(!module_function_init(m
, mf
, mayfail
))) {
176 tree_insert_after_find(&mf
->entry
, &ins
);
181 static int module_test(const struct tree_entry
*e
, uintptr_t id
)
183 const struct module_designator
*md
= cast_cpp(const struct module_designator
*, num_to_ptr(id
));
184 const struct module
*m
= get_struct(e
, struct module
, entry
);
185 return module_designator_compare(&m
->md
, md
);
188 static struct module
*module_find(const struct module_designator
*md
, bool create
, ajla_error_t
*mayfail
)
190 struct tree_insert_position ins
;
191 struct tree_entry
*e
;
194 e
= tree_find_for_insert(&modules
, module_test
, ptr_to_num(md
), &ins
);
195 if (likely(e
!= NULL
))
196 return get_struct(e
, struct module
, entry
);
201 m
= struct_alloc_array_mayfail(mem_alloc_mayfail
, struct module
, md
.path
, md
->path_len
, mayfail
);
205 m
->md
.path_len
= md
->path_len
;
206 m
->md
.path_idx
= md
->path_idx
;
207 m
->md
.program
= md
->program
;
208 memcpy(m
->md
.path
, md
->path
, md
->path_len
);
210 tree_init(&m
->functions
);
212 tree_insert_after_find(&m
->entry
, &ins
);
217 pointer_t
*module_load_function(const struct module_designator
*md
, const struct function_designator
*fd
, bool optimizer
, ajla_error_t
*mayfail
)
220 struct module_function
*mf
;
223 rwlock_lock_read(&modules_mutex
);
225 m
= module_find(md
, create
, mayfail
);
229 mf
= module_find_function(m
, fd
, create
, mayfail
);
234 rwlock_unlock_read(&modules_mutex
);
236 rwlock_unlock_write(&modules_mutex
);
239 return &mf
->optimizer
;
241 return &mf
->function
;
244 if (unlikely(create
)) {
245 rwlock_unlock_write(&modules_mutex
);
249 rwlock_unlock_read(&modules_mutex
);
250 rwlock_lock_write(&modules_mutex
);
255 static void module_finish_function(struct module_function
*mf
)
257 if (!pointer_is_thunk(mf
->function
)) {
258 struct data
*d
= pointer_get_data(mf
->function
);
259 struct tree_entry
*e
;
262 profile_collect(da(d
,function
)->function_name
, load_relaxed(&da(d
,function
)->profiling_counter
), load_relaxed(&da(d
,function
)->call_counter
));
264 if (profiling_escapes
) {
266 for (ip_rel
= 0; ip_rel
< da(d
,function
)->code_size
; ip_rel
++) {
267 struct stack_trace_entry ste
;
268 profile_counter_t profiling_counter
= load_relaxed(&da(d
,function
)->escape_data
[ip_rel
].counter
);
269 if (likely(!profiling_counter
))
271 if (unlikely(!stack_trace_get_location(d
, ip_rel
, &ste
)))
273 profile_escape_collect(ste
.function_name
, profiling_counter
, ste
.line
, da(d
,function
)->code
[ip_rel
], load_relaxed(&da(d
,function
)->escape_data
[ip_rel
].line
));
278 if (likely(!pointer_is_thunk(da(d
,function
)->codegen
))) {
279 struct data
*codegen
= pointer_get_data(da(d
,function
)->codegen
);
280 if (unlikely(!da(codegen
,codegen
)->is_saved
))
284 for (e
= tree_first(&da(d
,function
)->cache
); e
&& !new_cache
; e
= tree_next(e
)) {
285 struct cache_entry
*ce
= get_struct(e
, struct cache_entry
, entry
);
286 if (ce
->save
&& da(d
,function
)->module_designator
) {
291 save_start_function(d
, new_cache
);
292 while ((e
= tree_first(&da(d
,function
)->cache
))) {
293 struct cache_entry
*ce
= get_struct(e
, struct cache_entry
, entry
);
294 tree_delete(&ce
->entry
);
295 if (ce
->save
&& da(d
,function
)->module_designator
) {
296 /*debug("saving: %s", da(d,function)->function_name);*/
297 save_cache_entry(d
, ce
);
299 free_cache_entry(d
, ce
);
301 save_finish_function(d
);
305 static void module_free_function(struct module_function
*mf
)
307 pointer_dereference(mf
->function
);
308 pointer_dereference(mf
->optimizer
);
312 struct module_designator
*module_designator_alloc(unsigned path_idx
, const uint8_t *path
, size_t path_len
, bool program
, ajla_error_t
*mayfail
)
314 struct module_designator
*md
= struct_alloc_array_mayfail(mem_alloc_mayfail
, struct module_designator
, path
, path_len
, mayfail
);
317 md
->path_idx
= path_idx
;
318 md
->path_len
= path_len
;
319 md
->program
= program
;
320 memcpy(md
->path
, path
, path_len
);
324 void module_designator_free(struct module_designator
*md
)
329 size_t module_designator_length(const struct module_designator
*md
)
331 return offsetof(struct module_designator
, path
[md
->path_len
]);
334 int module_designator_compare(const struct module_designator
*md1
, const struct module_designator
*md2
)
336 if (md1
->path_idx
< md2
->path_idx
)
338 if (md1
->path_idx
> md2
->path_idx
)
340 if (md1
->program
!= md2
->program
)
341 return md1
->program
- md2
->program
;
342 if (md1
->path_len
< md2
->path_len
)
344 if (md1
->path_len
> md2
->path_len
)
346 return memcmp(md1
->path
, md2
->path
, md1
->path_len
);
349 struct function_designator
*function_designator_alloc(const pcode_t
*p
, ajla_error_t
*mayfail
)
352 size_t n_entries
= p
[0];
353 struct function_designator
*fd
;
354 ajla_assert_lo(p
[0] > 0, (file_line
, "function_designator_alloc: invalid lenfth %ld", (long)p
[0]));
355 fd
= struct_alloc_array_mayfail(mem_alloc_mayfail
, struct function_designator
, entries
, n_entries
, mayfail
);
358 fd
->n_entries
= n_entries
;
359 for (i
= 0; i
< n_entries
; i
++)
360 fd
->entries
[i
] = p
[1 + i
];
364 struct function_designator
*function_designator_alloc_single(pcode_t idx
, ajla_error_t
*mayfail
)
369 return function_designator_alloc(p
, mayfail
);
372 void function_designator_free(struct function_designator
*fd
)
377 size_t function_designator_length(const struct function_designator
*fd
)
379 return offsetof(struct function_designator
, entries
[fd
->n_entries
]);
382 int function_designator_compare(const struct function_designator
*fd1
, const struct function_designator
*fd2
)
384 if (fd1
->n_entries
< fd2
->n_entries
)
386 if (fd1
->n_entries
> fd2
->n_entries
)
388 /*return memcmp(fd1->entries, fd2->entries, fd1->n_entries * sizeof(fd1->entries[0]));*/
391 for (i
= 0; i
< fd1
->n_entries
; i
++) {
392 if (fd1
->entries
[i
] < fd2
->entries
[i
])
394 if (fd1
->entries
[i
] > fd2
->entries
[i
])
402 void name(module_init
)(void)
405 struct module_designator
*md
;
406 struct function_designator
*fd
;
409 rwlock_init(&modules_mutex
);
411 fd
= function_designator_alloc_single(0, NULL
);
414 md
= module_designator_alloc(0, cast_ptr(const uint8_t *, n
), strlen(n
), false, NULL
);
415 start_fn
= module_load_function(md
, fd
, false, NULL
);
416 module_designator_free(md
);
418 n
= "compiler/compiler";
419 md
= module_designator_alloc(0, cast_ptr(const uint8_t *, n
), strlen(n
), false, NULL
);
420 optimizer_fn
= module_load_function(md
, fd
, false, NULL
);
421 module_designator_free(md
);
423 function_designator_free(fd
);
426 void name(module_done
)(void)
428 struct tree_entry
*e1
, *e2
;
430 for (e1
= tree_first(&modules
); e1
; e1
= tree_next(e1
)) {
431 struct module
*m
= get_struct(e1
, struct module
, entry
);
432 /*debug("saving: %.*s", (int)m->md.path_len, m->md.path);*/
433 for (e2
= tree_first(&m
->functions
); e2
; e2
= tree_next(e2
)) {
434 struct module_function
*mf
= get_struct(e2
, struct module_function
, entry
);
435 module_finish_function(mf
);
438 while (!tree_is_empty(&modules
)) {
439 struct module
*m
= get_struct(tree_any(&modules
), struct module
, entry
);
440 tree_delete(&m
->entry
);
441 while (!tree_is_empty(&m
->functions
)) {
442 struct module_function
*mf
= get_struct(tree_any(&m
->functions
), struct module_function
, entry
);
443 module_free_function(mf
);
444 tree_delete(&mf
->entry
);
449 rwlock_done(&modules_mutex
);