in vm/vmcore/src/lil/lil.cpp [1915:2054]
bool lil_is_valid(LilCodeStub* cs)
{
unsigned inst_number = 0;
LilInstruction* i = NULL;
if (!cs) ERR("code stub is null");
lil_compute_contexts(cs);
if (cs->ctxt_state == LCSC_Error) ERR("control flow contexts inconsistent");
// Check instructions
bool last_was_terminal = false;
LilInstructionIterator iter(cs, true);
while (!iter.at_end()) {
inst_number++;
i = iter.get_current();
LilInstructionContext* c = iter.get_context();
switch (i->tag) {
case LIT_Label:
{
LilLabel l = i->u.label.l;
LilInstruction *label_def = lil_find_label(cs, l);
if (label_def != i) {
char buffer[256];
sprintf(buffer, "label %s redefined", l);
ERR(buffer);
}
break;
}
case LIT_Locals:
break;
case LIT_StdPlaces:
break;
case LIT_Alloc:
if (c->out_sig) ERR("alloc between out and call");
if (!lil_is_valid_variable(cs, c, &(i->u.alloc.dst))) ERR("invalid variable in alloc");
break;
case LIT_Asgn:
if (!lil_is_valid_operand(cs, c, &(i->u.asgn.o1))) ERR("invalid first operand in assignment");
if (lil_operation_is_binary(i->u.asgn.op)) {
if (!lil_is_valid_operand(cs, c, &(i->u.asgn.o2))) ERR("invalid second operand in assignment");
if (!lil_verify_binary_op(i->u.asgn.op, lil_ic_get_type(cs, c, &i->u.asgn.o1), lil_ic_get_type(cs, c, &i->u.asgn.o2)))
ERR("operand type mismatch in assignment");
} else {
if (!lil_verify_unary_op(i->u.asgn.op, lil_ic_get_type(cs, c, &i->u.asgn.o1)))
ERR("operand type mismatch in assignment");
}
// ? 20040205: This is a hack to get the object allocation fastpath to type check
if (i->u.asgn.op == LO_Sx4 && !i->u.asgn.o1.is_immed && i->u.asgn.o1.val.var.tag == LVK_In && i->u.asgn.o1.val.var.index == 0) {
if (!lil_is_valid_asgn(cs, c, &i->u.asgn.dst, LT_PInt))
ERR("invalid destination or type incompatibility in assignment");
} else if (!lil_is_valid_asgn(cs, c, &i->u.asgn.dst, lil_type_asgn(cs, c, i))) {
ERR("invalid destination or type incompatibility in assignment");
}
break;
case LIT_Ts:
if (!lil_is_valid_asgn(cs, c, &i->u.ts, LT_PInt)) ERR("invalid destination in ts");
break;
case LIT_Handles:
if (c->m2n!=LMS_Handles) ERR("handles not dominated by push_m2n handles");
if (!lil_is_valid_operand(cs, c, &(i->u.handles))) ERR("invalid operand in handles");
if (lil_ic_get_type(cs, c, &i->u.handles)!=LT_PInt) ERR("operand not platform int in handles");
break;
case LIT_Ld:
if (!lil_is_valid_asgn(cs, c, &i->u.ldst.operand.val.var, (i->u.ldst.extend==LLX_None ? i->u.ldst.t : LT_PInt)))
ERR("invalid destination in load");
if (!lil_is_valid_address(cs, c, i)) ERR("invalid address in load");
break;
case LIT_St:
if (!lil_is_valid_address(cs, c, i)) ERR("invalid address in store");
if (!i->u.ldst.operand.is_immed && i->u.ldst.t!=lil_ic_get_type(cs, c, &i->u.ldst.operand)) ERR("type mismatch in store");
if (!lil_is_valid_operand(cs, c, &(i->u.ldst.operand))) ERR("invalid source in store");
break;
case LIT_Inc:
if (!lil_is_valid_address(cs, c, i)) ERR("invalid address in inc");
break;
case LIT_Cas:
if (!lil_is_valid_address(cs, c, i)) ERR("invalid address in cas");
if (!i->u.ldst.compare.is_immed && i->u.ldst.t!=lil_ic_get_type(cs, c, &i->u.ldst.operand)) ERR("type mismatch in cas compare");
if (!i->u.ldst.operand.is_immed && i->u.ldst.t!=lil_ic_get_type(cs, c, &i->u.ldst.operand)) ERR("type mismatch in cas source");
if (!lil_is_valid_operand(cs, c, &(i->u.ldst.compare))) ERR("invalid compare in cas");
if (!lil_is_valid_operand(cs, c, &(i->u.ldst.operand))) ERR("invalid source in cas");
if (!lil_is_valid_label(cs, i->u.ldst.l)) ERR("bad target in cas");
break;
case LIT_J:
if (!lil_is_valid_label(cs, i->u.j)) ERR("bad target in j");
break;
case LIT_Jc:
// Should do typechecks here
if (!lil_is_valid_label(cs, i->u.jc.l)) ERR("bad target in jc");
if (!lil_is_valid_operand(cs, c, &(i->u.jc.c.o1))) ERR("invalid first operand in condition");
if (lil_predicate_is_binary(i->u.jc.c.tag)) {
if (!lil_is_valid_operand(cs, c, &(i->u.jc.c.o2))) ERR("invalid second operand in condition");
if (!lil_verify_binary_cond(i->u.jc.c.tag, lil_ic_get_type(cs, c, &(i->u.jc.c.o1)), lil_ic_get_type(cs, c, &(i->u.jc.c.o2))))
ERR("operand type mismatch in conditional jump");
}
break;
case LIT_Out:
break;
case LIT_In2Out:
if (cs->sig.arbitrary) ERR("in2out in arbitrary code stub");
break;
case LIT_Call:
if (i->u.call.k!=LCK_TailCall && !c->out_sig) ERR("call not dominated by out or in2out");
if (!lil_is_valid_operand(cs, c, &(i->u.call.target))) ERR("invalid operand in call");
if (lil_ic_get_type(cs, c, &i->u.call.target)!=LT_PInt) ERR("operand not platform int in call");
break;
case LIT_Ret:
if (cs->sig.arbitrary) ERR("cannot return from an arbitrary signature entry");
if (cs->sig.ret_type!=LT_Void && cs->sig.ret_type!=c->ret)
ERR("ret with invalid return value");
if (c->m2n) ERR("return with m2n");
break;
case LIT_PushM2N:
if (c->amt_alloced>0) ERR("alloc before push_m2n");
if (c->m2n!=LMS_NoM2n) ERR("push m2n twice");
break;
case LIT_M2NSaveAll:
if (c->m2n==LMS_NoM2n) ERR("m2n save all not dominated by push m2n");
break;
case LIT_PopM2N:
if (c->m2n==LMS_NoM2n) ERR("pop m2n not dominated by push");
break;
case LIT_Print:
if (!lil_is_valid_operand(cs, c, &i->u.print.arg))
ERR("invalid argument to print");
break;
default:
ERR("unknown instruction");
}
iter.goto_next();
last_was_terminal = (c->s==LCS_Terminal);
}
if (!last_was_terminal) ERR("last instruction not terminal");
return true;
}