Improve linking time by marking subtrees with unbound symbols

This commit is contained in:
Muh Muhten authored and Nico Williams committed 2019-02-08 22:41:31 -06:00
1 parent 2660b04a73
commit 88613f5469
1 file changed
+25 -4
+25 -4
View File
@@ -49,9 +49,10 @@ struct inst {
// Unbound instructions (references to other things that may or may not // Unbound instructions (references to other things that may or may not
// exist) are created by "gen_foo_unbound", and bindings are created by // exist) are created by "gen_foo_unbound", and bindings are created by
// block_bind(definition, body), which binds all instructions in // block_bind(definition, body), which binds all instructions in
// body which are unboudn and refer to "definition" by name. // body which are unbound and refer to "definition" by name.
struct inst* bound_by; struct inst* bound_by;
char* symbol; char* symbol;
int any_unbound;
int nformals; int nformals;
int nactuals; int nactuals;
@@ -73,6 +74,7 @@ static inst* inst_new(opcode op) {
i->bytecode_pos = -1; i->bytecode_pos = -1;
i->bound_by = 0; i->bound_by = 0;
i->symbol = 0; i->symbol = 0;
i->any_unbound = 0;
i->nformals = -1; i->nformals = -1;
i->nactuals = -1; i->nactuals = -1;
i->subfn = gen_noop(); i->subfn = gen_noop();
@@ -156,6 +158,7 @@ block gen_const_global(jv constant, const char *name) {
inst* i = inst_new(STORE_GLOBAL); inst* i = inst_new(STORE_GLOBAL);
i->imm.constant = constant; i->imm.constant = constant;
i->symbol = strdup(name); i->symbol = strdup(name);
i->any_unbound = 0;
return inst_block(i); return inst_block(i);
} }
@@ -211,6 +214,7 @@ block gen_op_unbound(opcode op, const char* name) {
assert(opcode_describe(op)->flags & OP_HAS_BINDING); assert(opcode_describe(op)->flags & OP_HAS_BINDING);
inst* i = inst_new(op); inst* i = inst_new(op);
i->symbol = strdup(name); i->symbol = strdup(name);
i->any_unbound = 1;
return inst_block(i); return inst_block(i);
} }
@@ -224,6 +228,7 @@ block gen_op_bound(opcode op, block binder) {
assert(block_is_single(binder)); assert(block_is_single(binder));
block b = gen_op_unbound(op, binder.first->symbol); block b = gen_op_unbound(op, binder.first->symbol);
b.first->bound_by = binder.first; b.first->bound_by = binder.first;
b.first->any_unbound = 0;
return b; return b;
} }
@@ -324,7 +329,7 @@ static int block_count_refs(block binder, block body) {
return nrefs; return nrefs;
} }
static int block_bind_subblock(block binder, block body, int bindflags, int break_distance) { static int block_bind_subblock_inner(int* any_unbound, block binder, block body, int bindflags, int break_distance) {
assert(block_is_single(binder)); assert(block_is_single(binder));
assert((opcode_describe(binder.first->op)->flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD)); assert((opcode_describe(binder.first->op)->flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD));
assert(binder.first->symbol); assert(binder.first->symbol);
@@ -336,6 +341,9 @@ static int block_bind_subblock(block binder, block body, int bindflags, int brea
binder.first->nformals = block_count_formals(binder); binder.first->nformals = block_count_formals(binder);
int nrefs = 0; int nrefs = 0;
for (inst* i = body.first; i; i = i->next) { for (inst* i = body.first; i; i = i->next) {
if (i->any_unbound == 0)
continue;
int flags = opcode_describe(i->op)->flags; int flags = opcode_describe(i->op)->flags;
if ((flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD) && i->bound_by == 0 && if ((flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD) && i->bound_by == 0 &&
(!strcmp(i->symbol, binder.first->symbol) || (!strcmp(i->symbol, binder.first->symbol) ||
@@ -357,14 +365,25 @@ static int block_bind_subblock(block binder, block body, int bindflags, int brea
// a break whenever we come across a STOREV of *anonlabel... // a break whenever we come across a STOREV of *anonlabel...
break_distance++; break_distance++;
} }
i->any_unbound = (i->symbol && !i->bound_by);
// binding recurses into closures // binding recurses into closures
nrefs += block_bind_subblock(binder, i->subfn, bindflags, break_distance); nrefs += block_bind_subblock_inner(&i->any_unbound, binder, i->subfn, bindflags, break_distance);
// binding recurses into argument list // binding recurses into argument list
nrefs += block_bind_subblock(binder, i->arglist, bindflags, break_distance); nrefs += block_bind_subblock_inner(&i->any_unbound, binder, i->arglist, bindflags, break_distance);
if (i->any_unbound)
*any_unbound = 1;
} }
return nrefs; return nrefs;
} }
static int block_bind_subblock(block binder, block body, int bindflags, int break_distance) {
int any_unbound;
return block_bind_subblock_inner(&any_unbound, binder, body, bindflags, break_distance);
}
static int block_bind_each(block binder, block body, int bindflags) { static int block_bind_each(block binder, block body, int bindflags) {
assert(block_has_only_binders(binder, bindflags)); assert(block_has_only_binders(binder, bindflags));
bindflags |= OP_HAS_BINDING; bindflags |= OP_HAS_BINDING;
@@ -550,6 +569,7 @@ block gen_function(const char* name, block formals, block body) {
} }
i->subfn = body; i->subfn = body;
i->symbol = strdup(name); i->symbol = strdup(name);
i->any_unbound = -1;
i->arglist = formals; i->arglist = formals;
block b = inst_block(i); block b = inst_block(i);
block_bind_subblock(b, b, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0); block_bind_subblock(b, b, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0);
@@ -1081,6 +1101,7 @@ block gen_cbinding(const struct cfunction* cfunctions, int ncfunctions, block co
inst* i = inst_new(CLOSURE_CREATE_C); inst* i = inst_new(CLOSURE_CREATE_C);
i->imm.cfunc = &cfunctions[cfunc]; i->imm.cfunc = &cfunctions[cfunc];
i->symbol = strdup(i->imm.cfunc->name); i->symbol = strdup(i->imm.cfunc->name);
i->any_unbound = 0;
code = block_bind(inst_block(i), code, OP_IS_CALL_PSEUDO); code = block_bind(inst_block(i), code, OP_IS_CALL_PSEUDO);
} }
return code; return code;