fast compile

This commit is contained in:
Yuichi Nishiwaki 2015-06-27 15:30:17 +09:00
parent 4a8e59e04b
commit 03792f85de
1 changed files with 92 additions and 120 deletions

View File

@ -331,9 +331,8 @@ pic_expand(pic_state *pic, pic_value expr, struct pic_env *env)
return v; return v;
} }
typedef kvec_t(pic_sym *) svec_t; KHASH_DECLARE(a, pic_sym *, int)
KHASH_DEFINE2(a, pic_sym *, int, 0, kh_ptr_hash_func, kh_ptr_hash_equal)
#define kv_push_sym(v, x) kv_push(pic_sym *, (v), (x))
/** /**
* scope object * scope object
@ -341,8 +340,8 @@ typedef kvec_t(pic_sym *) svec_t;
typedef struct analyze_scope { typedef struct analyze_scope {
int depth; int depth;
bool varg; pic_sym *rest; /* Nullable */
svec_t args, locals, captures; /* rest args variable is counted as a local */ khash_t(a) args, locals, captures; /* rest args variable is counted as a local */
pic_value defer; pic_value defer;
struct analyze_scope *up; struct analyze_scope *up;
} analyze_scope; } analyze_scope;
@ -364,6 +363,7 @@ analyze_state_init(analyze_state *state, pic_state *pic)
{ {
pic_sym *sym; pic_sym *sym;
khiter_t it; khiter_t it;
int ret;
state->pic = pic; state->pic = pic;
state->scope = NULL; state->scope = NULL;
@ -372,7 +372,7 @@ analyze_state_init(analyze_state *state, pic_state *pic)
push_scope(state, &state->s, pic_nil_value()); push_scope(state, &state->s, pic_nil_value());
pic_dict_for_each (sym, pic->globals, it) { pic_dict_for_each (sym, pic->globals, it) {
kv_push_sym(state->scope->locals, sym); kh_put(a, &state->scope->locals, sym, &ret);
} }
} }
@ -383,26 +383,24 @@ analyze_state_destroy(analyze_state *state)
} }
static bool static bool
analyze_args(pic_state *pic, pic_value formals, bool *varg, svec_t *args, svec_t *locals) analyze_args(pic_state *pic, pic_value formals, analyze_scope *scope)
{ {
pic_value v, t; pic_value v, t;
pic_sym *sym; int ret;
for (v = formals; pic_pair_p(v); v = pic_cdr(pic, v)) { for (v = formals; pic_pair_p(v); v = pic_cdr(pic, v)) {
t = pic_car(pic, v); t = pic_car(pic, v);
if (! pic_sym_p(t)) { if (! pic_sym_p(t)) {
return false; return false;
} }
sym = pic_sym_ptr(t); kh_put(a, &scope->args, pic_sym_ptr(t), &ret);
kv_push_sym(*args, sym);
} }
if (pic_nil_p(v)) { if (pic_nil_p(v)) {
*varg = false; scope->rest = NULL;
} }
else if (pic_sym_p(v)) { else if (pic_sym_p(v)) {
*varg = true; scope->rest = pic_sym_ptr(v);
sym = pic_sym_ptr(v); kh_put(a, &scope->locals, pic_sym_ptr(v), &ret);
kv_push_sym(*locals, sym);
} }
else { else {
return false; return false;
@ -415,16 +413,14 @@ static bool
push_scope(analyze_state *state, analyze_scope *scope, pic_value formals) push_scope(analyze_state *state, analyze_scope *scope, pic_value formals)
{ {
pic_state *pic = state->pic; pic_state *pic = state->pic;
bool varg;
kv_init(scope->args); kh_init(a, &scope->args);
kv_init(scope->locals); kh_init(a, &scope->locals);
kv_init(scope->captures); kh_init(a, &scope->captures);
if (analyze_args(pic, formals, &varg, &scope->args, &scope->locals)) { if (analyze_args(pic, formals, scope)) {
scope->up = state->scope; scope->up = state->scope;
scope->depth = scope->up ? scope->up->depth + 1 : 0; scope->depth = scope->up ? scope->up->depth + 1 : 0;
scope->varg = varg;
scope->defer = pic_nil_value(); scope->defer = pic_nil_value();
state->scope = scope; state->scope = scope;
@ -432,9 +428,9 @@ push_scope(analyze_state *state, analyze_scope *scope, pic_value formals)
return true; return true;
} }
else { else {
kv_destroy(scope->args); kh_destroy(a, &scope->args);
kv_destroy(scope->locals); kh_destroy(a, &scope->locals);
kv_destroy(scope->captures); kh_destroy(a, &scope->captures);
return false; return false;
} }
} }
@ -446,9 +442,9 @@ pop_scope(analyze_state *state)
analyze_scope *scope; analyze_scope *scope;
scope = state->scope; scope = state->scope;
kv_destroy(scope->args); kh_destroy(a, &scope->args);
kv_destroy(scope->locals); kh_destroy(a, &scope->locals);
kv_destroy(scope->captures); kh_destroy(a, &scope->captures);
scope = scope->up; scope = scope->up;
state->scope = scope; state->scope = scope;
@ -457,34 +453,15 @@ pop_scope(analyze_state *state)
static bool static bool
lookup_scope(analyze_scope *scope, pic_sym *sym) lookup_scope(analyze_scope *scope, pic_sym *sym)
{ {
size_t i; return kh_get(a, &scope->args, sym) != kh_end(&scope->args) || kh_get(a, &scope->locals, sym) != kh_end(&scope->locals);
/* args */
for (i = 0; i < kv_size(scope->args); ++i) {
if (kv_A(scope->args, i) == sym)
return true;
}
/* locals */
for (i = 0; i < kv_size(scope->locals); ++i) {
if (kv_A(scope->locals, i) == sym)
return true;
}
return false;
} }
static void static void
capture_var(pic_state *pic, analyze_scope *scope, pic_sym *sym) capture_var(pic_state *pic, analyze_scope *scope, pic_sym *sym)
{ {
size_t i; int ret;
for (i = 0; i < kv_size(scope->captures); ++i) { kh_put(a, &scope->captures, sym, &ret);
if (kv_A(scope->captures, i) == sym) {
break;
}
}
if (i == kv_size(scope->captures)) {
kv_push_sym(scope->captures, sym);
}
} }
static int static int
@ -511,13 +488,14 @@ define_var(analyze_state *state, pic_sym *sym)
{ {
pic_state *pic = state->pic; pic_state *pic = state->pic;
analyze_scope *scope = state->scope; analyze_scope *scope = state->scope;
int ret;
if (lookup_scope(scope, sym)) { if (lookup_scope(scope, sym)) {
pic_warnf(pic, "redefining variable: ~s", pic_obj_value(sym)); pic_warnf(pic, "redefining variable: ~s", pic_obj_value(sym));
return; return;
} }
kv_push_sym(scope->locals, sym); kh_put(a, &scope->locals, sym, &ret);
} }
static pic_value analyze_node(analyze_state *, pic_value, bool); static pic_value analyze_node(analyze_state *, pic_value, bool);
@ -633,36 +611,40 @@ analyze_procedure(analyze_state *state, pic_value name, pic_value formals, pic_v
{ {
pic_state *pic = state->pic; pic_state *pic = state->pic;
analyze_scope scope; analyze_scope scope;
pic_value args, locals, varg, captures, body; pic_value rest = pic_undef_value(), body;
pic_vec *args, *locals, *captures;
assert(pic_sym_p(name) || pic_false_p(name)); assert(pic_sym_p(name) || pic_false_p(name));
if (push_scope(state, &scope, formals)) { if (push_scope(state, &scope, formals)) {
analyze_scope *scope = state->scope; analyze_scope *scope = state->scope;
size_t i; size_t i, j;
args = pic_nil_value(); /* analyze body */
for (i = kv_size(scope->args); i > 0; --i) {
pic_push(pic, pic_obj_value(kv_A(scope->args, i - 1)), args);
}
varg = scope->varg
? pic_true_value()
: pic_false_value();
/* To know what kind of local variables are defined, analyze body at first. */
body = analyze(state, pic_cons(pic, pic_obj_value(pic->uBEGIN), body_exprs), true); body = analyze(state, pic_cons(pic, pic_obj_value(pic->uBEGIN), body_exprs), true);
analyze_deferred(state); analyze_deferred(state);
locals = pic_nil_value(); args = pic_make_vec(pic, kh_size(&scope->args));
for (i = kv_size(scope->locals); i > 0; --i) { for (i = 0; pic_pair_p(formals); formals = pic_cdr(pic, formals), i++) {
pic_push(pic, pic_obj_value(kv_A(scope->locals, i - 1)), locals); args->data[i] = pic_car(pic, formals);
} }
captures = pic_nil_value(); if (scope->rest != NULL) {
for (i = kv_size(scope->captures); i > 0; --i) { rest = pic_obj_value(scope->rest);
pic_push(pic, pic_obj_value(kv_A(scope->captures, i - 1)), captures); }
locals = pic_make_vec(pic, kh_size(&scope->locals));
for (i = kh_begin(&scope->locals), j = 0; i < kh_end(&scope->locals); ++i) {
if (kh_exist(&scope->locals, i)) {
locals->data[j++] = pic_obj_value(kh_key(&scope->locals, i));
}
}
captures = pic_make_vec(pic, kh_size(&scope->captures));
for (i = kh_begin(&scope->captures), j = 0; i < kh_end(&scope->captures); ++i) {
if (kh_exist(&scope->captures, i)) {
captures->data[j++] = pic_obj_value(kh_key(&scope->captures, i));
}
} }
pop_scope(state); pop_scope(state);
@ -671,7 +653,7 @@ analyze_procedure(analyze_state *state, pic_value name, pic_value formals, pic_v
pic_errorf(pic, "invalid formal syntax: ~s", formals); pic_errorf(pic, "invalid formal syntax: ~s", formals);
} }
return pic_list7(pic, pic_obj_value(pic->sLAMBDA), name, args, locals, varg, captures, body); return pic_list7(pic, pic_obj_value(pic->sLAMBDA), name, rest, pic_obj_value(args), pic_obj_value(locals), pic_obj_value(captures), body);
} }
static pic_value static pic_value
@ -1134,8 +1116,8 @@ pic_analyze(pic_state *pic, pic_value obj)
typedef struct codegen_context { typedef struct codegen_context {
pic_sym *name; pic_sym *name;
/* rest args variable is counted as a local */ /* rest args variable is counted as a local */
bool varg; pic_sym *rest;
svec_t args, locals, captures; pic_vec *args, *locals, *captures;
/* actual bit code sequence */ /* actual bit code sequence */
pic_code *code; pic_code *code;
size_t clen, ccapa; size_t clen, ccapa;
@ -1161,16 +1143,18 @@ typedef struct codegen_state {
codegen_context c, *cxt; codegen_context c, *cxt;
} codegen_state; } codegen_state;
static void push_codegen_context(codegen_state *, codegen_context *, pic_value, pic_value, pic_value, bool, pic_value); static void push_codegen_context(codegen_state *, codegen_context *, pic_value, pic_sym *, pic_vec *, pic_vec *, pic_vec *);
static struct pic_irep *pop_codegen_context(codegen_state *); static struct pic_irep *pop_codegen_context(codegen_state *);
static void static void
codegen_state_init(codegen_state *state, pic_state *pic) codegen_state_init(codegen_state *state, pic_state *pic)
{ {
pic_vec *empty = pic_make_vec(pic, 0);
state->pic = pic; state->pic = pic;
state->cxt = NULL; state->cxt = NULL;
push_codegen_context(state, &state->c, pic_false_value(), pic_nil_value(), pic_nil_value(), false, pic_nil_value()); push_codegen_context(state, &state->c, pic_false_value(), NULL, empty, empty, empty);
} }
static struct pic_irep * static struct pic_irep *
@ -1255,19 +1239,19 @@ create_activation(codegen_state *state)
regs = pic_make_reg(pic); regs = pic_make_reg(pic);
offset = 1; offset = 1;
for (i = 0; i < kv_size(cxt->args); ++i) { for (i = 0; i < cxt->args->len; ++i) {
n = i + offset; n = i + offset;
pic_reg_set(pic, regs, kv_A(cxt->args, i), pic_size_value(n)); pic_reg_set(pic, regs, pic_sym_ptr(cxt->args->data[i]), pic_size_value(n));
} }
offset += i; offset += i;
for (i = 0; i < kv_size(cxt->locals); ++i) { for (i = 0; i < cxt->locals->len; ++i) {
n = i + offset; n = i + offset;
pic_reg_set(pic, regs, kv_A(cxt->locals, i), pic_size_value(n)); pic_reg_set(pic, regs, pic_sym_ptr(cxt->locals->data[i]), pic_size_value(n));
} }
for (i = 0; i < kv_size(cxt->captures); ++i) { for (i = 0; i < cxt->captures->len; ++i) {
n = (size_t)pic_int(pic_reg_ref(pic, regs, kv_A(cxt->captures, i))); n = (size_t)pic_int(pic_reg_ref(pic, regs, pic_sym_ptr(cxt->captures->data[i])));
if (n <= kv_size(cxt->args) || (cxt->varg && n == kv_size(cxt->args) + 1)) { if (n <= cxt->args->len || cxt->rest == pic_sym_ptr(cxt->captures->data[i])) {
/* copy arguments to capture variable area */ /* copy arguments to capture variable area */
emit_i(state, OP_LREF, (int)n); emit_i(state, OP_LREF, (int)n);
} else { } else {
@ -1278,10 +1262,9 @@ create_activation(codegen_state *state)
} }
static void static void
push_codegen_context(codegen_state *state, codegen_context *cxt, pic_value name, pic_value args, pic_value locals, bool varg, pic_value captures) push_codegen_context(codegen_state *state, codegen_context *cxt, pic_value name, pic_sym *rest, pic_vec *args, pic_vec *locals, pic_vec *captures)
{ {
pic_state *pic = state->pic; pic_state *pic = state->pic;
pic_value var, it;
assert(pic_sym_p(name) || pic_false_p(name)); assert(pic_sym_p(name) || pic_false_p(name));
@ -1289,21 +1272,11 @@ push_codegen_context(codegen_state *state, codegen_context *cxt, pic_value name,
cxt->name = pic_false_p(name) cxt->name = pic_false_p(name)
? pic_intern_cstr(pic, "(anonymous lambda)") ? pic_intern_cstr(pic, "(anonymous lambda)")
: pic_sym_ptr(name); : pic_sym_ptr(name);
cxt->varg = varg; cxt->rest = rest;
kv_init(cxt->args); cxt->args = args;
kv_init(cxt->locals); cxt->locals = locals;
kv_init(cxt->captures); cxt->captures = captures;
pic_for_each (var, args, it) {
kv_push_sym(cxt->args, pic_sym_ptr(var));
}
pic_for_each (var, locals, it) {
kv_push_sym(cxt->locals, pic_sym_ptr(var));
}
pic_for_each (var, captures, it) {
kv_push_sym(cxt->captures, pic_sym_ptr(var));
}
cxt->code = pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(pic_code)); cxt->code = pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(pic_code));
cxt->clen = 0; cxt->clen = 0;
@ -1336,10 +1309,10 @@ pop_codegen_context(codegen_state *state)
/* create irep */ /* create irep */
irep = (struct pic_irep *)pic_obj_alloc(pic, sizeof(struct pic_irep), PIC_TT_IREP); irep = (struct pic_irep *)pic_obj_alloc(pic, sizeof(struct pic_irep), PIC_TT_IREP);
irep->name = state->cxt->name; irep->name = state->cxt->name;
irep->varg = state->cxt->varg; irep->varg = state->cxt->rest != NULL;
irep->argc = (int)kv_size(state->cxt->args) + 1; irep->argc = (int)state->cxt->args->len + 1;
irep->localc = (int)kv_size(state->cxt->locals); irep->localc = (int)state->cxt->locals->len;
irep->capturec = (int)kv_size(state->cxt->captures); irep->capturec = (int)state->cxt->captures->len;
irep->code = pic_realloc(pic, state->cxt->code, sizeof(pic_code) * state->cxt->clen); irep->code = pic_realloc(pic, state->cxt->code, sizeof(pic_code) * state->cxt->clen);
irep->clen = state->cxt->clen; irep->clen = state->cxt->clen;
irep->irep = pic_realloc(pic, state->cxt->irep, sizeof(struct pic_irep *) * state->cxt->ilen); irep->irep = pic_realloc(pic, state->cxt->irep, sizeof(struct pic_irep *) * state->cxt->ilen);
@ -1349,11 +1322,6 @@ pop_codegen_context(codegen_state *state)
irep->syms = pic_realloc(pic, state->cxt->syms, sizeof(pic_sym *) * state->cxt->slen); irep->syms = pic_realloc(pic, state->cxt->syms, sizeof(pic_sym *) * state->cxt->slen);
irep->slen = state->cxt->slen; irep->slen = state->cxt->slen;
/* finalize */
kv_destroy(cxt->args);
kv_destroy(cxt->locals);
kv_destroy(cxt->captures);
/* destroy context */ /* destroy context */
cxt = cxt->up; cxt = cxt->up;
state->cxt = cxt; state->cxt = cxt;
@ -1371,8 +1339,8 @@ index_capture(codegen_state *state, pic_sym *sym, int depth)
cxt = cxt->up; cxt = cxt->up;
} }
for (i = 0; i < kv_size(cxt->captures); ++i) { for (i = 0; i < cxt->captures->len; ++i) {
if (kv_A(cxt->captures, i) == sym) if (pic_sym_ptr(cxt->captures->data[i]) == sym)
return (int)i; return (int)i;
} }
return -1; return -1;
@ -1385,13 +1353,13 @@ index_local(codegen_state *state, pic_sym *sym)
size_t i, offset; size_t i, offset;
offset = 1; offset = 1;
for (i = 0; i < kv_size(cxt->args); ++i) { for (i = 0; i < cxt->args->len; ++i) {
if (kv_A(cxt->args, i) == sym) if (pic_sym_ptr(cxt->args->data[i]) == sym)
return (int)(i + offset); return (int)(i + offset);
} }
offset += i; offset += i;
for (i = 0; i < kv_size(cxt->locals); ++i) { for (i = 0; i < cxt->locals->len; ++i) {
if (kv_A(cxt->locals, i) == sym) if (pic_sym_ptr(cxt->locals->data[i]) == sym)
return (int)(i + offset); return (int)(i + offset);
} }
return -1; return -1;
@ -1444,7 +1412,7 @@ codegen(codegen_state *state, pic_value obj)
name = pic_sym_ptr(pic_list_ref(pic, obj, 1)); name = pic_sym_ptr(pic_list_ref(pic, obj, 1));
if ((i = index_capture(state, name, 0)) != -1) { if ((i = index_capture(state, name, 0)) != -1) {
emit_i(state, OP_LREF, i + (int)kv_size(cxt->args) + (int)kv_size(cxt->locals) + 1); emit_i(state, OP_LREF, i + (int)cxt->args->len + (int)cxt->locals->len + 1);
return; return;
} }
emit_i(state, OP_LREF, index_local(state, name)); emit_i(state, OP_LREF, index_local(state, name));
@ -1479,7 +1447,7 @@ codegen(codegen_state *state, pic_value obj)
name = pic_sym_ptr(pic_list_ref(pic, var, 1)); name = pic_sym_ptr(pic_list_ref(pic, var, 1));
if ((i = index_capture(state, name, 0)) != -1) { if ((i = index_capture(state, name, 0)) != -1) {
emit_i(state, OP_LSET, i + (int)kv_size(cxt->args) + (int)kv_size(cxt->locals) + 1); emit_i(state, OP_LSET, i + (int)cxt->args->len + (int)cxt->locals->len + 1);
emit_n(state, OP_PUSHUNDEF); emit_n(state, OP_PUSHUNDEF);
return; return;
} }
@ -1697,18 +1665,22 @@ codegen_lambda(codegen_state *state, pic_value obj)
{ {
pic_state *pic = state->pic; pic_state *pic = state->pic;
codegen_context cxt; codegen_context cxt;
pic_value name, args, locals, closes, body; pic_value name, rest_opt, body;
bool varg; pic_sym *rest = NULL;
pic_vec *args, *locals, *captures;
name = pic_list_ref(pic, obj, 1); name = pic_list_ref(pic, obj, 1);
args = pic_list_ref(pic, obj, 2); rest_opt = pic_list_ref(pic, obj, 2);
locals = pic_list_ref(pic, obj, 3); if (pic_sym_p(rest_opt)) {
varg = pic_true_p(pic_list_ref(pic, obj, 4)); rest = pic_sym_ptr(rest_opt);
closes = pic_list_ref(pic, obj, 5); }
args = pic_vec_ptr(pic_list_ref(pic, obj, 3));
locals = pic_vec_ptr(pic_list_ref(pic, obj, 4));
captures = pic_vec_ptr(pic_list_ref(pic, obj, 5));
body = pic_list_ref(pic, obj, 6); body = pic_list_ref(pic, obj, 6);
/* inner environment */ /* inner environment */
push_codegen_context(state, &cxt, name, args, locals, varg, closes); push_codegen_context(state, &cxt, name, rest, args, locals, captures);
{ {
/* body */ /* body */
codegen(state, body); codegen(state, body);