optimizing let compilation

This commit is contained in:
Alex Shinn 2009-03-11 01:25:56 +09:00
parent ec57daaf5f
commit 66b44631e4
2 changed files with 73 additions and 24 deletions

95
eval.c
View file

@ -54,18 +54,24 @@ static void env_define(env e, sexp key, sexp value) {
} }
} }
static env extend_env_closure (env e, sexp fv) { static env extend_env_closure (env e, sexp fv, int offset) {
int i; int i;
env e2 = (env) SEXP_ALLOC(sizeof(struct env)); env e2 = (env) SEXP_ALLOC(sizeof(struct env));
e2->tag = SEXP_ENV; e2->tag = SEXP_ENV;
e2->parent = e; e2->parent = e;
e2->bindings = SEXP_NULL; e2->bindings = SEXP_NULL;
for (i=0; SEXP_PAIRP(fv); fv = SEXP_CDR(fv), i++) for (i=offset; SEXP_PAIRP(fv); fv = SEXP_CDR(fv), i--)
e2->bindings = sexp_cons(sexp_cons(SEXP_CAR(fv), sexp_make_integer(i)), e2->bindings = sexp_cons(sexp_cons(SEXP_CAR(fv), sexp_make_integer(i)),
e2->bindings); e2->bindings);
return e2; return e2;
} }
static int core_code (env e, sexp sym) {
sexp cell = env_cell(e, sym);
if (! cell || ! SEXP_COREP(SEXP_CDR(cell))) return 0;
return (((core_form)SEXP_CDR(cell))->code);
}
static sexp sexp_reverse_flatten_dot (sexp ls) { static sexp sexp_reverse_flatten_dot (sexp ls) {
sexp res; sexp res;
for (res=SEXP_NULL; SEXP_PAIRP(ls); ls=SEXP_CDR(ls)) for (res=SEXP_NULL; SEXP_PAIRP(ls); ls=SEXP_CDR(ls))
@ -136,7 +142,7 @@ static sexp sexp_make_procedure(char flags, unsigned short num_args,
void analyze(sexp obj, bytecode *bc, unsigned int *i, env e, void analyze(sexp obj, bytecode *bc, unsigned int *i, env e,
sexp params, sexp fv, sexp sv, unsigned int *d, int tailp) { sexp params, sexp fv, sexp sv, unsigned int *d, int tailp) {
int tmp1, tmp2, tmp3; int tmp1, tmp2, tmp3;
env e2 = e; env e2;
sexp o1, o2, cell; sexp o1, o2, cell;
if (SEXP_PAIRP(obj)) { if (SEXP_PAIRP(obj)) {
@ -156,18 +162,21 @@ void analyze(sexp obj, bytecode *bc, unsigned int *i, env e,
case CORE_DEFINE: case CORE_DEFINE:
if ((((core_form)o1)->code == CORE_DEFINE) if ((((core_form)o1)->code == CORE_DEFINE)
&& SEXP_PAIRP(SEXP_CADR(obj))) { && SEXP_PAIRP(SEXP_CADR(obj))) {
o2 = SEXP_CAR(SEXP_CADR(obj));
analyze_lambda(SEXP_CAR(SEXP_CADR(obj)), analyze_lambda(SEXP_CAR(SEXP_CADR(obj)),
SEXP_CDR(SEXP_CADR(obj)), SEXP_CDR(SEXP_CADR(obj)),
SEXP_CDDR(obj), SEXP_CDDR(obj),
bc, i, e, params, fv, sv, d, 0); bc, i, e, params, fv, sv, d, 0);
} else { } else {
o2 = SEXP_CADR(obj);
analyze(SEXP_CADDR(obj), bc, i, e, params, fv, sv, d, 0); analyze(SEXP_CADDR(obj), bc, i, e, params, fv, sv, d, 0);
} }
emit(bc, i, OP_GLOBAL_SET); if (! e->parent) {
emit_word(bc, i, (sexp_uint_t) (SEXP_PAIRP(SEXP_CADR(obj)) emit(bc, i, OP_GLOBAL_SET);
? SEXP_CAR(SEXP_CADR(obj)) emit_word(bc, i, (sexp_uint_t) o2);
: SEXP_CADR(obj))); emit_push(bc, i, SEXP_UNDEF);
emit_push(bc, i, SEXP_UNDEF); } else {
}
(*d)++; (*d)++;
break; break;
case CORE_SET: case CORE_SET:
@ -285,14 +294,33 @@ void analyze(sexp obj, bytecode *bc, unsigned int *i, env e,
} }
} else if (SEXP_PAIRP(SEXP_CAR(obj))) { } else if (SEXP_PAIRP(SEXP_CAR(obj))) {
o2 = env_cell(e, SEXP_CAAR(obj)); o2 = env_cell(e, SEXP_CAAR(obj));
/* if (o2 */ if (o2
/* && SEXP_COREP(SEXP_CDR(o2)) */ && SEXP_COREP(SEXP_CDR(o2))
/* && (((core_form)SEXP_CDR(o2))->code == CORE_LAMBDA)) { */ && (((core_form)SEXP_CDR(o2))->code == CORE_LAMBDA)
/* /\* let *\/ */ && sexp_listp(SEXP_CADR(SEXP_CAR(obj)))) {
/* } else { */ /* let */
tmp1 = sexp_length(SEXP_CADR(SEXP_CAR(obj)));
e2 = extend_env_closure(e, SEXP_CADR(SEXP_CAR(obj)), (*d));
for (o2=sexp_reverse(SEXP_CDR(obj)); SEXP_PAIRP(o2); o2=SEXP_CDR(o2))
analyze(SEXP_CAR(o2), bc, i, e, params, fv, sv, d, 0);
params = sexp_append(SEXP_CADR(SEXP_CAR(obj)), params);
for (o2=SEXP_CDDR(SEXP_CAR(obj)); SEXP_PAIRP(o2); o2=SEXP_CDR(o2)) {
if (SEXP_PAIRP(SEXP_CDR(o2))) {
analyze(SEXP_CAR(o2), bc, i, e2, params, fv, sv, d, 0);
emit(bc, i, OP_DROP);
} else {
analyze(SEXP_CAR(o2), bc, i, e2, params, fv, sv, d, tailp);
}
}
emit(bc, i, OP_STACK_SET);
emit_word(bc, i, tmp1+1);
(*d) -= tmp1;
for (tmp1; tmp1>0; tmp1--)
emit(bc, i, OP_DROP);
} else {
/* computed application */ /* computed application */
analyze_app(obj, bc, i, e, params, fv, sv, d, tailp); analyze_app(obj, bc, i, e, params, fv, sv, d, tailp);
/* } */ }
} else { } else {
errx(1, "invalid operator: %s", SEXP_CAR(obj)); errx(1, "invalid operator: %s", SEXP_CAR(obj));
} }
@ -307,13 +335,15 @@ void analyze(sexp obj, bytecode *bc, unsigned int *i, env e,
void analyze_var_ref (sexp obj, bytecode *bc, unsigned int *i, env e, void analyze_var_ref (sexp obj, bytecode *bc, unsigned int *i, env e,
sexp params, sexp fv, sexp sv, unsigned int *d) { sexp params, sexp fv, sexp sv, unsigned int *d) {
int tmp; int tmp;
sexp o1;
/* fprintf(stderr, "symbol lookup, param length: %d sv: ", length(params)); */ /* fprintf(stderr, "symbol lookup, param length: %d sv: ", length(params)); */
/* sexp_write(sv, stderr); */ /* sexp_write(sv, stderr); */
/* fprintf(stderr, "\n"); */ /* fprintf(stderr, "\n"); */
if ((tmp = sexp_list_index(params, obj)) >= 0) { if ((tmp = sexp_list_index(params, obj)) >= 0) {
/* fprintf(stderr, "compiling local ref: %p => %d (d = %d)\n", obj, tmp, *d); */ /* fprintf(stderr, "compiling local ref: %p => %d (d = %d)\n", obj, tmp, *d); */
o1 = env_cell(e, obj);
emit(bc, i, OP_STACK_REF); emit(bc, i, OP_STACK_REF);
emit_word(bc, i, tmp + *d + 4); emit_word(bc, i, *d - sexp_unbox_integer(SEXP_CDR(o1)));
} else if ((tmp = sexp_list_index(fv, obj)) >= 0) { } else if ((tmp = sexp_list_index(fv, obj)) >= 0) {
/* fprintf(stderr, "compiling closure ref: %p => %d\n", obj, tmp); */ /* fprintf(stderr, "compiling closure ref: %p => %d\n", obj, tmp); */
emit(bc, i, OP_CLOSURE_REF); emit(bc, i, OP_CLOSURE_REF);
@ -345,10 +375,6 @@ void analyze_app (sexp obj, bytecode *bc, unsigned int *i, env e,
/* maybe overwrite the current frame */ /* maybe overwrite the current frame */
if (tailp) { if (tailp) {
/* args ... */
/* i */
/* ip */
/* cp */
emit(bc, i, OP_TAIL_CALL); emit(bc, i, OP_TAIL_CALL);
emit_word(bc, i, (sexp_uint_t) sexp_make_integer(sexp_length(params)+(*d))); emit_word(bc, i, (sexp_uint_t) sexp_make_integer(sexp_length(params)+(*d)));
emit_word(bc, i, (sexp_uint_t) sexp_make_integer(len)); emit_word(bc, i, (sexp_uint_t) sexp_make_integer(len));
@ -421,7 +447,7 @@ void analyze_lambda (sexp name, sexp formals, sexp body,
int k; int k;
flat_formals = sexp_flatten_dot(formals); flat_formals = sexp_flatten_dot(formals);
fv2 = free_vars(e, flat_formals, body, SEXP_NULL); fv2 = free_vars(e, flat_formals, body, SEXP_NULL);
e2 = extend_env_closure(e, flat_formals); e2 = extend_env_closure(e, flat_formals, -4);
/* fprintf(stderr, "%d free-vars\n", sexp_length(fv2)); */ /* fprintf(stderr, "%d free-vars\n", sexp_length(fv2)); */
/* sexp_write(fv2, cur_error_port); */ /* sexp_write(fv2, cur_error_port); */
/* fprintf(stderr, "\n"); */ /* fprintf(stderr, "\n"); */
@ -449,9 +475,9 @@ void analyze_lambda (sexp name, sexp formals, sexp body,
} }
bytecode compile(sexp params, sexp obj, env e, sexp fv, sexp sv, int done_p) { bytecode compile(sexp params, sexp obj, env e, sexp fv, sexp sv, int done_p) {
unsigned int i = 0, j, d = 0; unsigned int i = 0, j, d = 0, define_ok=1;
bytecode bc = (bytecode) SEXP_ALLOC(sizeof(struct bytecode)+INIT_BCODE_SIZE); bytecode bc = (bytecode) SEXP_ALLOC(sizeof(struct bytecode)+INIT_BCODE_SIZE);
sexp sv2 = set_vars(e, params, obj, SEXP_NULL), ls; sexp sv2 = set_vars(e, params, obj, SEXP_NULL), internals=SEXP_NULL, ls;
bc->tag = SEXP_BYTECODE; bc->tag = SEXP_BYTECODE;
bc->len = INIT_BCODE_SIZE; bc->len = INIT_BCODE_SIZE;
/* box mutable vars */ /* box mutable vars */
@ -467,6 +493,28 @@ bytecode compile(sexp params, sexp obj, env e, sexp fv, sexp sv, int done_p) {
} }
} }
sv = sexp_append(sv2, sv); sv = sexp_append(sv2, sv);
/* determine internal defines */
/* for (ls=SEXP_NULL; SEXP_PAIRP(obj); obj=SEXP_CDR(obj)) { */
/* core = SEXP_PAIRP(SEXP_CAR(obj)) && SEXP_SYMBOLP(SEXP_CAAR(obj)) */
/* && core_code(SEXP_CAAR(obj)); */
/* if (core == CORE_BEGIN) { */
/* obj = sexp_cons(SEXP_CAR(obj), */
/* sexp_append(SEXP_CDAR(obj), SEXP_CDR(obj))); */
/* } else { */
/* if (core == CORE_DEFINE) { */
/* if (! define_ok) */
/* errx(1, "definition in non-definition context: %p", obj); */
/* internals = sexp_cons(SEXP_CADR(obj), internals); */
/* } else { */
/* define_ok = 0; */
/* } */
/* ls = sexp_cons(SEXP_CAR(obj), ls); */
/* } */
/* } */
/* obj = sexp_reverse(ls); */
/* if (SEXP_PAIRP(internals)) { */
/* e = extend_env_closure(e, internals); */
/* } */
/* analyze body sequence */ /* analyze body sequence */
for ( ; SEXP_PAIRP(obj); obj=SEXP_CDR(obj)) { for ( ; SEXP_PAIRP(obj); obj=SEXP_CDR(obj)) {
if (SEXP_PAIRP(SEXP_CDR(obj))) { if (SEXP_PAIRP(SEXP_CDR(obj))) {
@ -693,7 +741,8 @@ sexp vm(bytecode bc, env e, sexp* stack, unsigned int top) {
/* restore frame info */ /* restore frame info */
stack[top-j-i] = stack[top]; stack[top-j-i] = stack[top];
stack[top-j-i+1] = stack[top+1]; stack[top-j-i+1] = stack[top+1];
top -= (j-i); top -= (j-i-1);
stack[top-1] = tmp1;
/* print_stack(stack, top); */ /* print_stack(stack, top); */
/* exit(0); */ /* exit(0); */
bc = sexp_procedure_code(tmp1); bc = sexp_procedure_code(tmp1);

2
eval.h
View file

@ -64,7 +64,7 @@ typedef struct core_form {
} *core_form; } *core_form;
enum core_form_names { enum core_form_names {
CORE_DEFINE, CORE_DEFINE = 1,
CORE_SET, CORE_SET,
CORE_LAMBDA, CORE_LAMBDA,
CORE_IF, CORE_IF,