From c38e5b1b2c9b12fde377e3c183c2d496d17ba1d9 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Sun, 13 Jul 2014 18:36:27 -0500 Subject: [PATCH] Lib defs don't bind to each other; fix #479 again --- compile.c | 49 +++++++++++++++++++++++++++++++++++++++++-------- parser.y | 2 +- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/compile.c b/compile.c index 64ff41d0..b0ff054c 100644 --- a/compile.c +++ b/compile.c @@ -243,6 +243,20 @@ static int block_count_actuals(block b) { return args; } +static int block_count_refs(block binder, block body) { + int nrefs = 0; + for (inst* i = body.first; i; i = i->next) { + if (i != binder.first && i->bound_by == binder.first) { + nrefs++; + } + // counting recurses into closures + nrefs += block_count_refs(binder, i->subfn); + // counting recurses into argument list + nrefs += block_count_refs(binder, i->arglist); + } + return nrefs; +} + static int block_bind_subblock(block binder, block body, int bindflags) { assert(block_is_single(binder)); assert((opcode_describe(binder.first->op)->flags & bindflags) == bindflags); @@ -274,12 +288,14 @@ static int block_bind_subblock(block binder, block body, int bindflags) { return nrefs; } -static void 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)); bindflags |= OP_HAS_BINDING; + int nrefs = 0; for (inst* curr = binder.first; curr; curr = curr->next) { - block_bind_subblock(inst_block(curr), body, bindflags); + nrefs += block_bind_subblock(inst_block(curr), body, bindflags); } + return nrefs; } block block_bind(block binder, block body, int bindflags) { @@ -287,18 +303,35 @@ block block_bind(block binder, block body, int bindflags) { return block_join(binder, body); } +// Bind binder to body and throw away any defs in binder not referenced +// (directly or indirectly) from body. block block_bind_referenced(block binder, block body, int bindflags) { assert(block_has_only_binders(binder, bindflags)); bindflags |= OP_HAS_BINDING; block refd = gen_noop(); - for (inst* curr; (curr = block_take(&binder));) { - block b = inst_block(curr); - if (block_bind_subblock(b, body, bindflags)) { - refd = BLOCK(refd, b); - } else { - block_free(b); + block unrefd = gen_noop(); + int nrefs; + for (int last_kept = 0, kept = 0; ; ) { + for (inst* curr; (curr = block_take(&binder));) { + block b = inst_block(curr); + nrefs = block_bind_each(b, body, bindflags); + // Check if this binder is referenced from any of the ones we + // already know are referenced by body. + nrefs += block_count_refs(b, refd); + if (nrefs) { + refd = BLOCK(refd, b); + kept++; + } else { + unrefd = BLOCK(unrefd, b); + } } + if (kept == last_kept) + break; + last_kept = kept; + binder = unrefd; + unrefd = gen_noop(); } + block_free(unrefd); return block_join(refd, body); } diff --git a/parser.y b/parser.y index 55a01fa0..79483713 100644 --- a/parser.y +++ b/parser.y @@ -217,7 +217,7 @@ FuncDefs: $$ = gen_noop(); } | FuncDef FuncDefs { - $$ = block_join($1, $2); + $$ = block_bind($1, $2, OP_IS_CALL_PSEUDO); } Exp: