Skip to content

Commit

Permalink
Make builtin binding fast again by binding only referenced symbols
Browse files Browse the repository at this point in the history
Avoid doing the internal binding of top-level symbols in the parser,
leaving that work to be done in a post-processing step. For builtins,
this lets us do a reference-aware bind step (block_bind_incremental)
*after* generating builtins/0.

Libraries are a bit trickier since they may be bound multiple times, so
instead of thinking through the implications I added (block_bind_self)
to resolve all internal symbols immediately.
  • Loading branch information
muhmuhten authored and nicowilliams committed Feb 21, 2019
1 parent b2b0bd3 commit e843a4f
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 9 deletions.
4 changes: 2 additions & 2 deletions src/builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -1743,7 +1743,7 @@ static block bind_bytecoded_builtins(block b) {
BLOCK(gen_param("start"), gen_param("end")),
range));
}
return block_bind(builtins, b, OP_IS_CALL_PSEUDO);
return BLOCK(builtins, b);
}

static const char jq_builtins[] =
Expand Down Expand Up @@ -1793,7 +1793,7 @@ int builtins_bind(jq_state *jq, block* bb) {
builtins = gen_cbinding(function_list, sizeof(function_list)/sizeof(function_list[0]), builtins);
builtins = gen_builtin_list(builtins);

*bb = block_bind(builtins, *bb, OP_IS_CALL_PSEUDO);
*bb = block_bind_incremental(builtins, *bb, OP_IS_CALL_PSEUDO);
*bb = block_drop_unreferenced(*bb);
return nerrors;
}
51 changes: 47 additions & 4 deletions src/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,9 @@ block gen_op_unbound(opcode op, const char* name) {

block gen_op_var_fresh(opcode op, const char* name) {
assert(opcode_describe(op)->flags & OP_HAS_VARIABLE);
return block_bind(gen_op_unbound(op, name),
gen_noop(), OP_HAS_VARIABLE);
block b = gen_op_unbound(op, name);
b.first->bound_by = b.first;
return b;
}

block gen_op_bound(opcode op, block binder) {
Expand Down Expand Up @@ -382,7 +383,7 @@ static int block_bind_each(block binder, block body, int bindflags) {
return nrefs;
}

block block_bind(block binder, block body, int bindflags) {
static block block_bind(block binder, block body, int bindflags) {
block_bind_each(binder, body, bindflags);
return block_join(binder, body);
}
Expand Down Expand Up @@ -434,6 +435,48 @@ block block_bind_referenced(block binder, block body, int bindflags) {
return body;
}

static inst* block_take_last(block* b) {
inst* i = b->last;
if (i == 0)
return 0;
if (i->prev) {
i->prev->next = i->next;
b->last = i->prev;
i->prev = 0;
} else {
b->first = 0;
b->last = 0;
}
return i;
}

// Binds a sequence of binders, which *must not* alrady be bound to each other,
// to body, throwing away unreferenced defs
block block_bind_incremental(block binder, block body, int bindflags) {
assert(block_has_only_binders(binder, bindflags));
bindflags |= OP_HAS_BINDING;

inst* curr;
while ((curr = block_take_last(&binder))) {
body = block_bind_referenced(inst_block(curr), body, bindflags);
}
return body;
}

block block_bind_self(block binder, int bindflags) {
assert(block_has_only_binders(binder, bindflags));
bindflags |= OP_HAS_BINDING;
block body = gen_noop();

inst* curr;
while ((curr = block_take_last(&binder))) {
block b = inst_block(curr);
block_bind_subblock(b, body, bindflags, 0);
body = BLOCK(b, body);
}
return body;
}

static void block_mark_referenced(block body) {
int saw_top = 0;
for (inst* i = body.last; i; i = i->prev) {
Expand Down Expand Up @@ -1074,7 +1117,7 @@ block gen_cbinding(const struct cfunction* cfunctions, int ncfunctions, block co
i->imm.cfunc = &cfunctions[cfunc];
i->symbol = strdup(i->imm.cfunc->name);
i->any_unbound = 0;
code = block_bind(inst_block(i), code, OP_IS_CALL_PSEUDO);
code = BLOCK(inst_block(i), code);
}
return code;
}
Expand Down
3 changes: 2 additions & 1 deletion src/compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,10 @@ int block_has_only_binders(block, int bindflags);
int block_has_main(block);
int block_is_funcdef(block b);
int block_is_single(block b);
block block_bind(block binder, block body, int bindflags);
block block_bind_library(block binder, block body, int bindflags, const char* libname);
block block_bind_referenced(block binder, block body, int bindflags);
block block_bind_incremental(block binder, block body, int bindflags);
block block_bind_self(block binder, int bindflags);
block block_drop_unreferenced(block body);

jv block_take_imports(block* body);
Expand Down
1 change: 1 addition & 0 deletions src/linker.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ static int load_library(jq_state *jq, jv lib_path, int is_data, int raw, const c
jv_string(dirname(lib_origin)),
&program, lib_state);
free(lib_origin);
program = block_bind_self(program, OP_IS_CALL_PSEUDO);
}
}
state_idx = lib_state->ct++;
Expand Down
2 changes: 1 addition & 1 deletion src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -2423,7 +2423,7 @@ YYLTYPE yylloc = yyloc_default;
case 9:
#line 333 "src/parser.y" /* yacc.c:1646 */
{
(yyval.blk) = block_bind((yyvsp[-1].blk), (yyvsp[0].blk), OP_IS_CALL_PSEUDO);
(yyval.blk) = block_join((yyvsp[-1].blk), (yyvsp[0].blk));
}
#line 2429 "src/parser.c" /* yacc.c:1646 */
break;
Expand Down
2 changes: 1 addition & 1 deletion src/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ FuncDefs:
$$ = gen_noop();
} |
FuncDef FuncDefs {
$$ = block_bind($1, $2, OP_IS_CALL_PSEUDO);
$$ = block_join($1, $2);
}

Exp:
Expand Down

0 comments on commit e843a4f

Please sign in to comment.