[bugfix] codegen causes segv when default irep size is short

This commit is contained in:
Yuichi Nishiwaki 2015-05-28 00:21:49 +09:00
parent 9885bdd982
commit bb55bbfdde
1 changed files with 121 additions and 125 deletions

View File

@ -144,22 +144,17 @@ static bool
push_scope(analyze_state *state, pic_value formals) push_scope(analyze_state *state, pic_value formals)
{ {
pic_state *pic = state->pic; pic_state *pic = state->pic;
analyze_scope *scope; analyze_scope *scope = pic_alloc(pic, sizeof(analyze_scope));
bool varg; bool varg;
xvect args, locals, captures;
xv_init(args); xv_init(scope->args);
xv_init(locals); xv_init(scope->locals);
xv_init(captures); xv_init(scope->captures);
if (analyze_args(pic, formals, &varg, &args, &locals)) { if (analyze_args(pic, formals, &varg, &scope->args, &scope->locals)) {
scope = pic_alloc(pic, sizeof(analyze_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->varg = varg;
scope->args = args;
scope->locals = locals;
scope->captures = captures;
scope->defer = pic_nil_value(); scope->defer = pic_nil_value();
state->scope = scope; state->scope = scope;
@ -167,8 +162,10 @@ push_scope(analyze_state *state, pic_value formals)
return true; return true;
} }
else { else {
xv_destroy(args); xv_destroy(scope->args);
xv_destroy(locals); xv_destroy(scope->locals);
xv_destroy(scope->captures);
pic_free(pic, scope);
return false; return false;
} }
} }
@ -921,8 +918,69 @@ destroy_codegen_state(codegen_state *state)
} }
static void static void
create_activation(codegen_context *cxt) emit_n(codegen_state *state, enum pic_opcode insn)
{ {
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
if (cxt->clen >= cxt->ccapa) {
cxt->ccapa *= 2;
cxt->code = pic_realloc(pic, cxt->code, sizeof(pic_code) * cxt->ccapa);
}
cxt->code[cxt->clen].insn = insn;
cxt->clen++;
}
static void
emit_i(codegen_state *state, enum pic_opcode insn, int i)
{
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
if (cxt->clen >= cxt->ccapa) {
cxt->ccapa *= 2;
cxt->code = pic_realloc(pic, cxt->code, sizeof(pic_code) * cxt->ccapa);
}
cxt->code[cxt->clen].insn = insn;
cxt->code[cxt->clen].u.i = i;
cxt->clen++;
}
static void
emit_c(codegen_state *state, enum pic_opcode insn, char c)
{
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
if (cxt->clen >= cxt->ccapa) {
cxt->ccapa *= 2;
cxt->code = pic_realloc(pic, cxt->code, sizeof(pic_code) * cxt->ccapa);
}
cxt->code[cxt->clen].insn = insn;
cxt->code[cxt->clen].u.c = c;
cxt->clen++;
}
static void
emit_r(codegen_state *state, enum pic_opcode insn, int d, int i)
{
pic_state *pic = state->pic;
codegen_context *cxt = state->cxt;
if (cxt->clen >= cxt->ccapa) {
cxt->ccapa *= 2;
cxt->code = pic_realloc(pic, cxt->code, sizeof(pic_code) * cxt->ccapa);
}
cxt->code[cxt->clen].insn = insn;
cxt->code[cxt->clen].u.r.depth = d;
cxt->code[cxt->clen].u.r.idx = i;
cxt->clen++;
}
static void
create_activation(codegen_state *state)
{
codegen_context *cxt = state->cxt;
size_t i, n; size_t i, n;
xhash regs; xhash regs;
size_t offset; size_t offset;
@ -944,13 +1002,10 @@ create_activation(codegen_context *cxt)
n = xh_val(xh_get_ptr(&regs, xv_A(cxt->captures, i)), size_t); n = xh_val(xh_get_ptr(&regs, xv_A(cxt->captures, i)), size_t);
if (n <= xv_size(cxt->args) || (cxt->varg && n == xv_size(cxt->args) + 1)) { if (n <= xv_size(cxt->args) || (cxt->varg && n == xv_size(cxt->args) + 1)) {
/* copy arguments to capture variable area */ /* copy arguments to capture variable area */
cxt->code[cxt->clen].insn = OP_LREF; emit_i(state, OP_LREF, (int)n);
cxt->code[cxt->clen].u.i = (int)n;
cxt->clen++;
} else { } else {
/* otherwise, just extend the stack */ /* otherwise, just extend the stack */
cxt->code[cxt->clen].insn = OP_PUSHNONE; emit_n(state, OP_PUSHNONE);
cxt->clen++;
} }
} }
@ -1005,7 +1060,7 @@ push_codegen_context(codegen_state *state, pic_value name, pic_value args, pic_v
state->cxt = cxt; state->cxt = cxt;
create_activation(cxt); create_activation(state);
} }
static struct pic_irep * static struct pic_irep *
@ -1111,9 +1166,7 @@ codegen(codegen_state *state, pic_value obj)
sym = pic_sym_ptr(pic_car(pic, obj)); sym = pic_sym_ptr(pic_car(pic, obj));
if (sym == pic->sGREF) { if (sym == pic->sGREF) {
cxt->code[cxt->clen].insn = OP_GREF; emit_i(state, OP_GREF, index_symbol(state, pic_sym_ptr(pic_list_ref(pic, obj, 1))));
cxt->code[cxt->clen].u.i = index_symbol(state, pic_sym_ptr(pic_list_ref(pic, obj, 1)));
cxt->clen++;
return; return;
} else if (sym == pic->sCREF) { } else if (sym == pic->sCREF) {
pic_sym *name; pic_sym *name;
@ -1121,10 +1174,7 @@ codegen(codegen_state *state, pic_value obj)
depth = pic_int(pic_list_ref(pic, obj, 1)); depth = pic_int(pic_list_ref(pic, obj, 1));
name = pic_sym_ptr(pic_list_ref(pic, obj, 2)); name = pic_sym_ptr(pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_CREF; emit_r(state, OP_CREF, depth, index_capture(state, name, depth));
cxt->code[cxt->clen].u.r.depth = depth;
cxt->code[cxt->clen].u.r.idx = index_capture(state, name, depth);
cxt->clen++;
return; return;
} else if (sym == pic->sLREF) { } else if (sym == pic->sLREF) {
pic_sym *name; pic_sym *name;
@ -1132,14 +1182,10 @@ 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) {
cxt->code[cxt->clen].insn = OP_LREF; emit_i(state, OP_LREF, i + (int)xv_size(cxt->args) + (int)xv_size(cxt->locals) + 1);
cxt->code[cxt->clen].u.i = i + (int)xv_size(cxt->args) + (int)xv_size(cxt->locals) + 1;
cxt->clen++;
return; return;
} }
cxt->code[cxt->clen].insn = OP_LREF; emit_i(state, OP_LREF, index_local(state, name));
cxt->code[cxt->clen].u.i = index_local(state, name);
cxt->clen++;
return; return;
} else if (sym == pic->sSETBANG) { } else if (sym == pic->sSETBANG) {
pic_value var, val; pic_value var, val;
@ -1151,11 +1197,8 @@ codegen(codegen_state *state, pic_value obj)
var = pic_list_ref(pic, obj, 1); var = pic_list_ref(pic, obj, 1);
type = pic_sym_ptr(pic_list_ref(pic, var, 0)); type = pic_sym_ptr(pic_list_ref(pic, var, 0));
if (type == pic->sGREF) { if (type == pic->sGREF) {
cxt->code[cxt->clen].insn = OP_GSET; emit_i(state, OP_GSET, index_symbol(state, pic_sym_ptr(pic_list_ref(pic, var, 1))));
cxt->code[cxt->clen].u.i = index_symbol(state, pic_sym_ptr(pic_list_ref(pic, var, 1))); emit_n(state, OP_PUSHNONE);
cxt->clen++;
cxt->code[cxt->clen].insn = OP_PUSHNONE;
cxt->clen++;
return; return;
} }
else if (type == pic->sCREF) { else if (type == pic->sCREF) {
@ -1164,12 +1207,8 @@ codegen(codegen_state *state, pic_value obj)
depth = pic_int(pic_list_ref(pic, var, 1)); depth = pic_int(pic_list_ref(pic, var, 1));
name = pic_sym_ptr(pic_list_ref(pic, var, 2)); name = pic_sym_ptr(pic_list_ref(pic, var, 2));
cxt->code[cxt->clen].insn = OP_CSET; emit_r(state, OP_CSET, depth, index_capture(state, name, depth));
cxt->code[cxt->clen].u.r.depth = depth; emit_n(state, OP_PUSHNONE);
cxt->code[cxt->clen].u.r.idx = index_capture(state, name, depth);
cxt->clen++;
cxt->code[cxt->clen].insn = OP_PUSHNONE;
cxt->clen++;
return; return;
} }
else if (type == pic->sLREF) { else if (type == pic->sLREF) {
@ -1178,18 +1217,12 @@ 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) {
cxt->code[cxt->clen].insn = OP_LSET; emit_i(state, OP_LSET, i + (int)xv_size(cxt->args) + (int)xv_size(cxt->locals) + 1);
cxt->code[cxt->clen].u.i = i + (int)xv_size(cxt->args) + (int)xv_size(cxt->locals) + 1; emit_n(state, OP_PUSHNONE);
cxt->clen++;
cxt->code[cxt->clen].insn = OP_PUSHNONE;
cxt->clen++;
return; return;
} }
cxt->code[cxt->clen].insn = OP_LSET; emit_i(state, OP_LSET, index_local(state, name));
cxt->code[cxt->clen].u.i = index_local(state, name); emit_n(state, OP_PUSHNONE);
cxt->clen++;
cxt->code[cxt->clen].insn = OP_PUSHNONE;
cxt->clen++;
return; return;
} }
} }
@ -1201,9 +1234,7 @@ codegen(codegen_state *state, pic_value obj)
cxt->irep = pic_realloc(pic, cxt->irep, sizeof(struct pic_irep *) * cxt->icapa); cxt->irep = pic_realloc(pic, cxt->irep, sizeof(struct pic_irep *) * cxt->icapa);
} }
k = (int)cxt->ilen++; k = (int)cxt->ilen++;
cxt->code[cxt->clen].insn = OP_LAMBDA; emit_i(state, OP_LAMBDA, k);
cxt->code[cxt->clen].u.i = k;
cxt->clen++;
cxt->irep[k] = codegen_lambda(state, obj); cxt->irep[k] = codegen_lambda(state, obj);
return; return;
@ -1213,13 +1244,16 @@ codegen(codegen_state *state, pic_value obj)
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_JMPIF; s = (int)cxt->clen;
s = (int)cxt->clen++;
emit_n(state, OP_JMPIF);
/* if false branch */ /* if false branch */
codegen(state, pic_list_ref(pic, obj, 3)); codegen(state, pic_list_ref(pic, obj, 3));
cxt->code[cxt->clen].insn = OP_JMP;
t = (int)cxt->clen++; t = (int)cxt->clen;
emit_n(state, OP_JMP);
cxt->code[s].u.i = (int)cxt->clen - s; cxt->code[s].u.i = (int)cxt->clen - s;
@ -1234,8 +1268,7 @@ codegen(codegen_state *state, pic_value obj)
pic_for_each (elt, pic_cdr(pic, obj), it) { pic_for_each (elt, pic_cdr(pic, obj), it) {
if (i++ != 0) { if (i++ != 0) {
cxt->code[cxt->clen].insn = OP_POP; emit_n(state, OP_POP);
cxt->clen++;
} }
codegen(state, elt); codegen(state, elt);
} }
@ -1247,26 +1280,16 @@ codegen(codegen_state *state, pic_value obj)
obj = pic_list_ref(pic, obj, 1); obj = pic_list_ref(pic, obj, 1);
switch (pic_type(obj)) { switch (pic_type(obj)) {
case PIC_TT_BOOL: case PIC_TT_BOOL:
if (pic_true_p(obj)) { emit_n(state, (pic_true_p(obj) ? OP_PUSHTRUE : OP_PUSHFALSE));
cxt->code[cxt->clen].insn = OP_PUSHTRUE;
} else {
cxt->code[cxt->clen].insn = OP_PUSHFALSE;
}
cxt->clen++;
return; return;
case PIC_TT_INT: case PIC_TT_INT:
cxt->code[cxt->clen].insn = OP_PUSHINT; emit_i(state, OP_PUSHINT, pic_int(obj));
cxt->code[cxt->clen].u.i = pic_int(obj);
cxt->clen++;
return; return;
case PIC_TT_NIL: case PIC_TT_NIL:
cxt->code[cxt->clen].insn = OP_PUSHNIL; emit_n(state, OP_PUSHNIL);
cxt->clen++;
return; return;
case PIC_TT_CHAR: case PIC_TT_CHAR:
cxt->code[cxt->clen].insn = OP_PUSHCHAR; emit_c(state, OP_PUSHCHAR, pic_char(obj));
cxt->code[cxt->clen].u.c = pic_char(obj);
cxt->clen++;
return; return;
default: default:
if (cxt->plen >= cxt->pcapa) { if (cxt->plen >= cxt->pcapa) {
@ -1275,122 +1298,103 @@ codegen(codegen_state *state, pic_value obj)
} }
pidx = (int)cxt->plen++; pidx = (int)cxt->plen++;
cxt->pool[pidx] = obj; cxt->pool[pidx] = obj;
cxt->code[cxt->clen].insn = OP_PUSHCONST; emit_i(state, OP_PUSHCONST, pidx);
cxt->code[cxt->clen].u.i = pidx;
cxt->clen++;
return; return;
} }
} }
else if (sym == pic->sCONS) { else if (sym == pic->sCONS) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2)); codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_CONS; emit_n(state, OP_CONS);
cxt->clen++;
return; return;
} }
else if (sym == pic->sCAR) { else if (sym == pic->sCAR) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_CAR; emit_n(state, OP_CAR);
cxt->clen++;
return; return;
} }
else if (sym == pic->sCDR) { else if (sym == pic->sCDR) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_CDR; emit_n(state, OP_CDR);
cxt->clen++;
return; return;
} }
else if (sym == pic->sNILP) { else if (sym == pic->sNILP) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_NILP; emit_n(state, OP_NILP);
cxt->clen++;
return; return;
} }
else if (sym == pic->sSYMBOLP) { else if (sym == pic->sSYMBOLP) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_SYMBOLP; emit_n(state, OP_SYMBOLP);
cxt->clen++;
return; return;
} }
else if (sym == pic->sPAIRP) { else if (sym == pic->sPAIRP) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_PAIRP; emit_n(state, OP_PAIRP);
cxt->clen++;
return; return;
} }
else if (sym == pic->sADD) { else if (sym == pic->sADD) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2)); codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_ADD; emit_n(state, OP_ADD);
cxt->clen++;
return; return;
} }
else if (sym == pic->sSUB) { else if (sym == pic->sSUB) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2)); codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_SUB; emit_n(state, OP_SUB);
cxt->clen++;
return; return;
} }
else if (sym == pic->sMUL) { else if (sym == pic->sMUL) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2)); codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_MUL; emit_n(state, OP_MUL);
cxt->clen++;
return; return;
} }
else if (sym == pic->sDIV) { else if (sym == pic->sDIV) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2)); codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_DIV; emit_n(state, OP_DIV);
cxt->clen++;
return; return;
} }
else if (sym == pic->sMINUS) { else if (sym == pic->sMINUS) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_MINUS; emit_n(state, OP_MINUS);
cxt->clen++;
return; return;
} }
else if (sym == pic->sEQ) { else if (sym == pic->sEQ) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2)); codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_EQ; emit_n(state, OP_EQ);
cxt->clen++;
return; return;
} }
else if (sym == pic->sLT) { else if (sym == pic->sLT) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2)); codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_LT; emit_n(state, OP_LT);
cxt->clen++;
return; return;
} }
else if (sym == pic->sLE) { else if (sym == pic->sLE) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
codegen(state, pic_list_ref(pic, obj, 2)); codegen(state, pic_list_ref(pic, obj, 2));
cxt->code[cxt->clen].insn = OP_LE; emit_n(state, OP_LE);
cxt->clen++;
return; return;
} }
else if (sym == pic->sGT) { else if (sym == pic->sGT) {
codegen(state, pic_list_ref(pic, obj, 2)); codegen(state, pic_list_ref(pic, obj, 2));
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_LT; emit_n(state, OP_LT);
cxt->clen++;
return; return;
} }
else if (sym == pic->sGE) { else if (sym == pic->sGE) {
codegen(state, pic_list_ref(pic, obj, 2)); codegen(state, pic_list_ref(pic, obj, 2));
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_LE; emit_n(state, OP_LE);
cxt->clen++;
return; return;
} }
else if (sym == pic->sNOT) { else if (sym == pic->sNOT) {
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
cxt->code[cxt->clen].insn = OP_NOT; emit_n(state, OP_NOT);
cxt->clen++;
return; return;
} }
else if (sym == pic->sCALL || sym == pic->sTAILCALL) { else if (sym == pic->sCALL || sym == pic->sTAILCALL) {
@ -1400,9 +1404,7 @@ codegen(codegen_state *state, pic_value obj)
pic_for_each (elt, pic_cdr(pic, obj), it) { pic_for_each (elt, pic_cdr(pic, obj), it) {
codegen(state, elt); codegen(state, elt);
} }
cxt->code[cxt->clen].insn = (sym == pic->sCALL) ? OP_CALL : OP_TAILCALL; emit_i(state, (sym == pic->sCALL ? OP_CALL : OP_TAILCALL), len - 1);
cxt->code[cxt->clen].u.i = len - 1;
cxt->clen++;
return; return;
} }
else if (sym == pic->sCALL_WITH_VALUES || sym == pic->sTAILCALL_WITH_VALUES) { else if (sym == pic->sCALL_WITH_VALUES || sym == pic->sTAILCALL_WITH_VALUES) {
@ -1410,13 +1412,9 @@ codegen(codegen_state *state, pic_value obj)
codegen(state, pic_list_ref(pic, obj, 2)); codegen(state, pic_list_ref(pic, obj, 2));
codegen(state, pic_list_ref(pic, obj, 1)); codegen(state, pic_list_ref(pic, obj, 1));
/* call producer */ /* call producer */
cxt->code[cxt->clen].insn = OP_CALL; emit_i(state, OP_CALL, 1);
cxt->code[cxt->clen].u.i = 1;
cxt->clen++;
/* call consumer */ /* call consumer */
cxt->code[cxt->clen].insn = (sym == pic->sCALL_WITH_VALUES) ? OP_CALL : OP_TAILCALL; emit_i(state, (sym == pic->sCALL_WITH_VALUES ? OP_CALL : OP_TAILCALL), -1);
cxt->code[cxt->clen].u.i = -1;
cxt->clen++;
return; return;
} }
else if (sym == pic->sRETURN) { else if (sym == pic->sRETURN) {
@ -1426,9 +1424,7 @@ codegen(codegen_state *state, pic_value obj)
pic_for_each (elt, pic_cdr(pic, obj), it) { pic_for_each (elt, pic_cdr(pic, obj), it) {
codegen(state, elt); codegen(state, elt);
} }
cxt->code[cxt->clen].insn = OP_RET; emit_i(state, OP_RET, len - 1);
cxt->code[cxt->clen].u.i = len - 1;
cxt->clen++;
return; return;
} }
pic_errorf(pic, "codegen: unknown AST type ~s", obj); pic_errorf(pic, "codegen: unknown AST type ~s", obj);