fix identify_loops so that it actually identifies loops
[ajla.git] / funct.c
blobe76afefc3013cc09f1d58895dca07a8be993605b
1 /*
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
9 * version.
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/>.
19 #include "ajla.h"
21 #ifndef FILE_OMIT
23 #include "layout.h"
24 #include "data.h"
25 #include "code-op.h"
26 #include "task.h"
28 #include "funct.h"
30 #define N_ARGUMENTS 1
31 #define N_RETURN_VALUES 1
32 #define N_SLOTS 2
34 shared_var uchar_efficient_t function_slots[N_SLOTS];
35 #define FUNCTION_CALL_SLOT (function_slots[0])
36 #define FUNCTION_RETURN_SLOT (function_slots[1])
38 shared_var uchar_efficient_t function_ip_return;
39 shared_var uchar_efficient_t function_ip_eval;
41 static pointer_t internal_function_ptr;
42 #define internal_function pointer_get_data(internal_function_ptr)
44 void * attr_fastcall function_call_internal(frame_s *fp, const code_t *ip)
46 struct data *in;
47 void *ret;
49 in = pointer_get_data(*frame_pointer(fp, FUNCTION_CALL_SLOT));
51 ret = da(in,internal)->fn(fp, ip, da(in,internal)->arguments);
53 return ret;
56 static void function_free_argument(frame_s *fp)
58 frame_free_and_clear(fp, FUNCTION_CALL_SLOT);
61 static void * function_jump_to(frame_s *fp, ip_t ip)
63 struct execution_control *ex = frame_execution_control(fp);
64 ex->current_frame = fp;
65 ex->current_ip = ip;
66 return ex;
69 void * attr_fastcall function_return(frame_s *fp, pointer_t ptr)
71 function_free_argument(fp);
72 frame_set_pointer(fp, FUNCTION_RETURN_SLOT, ptr);
73 return function_jump_to(fp, function_ip_return);
76 static struct data *data_alloc_internal(void *(*fn)(frame_s *fp, const code_t *ip, union internal_arg arguments[]), unsigned n_arguments, union internal_arg arguments[], ajla_error_t *mayfail)
78 struct data *in;
80 in = data_alloc_flexible(internal, arguments, n_arguments, mayfail);
81 if (unlikely(!in))
82 return NULL;
84 da(in,internal)->fn = fn;
85 if (n_arguments)
86 memcpy(da(in,internal)->arguments, arguments, n_arguments * sizeof(union internal_arg));
88 return in;
91 pointer_t attr_fastcall function_build_internal_thunk(void *(*fn)(frame_s *fp, const code_t *ip, union internal_arg arguments[]), unsigned n_arguments, union internal_arg arguments[])
93 ajla_error_t err;
94 struct data *in;
95 struct data *function_reference;
96 struct thunk *result;
98 in = data_alloc_internal(fn, n_arguments, arguments, &err);
99 if (unlikely(!in))
100 goto exception_err;
102 function_reference = data_alloc_function_reference_mayfail(1, &err pass_file_line);
103 if (unlikely(!function_reference)) {
104 data_dereference(in);
105 goto exception_err;
107 da(function_reference,function_reference)->is_indirect = false;
108 da(function_reference,function_reference)->u.direct = &internal_function_ptr;
110 da(function_reference,function_reference)->arguments[0].tag = TYPE_TAG_unknown;
111 da(function_reference,function_reference)->arguments[0].u.ptr = pointer_data(in);
113 if (unlikely(!thunk_alloc_function_call(pointer_data(function_reference), 1, &result, &err))) {
114 data_dereference(function_reference);
115 goto exception_err;
118 return pointer_thunk(result);
120 exception_err:
121 return pointer_error(err, NULL, NULL pass_file_line);
124 struct execution_control *function_evaluate_prepare(ajla_error_t *mayfail)
126 struct execution_control *ex;
127 frame_s *fp;
129 ex = execution_control_alloc(mayfail);
130 if (!ex)
131 goto fail;
133 fp = stack_alloc(ex, internal_function, mayfail);
134 if (unlikely(!fp))
135 goto fail_free_ex;
137 ex->current_frame = fp;
138 frame_init(fp, internal_function, 0, CALL_MODE_NORMAL);
140 ex->current_ip = function_ip_eval;
141 ex->thunk = NULL;
143 return ex;
145 fail_free_ex:
146 execution_control_free(ex);
147 fail:
148 return NULL;
151 void function_evaluate_submit(struct execution_control *ex, pointer_t ptr, void (*callback)(void *, pointer_t), void *callback_cookie)
153 ex->callback = callback;
154 ex->callback_cookie = callback_cookie;
155 frame_set_pointer(ex->current_frame, FUNCTION_RETURN_SLOT, ptr);
156 task_submit(ex, true);
159 void function_init_common(struct data *fn)
161 da(fn,function)->loaded_cache = NULL;
162 tree_init(&da(fn,function)->cache);
163 store_relaxed(&da(fn,function)->profiling_counter, 0);
164 store_relaxed(&da(fn,function)->call_counter, 0);
165 da(fn,function)->is_saved = false;
168 void name(function_init)(void)
170 struct layout *layout;
171 struct data *ft, *int_fn;
172 frame_t n_slots;
173 struct local_variable *lv;
174 struct local_arg *ar;
175 arg_t ia;
176 ip_t ip;
177 ip_t code_size = 6;
179 layout = layout_start(slot_bits, frame_flags_per_slot_bits, frame_align, frame_offset, NULL);
180 for (ia = 0; ia < N_SLOTS; ia++) {
181 layout_add(layout, 1, 1, NULL);
183 layout_compute(layout, false, NULL);
185 ft = data_alloc_flexible(function_types, types, 0, NULL);
186 da(ft,function_types)->n_types = 0;
188 int_fn = data_alloc_flexible(function, local_directory, 0, NULL);
190 n_slots = layout_size(layout);
191 da(int_fn,function)->frame_slots = frame_offset / slot_size + n_slots;
192 da(int_fn,function)->n_bitmap_slots = bitmap_slots(n_slots);
193 da(int_fn,function)->n_arguments = N_ARGUMENTS;
194 da(int_fn,function)->n_return_values = N_RETURN_VALUES;
195 da(int_fn,function)->code = mem_alloc_array_mayfail(mem_alloc_mayfail, code_t *, 0, 0, code_size, sizeof(code_t), NULL);
196 da(int_fn,function)->code_size = code_size;
197 da(int_fn,function)->local_variables = lv = mem_alloc_array_mayfail(mem_calloc_mayfail, struct local_variable *, 0, 0, n_slots, sizeof(struct local_variable), NULL);
198 da(int_fn,function)->local_variables_flags = mem_alloc_array_mayfail(mem_calloc_mayfail, struct local_variable_flags *, 0, 0, n_slots, sizeof(struct local_variable_flags), NULL);
199 da(int_fn,function)->args = ar = mem_alloc(struct local_arg *, N_ARGUMENTS * sizeof(struct local_arg));
200 da(int_fn,function)->types_ptr = pointer_data(ft);
201 da(int_fn,function)->record_definition = NULL;
202 da(int_fn,function)->function_name = str_dup("internal_function", -1, NULL);
203 da(int_fn,function)->lp = NULL;
204 da(int_fn,function)->lp_size = 0;
205 da(int_fn,function)->local_directory_size = 0;
206 #ifdef HAVE_CODEGEN
207 da(int_fn,function)->codegen = pointer_thunk(thunk_alloc_exception_error(error_ajla(EC_ASYNC, AJLA_ERROR_NOT_SUPPORTED), NULL, NULL, NULL pass_file_line));
208 store_relaxed(&da(int_fn,function)->codegen_failed, 0);
209 #endif
210 function_init_common(int_fn);
211 if (profiling_escapes)
212 da(int_fn,function)->escape_data = mem_alloc_array_mayfail(mem_calloc_mayfail, struct escape_data *, 0, 0, code_size, sizeof(struct escape_data), NULL);
213 da(int_fn,function)->leaf = true;
215 for (ia = 0; ia < N_SLOTS; ia++) {
216 function_slots[ia] = layout_get(layout, ia);
217 lv[function_slots[ia]].type = type_get_unknown();
218 if (likely(ia < N_ARGUMENTS)) {
219 ar[ia].slot = function_slots[ia];
220 ar[ia].may_be_borrowed = false;
221 ar[ia].may_be_flat = false;
225 ip = 0;
226 #define gen_code(n) (da(int_fn,function)->code[ip++] = (n))
227 gen_code(OPCODE_INTERNAL_FUNCTION);
228 gen_code(OPCODE_UNREACHABLE);
229 function_ip_return = ip;
230 gen_code(OPCODE_RETURN);
231 if (N_RETURN_VALUES != 1)
232 internal(file_line, "function_init: N_RETURN_VALUES is %d", N_RETURN_VALUES);
233 gen_code(FUNCTION_RETURN_SLOT | (OPCODE_FLAG_FREE_ARGUMENT << 8));
234 function_ip_eval = ip;
235 gen_code(OPCODE_EXIT_THREAD);
236 gen_code(FUNCTION_RETURN_SLOT);
237 #undef gen_code
239 if (unlikely(ip != code_size))
240 internal(file_line, "function_init: code size mismatch: %"PRIuMAX" != %"PRIuMAX"", (uintmax_t)ip, (uintmax_t)code_size);
242 internal_function_ptr = pointer_data(int_fn);
244 layout_free(layout);
247 void name(function_done)(void)
249 pointer_dereference(internal_function_ptr);
250 pointer_poison(&internal_function_ptr);
253 #endif