xref: /inferno-os/limbo/stubs.c (revision 1ff104bedb296e04ccdfedf022dd220299243f14)
1 #include "limbo.h"
2 
3 static long	stubalign(long offset, int a, char** b, char *e);
4 static void		pickadtstub(Type *t);
5 
6 void
emit(Decl * globals)7 emit(Decl *globals)
8 {
9 	Decl *m, *d, *id;
10 
11 	for(m = globals; m != nil; m = m->next){
12 		if(m->store != Dtype || m->ty->kind != Tmodule)
13 			continue;
14 		m->ty = usetype(m->ty);
15 		for(d = m->ty->ids; d != nil; d = d->next){
16 			d->ty = usetype(d->ty);
17 			if(d->store == Dglobal || d->store == Dfn)
18 				modrefable(d->ty);
19 			if(d->store == Dtype && d->ty->kind == Tadt){
20 				for(id = d->ty->ids; id != nil; id = id->next){
21 					id->ty = usetype(id->ty);
22 					modrefable(d->ty);
23 				}
24 			}
25 		}
26 	}
27 	if(emitstub){
28 		adtstub(globals);
29 		modstub(globals);
30 	}
31 	if(emittab != nil)
32 		modtab(globals);
33 	if(emitcode)
34 		modcode(globals);
35 }
36 
37 static char*
lowercase(char * f)38 lowercase(char *f)
39 {
40 	char *s = f;
41 
42 	for( ; *s != 0; s++)
43 		if(*s >= 'A' && *s <= 'Z')
44 			*s += 'a' - 'A';
45 	return f;
46 }
47 
48 void
modcode(Decl * globals)49 modcode(Decl *globals)
50 {
51 	Decl *d, *id;
52 	char buf[32];
53 
54 	if(emitdyn){
55 		strcpy(buf, emitcode);
56 		lowercase(buf);
57 		print("#include \"%s.h\"\n", buf);
58 	}
59 	else{
60 		print("#include <lib9.h>\n");
61 		print("#include <isa.h>\n");
62 		print("#include <interp.h>\n");
63 		print("#include \"%smod.h\"\n", emitcode);
64 	}
65 	print("\n");
66 
67 	for(d = globals; d != nil; d = d->next)
68 		if(d->store == Dtype && d->ty->kind == Tmodule && strcmp(d->sym->name, emitcode) == 0)
69 			break;
70 
71 	if(d == nil)
72 		return;
73 
74 	/*
75 	 * stub types
76 	 */
77 	for(id = d->ty->ids; id != nil; id = id->next){
78 		if(id->store == Dtype && id->ty->kind == Tadt){
79 			id->ty = usetype(id->ty);
80 			print("Type*\tT_%s;\n", id->sym->name);
81 		}
82 	}
83 
84 	/*
85 	 * type maps
86 	 */
87 	if(emitdyn){
88 		for(id = d->ty->ids; id != nil; id = id->next)
89 			if(id->store == Dtype && id->ty->kind == Tadt)
90 				print("uchar %s_map[] = %s_%s_map;\n",
91 					id->sym->name, emitcode, id->sym->name);
92 	}
93 
94 	/*
95 	  * heap allocation and garbage collection for a type
96 	 */
97 	if(emitdyn){
98 		for(id = d->ty->ids; id != nil; id = id->next)
99 			if(id->store == Dtype && id->ty->kind == Tadt){
100 				print("\n%s_%s*\n%salloc%s(void)\n{\n\tHeap *h;\n\n\th = heap(T_%s);\n\treturn H2D(%s_%s*, h);\n}\n", emitcode, id->sym->name, emitcode, id->sym->name, id->sym->name, emitcode, id->sym->name);
101 				print("\nvoid\n%sfree%s(Heap *h, int swept)\n{\n\t%s_%s *d;\n\n\td = H2D(%s_%s*, h);\n\tfreeheap(h, swept);\n}\n", emitcode, id->sym->name, emitcode, id->sym->name, emitcode, id->sym->name);
102 			}
103 	}
104 
105 	/*
106 	 * initialization function
107 	 */
108 	if(emitdyn)
109 		print("\nvoid\n%sinit(void)\n{\n", emitcode);
110 	else{
111 		print("\nvoid\n%smodinit(void)\n{\n", emitcode);
112 		print("\tbuiltinmod(\"$%s\", %smodtab, %smodlen);\n", emitcode, emitcode, emitcode);
113 	}
114 	for(id = d->ty->ids; id != nil; id = id->next){
115 		if(id->store == Dtype && id->ty->kind == Tadt){
116 			if(emitdyn)
117 				print("\tT_%s = dtype(%sfree%s, %s_%s_size, %s_map, sizeof(%s_map));\n",
118 					id->sym->name, emitcode, id->sym->name, emitcode, id->sym->name, id->sym->name, id->sym->name);
119 			else
120 				print("\tT_%s = dtype(freeheap, sizeof(%s), %smap, sizeof(%smap));\n",
121 					id->sym->name, id->sym->name, id->sym->name, id->sym->name);
122 		}
123 	}
124 	print("}\n");
125 
126 	/*
127 	 * end function
128 	 */
129 	if(emitdyn){
130 		print("\nvoid\n%send(void)\n{\n", emitcode);
131 		for(id = d->ty->ids; id != nil; id = id->next)
132 			if(id->store == Dtype && id->ty->kind == Tadt)
133 				print("\tfreetype(T_%s);\n", id->sym->name);
134 		print("}\n");
135 	}
136 
137 	/*
138 	 * stub functions
139 	 */
140 	for(id = d->ty->tof->ids; id != nil; id = id->next){
141 		print("\nvoid\n%s_%s(void *fp)\n{\n\tF_%s_%s *f = fp;\n",
142 			id->dot->sym->name, id->sym->name,
143 			id->dot->sym->name, id->sym->name);
144 		if(id->ty->tof != tnone && tattr[id->ty->tof->kind].isptr){
145 			print("\tvoid *r;\n");
146 			print("\n\tr = *f->ret;\n\t*f->ret = H;\n\tdestroy(r);\n");
147 		}
148 		print("}\n");
149 	}
150 
151 	if(emitdyn)
152 		print("\n#include \"%smod.h\"\n", buf);
153 }
154 
155 void
modtab(Decl * globals)156 modtab(Decl *globals)
157 {
158 	int n;
159 	Desc *md;
160 	Decl *d, *id;
161 
162 	print("typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;\n");
163 	for(d = globals; d != nil; d = d->next){
164 		if(d->store == Dtype && d->ty->kind == Tmodule && strcmp(d->sym->name, emittab) == 0){
165 			n = 0;
166 			print("Runtab %smodtab[]={\n", d->sym->name);
167 			for(id = d->ty->tof->ids; id != nil; id = id->next){
168 				n++;
169 				print("\t\"");
170 				if(id->dot != d)
171 					print("%s.", id->dot->sym->name);
172 				print("%s\",0x%lux,%s_%s,", id->sym->name, sign(id),
173 					id->dot->sym->name, id->sym->name);
174 				if(id->ty->varargs)
175 					print("0,0,{0},");
176 				else{
177 					md = mkdesc(idoffsets(id->ty->ids, MaxTemp, MaxAlign), id->ty->ids);
178 					print("%ld,%ld,%M,", md->size, md->nmap, md);
179 				}
180 				print("\n");
181 			}
182 			print("\t0\n};\n");
183 			print("#define %smodlen	%d\n", d->sym->name, n);
184 		}
185 	}
186 }
187 
188 /*
189  * produce activation records for all the functions in modules
190  */
191 void
modstub(Decl * globals)192 modstub(Decl *globals)
193 {
194 	Type *t;
195 	Decl *d, *id, *m;
196 	char buf[StrSize*2], *p;
197 	long offset;
198 	int arg;
199 
200 	for(d = globals; d != nil; d = d->next){
201 		if(d->store != Dtype || d->ty->kind != Tmodule)
202 			continue;
203 		arg = 0;
204 		for(id = d->ty->tof->ids; id != nil; id = id->next){
205 			if(emitdyn && id->dot->dot != nil)
206 				seprint(buf, buf+sizeof(buf), "%s_%s_%s", id->dot->dot->sym->name, id->dot->sym->name, id->sym->name);
207 			else
208 				seprint(buf, buf+sizeof(buf), "%s_%s", id->dot->sym->name, id->sym->name);
209 			print("void %s(void*);\ntypedef struct F_%s F_%s;\nstruct F_%s\n{\n",
210 				buf, buf, buf, buf);
211 			print("	WORD	regs[NREG-1];\n");
212 			if(id->ty->tof != tnone)
213 				print("	%R*	ret;\n", id->ty->tof);
214 			else
215 				print("	WORD	noret;\n");
216 			print("	uchar	temps[%d];\n", MaxTemp-NREG*IBY2WD);
217 			offset = MaxTemp;
218 			for(m = id->ty->ids; m != nil; m = m->next){
219 				if(m->sym != nil)
220 					p = m->sym->name;
221 				else{
222 					seprint(buf, buf+sizeof(buf), "arg%d", arg);
223 					p = buf;
224 				}
225 
226 				/*
227 				 * explicit pads for structure alignment
228 				 */
229 				t = m->ty;
230 				offset = stubalign(offset, t->align, nil, nil);
231 				if(offset != m->offset)
232 					yyerror("module stub must not contain data objects");
233 					// fatal("modstub bad offset");
234 				print("	%R	%s;\n", t, p);
235 				arg++;
236 				offset += t->size;
237 			}
238 			if(id->ty->varargs)
239 				print("	WORD	vargs;\n");
240 			print("};\n");
241 		}
242 		for(id = d->ty->ids; id != nil; id = id->next)
243 			if(id->store == Dconst)
244 				constub(id);
245 	}
246 }
247 
248 static void
chanstub(char * in,Decl * id)249 chanstub(char *in, Decl *id)
250 {
251 	Desc *desc;
252 
253 	print("typedef %R %s_%s;\n", id->ty->tof, in, id->sym->name);
254 	desc = mktdesc(id->ty->tof);
255 	print("#define %s_%s_size %ld\n", in, id->sym->name, desc->size);
256 	print("#define %s_%s_map %M\n", in, id->sym->name, desc);
257 }
258 
259 /*
260  * produce c structs for all adts
261  */
262 void
adtstub(Decl * globals)263 adtstub(Decl *globals)
264 {
265 	Type *t, *tt;
266 	Desc *desc;
267 	Decl *m, *d, *id;
268 	char buf[2*StrSize];
269 	long offset;
270 
271 	for(m = globals; m != nil; m = m->next){
272 		if(m->store != Dtype || m->ty->kind != Tmodule)
273 			continue;
274 		for(d = m->ty->ids; d != nil; d = d->next){
275 			if(d->store != Dtype)
276 				continue;
277 			t = usetype(d->ty);
278 			d->ty = t;
279 			dotprint(buf, buf+sizeof(buf), d->ty->decl, '_');
280 			switch(d->ty->kind){
281 			case Tadt:
282 				print("typedef struct %s %s;\n", buf, buf);
283 				break;
284 			case Tint:
285 			case Tbyte:
286 			case Treal:
287 			case Tbig:
288 			case Tfix:
289 				print("typedef %T %s;\n", t, buf);
290 				break;
291 			}
292 		}
293 	}
294 	for(m = globals; m != nil; m = m->next){
295 		if(m->store != Dtype || m->ty->kind != Tmodule)
296 			continue;
297 		for(d = m->ty->ids; d != nil; d = d->next){
298 			if(d->store != Dtype)
299 				continue;
300 			t = d->ty;
301 			if(t->kind == Tadt || t->kind == Ttuple && t->decl->sym != anontupsym){
302 				if(t->tags != nil){
303 					pickadtstub(t);
304 					continue;
305 				}
306 				dotprint(buf, buf+sizeof(buf), t->decl, '_');
307 				print("struct %s\n{\n", buf);
308 				offset = 0;
309 				for(id = t->ids; id != nil; id = id->next){
310 					if(id->store == Dfield){
311 						tt = id->ty;
312 						offset = stubalign(offset, tt->align, nil, nil);
313 						if(offset != id->offset)
314 							fatal("adtstub bad offset");
315 						print("	%R	%s;\n", tt, id->sym->name);
316 						offset += tt->size;
317 					}
318 				}
319 				if(t->ids == nil){
320 					print("	char	dummy[1];\n");
321 					offset = 1;
322 				}
323 				offset = stubalign(offset, t->align, nil ,nil);
324 				offset = stubalign(offset, IBY2WD, nil , nil);
325 				if(offset != t->size && t->ids != nil)
326 					fatal("adtstub: bad size");
327 				print("};\n");
328 
329 				for(id = t->ids; id != nil; id = id->next)
330 					if(id->store == Dconst)
331 						constub(id);
332 
333 				for(id = t->ids; id != nil; id = id->next)
334 					if(id->ty->kind == Tchan)
335 						chanstub(buf, id);
336 
337 				desc = mktdesc(t);
338 				if(offset != desc->size && t->ids != nil)
339 					fatal("adtstub: bad desc size");
340 				print("#define %s_size %ld\n", buf, offset);
341 				print("#define %s_map %M\n", buf, desc);
342 if(0)
343 				print("struct %s_check {int s[2*(sizeof(%s)==%s_size)-1];};\n", buf, buf, buf);
344 			}else if(t->kind == Tchan)
345 				chanstub(m->sym->name, d);
346 		}
347 	}
348 }
349 
350 /*
351  * emit an expicit pad field for aligning emitted c structs
352  * according to limbo's definition
353  */
354 static long
stubalign(long offset,int a,char ** buf,char * end)355 stubalign(long offset, int a, char **buf, char *end)
356 {
357 	long x;
358 
359 	x = offset & (a-1);
360 	if(x == 0)
361 		return offset;
362 	x = a - x;
363 	if(buf == nil)
364 		print("\tuchar\t_pad%ld[%ld];\n", offset, x);
365 	else
366 		*buf = seprint(*buf, end, "uchar\t_pad%ld[%ld]; ", offset, x);
367 	offset += x;
368 	if((offset & (a-1)) || x >= a)
369 		fatal("compiler stub misalign");
370 	return offset;
371 }
372 
373 void
constub(Decl * id)374 constub(Decl *id)
375 {
376 	char buf[StrSize*2];
377 
378 	seprint(buf, buf+sizeof(buf), "%s_%s", id->dot->sym->name, id->sym->name);
379 	switch(id->ty->kind){
380 	case Tbyte:
381 		print("#define %s %d\n", buf, (int)id->init->val & 0xff);
382 		break;
383 	case Tint:
384 	case Tfix:
385 		print("#define %s %ld\n", buf, (long)id->init->val);
386 		break;
387 	case Tbig:
388 		print("#define %s %ld\n", buf, (long)id->init->val);
389 		break;
390 	case Treal:
391 		print("#define %s %g\n", buf, id->init->rval);
392 		break;
393 	case Tstring:
394 		print("#define %s \"%s\"\n", buf, id->init->decl->sym->name);
395 		break;
396 	}
397 }
398 
399 int
mapconv(Fmt * f)400 mapconv(Fmt *f)
401 {
402 	Desc *d;
403 	char *s, *e, buf[1024];
404 	int i;
405 
406 	d = va_arg(f->args, Desc*);
407 	e = buf+sizeof(buf);
408 	s = buf;
409 	s = secpy(s, e, "{");
410 	for(i = 0; i < d->nmap; i++)
411 		s = seprint(s, e, "0x%x,", d->map[i]);
412 	if(i == 0)
413 		s = seprint(s, e, "0");
414 	seprint(s, e, "}");
415 	return fmtstrcpy(f, buf);
416 }
417 
418 char*
dotprint(char * buf,char * end,Decl * d,int dot)419 dotprint(char *buf, char *end, Decl *d, int dot)
420 {
421 	if(d->dot != nil){
422 		buf = dotprint(buf, end, d->dot, dot);
423 		if(buf < end)
424 			*buf++ = dot;
425 	}
426 	if(d->sym == nil)
427 		return buf;
428 	return seprint(buf, end, "%s", d->sym->name);
429 }
430 
431 char *ckindname[Tend] =
432 {
433 	/* Tnone */	"void",
434 	/* Tadt */	"struct",
435 	/* Tadtpick */	"?adtpick?",
436 	/* Tarray */	"Array*",
437 	/* Tbig */	"LONG",
438 	/* Tbyte */	"BYTE",
439 	/* Tchan */	"Channel*",
440 	/* Treal */	"REAL",
441 	/* Tfn */	"?fn?",
442 	/* Tint */	"WORD",
443 	/* Tlist */	"List*",
444 	/* Tmodule */	"Modlink*",
445 	/* Tref */	"?ref?",
446 	/* Tstring */	"String*",
447 	/* Ttuple */	"?tuple?",
448 	/* Texception */	"?exception",
449 	/* Tfix */		"WORD",
450 	/* Tpoly */	"void*",
451 
452 	/* Tainit */	"?ainit?",
453 	/* Talt */	"?alt?",
454 	/* Tany */	"void*",
455 	/* Tarrow */	"?arrow?",
456 	/* Tcase */	"?case?",
457 	/* Tcasel */	"?casel",
458 	/* Tcasec */	"?casec?",
459 	/* Tdot */	"?dot?",
460 	/* Terror */	"?error?",
461 	/* Tgoto */	"?goto?",
462 	/* Tid */	"?id?",
463 	/* Tiface */	"?iface?",
464 	/* Texcept */	"?except?",
465 	/* Tinst */	"?inst?",
466 };
467 
468 char*
ctprint(char * buf,char * end,Type * t)469 ctprint(char *buf, char *end, Type *t)
470 {
471 	Decl *id;
472 	Type *tt;
473 	long offset;
474 
475 	if(t == nil)
476 		return secpy(buf, end, "void");
477 	switch(t->kind){
478 	case Tref:
479 		return seprint(buf, end, "%R*", t->tof);
480 	case Tarray:
481 	case Tlist:
482 	case Tint:
483 	case Tbig:
484 	case Tstring:
485 	case Treal:
486 	case Tbyte:
487 	case Tnone:
488 	case Tany:
489 	case Tchan:
490 	case Tmodule:
491 	case Tfix:
492 	case Tpoly:
493 		return seprint(buf, end, "%s", ckindname[t->kind]);
494 	case Tadtpick:
495 		return ctprint(buf, end, t->decl->dot->ty);
496 	case Tadt:
497 	case Ttuple:
498 		if(t->decl->sym != anontupsym)
499 			return dotprint(buf, end, t->decl, '_');
500 		offset = 0;
501 		buf = secpy(buf, end, "struct{ ");
502 		for(id = t->ids; id != nil; id = id->next){
503 			tt = id->ty;
504 			offset = stubalign(offset, tt->align, &buf, end);
505 			if(offset != id->offset)
506 				fatal("ctypeconv tuple bad offset");
507 			buf = seprint(buf, end, "%R %s; ", tt, id->sym->name);
508 			offset += tt->size;
509 		}
510 		offset = stubalign(offset, t->align, &buf, end);
511 		if(offset != t->size)
512 			fatal("ctypeconv tuple bad t=%T size=%ld offset=%ld", t, t->size, offset);
513 		return secpy(buf, end, "}");
514 	default:
515 		if(t->kind >= Tend)
516 			yyerror("no C equivalent for type %d", t->kind);
517 		else
518 			yyerror("no C equivalent for type %s", kindname[t->kind]);
519 		break;
520 	}
521 	return buf;
522 }
523 
524 static void
pickadtstub(Type * t)525 pickadtstub(Type *t)
526 {
527 	Type *tt;
528 	Desc *desc;
529 	Decl *id, *tg;
530 	char buf[2*StrSize];
531 	int ok;
532 	long offset, tgoffset;
533 
534 	dotprint(buf, buf+sizeof(buf), t->decl, '_');
535 	offset = 0;
536 	for(tg = t->tags; tg != nil; tg = tg->next)
537 		print("#define %s_%s %ld\n", buf, tg->sym->name, offset++);
538 	print("struct %s\n{\n", buf);
539 	print("	int	pick;\n");
540 	offset = IBY2WD;
541 	for(id = t->ids; id != nil; id = id->next){
542 		if(id->store == Dfield){
543 			tt = id->ty;
544 			offset = stubalign(offset, tt->align, nil, nil);
545 			if(offset != id->offset)
546 				fatal("pickadtstub bad offset");
547 			print("	%R	%s;\n", tt, id->sym->name);
548 			offset += tt->size;
549 		}
550 	}
551 	print("	union{\n");
552 	for(tg = t->tags; tg != nil; tg = tg->next){
553 		tgoffset = offset;
554 		print("		struct{\n");
555 		for(id = tg->ty->ids; id != nil; id = id->next){
556 			if(id->store == Dfield){
557 				tt = id->ty;
558 				tgoffset = stubalign(tgoffset, tt->align, nil, nil);
559 				if(tgoffset != id->offset)
560 					fatal("pickadtstub bad offset");
561 				print("			%R	%s;\n", tt, id->sym->name);
562 				tgoffset += tt->size;
563 			}
564 		}
565 		if(tg->ty->ids == nil)
566 			print("			char	dummy[1];\n");
567 		print("		} %s;\n", tg->sym->name);
568 	}
569 	print("	} u;\n");
570 	print("};\n");
571 
572 	for(id = t->ids; id != nil; id = id->next)
573 		if(id->store == Dconst)
574 			constub(id);
575 
576 	for(id = t->ids; id != nil; id = id->next)
577 		if(id->ty->kind == Tchan)
578 			chanstub(buf, id);
579 
580 	for(tg = t->tags; tg != nil; tg = tg->next){
581 		ok = tg->ty->tof->ok;
582 		tg->ty->tof->ok = OKverify;
583 		sizetype(tg->ty->tof);
584 		tg->ty->tof->ok = OKmask;
585 		desc = mktdesc(tg->ty->tof);
586 		tg->ty->tof->ok = ok;
587 		print("#define %s_%s_size %ld\n", buf, tg->sym->name, tg->ty->size);
588 		print("#define %s_%s_map %M\n", buf, tg->sym->name, desc);
589 	}
590 }
591