shithub: femtolisp

ref: 76aec5fa7a058f6a9f69570efe13dff3cb957e76
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_LOADC0:
		case OP_LOADC1:
			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_AREF2: case OP_TRYCATCH:
			sp--;
			break;

		case OP_AREF:
			n = 2 + *ip++;
			sp -= n;
			break;

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

		case OP_TCALL: case OP_CALL: case OP_CLOSURE: case OP_SHIFT:
			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++;
			ip++;
			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
			SWAP_INT32(ip);
			ip += 4;
			break;
		}
	}
	assert(ip == end);
	return maxsp+4;
}