array: fix a crash in array_create if memory allocation failed and had to
[ajla.git] / builtin.c
blob244186547778af00bc01332857244cc8a9e4e645
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 #include "mem_al.h"
22 #include "os.h"
23 #include "os_util.h"
25 #include "builtin.h"
27 #ifndef wake_up_wait_list
28 void u_name(save_register_dependence)(const char *path_name);
29 void c_name(save_register_dependence)(const char *path_name);
30 #endif
32 #include <fcntl.h>
34 const char *builtin_lib_path;
36 static char *builtin_ptr;
37 static size_t builtin_size;
38 #ifdef OS_HAS_MMAP
39 static bool builtin_mapped;
40 #endif
42 struct builtin_file_info {
43 uint32_t module_info;
44 uint32_t n_modules;
45 uint32_t signature;
48 struct builtin_module_info {
49 uint32_t function_info;
50 uint32_t n_functions;
53 struct builtin_function_info {
54 uint32_t pcode;
55 uint32_t n_pcode;
58 struct builtin_module_name {
59 uint32_t len;
60 uint32_t name[FLEXIBLE_ARRAY];
63 #define builtin_file cast_ptr(const struct builtin_file_info *, builtin_ptr + builtin_size - sizeof(struct builtin_file_info))
65 static int builtin_compare(size_t idx, const uint8_t *path, size_t path_len)
67 const struct builtin_module_info *mod;
68 const struct builtin_function_info *fi;
69 const struct builtin_module_name *name;
70 size_t min_len, i;
72 mod = cast_ptr(const struct builtin_module_info *, builtin_ptr + builtin_file->module_info);
73 mod += idx;
74 fi = cast_ptr(const struct builtin_function_info *, builtin_ptr + mod->function_info);
75 fi += mod->n_functions;
76 name = cast_ptr(const struct builtin_module_name *, fi);
78 min_len = minimum(name->len, path_len);
79 for (i = 0; i < min_len; i++) {
80 if (name->name[i] < path[i])
81 return -1;
82 if (name->name[i] > path[i])
83 return 1;
86 if (unlikely(name->len > path_len))
87 return 1;
88 if (unlikely(name->len < path_len))
89 return -1;
90 return 0;
93 static const struct builtin_module_info *builtin_find_module(const uint8_t *path, size_t path_len)
95 const struct builtin_module_info *mod;
96 size_t s;
97 int c;
98 binary_search(size_t, builtin_file->n_modules, s, !(c = builtin_compare(s, path, path_len)), c < 0, goto not_found);
99 mod = cast_ptr(const struct builtin_module_info *, builtin_ptr + builtin_file->module_info);
100 mod += s;
101 return mod;
102 not_found:
103 internal(file_line, "builtin_find_module: builtin module %.*s not found", (int)path_len, path);
104 return NULL;
107 static void builtin_walk_nested(const pcode_t **start, size_t *size, size_t n_entries, const pcode_t *entries)
109 while (--n_entries) {
110 pcode_t entry = *++entries;
111 const pcode_t *ptr;
112 ajla_assert_lo(entry < (*start)[2], (file_line, "builtin_walk_nested: invalid nested function: %"PRIuMAX", %"PRIuMAX"", (uintmax_t)entry, (uintmax_t)(*start)[2]));
113 ptr = (*start) + 9;
114 ptr += 1 + ((*ptr + 3) >> 2);
115 while (entry--) {
116 ptr += *ptr + 1;
118 *start = ptr + 1;
119 *size = *ptr;
123 void builtin_find_function(const uint8_t *path, size_t path_len, size_t n_entries, const pcode_t *entries, const pcode_t **start, size_t *size)
125 const struct builtin_function_info *f;
126 const struct builtin_module_info *m = builtin_find_module(path, path_len);
127 ajla_assert_lo((size_t)entries[0] < m->n_functions, (file_line, "builtin_find_function: invalid index"));
128 f = cast_ptr(const struct builtin_function_info *, builtin_ptr + m->function_info);
129 f += entries[0];
130 *start = cast_ptr(const pcode_t *, builtin_ptr + f->pcode);
131 *size = f->n_pcode;
132 builtin_walk_nested(start, size, n_entries, entries);
135 void builtin_init(void)
137 ajla_error_t sink;
138 handle_t h;
139 os_stat_t st;
140 const char *pte, *builtin_path;
142 pte = os_get_path_to_exe();
143 builtin_lib_path = pte;
144 builtin_path = os_join_paths(pte, "builtin.pcd", true, NULL);
145 h = os_open(os_cwd, builtin_path, O_RDONLY, 0, &sink);
146 if (unlikely(handle_is_valid(h)))
147 goto found_builtin;
148 mem_free(builtin_path);
150 #ifdef AJLA_LIB
151 builtin_lib_path = AJLA_LIB;
152 builtin_path = os_join_paths(AJLA_LIB, "builtin.pcd", true, NULL);
153 h = os_open(os_cwd, builtin_path, O_RDONLY, 0, &sink);
154 if (unlikely(handle_is_valid(h)))
155 goto found_builtin;
156 mem_free(builtin_path);
157 #endif
159 fatal("unable to find builtin.pcd");
161 found_builtin:
162 os_fstat(h, &st, NULL);
163 if (unlikely(!S_ISREG(st.st_mode)))
164 fatal("builtin file is not a regular file");
165 builtin_size = (size_t)st.st_size;
166 if (unlikely(st.st_size != (os_off_t)builtin_size) || unlikely(builtin_size < sizeof(struct builtin_file_info)) || unlikely((builtin_size & 3) != 0))
167 fatal("builtin file has invalid size");
169 #ifdef OS_HAS_MMAP
171 struct builtin_file_info fi;
172 os_pread_all(h, cast_ptr(char *, &fi), sizeof(struct builtin_file_info), builtin_size - sizeof(struct builtin_file_info), NULL);
173 if (likely(fi.signature == 0x616C6A41)) {
174 void *ptr = os_mmap(NULL, builtin_size, PROT_READ, MAP_PRIVATE, h, 0, &sink);
175 if (likely(ptr != MAP_FAILED)) {
176 builtin_ptr = ptr;
177 builtin_mapped = true;
178 os_close(h);
179 goto finalize;
181 } else if (unlikely(fi.signature != 0x416A6C61))
182 goto bad_sig;
184 builtin_mapped = false;
185 #endif
186 builtin_ptr = mem_alloc(char *, builtin_size);
187 os_pread_all(h, builtin_ptr, builtin_size, 0, NULL);
188 os_close(h);
190 if (unlikely(builtin_file->signature != 0x616C6A41)) {
191 size_t i;
192 if (unlikely(builtin_file->signature != 0x416A6C61))
193 #ifdef OS_HAS_MMAP
194 bad_sig:
195 #endif
196 fatal("builtin file doesn't have a signature");
197 for (i = 0; i < builtin_size; i += 4) {
198 char *p = &builtin_ptr[i];
199 char a[4];
200 a[0] = p[0];
201 a[1] = p[1];
202 a[2] = p[2];
203 a[3] = p[3];
204 p[0] = a[3];
205 p[1] = a[2];
206 p[2] = a[1];
207 p[3] = a[0];
210 goto finalize; /* avoid warning */
211 finalize:
212 call(save_register_dependence)(builtin_path);
213 mem_free(builtin_path);
216 void builtin_done(void)
218 #ifdef OS_HAS_MMAP
219 if (likely(builtin_mapped))
220 os_munmap(builtin_ptr, builtin_size, true);
221 else
222 #endif
224 mem_free(builtin_ptr);