shithub: femtolisp

ref: b307865d7a8cc2e9ae02104907656c7f159ac5d3
dir: /maxstack.inc/

View raw version
static uint32_t compute_maxstack(uint8_t *code, size_t len)
{
    uint8_t *ip = code+4, *end = code+len;
    uint8_t op;
    uint32_t i, n, sp = 0, maxsp = 0;

    while (ip < end) {
        if ((int32_t)sp > (int32_t)maxsp)
            maxsp = sp;
        op = *ip++;
        switch (op) {
        case OP_LOADA: case OP_LOADI8: case OP_LOADV: case OP_LOADG:
            ip++; // fallthrough
        case OP_LOADA0: case OP_LOADA1:
        case OP_DUP: case OP_LOADT: case OP_LOADF: case OP_LOADNIL:
        case OP_LOAD0:
        case OP_LOAD1: case OP_LOADC00:
        case OP_LOADC01:
            sp++;
            break;

        case OP_BRF: case OP_BRT:
            SWAP_INT16(ip);
            ip += 2;
            sp--;
            break;

        case OP_POP: case OP_RET:
        case OP_CONS: case OP_SETCAR: case OP_SETCDR:
        case OP_EQ: case OP_EQV: case OP_EQUAL: case OP_ADD2: case OP_SUB2:
        case OP_IDIV: case OP_NUMEQ: case OP_LT: case OP_COMPARE:
        case OP_AREF: case OP_TRYCATCH:
            sp--;
            break;

        case OP_ARGC: case OP_SETG: case OP_SETA:
            ip++;
            break;

        case OP_TCALL: case OP_CALL:
            n = *ip++;  // nargs
            sp -= n;
            break;

        case OP_LOADVL: case OP_LOADGL: case OP_LOADAL:
            sp++; // fallthrough
        case OP_SETGL: case OP_SETAL: case OP_LARGC:
            SWAP_INT32(ip);
            ip += 4;
            break;

        case OP_LOADC:
            sp++; // fallthrough
        case OP_SETC:
            ip += 2;
            break;

        case OP_VARGC:
            n = *ip++;
            sp += n+2;
            break;
        case OP_LVARGC:
            SWAP_INT32(ip);
            n = GET_INT32(ip); ip += 4;
            sp += n+2;
            break;
        case OP_OPTARGS:
            SWAP_INT32(ip);
            i = GET_INT32(ip); ip += 4;
            SWAP_INT32(ip);
            n = abs(GET_INT32(ip)); ip += 4;
            sp += n-i;
            break;
        case OP_KEYARGS:
            SWAP_INT32(ip);
            i = GET_INT32(ip); ip += 4;
            SWAP_INT32(ip);
            ip += 4;
            SWAP_INT32(ip);
            n = abs(GET_INT32(ip)); ip += 4;
            sp += n-i;
            break;
        case OP_BRBOUND:
            SWAP_INT32(ip);
            ip += 4;
            sp++;
            break;
        case OP_TCALLL: case OP_CALLL:
            SWAP_INT32(ip);
            n = GET_INT32(ip); ip+=4;
            sp -= n;
            break;
        case OP_JMP:
            SWAP_INT16(ip);
            ip += 2; break;
        case OP_JMPL:
            SWAP_INT32(ip);
            ip += 4; break;
        case OP_BRFL: case OP_BRTL:
            SWAP_INT32(ip);
            ip += 4;
            sp--;
            break;
        case OP_BRNE:
            SWAP_INT16(ip);
            ip += 2;
            sp -= 2;
            break;
        case OP_BRNEL:
            SWAP_INT32(ip);
            ip += 4;
            sp -= 2;
            break;
        case OP_BRNN: case OP_BRN:
            SWAP_INT16(ip);
            ip += 2;
            sp--;
            break;
        case OP_BRNNL: case OP_BRNL:
            SWAP_INT32(ip);
            ip += 4; // fallthrough

        case OP_TAPPLY: case OP_APPLY:
        case OP_LIST: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
        case OP_VECTOR:
            n = *ip++;
            sp -= n-1;
            break;

        case OP_FOR:
            if (maxsp < sp+2)
                maxsp = sp+2; // fallthrough
        case OP_ASET:
            sp -= 2;
            break;

        case OP_LOADCL:
            sp++; // fallthrough
        case OP_SETCL:
            SWAP_INT32(ip);
            ip += 4;
            SWAP_INT32(ip);
            ip += 4;
            break;
        }
    }
    assert(ip == end);
    return maxsp+5;
}