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. */
11 static uint8_t obuf[8192];
12 static uint8_t *optr;
13 static char modname[80];
14 static size_t modnamelen;
15 static char funcname[80];
16 static int modstate, regfunc;
17 static int ffid, recffid, ffasmfunc;
18 
19 enum {
20   REGFUNC_OK,
21   REGFUNC_NOREG,
22   REGFUNC_NOREGUV
23 };
24 
libdef_name(const char * p,int kind)25 static 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 
libdef_endmodule(BuildCtx * ctx)48 static 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 
libdef_module(BuildCtx * ctx,char * p,int arg)72 static 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 
find_ffofs(BuildCtx * ctx,const char * name)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 
libdef_func(BuildCtx * ctx,char * p,int arg)109 static 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 
find_rec(char * name)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 
libdef_rec(BuildCtx * ctx,char * p,int arg)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 
memcpy_endian(void * dst,void * src,size_t n)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-1];
201   }
202 }
203 
libdef_push(BuildCtx * ctx,char * p,int arg)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 
libdef_set(BuildCtx * ctx,char * p,int arg)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[2]++;  /* Bump hash table size. */
257   }
258 }
259 
libdef_regfunc(BuildCtx * ctx,char * p,int arg)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. */
emit_lib(BuildCtx * ctx)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   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