diff options
Diffstat (limited to 'src/buildvm_lib.c')
-rw-r--r-- | src/buildvm_lib.c | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/src/buildvm_lib.c b/src/buildvm_lib.c new file mode 100644 index 00000000..cc572200 --- /dev/null +++ b/src/buildvm_lib.c | |||
@@ -0,0 +1,365 @@ | |||
1 | /* | ||
2 | ** LuaJIT VM builder: library definition compiler. | ||
3 | ** Copyright (C) 2005-2009 Mike Pall. See Copyright Notice in luajit.h | ||
4 | */ | ||
5 | |||
6 | #include "lj_obj.h" | ||
7 | #include "lj_lib.h" | ||
8 | |||
9 | #include "buildvm.h" | ||
10 | |||
11 | /* Context for library definitions. */ | ||
12 | static uint8_t obuf[8192]; | ||
13 | static uint8_t *optr; | ||
14 | static char modname[80]; | ||
15 | static size_t modnamelen; | ||
16 | static char funcname[80]; | ||
17 | static int modstate, regfunc; | ||
18 | static int ffid, recffid; | ||
19 | |||
20 | enum { | ||
21 | REGFUNC_OK, | ||
22 | REGFUNC_NOREG, | ||
23 | REGFUNC_NOREGUV | ||
24 | }; | ||
25 | |||
26 | static void libdef_name(char *p, int kind) | ||
27 | { | ||
28 | size_t n = strlen(p); | ||
29 | if (kind != LIBINIT_STRING) { | ||
30 | if (n > modnamelen && p[modnamelen] == '_' && | ||
31 | !strncmp(p, modname, modnamelen)) { | ||
32 | p += modnamelen+1; | ||
33 | n -= modnamelen+1; | ||
34 | } | ||
35 | } | ||
36 | if (n > LIBINIT_MAXSTR) { | ||
37 | fprintf(stderr, "Error: string too long: '%s'\n", p); | ||
38 | exit(1); | ||
39 | } | ||
40 | if (optr+1+n+2 > obuf+sizeof(obuf)) { /* +2 for caller. */ | ||
41 | fprintf(stderr, "Error: output buffer overflow\n"); | ||
42 | exit(1); | ||
43 | } | ||
44 | *optr++ = (uint8_t)(n | kind); | ||
45 | memcpy(optr, p, n); | ||
46 | optr += n; | ||
47 | } | ||
48 | |||
49 | static void libdef_endmodule(BuildCtx *ctx) | ||
50 | { | ||
51 | if (modstate != 0) { | ||
52 | char line[80]; | ||
53 | const uint8_t *p; | ||
54 | int n; | ||
55 | if (modstate == 1) | ||
56 | fprintf(ctx->fp, " (lua_CFunction)0"); | ||
57 | fprintf(ctx->fp, "\n};\n"); | ||
58 | fprintf(ctx->fp, "static const uint8_t %s%s[] = {\n", | ||
59 | LABEL_PREFIX_LIBINIT, modname); | ||
60 | line[0] = '\0'; | ||
61 | for (n = 0, p = obuf; p < optr; p++) { | ||
62 | n += sprintf(line+n, "%d,", *p); | ||
63 | if (n >= 75) { | ||
64 | fprintf(ctx->fp, "%s\n", line); | ||
65 | n = 0; | ||
66 | line[0] = '\0'; | ||
67 | } | ||
68 | } | ||
69 | fprintf(ctx->fp, "%s%d\n};\n#endif\n\n", line, LIBINIT_END); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | static void libdef_module(BuildCtx *ctx, char *p, int arg) | ||
74 | { | ||
75 | UNUSED(arg); | ||
76 | if (ctx->mode == BUILD_libdef) { | ||
77 | libdef_endmodule(ctx); | ||
78 | optr = obuf; | ||
79 | *optr++ = (uint8_t)ffid; | ||
80 | *optr++ = 0; | ||
81 | modstate = 1; | ||
82 | fprintf(ctx->fp, "#ifdef %sMODULE_%s\n", LIBDEF_PREFIX, p); | ||
83 | fprintf(ctx->fp, "#undef %sMODULE_%s\n", LIBDEF_PREFIX, p); | ||
84 | fprintf(ctx->fp, "static const lua_CFunction %s%s[] = {\n", | ||
85 | LABEL_PREFIX_LIBCF, p); | ||
86 | } | ||
87 | modnamelen = strlen(p); | ||
88 | if (modnamelen > sizeof(modname)-1) { | ||
89 | fprintf(stderr, "Error: module name too long: '%s'\n", p); | ||
90 | exit(1); | ||
91 | } | ||
92 | strcpy(modname, p); | ||
93 | } | ||
94 | |||
95 | static int find_ffofs(BuildCtx *ctx, const char *name) | ||
96 | { | ||
97 | int i; | ||
98 | for (i = 0; i < ctx->nglob; i++) { | ||
99 | const char *gl = ctx->globnames[i]; | ||
100 | if (gl[0] == 'f' && gl[1] == 'f' && gl[2] == '_' && !strcmp(gl+3, name)) { | ||
101 | return (int)((uint8_t *)ctx->glob[i] - ctx->code); | ||
102 | } | ||
103 | } | ||
104 | fprintf(stderr, "Error: undefined fast function %s%s\n", | ||
105 | LABEL_PREFIX_FF, name); | ||
106 | exit(1); | ||
107 | } | ||
108 | |||
109 | static void libdef_func(BuildCtx *ctx, char *p, int arg) | ||
110 | { | ||
111 | if (ctx->mode == BUILD_libdef) { | ||
112 | int ofs = arg != LIBINIT_CF ? find_ffofs(ctx, p) : 0; | ||
113 | if (modstate == 0) { | ||
114 | fprintf(stderr, "Error: no module for function definition %s\n", p); | ||
115 | exit(1); | ||
116 | } | ||
117 | if (regfunc == REGFUNC_NOREG) { | ||
118 | if (optr+1 > obuf+sizeof(obuf)) { | ||
119 | fprintf(stderr, "Error: output buffer overflow\n"); | ||
120 | exit(1); | ||
121 | } | ||
122 | *optr++ = LIBINIT_FFID; | ||
123 | } else { | ||
124 | if (arg != LIBINIT_ASM_) { | ||
125 | if (modstate != 1) fprintf(ctx->fp, ",\n"); | ||
126 | modstate = 2; | ||
127 | fprintf(ctx->fp, " %s%s", arg ? LABEL_PREFIX_FFH : LABEL_PREFIX_CF, p); | ||
128 | } | ||
129 | if (regfunc != REGFUNC_NOREGUV) obuf[1]++; /* Bump hash table size. */ | ||
130 | libdef_name(regfunc == REGFUNC_NOREGUV ? "" : p, arg); | ||
131 | if (arg) { | ||
132 | *optr++ = (uint8_t)ofs; | ||
133 | *optr++ = (uint8_t)(ofs >> 8); | ||
134 | } | ||
135 | } | ||
136 | } else if (ctx->mode == BUILD_ffdef) { | ||
137 | fprintf(ctx->fp, "FFDEF(%s)\n", p); | ||
138 | } else if (ctx->mode == BUILD_recdef) { | ||
139 | if (strlen(p) > sizeof(funcname)-1) { | ||
140 | fprintf(stderr, "Error: function name too long: '%s'\n", p); | ||
141 | exit(1); | ||
142 | } | ||
143 | strcpy(funcname, p); | ||
144 | } else if (ctx->mode == BUILD_vmdef) { | ||
145 | int i; | ||
146 | for (i = 1; p[i] && modname[i-1]; i++) | ||
147 | if (p[i] == '_') p[i] = '.'; | ||
148 | fprintf(ctx->fp, "\"%s\",\n", p); | ||
149 | } | ||
150 | ffid++; | ||
151 | regfunc = REGFUNC_OK; | ||
152 | } | ||
153 | |||
154 | static uint32_t find_rec(char *name) | ||
155 | { | ||
156 | char *p = (char *)obuf; | ||
157 | uint32_t n; | ||
158 | for (n = 2; *p; n++) { | ||
159 | if (strcmp(p, name) == 0) | ||
160 | return n; | ||
161 | p += strlen(p)+1; | ||
162 | } | ||
163 | if (p+strlen(name)+1 >= (char *)obuf+sizeof(obuf)) { | ||
164 | fprintf(stderr, "Error: output buffer overflow\n"); | ||
165 | exit(1); | ||
166 | } | ||
167 | strcpy(p, name); | ||
168 | return n; | ||
169 | } | ||
170 | |||
171 | static void libdef_rec(BuildCtx *ctx, char *p, int arg) | ||
172 | { | ||
173 | UNUSED(arg); | ||
174 | if (ctx->mode == BUILD_recdef) { | ||
175 | char *q; | ||
176 | uint32_t n; | ||
177 | for (; recffid+1 < ffid; recffid++) | ||
178 | fprintf(ctx->fp, ",\n0"); | ||
179 | recffid = ffid; | ||
180 | if (*p == '.') p = funcname; | ||
181 | q = strchr(p, ' '); | ||
182 | if (q) *q++ = '\0'; | ||
183 | n = find_rec(p); | ||
184 | if (q) | ||
185 | fprintf(ctx->fp, ",\n0x%02x00+(%s)", n, q); | ||
186 | else | ||
187 | fprintf(ctx->fp, ",\n0x%02x00", n); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | static void memcpy_endian(void *dst, void *src, size_t n) | ||
192 | { | ||
193 | union { uint8_t b; uint32_t u; } host_endian; | ||
194 | host_endian.u = 1; | ||
195 | if (host_endian.b == LJ_ENDIAN_SELECT(1, 0)) { | ||
196 | memcpy(dst, src, n); | ||
197 | } else { | ||
198 | size_t i; | ||
199 | for (i = 0; i < n; i++) | ||
200 | ((uint8_t *)dst)[i] = ((uint8_t *)src)[n-i]; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | static void libdef_push(BuildCtx *ctx, char *p, int arg) | ||
205 | { | ||
206 | UNUSED(arg); | ||
207 | if (ctx->mode == BUILD_libdef) { | ||
208 | int len = (int)strlen(p); | ||
209 | if (*p == '"') { | ||
210 | if (len > 1 && p[len-1] == '"') { | ||
211 | p[len-1] = '\0'; | ||
212 | libdef_name(p+1, LIBINIT_STRING); | ||
213 | return; | ||
214 | } | ||
215 | } else if (*p >= '0' && *p <= '9') { | ||
216 | char *ep; | ||
217 | double d = strtod(p, &ep); | ||
218 | if (*ep == '\0') { | ||
219 | if (optr+1+sizeof(double) > obuf+sizeof(obuf)) { | ||
220 | fprintf(stderr, "Error: output buffer overflow\n"); | ||
221 | exit(1); | ||
222 | } | ||
223 | *optr++ = LIBINIT_NUMBER; | ||
224 | memcpy_endian(optr, &d, sizeof(double)); | ||
225 | optr += sizeof(double); | ||
226 | return; | ||
227 | } | ||
228 | } else if (!strcmp(p, "lastcl")) { | ||
229 | if (optr+1 > obuf+sizeof(obuf)) { | ||
230 | fprintf(stderr, "Error: output buffer overflow\n"); | ||
231 | exit(1); | ||
232 | } | ||
233 | *optr++ = LIBINIT_LASTCL; | ||
234 | return; | ||
235 | } else if (len > 4 && !strncmp(p, "top-", 4)) { | ||
236 | if (optr+2 > obuf+sizeof(obuf)) { | ||
237 | fprintf(stderr, "Error: output buffer overflow\n"); | ||
238 | exit(1); | ||
239 | } | ||
240 | *optr++ = LIBINIT_COPY; | ||
241 | *optr++ = (uint8_t)atoi(p+4); | ||
242 | return; | ||
243 | } | ||
244 | fprintf(stderr, "Error: bad value for %sPUSH(%s)\n", LIBDEF_PREFIX, p); | ||
245 | exit(1); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static void libdef_set(BuildCtx *ctx, char *p, int arg) | ||
250 | { | ||
251 | UNUSED(arg); | ||
252 | if (ctx->mode == BUILD_libdef) { | ||
253 | if (p[0] == '!' && p[1] == '\0') p[0] = '\0'; /* Set env. */ | ||
254 | libdef_name(p, LIBINIT_STRING); | ||
255 | *optr++ = LIBINIT_SET; | ||
256 | obuf[1]++; /* Bump hash table size. */ | ||
257 | } | ||
258 | } | ||
259 | |||
260 | static void libdef_regfunc(BuildCtx *ctx, char *p, int arg) | ||
261 | { | ||
262 | UNUSED(ctx); UNUSED(p); | ||
263 | regfunc = arg; | ||
264 | } | ||
265 | |||
266 | typedef void (*LibDefFunc)(BuildCtx *ctx, char *p, int arg); | ||
267 | |||
268 | typedef struct LibDefHandler { | ||
269 | const char *suffix; | ||
270 | const char *stop; | ||
271 | const LibDefFunc func; | ||
272 | const int arg; | ||
273 | } LibDefHandler; | ||
274 | |||
275 | static const LibDefHandler libdef_handlers[] = { | ||
276 | { "MODULE_", " \t\r\n", libdef_module, 0 }, | ||
277 | { "CF(", ")", libdef_func, LIBINIT_CF }, | ||
278 | { "ASM(", ")", libdef_func, LIBINIT_ASM }, | ||
279 | { "ASM_(", ")", libdef_func, LIBINIT_ASM_ }, | ||
280 | { "REC(", ")", libdef_rec, 0 }, | ||
281 | { "PUSH(", ")", libdef_push, 0 }, | ||
282 | { "SET(", ")", libdef_set, 0 }, | ||
283 | { "NOREGUV", NULL, libdef_regfunc, REGFUNC_NOREGUV }, | ||
284 | { "NOREG", NULL, libdef_regfunc, REGFUNC_NOREG }, | ||
285 | { NULL, NULL, (LibDefFunc)0, 0 } | ||
286 | }; | ||
287 | |||
288 | /* Emit C source code for library function definitions. */ | ||
289 | void emit_lib(BuildCtx *ctx) | ||
290 | { | ||
291 | const char *fname; | ||
292 | |||
293 | if (ctx->mode == BUILD_ffdef || ctx->mode == BUILD_libdef || | ||
294 | ctx->mode == BUILD_recdef) | ||
295 | fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n"); | ||
296 | else if (ctx->mode == BUILD_vmdef) | ||
297 | fprintf(ctx->fp, "ffnames = {\n[0]=\"Lua\",\n\"C\",\n"); | ||
298 | if (ctx->mode == BUILD_recdef) | ||
299 | fprintf(ctx->fp, "static const uint16_t recff_idmap[] = {\n0,\n0x0100"); | ||
300 | recffid = ffid = FF_C+1; | ||
301 | |||
302 | while ((fname = *ctx->args++)) { | ||
303 | char buf[256]; /* We don't care about analyzing lines longer than that. */ | ||
304 | FILE *fp; | ||
305 | if (fname[0] == '-' && fname[1] == '\0') { | ||
306 | fp = stdin; | ||
307 | } else { | ||
308 | fp = fopen(fname, "r"); | ||
309 | if (!fp) { | ||
310 | fprintf(stderr, "Error: cannot open input file '%s': %s\n", | ||
311 | fname, strerror(errno)); | ||
312 | exit(1); | ||
313 | } | ||
314 | } | ||
315 | modstate = 0; | ||
316 | regfunc = REGFUNC_OK; | ||
317 | while (fgets(buf, sizeof(buf), fp) != NULL) { | ||
318 | char *p; | ||
319 | for (p = buf; (p = strstr(p, LIBDEF_PREFIX)) != NULL; ) { | ||
320 | const LibDefHandler *ldh; | ||
321 | p += sizeof(LIBDEF_PREFIX)-1; | ||
322 | for (ldh = libdef_handlers; ldh->suffix != NULL; ldh++) { | ||
323 | size_t n, len = strlen(ldh->suffix); | ||
324 | if (!strncmp(p, ldh->suffix, len)) { | ||
325 | p += len; | ||
326 | n = ldh->stop ? strcspn(p, ldh->stop) : 0; | ||
327 | if (!p[n]) break; | ||
328 | p[n] = '\0'; | ||
329 | ldh->func(ctx, p, ldh->arg); | ||
330 | p += n+1; | ||
331 | break; | ||
332 | } | ||
333 | } | ||
334 | if (ldh->suffix == NULL) { | ||
335 | buf[strlen(buf)-1] = '\0'; | ||
336 | fprintf(stderr, "Error: unknown library definition tag %s%s\n", | ||
337 | LIBDEF_PREFIX, p); | ||
338 | exit(1); | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | fclose(fp); | ||
343 | if (ctx->mode == BUILD_libdef) { | ||
344 | libdef_endmodule(ctx); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | if (ctx->mode == BUILD_ffdef) { | ||
349 | fprintf(ctx->fp, "\n#undef FFDEF\n\n"); | ||
350 | } else if (ctx->mode == BUILD_vmdef) { | ||
351 | fprintf(ctx->fp, "}\n\n"); | ||
352 | } else if (ctx->mode == BUILD_recdef) { | ||
353 | char *p = (char *)obuf; | ||
354 | fprintf(ctx->fp, "\n};\n\n"); | ||
355 | fprintf(ctx->fp, "static const RecordFunc recff_func[] = {\n" | ||
356 | "recff_nyi,\n" | ||
357 | "recff_c"); | ||
358 | while (*p) { | ||
359 | fprintf(ctx->fp, ",\nrecff_%s", p); | ||
360 | p += strlen(p)+1; | ||
361 | } | ||
362 | fprintf(ctx->fp, "\n};\n\n"); | ||
363 | } | ||
364 | } | ||
365 | |||