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/>.
31 #define N_RETURN_VALUES 1
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
)
49 in
= pointer_get_data(*frame_pointer(fp
, FUNCTION_CALL_SLOT
));
51 ret
= da(in
,internal
)->fn(fp
, ip
, da(in
,internal
)->arguments
);
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
;
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
)
80 in
= data_alloc_flexible(internal
, arguments
, n_arguments
, mayfail
);
84 da(in
,internal
)->fn
= fn
;
86 memcpy(da(in
,internal
)->arguments
, arguments
, n_arguments
* sizeof(union internal_arg
));
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
[])
95 struct data
*function_reference
;
98 in
= data_alloc_internal(fn
, n_arguments
, arguments
, &err
);
102 function_reference
= data_alloc_function_reference_mayfail(1, &err pass_file_line
);
103 if (unlikely(!function_reference
)) {
104 data_dereference(in
);
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
);
118 return pointer_thunk(result
);
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
;
129 ex
= execution_control_alloc(mayfail
);
133 fp
= stack_alloc(ex
, internal_function
, mayfail
);
137 ex
->current_frame
= fp
;
138 frame_init(fp
, internal_function
, 0, CALL_MODE_NORMAL
);
140 ex
->current_ip
= function_ip_eval
;
146 execution_control_free(ex
);
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
;
173 struct local_variable
*lv
;
174 struct local_arg
*ar
;
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;
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);
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;
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
);
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
);
247 void name(function_done
)(void)
249 pointer_dereference(internal_function_ptr
);
250 pointer_poison(&internal_function_ptr
);