shithub: mc

Download patch

ref: 02201160614e5f25a7a73d86ed26a1f90fa4f5bb
parent: 16a7bb8f8cc86b22ce157e0944f66f60a556590f
author: Ori Bernstein <ori@markovcorp.com>
date: Tue Feb 26 08:03:14 EST 2019

Add support for `__fini__` functions.

--- a/6/main.c
+++ b/6/main.c
@@ -293,8 +293,12 @@
 		if (debugopt['T'])
 			dump(file, stdout);
 		loaduses();
-		if (hasmain(file))
-			geninit();
+		if (hasmain(file)) {
+			genautocall(file->file.init, file->file.ninit,
+			    file->file.localinit, "__init__");
+			genautocall(file->file.fini, file->file.nfini,
+			    file->file.localfini, "__fini__");
+		}
 		infer();
 		tagexports(0);
 		/* after all type inference */
--- a/6/simp.c
+++ b/6/simp.c
@@ -1403,7 +1403,7 @@
 	n = dcl->decl.name;
 	if (!n->name.ns && streq(n->name.name, "main"))
 		return 1;
-	if (streq(n->name.name, "__init__"))
+	if (streq(n->name.name, "__init__") || streq(n->name.name, "__fini__"))
 		return 1;
 	return 0;
 }
--- a/mbld/libs.myr
+++ b/mbld/libs.myr
@@ -22,7 +22,8 @@
 		incs : byte[:][:] -> void)
 ;;
 
-const Abiversion = 20
+/* Keep in sync with parse/parse.h */
+const Abiversion = 21
 
 const builtlib = {b, mt, dep, dyndep
 	var ldep, l, u
--- a/parse/dump.c
+++ b/parse/dump.c
@@ -185,7 +185,7 @@
 		findentf(fd, depth + 1, "ishidden=%d\n", n->decl.ishidden);
 		findentf(fd, depth + 1, "isimport=%d\n", n->decl.isimport);
 		findentf(fd, depth + 1, "isnoret=%d\n", n->decl.isnoret);
-		findentf(fd, depth + 1, "isexportinit=%d\n", n->decl.isexportinit);
+		findentf(fd, depth + 1, "isexportval=%d\n", n->decl.isexportval);
 		findentf(fd, depth, ")\n");
 		outsym(n, fd, depth + 1);
 		outnode(n->decl.init, fd, depth + 1);
--- a/parse/export.c
+++ b/parse/export.c
@@ -112,7 +112,7 @@
 }
 
 int
-isexportinit(Node *n)
+isexportval(Node *n)
 {
 	if (n->decl.isgeneric && !n->decl.trait)
 		return 1;
@@ -185,8 +185,8 @@
 		tagtype(st, n->decl.type, ingeneric, hidelocal);
 		if (hidelocal && n->decl.ispkglocal)
 			n->decl.vis = Vishidden;
-		n->decl.isexportinit = isexportinit(n);
-		if (n->decl.isexportinit || ingeneric)
+		n->decl.isexportval = isexportval(n);
+		if (n->decl.isexportval || ingeneric)
 			tagnode(st, n->decl.init, n->decl.isgeneric, hidelocal);
 		break;
 	case Nfunc:
@@ -229,8 +229,12 @@
 	/* tag the initializers */
 	for (i = 0; i < file->file.ninit; i++)
 		tagnode(st, file->file.init[i], 0, hidelocal);
+	for (i = 0; i < file->file.nfini; i++)
+		tagnode(st, file->file.fini[i], 0, hidelocal);
 	if (file->file.localinit)
 		tagnode(st, file->file.localinit, 0, hidelocal);
+	if (file->file.localfini)
+		tagnode(st, file->file.localfini, 0, hidelocal);
 
 	/* tag the exported nodes */
 	k = htkeys(st->dcl, &n);
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -29,14 +29,14 @@
 void yyerror(const char *s);
 int yylex(void);
 
-static Op binop(int toktype);
-static Node *mkpseudodecl(Srcloc l, Type *t);
-static void installucons(Stab *st, Type *t);
-static void setattrs(Node *dcl, char **attrs, size_t nattrs);
-static void setwith(Type *ty, Traitspec **spec, size_t nspec);
-static void setupinit(Node *n);
-static void addinit(Node *blk, Node *dcl);
-static void setuname(Type *ty);
+static Op binop(int);
+static Node *mkpseudodecl(Srcloc, Type *);
+static void installucons(Stab *, Type *);
+static void setattrs(Node *, char **attrs, size_t);
+static void setwith(Type *, Traitspec **, size_t);
+static void mangleautocall(Node *, char *);
+static void addinit(Node *, Node *);
+static void setuname(Type *);
 
 %}
 
@@ -249,18 +249,20 @@
 	}
 	| decl {
 		size_t i;
-		Node *n;
+		Node *n, *d;
 
 		for (i = 0; i < $1.nn; i++) {
-			if (!strcmp(declname($1.nl[i]), "__init__"))
-				setupinit($1.nl[i]);
+			d = $1.nl[i];
 			/* putdcl can merge, so we need to getdcl after */
-			putdcl(file->file.globls, $1.nl[i]);
-			n = getdcl(file->file.globls, $1.nl[i]->decl.name);
+			mangleautocall(d, declname(d));
+			putdcl(file->file.globls, d);
+			n = getdcl(file->file.globls, d->decl.name);
 			lappend(&file->file.stmts, &file->file.nstmts, n);
-			$1.nl[i]->decl.isglobl = 1;
-			if ($1.nl[i]->decl.isinit)
-				file->file.localinit = $1.nl[i];
+			d->decl.isglobl = 1;
+			if (d->decl.isinit)
+				file->file.localinit = d;
+			if (d->decl.isfini)
+				file->file.localfini = d;
 		}
 	}
 	| /* empty */
@@ -1129,24 +1131,26 @@
 }
 
 static void
-setupinit(Node *n)
+mangleautocall(Node *n, char *fn)
 {
 	char name[1024];
 	char *p, *s;
 
-	bprintf(name, sizeof name, "%s$__init__", file->file.files[0]);
-	s = strrchr(name, '/');
-	if (s)
+	if (strcmp(fn, "__init__") == 0)
+		n->decl.isinit = 1;
+	else if (strcmp(fn, "__fini__") == 0)
+		n->decl.isfini = 1;
+	else
+		return;
+
+	bprintf(name, sizeof name, "%s$%s", file->file.files[0], fn);
+	if ((s = strrchr(name, '/')) != NULL)
 		s++;
 	else
 		s = name;
-	p = s;
-	while (*p) {
+	for(p = s; *p; p++)
 		if (!isalnum(*p) && *p != '_')
 			*p = '$';
-		p++;
-	}
-	n->decl.isinit = 1;
 	n->decl.vis = Vishidden;
 	n->decl.name->name.name = strdup(s);
 }
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -2654,6 +2654,7 @@
 static void
 typesub(Node *n, int noerr)
 {
+	char *name;
 	size_t i;
 
 	if (!n)
@@ -2675,9 +2676,10 @@
 			if (!maincompatible(tybase(decltype(n))))
 				fatal(n, "main must be (->void) or (byte[:][:] -> void), got %s",
 						tystr(decltype(n)));
-		if (streq(declname(n), "__init__"))
+		name = declname(n);
+		if (streq(name, "__init__") || streq(name, "__fini__"))
 			if (!initcompatible(tybase(decltype(n))))
-				fatal(n, "__init__ must be (->void), got %s", tystr(decltype(n)));
+				fatal(n, "%s must be (->void), got %s", name, tystr(decltype(n)));
 		popenv(n->decl.env);
 		break;
 	case Nblock:
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -1,4 +1,4 @@
-#define Abiversion 20
+#define Abiversion 21
 
 typedef struct Srcloc Srcloc;
 typedef struct Tysubst Tysubst;
@@ -217,9 +217,13 @@
 			Node **init;	/* all __init__ function names of our deps. NB, this
 					   is a Nname, not an Ndecl */
 			size_t ninit;
+			Node **fini;	/* all __fini__ function names of our deps. NB, this
+					   is a Nname, not an Ndecl */
+			size_t nfini;
 			Node **impl;	/* impls defined in this file, across all namespaces */
 			size_t nimpl;
 			Node *localinit;/* and the local one, if any */
+			Node *localfini;/* and the local one, if any */
 			Stab *globls;	/* global symtab */
 			Stab *builtins;	/* global symtab */
 			Htab *ns;	/* namespaces */
@@ -331,8 +335,9 @@
 			char ishidden;
 			char isimport;
 			char isnoret;
-			char isexportinit;
+			char isexportval;
 			char isinit;
+			char isfini;
 		} decl;
 
 		struct {
@@ -549,7 +554,7 @@
 Node *specializedcl(Node *n, Type *param, Type *to, Node **name);
 Type *tyspecialize(Type *t, Tysubst *tymap, Htab *delayed);
 Node *genericname(Node *n, Type *param, Type *t);
-void geninit(void);
+void genautocall(Node **, size_t, Node *, char *);
 
 /* usefiles */
 void loaduses(void);
--- a/parse/specialize.c
+++ b/parse/specialize.c
@@ -639,24 +639,24 @@
 }
 
 void
-geninit(void)
+genautocall(Node **call, size_t ncall, Node *local, char *fn)
 {
 	Node *name, *decl, *func, *block, *init;
 	Type *tyvoid, *tyvoidfn;
 	size_t i;
 
-	name = mkname(Zloc, "__init__");
+	name = mkname(Zloc, fn);
 	decl = mkdecl(Zloc, name, mktyvar(Zloc));
 	block = mkblock(Zloc, mkstab(0));
 	tyvoid = mktype(Zloc, Tyvoid);
 	tyvoidfn = mktyfunc(Zloc, NULL, 0, tyvoid);
 
-	for (i = 0; i < file->file.ninit; i++) {
-		init = initdecl(file, file->file.init[i], tyvoidfn);
+	for (i = 0; i < ncall; i++) {
+		init = initdecl(file, call[i], tyvoidfn);
 		callinit(block, init, tyvoid, tyvoidfn);
 	}
-	if (file->file.localinit)
-		callinit(block, file->file.localinit, tyvoid, tyvoidfn);
+	if (local)
+		callinit(block, local, tyvoid, tyvoidfn);
 
 	func = mkfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid), block);
 	init = mkexpr(Zloc, Olit, func, NULL);
--- a/parse/stab.c
+++ b/parse/stab.c
@@ -404,7 +404,7 @@
 	old->decl.ishidden = e->decl.ishidden || g->decl.ishidden;
 	old->decl.isimport = e->decl.isimport || g->decl.isimport;
 	old->decl.isnoret = e->decl.isnoret || g->decl.isnoret;
-	old->decl.isexportinit = e->decl.isexportinit || g->decl.isexportinit;
+	old->decl.isexportval = e->decl.isexportval || g->decl.isexportval;
 	old->decl.isglobl = e->decl.isglobl || g->decl.isglobl;
 	old->decl.ispkglocal = e->decl.ispkglocal || g->decl.ispkglocal;
 	old->decl.isextern = e->decl.isextern || g->decl.isextern;
--- a/parse/use.c
+++ b/parse/use.c
@@ -39,7 +39,7 @@
 static Htab *trdeduptab;	/* map from name -> type, contains all Tynames loaded ever */
 static Htab *tidmap;		/* map from tid -> type */
 static Htab *trmap;		/* map from trait id -> trait */
-static Htab *initmap;		/* map from init name -> int */
+static Htab *autocallmap;	/* map from autocall name -> int */
 
 #define Builtinmask (1 << 30)
 static Typefix *typefix;	/* list of types we need to replace */
@@ -176,9 +176,10 @@
 	wrbool(fd, val->decl.isextern);
 	wrbool(fd, val->decl.ispkglocal);
 	wrbool(fd, val->decl.isnoret);
-	wrbool(fd, val->decl.isexportinit);
-	wrbool(fd, val->decl.isinit);
-	if (val->decl.isexportinit)
+	wrbool(fd, val->decl.isexportval);
+	wrbyte(fd, val->decl.isinit);
+	wrbyte(fd, val->decl.isfini);
+	if (val->decl.isexportval)
 		pickle(fd, val->decl.init);
 }
 
@@ -205,9 +206,10 @@
 	n->decl.ispkglocal = rdbool(fd);
 	n->decl.isnoret = rdbool(fd);
 	n->decl.isimport = 1;
-	n->decl.isexportinit = rdbool(fd);
+	n->decl.isexportval = rdbool(fd);
 	n->decl.isinit = rdbool(fd);
-	if (n->decl.isexportinit)
+	n->decl.isfini = rdbool(fd);
+	if (n->decl.isexportval)
 		n->decl.init = unpickle(fd);
 	return n;
 }
@@ -942,7 +944,7 @@
 loaduse(char *path, FILE *f, Stab *st, Vis vis)
 {
 	size_t startdecl, starttype, startimpl;
-	Node *dcl, *impl, *init;
+	Node *dcl, *impl, *fn;
 	Stab *s, *ns;
 	intptr_t tid;
 	size_t i, j;
@@ -990,8 +992,8 @@
 	}
 	tidmap = mkht(ptrhash, ptreq);
 	trmap = mkht(ptrhash, ptreq);
-	if (!initmap)
-		initmap = mkht(namehash, nameeq);
+	if (!autocallmap)
+		autocallmap = mkht(namehash, nameeq);
 	/* builtin traits */
 	for (i = 0; i < Ntraits; i++)
 		htput(trmap, itop(i), traittab[i]);
@@ -1024,11 +1026,15 @@
 			putdcl(s, dcl);
 			break;
 		case 'S':
-			init = unpickle(f);
-			if (!hthas(initmap, init)) {
-				htput(initmap, init, init);
-				lappend(&file->file.init, &file->file.ninit, init);
-			}
+		case 'E':
+			fn = unpickle(f);
+			if (hthas(autocallmap, fn))
+				break;
+			htput(autocallmap, fn, fn);
+			if (c == 'S')
+				lappend(&file->file.init, &file->file.ninit, fn);
+			else
+				lappend(&file->file.fini, &file->file.nfini, fn);
 			break;
 		case 'R':
 			tr = traitunpickle(f);
@@ -1289,7 +1295,7 @@
 		if (s->decl.vis == Visintern || s->decl.vis == Visbuiltin)
 			continue;
 		/* trait functions get written out with their traits */
-		if (s->decl.trait || s->decl.isinit)
+		if (s->decl.trait || s->decl.isinit || s->decl.isfini)
 			continue;
 		else if (s->decl.isgeneric)
 			wrbyte(f, 'G');
@@ -1304,6 +1310,14 @@
 	if (file->file.localinit) {
 		wrbyte(f, 'S');
 		pickle(f, file->file.localinit->decl.name);
+	}
+	for (i = 0; i < file->file.nfini; i++) {
+		wrbyte(f, 'E');
+		pickle(f, file->file.fini[i]);
+	}
+	if (file->file.localfini) {
+		wrbyte(f, 'E');
+		pickle(f, file->file.localfini->decl.name);
 	}
 	free(k);
 }
--- a/rt/start-freebsd.s
+++ b/rt/start-freebsd.s
@@ -51,11 +51,11 @@
 	addq	$0x10,%rsp
 
 	xorq %rbp,%rbp
-	/* call pre-main initializers */
-	call	__init__
 
-	/* enter the main program */
+	call	__init__
 	call	main
+	call	__fini__
+
 	/* exit(0) */
 	xorq	%rdi,%rdi
 	movq	$1,%rax
--- a/rt/start-linux.s
+++ b/rt/start-linux.s
@@ -48,10 +48,10 @@
 	syscall
 
 	xorq %rbp,%rbp
-	/* call pre-main initializers */
 	call	__init__
-	/* enter the main program */
 	call	main
+	call	__fini__
+
 	/* exit(0) */
 	xorq	%rdi,%rdi
 	movq	$60,%rax
--- a/rt/start-netbsd.s
+++ b/rt/start-netbsd.s
@@ -60,10 +60,11 @@
 	addq	$0x10,%rsp
 
 	xorq %rbp,%rbp
-	/* call pre-main initializers */
+
 	call	__init__
-	/* enter the main program */
 	call	main
+	call	__fini__
+
 	/* exit(0) */
 	xorq	%rdi,%rdi
 	movq	$1,%rax
--- a/rt/start-openbsd.s
+++ b/rt/start-openbsd.s
@@ -61,10 +61,11 @@
 	  to call kbind here, but this breaks
 	  when we dynamically link in libc.
 	 */
-	/* call pre-main initializers */
+
 	call	__init__
-	/* enter the main program */
 	call	main
+	call	__init__
+
 	/* exit(0) */
 	xorq	%rdi,%rdi
 	movq	$1,%rax
--- a/rt/start-osx.s
+++ b/rt/start-osx.s
@@ -48,9 +48,11 @@
 	syscall
 
 	xorq %rbp,%rbp
+
 	call	___init__
-	/* enter the main program */
 	call	_main
+	call	___fini__
+
 	/* exit */
 	xorq	%rdi,%rdi
 	movq	$0x2000001,%rax