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