1/*
2** LuaJIT VM builder: library definition compiler.
3** Copyright (C) 2005-2014 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#include "buildvm.h"
7#include "lj_obj.h"
8#include "lj_lib.h"
9
10/* Context for library definitions. */
11static uint8_t obuf[8192];
12static uint8_t *optr;
13static char modname[80];
14static size_t modnamelen;
15static char funcname[80];
16static int modstate, regfunc;
17static int ffid, recffid, ffasmfunc;
18
19enum {
20 REGFUNC_OK,
21 REGFUNC_NOREG,
22 REGFUNC_NOREGUV
23};
24
25static void libdef_name(const char *p, int kind)
26{
27 size_t n = strlen(p);
28 if (kind != LIBINIT_STRING) {
29 if (n > modnamelen && p[modnamelen] == '_' &&
30 !strncmp(p, modname, modnamelen)) {
31 p += modnamelen+1;
32 n -= modnamelen+1;
33 }
34 }
35 if (n > LIBINIT_MAXSTR) {
36 fprintf(stderr, "Error: string too long: '%s'\n", p);
37 exit(1);
38 }
39 if (optr+1+n+2 > obuf+sizeof(obuf)) { /* +2 for caller. */
40 fprintf(stderr, "Error: output buffer overflow\n");
41 exit(1);
42 }
43 *optr++ = (uint8_t)(n | kind);
44 memcpy(optr, p, n);
45 optr += n;
46}
47
48static void libdef_endmodule(BuildCtx *ctx)
49{
50 if (modstate != 0) {
51 char line[80];
52 const uint8_t *p;
53 int n;
54 if (modstate == 1)
55 fprintf(ctx->fp, " (lua_CFunction)0");
56 fprintf(ctx->fp, "\n};\n");
57 fprintf(ctx->fp, "static const uint8_t %s%s[] = {\n",
58 LABEL_PREFIX_LIBINIT, modname);
59 line[0] = '\0';
60 for (n = 0, p = obuf; p < optr; p++) {
61 n += sprintf(line+n, "%d,", *p);
62 if (n >= 75) {
63 fprintf(ctx->fp, "%s\n", line);
64 n = 0;
65 line[0] = '\0';
66 }
67 }
68 fprintf(ctx->fp, "%s%d\n};\n#endif\n\n", line, LIBINIT_END);
69 }
70}
71
72static void libdef_module(BuildCtx *ctx, char *p, int arg)
73{
74 UNUSED(arg);
75 if (ctx->mode == BUILD_libdef) {
76 libdef_endmodule(ctx);
77 optr = obuf;
78 *optr++ = (uint8_t)ffid;
79 *optr++ = (uint8_t)ffasmfunc;
80 *optr++ = 0; /* Hash table size. */
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
95static 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
109static void libdef_func(BuildCtx *ctx, char *p, int arg)
110{
111 if (arg != LIBINIT_CF)
112 ffasmfunc++;
113 if (ctx->mode == BUILD_libdef) {
114 if (modstate == 0) {
115 fprintf(stderr, "Error: no module for function definition %s\n", p);
116 exit(1);
117 }
118 if (regfunc == REGFUNC_NOREG) {
119 if (optr+1 > obuf+sizeof(obuf)) {
120 fprintf(stderr, "Error: output buffer overflow\n");
121 exit(1);
122 }
123 *optr++ = LIBINIT_FFID;
124 } else {
125 if (arg != LIBINIT_ASM_) {
126 if (modstate != 1) fprintf(ctx->fp, ",\n");
127 modstate = 2;
128 fprintf(ctx->fp, " %s%s", arg ? LABEL_PREFIX_FFH : LABEL_PREFIX_CF, p);
129 }
130 if (regfunc != REGFUNC_NOREGUV) obuf[2]++; /* Bump hash table size. */
131 libdef_name(regfunc == REGFUNC_NOREGUV ? "" : p, arg);
132 }
133 } else if (ctx->mode == BUILD_ffdef) {
134 fprintf(ctx->fp, "FFDEF(%s)\n", p);
135 } else if (ctx->mode == BUILD_recdef) {
136 if (strlen(p) > sizeof(funcname)-1) {
137 fprintf(stderr, "Error: function name too long: '%s'\n", p);
138 exit(1);
139 }
140 strcpy(funcname, p);
141 } else if (ctx->mode == BUILD_vmdef) {
142 int i;
143 for (i = 1; p[i] && modname[i-1]; i++)
144 if (p[i] == '_') p[i] = '.';
145 fprintf(ctx->fp, "\"%s\",\n", p);
146 } else if (ctx->mode == BUILD_bcdef) {
147 if (arg != LIBINIT_CF)
148 fprintf(ctx->fp, ",\n%d", find_ffofs(ctx, p));
149 }
150 ffid++;
151 regfunc = REGFUNC_OK;
152}
153
154static 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
171static 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
191static 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-1];
201 }
202}
203
204static 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
249static 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[2]++; /* Bump hash table size. */
257 }
258}
259
260static void libdef_regfunc(BuildCtx *ctx, char *p, int arg)
261{
262 UNUSED(ctx); UNUSED(p);
263 regfunc = arg;
264}
265
266typedef void (*LibDefFunc)(BuildCtx *ctx, char *p, int arg);
267
268typedef struct LibDefHandler {
269 const char *suffix;
270 const char *stop;
271 const LibDefFunc func;
272 const int arg;
273} LibDefHandler;
274
275static 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. */
289void 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 ffasmfunc = 0;
302
303 while ((fname = *ctx->args++)) {
304 char buf[256]; /* We don't care about analyzing lines longer than that. */
305 FILE *fp;
306 if (fname[0] == '-' && fname[1] == '\0') {
307 fp = stdin;
308 } else {
309 fp = fopen(fname, "r");
310 if (!fp) {
311 fprintf(stderr, "Error: cannot open input file '%s': %s\n",
312 fname, strerror(errno));
313 exit(1);
314 }
315 }
316 modstate = 0;
317 regfunc = REGFUNC_OK;
318 while (fgets(buf, sizeof(buf), fp) != NULL) {
319 char *p;
320 /* Simplistic pre-processor. Only handles top-level #if/#endif. */
321 if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') {
322 int ok = 1;
323 if (!strcmp(buf, "#if LJ_52\n"))
324 ok = LJ_52;
325 else if (!strcmp(buf, "#if LJ_HASJIT\n"))
326 ok = LJ_HASJIT;
327 else if (!strcmp(buf, "#if LJ_HASFFI\n"))
328 ok = LJ_HASFFI;
329 if (!ok) {
330 int lvl = 1;
331 while (fgets(buf, sizeof(buf), fp) != NULL) {
332 if (buf[0] == '#' && buf[1] == 'e' && buf[2] == 'n') {
333 if (--lvl == 0) break;
334 } else if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') {
335 lvl++;
336 }
337 }
338 continue;
339 }
340 }
341 for (p = buf; (p = strstr(p, LIBDEF_PREFIX)) != NULL; ) {
342 const LibDefHandler *ldh;
343 p += sizeof(LIBDEF_PREFIX)-1;
344 for (ldh = libdef_handlers; ldh->suffix != NULL; ldh++) {
345 size_t n, len = strlen(ldh->suffix);
346 if (!strncmp(p, ldh->suffix, len)) {
347 p += len;
348 n = ldh->stop ? strcspn(p, ldh->stop) : 0;
349 if (!p[n]) break;
350 p[n] = '\0';
351 ldh->func(ctx, p, ldh->arg);
352 p += n+1;
353 break;
354 }
355 }
356 if (ldh->suffix == NULL) {
357 buf[strlen(buf)-1] = '\0';
358 fprintf(stderr, "Error: unknown library definition tag %s%s\n",
359 LIBDEF_PREFIX, p);
360 exit(1);
361 }
362 }
363 }
364 fclose(fp);
365 if (ctx->mode == BUILD_libdef) {
366 libdef_endmodule(ctx);
367 }
368 }
369
370 if (ctx->mode == BUILD_ffdef) {
371 fprintf(ctx->fp, "\n#undef FFDEF\n\n");
372 fprintf(ctx->fp,
373 "#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n",
374 ffasmfunc);
375 } else if (ctx->mode == BUILD_vmdef) {
376 fprintf(ctx->fp, "}\n\n");
377 } else if (ctx->mode == BUILD_bcdef) {
378 int i;
379 fprintf(ctx->fp, "\n};\n\n");
380 fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_mode[] = {\n");
381 fprintf(ctx->fp, "BCDEF(BCMODE)\n");
382 for (i = ffasmfunc-1; i > 0; i--)
383 fprintf(ctx->fp, "BCMODE_FF,\n");
384 fprintf(ctx->fp, "BCMODE_FF\n};\n\n");
385 } else if (ctx->mode == BUILD_recdef) {
386 char *p = (char *)obuf;
387 fprintf(ctx->fp, "\n};\n\n");
388 fprintf(ctx->fp, "static const RecordFunc recff_func[] = {\n"
389 "recff_nyi,\n"
390 "recff_c");
391 while (*p) {
392 fprintf(ctx->fp, ",\nrecff_%s", p);
393 p += strlen(p)+1;
394 }
395 fprintf(ctx->fp, "\n};\n\n");
396 }
397}
398
399