bool lil_is_valid()

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;
}