diff options
-rw-r--r-- | builtin.c | 4 | ||||
-rw-r--r-- | compile.c | 24 | ||||
-rw-r--r-- | compile.h | 1 |
3 files changed, 24 insertions, 5 deletions
@@ -543,7 +543,7 @@ static block bind_bytecoded_builtins(block b) { range)); } - return block_bind(builtins, b, OP_IS_CALL_PSEUDO); + return block_bind_referenced(builtins, b, OP_IS_CALL_PSEUDO); } static const char* const jq_builtins[] = { @@ -572,7 +572,7 @@ block builtins_bind(block b) { block funcs; int nerrors = jq_parse_library(&src, &funcs); assert(!nerrors); - b = block_bind(funcs, b, OP_IS_CALL_PSEUDO); + b = block_bind_referenced(funcs, b, OP_IS_CALL_PSEUDO); locfile_free(&src); } b = bind_bytecoded_builtins(b); @@ -216,13 +216,14 @@ int block_has_only_binders(block binders, int bindflags) { return 1; } -static void block_bind_subblock(block binder, block body, int bindflags) { +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); assert(binder.first->symbol); assert(binder.first->bound_by == 0 || binder.first->bound_by == binder.first); binder.first->bound_by = binder.first; + int nrefs = 0; for (inst* i = body.first; i; i = i->next) { int flags = opcode_describe(i->op)->flags; if ((flags & bindflags) == bindflags && @@ -230,12 +231,14 @@ static void block_bind_subblock(block binder, block body, int bindflags) { !strcmp(i->symbol, binder.first->symbol)) { // bind this instruction i->bound_by = binder.first; + nrefs++; } // binding recurses into closures - block_bind_subblock(binder, i->subfn, bindflags); + nrefs += block_bind_subblock(binder, i->subfn, bindflags); // binding recurses into argument list - block_bind_subblock(binder, i->arglist, bindflags); + nrefs += block_bind_subblock(binder, i->arglist, bindflags); } + return nrefs; } static void block_bind_each(block binder, block body, int bindflags) { @@ -251,6 +254,21 @@ block block_bind(block binder, block body, int bindflags) { return block_join(binder, 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); + } + } + return block_join(refd, body); +} + block gen_function(const char* name, block formals, block body) { block_bind_each(formals, body, OP_IS_CALL_PSEUDO); inst* i = inst_new(CLOSURE_CREATE); @@ -50,6 +50,7 @@ void block_append(block* b, block b2); block block_join(block a, block b); int block_has_only_binders(block, int bindflags); block block_bind(block binder, block body, int bindflags); +block block_bind_referenced(block binder, block body, int bindflags); int block_compile(block, struct locfile*, struct bytecode**); |