shithub: femtolisp

ref: 991160b28f27849a616f39059f79cde0b312e01a
dir: /maxstack.inc/

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

	while(ip < end){
		opcode_t op = *ip++;
		if(op >= N_OPCODES)
			return -1;
		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_LOADVOID:
		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++;
			continue;

		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: case OP_BOXL:
			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;
			continue;
		case OP_JMPL:
			SWAP_INT32(ip);
			ip += 4;
			continue;
		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;

		case OP_CAR: case OP_CDR: case OP_CADR:
		case OP_NOT: case OP_NEG:
		case OP_CONSP: case OP_ATOMP: case OP_SYMBOLP:
		case OP_NULLP: case OP_BOOLEANP: case OP_NUMBERP:
		case OP_FIXNUMP: case OP_BOUNDP: case OP_BUILTINP:
		case OP_FUNCTIONP: case OP_VECTORP:
			continue;

		case OP_EOF_OBJECT: case N_OPCODES:
			return -1;
		}
		if((int32_t)sp > (int32_t)maxsp)
			maxsp = sp;
	}
	assert(ip == end);
	assert(maxsp >= 0);
	return maxsp+4;
}