shithub: femtolisp

ref: b08031edac53f6a4aed024e6662a9bbacc25458c
dir: /vm.inc/

View raw version
OP(OP_LOADA0)
	PUSH(FL(stack)[bp]);
	NEXT_OP;

OP(OP_LOADA1)
	PUSH(FL(stack)[bp+1]);
	NEXT_OP;

OP(OP_LOADV)
	v = fn_vals(FL(stack)[bp-1]);
	assert(*ip < vector_size(v));
	PUSH(vector_elt(v, *ip++));
	NEXT_OP;

OP(OP_BRF)
	ip += POP() != FL_f ? 2 : GET_INT16(ip);
	NEXT_OP;

OP(OP_POP)
	POPN(1);
	NEXT_OP;

OP(OP_TCALLL)
	tail = true;
	if(0){
OP(OP_CALLL)
		tail = false;
	}
	n = GET_INT32(ip);
	ip += 4;
	if(0){
OP(OP_TCALL)
		tail = true;
		if(0){
OP(OP_CALL)
			tail = false;
		}
		n = *ip++;  // nargs
	}
LABEL(do_call):
	FL(stack)[ipd] = (uintptr_t)ip;
	func = FL(stack)[FL(sp)-n-1];
	if(tag(func) == TAG_FUNCTION){
		if(func > (N_BUILTINS<<3)){
			if(tail){
				FL(curr_frame) = FL(stack)[FL(curr_frame)-3];
				for(s = -1; s < (fixnum_t)n; s++)
					FL(stack)[bp+s] = FL(stack)[FL(sp)-n+s];
				FL(sp) = bp+n;
			}
			nargs = n;
			goto apply_cl_top;
		}else{
			i = uintval(func);
			if(isbuiltin(func)){
				s = builtins[i].nargs;
				if(s >= 0)
					argcount(n, (unsigned)s);
				else if(s != ANYARGS && (signed)n < -s)
					argcount(n, (unsigned)-s);
				// remove function arg
				for(s = FL(sp)-n-1; s < (int)FL(sp)-1; s++)
					FL(stack)[s] = FL(stack)[s+1];
				FL(sp)--;
				switch(i){
				case OP_LIST:   goto LABEL(apply_list);
				case OP_VECTOR: goto LABEL(apply_vector);
				case OP_APPLY:  goto LABEL(apply_apply);
				case OP_ADD:	goto LABEL(apply_add);
				case OP_SUB:	goto LABEL(apply_sub);
				case OP_MUL:	goto LABEL(apply_mul);
				case OP_DIV:	goto LABEL(apply_div);
				case OP_AREF:	goto LABEL(apply_aref);
				case OP_ASET:	goto LABEL(apply_aset);
				default:
#if defined(COMPUTED_GOTO)
					goto *ops[i];
#else
					op = i;
					continue;
#endif
				}
			}
		}
	}else if(__likely(iscbuiltin(func))){
		s = FL(sp) - n;
		v = (((builtin_t*)ptr(func))[3])(&FL(stack)[s], n);
		FL(sp) = s;
		FL(stack)[s-1] = v;
		NEXT_OP;
	}
	type_error("function", func);

OP(OP_LOADGL)
	v = fn_vals(FL(stack)[bp-1]);
	v = vector_elt(v, GET_INT32(ip));
	ip += 4;
	if(0){
OP(OP_LOADG)
		v = fn_vals(FL(stack)[bp-1]);
		assert(*ip < vector_size(v));
		v = vector_elt(v, *ip);
		ip++;
	}
	assert(issymbol(v));
	sym = (symbol_t*)ptr(v);
	if(__unlikely(sym->binding == UNBOUND)){
		FL(stack)[ipd] = (uintptr_t)ip;
		unbound_error(v);
	}
	PUSH(sym->binding);
	NEXT_OP;

OP(OP_LOADA)
	i = *ip++;
	v = FL(stack)[bp+i];
	PUSH(v);
	NEXT_OP;

OP(OP_LOADC)
	i = *ip++;
	v = FL(stack)[bp+nargs];
	assert(isvector(v));
	assert(i < vector_size(v));
	PUSH(vector_elt(v, i));
	NEXT_OP;

OP(OP_BOX)
	i = *ip++;
	v = mk_cons();
	car_(v) = FL(stack)[bp+i];
	cdr_(v) = FL_nil;
	FL(stack)[bp+i] = v;
	NEXT_OP;

OP(OP_BOXL)
	i = GET_INT32(ip); ip += 4;
	v = mk_cons();
	car_(v) = FL(stack)[bp+i];
	cdr_(v) = FL_nil;
	FL(stack)[bp+i] = v;
	NEXT_OP;

OP(OP_SHIFT)
	i = *ip++;
	FL(stack)[FL(sp)-1-i] = FL(stack)[FL(sp)-1];
	FL(sp) -= i;
	NEXT_OP;

OP(OP_RET)
	v = POP();
	FL(sp) = FL(curr_frame);
	FL(curr_frame) = FL(stack)[FL(sp)-3];
	if(FL(curr_frame) == top_frame)
		return v;
	FL(sp) -= 4+nargs;
	ipd = FL(curr_frame)-1;
	ip = (uint8_t*)FL(stack)[ipd];
	nargs = FL(stack)[FL(curr_frame)-2];
	bp = FL(curr_frame) - 4 - nargs;
	FL(stack)[FL(sp)-1] = v;
	NEXT_OP;

OP(OP_DUP)
	FL(stack)[FL(sp)] = FL(stack)[FL(sp)-1];
	FL(sp)++;
	NEXT_OP;

OP(OP_CAR)
	v = FL(stack)[FL(sp)-1];
	if(__likely(iscons(v)))
		v = car_(v);
	else if(__unlikely(v != FL_nil)){
		FL(stack)[ipd] = (uintptr_t)ip;
		type_error("cons", v);
	}
	FL(stack)[FL(sp)-1] = v;
	NEXT_OP;

OP(OP_CDR)
	v = FL(stack)[FL(sp)-1];
	if(__likely(iscons(v)))
		v = cdr_(v);
	else if(__unlikely(v != FL_nil)){
		FL(stack)[ipd] = (uintptr_t)ip;
		type_error("cons", v);
	}
	FL(stack)[FL(sp)-1] = v;
	NEXT_OP;

OP(OP_CLOSURE)
	n = *ip++;
	assert(n > 0);
	pv = alloc_words(n + 1);
	v = tagptr(pv, TAG_VECTOR);
	i = 0;
	pv[i++] = fixnum(n);
	do{
		pv[i] = FL(stack)[FL(sp)-n + i-1];
		i++;
	}while(i <= n);
	POPN(n);
	PUSH(v);
	if(__unlikely((value_t*)FL(curheap) > (value_t*)FL(lim)-2))
		gc(0);
	pv = (value_t*)FL(curheap);
	FL(curheap) += 4*sizeof(value_t);
	e = FL(stack)[FL(sp)-2];  // closure to copy
	assert(isfunction(e));
	pv[0] = ((value_t*)ptr(e))[0];
	pv[1] = ((value_t*)ptr(e))[1];
	pv[2] = FL(stack)[FL(sp)-1];  // env
	pv[3] = ((value_t*)ptr(e))[3];
	POPN(1);
	FL(stack)[FL(sp)-1] = tagptr(pv, TAG_FUNCTION);
	NEXT_OP;

OP(OP_SETA)
	v = FL(stack)[FL(sp)-1];
	i = *ip++;
	FL(stack)[bp+i] = v;
	NEXT_OP;

OP(OP_JMP)
	ip += GET_INT16(ip);
	NEXT_OP;

OP(OP_LOADC0)
	PUSH(vector_elt(FL(stack)[bp+nargs], 0));
	NEXT_OP;

OP(OP_CONSP)
	FL(stack)[FL(sp)-1] = iscons(FL(stack)[FL(sp)-1]) ? FL_t : FL_f;
	NEXT_OP;

OP(OP_BRNE)
	ip += FL(stack)[FL(sp)-2] != FL(stack)[FL(sp)-1] ? GET_INT16(ip) : 2;
	POPN(2);
	NEXT_OP;

OP(OP_LOADT)
	PUSH(FL_t);
	NEXT_OP;

OP(OP_LOADVOID)
	PUSH(FL_void);
	NEXT_OP;

OP(OP_LOAD0)
	PUSH(fixnum(0));
	NEXT_OP;

OP(OP_LOADC1)
	PUSH(vector_elt(FL(stack)[bp+nargs], 1));
	NEXT_OP;

OP(OP_AREF2)
	n = 2;
	if(0){
OP(OP_AREF)
	FL(stack)[ipd] = (uintptr_t)ip;
	n = 3 + *ip++;
	}
LABEL(apply_aref):
	v = FL(stack)[FL(sp)-n];
	for(i = n-1; i > 0; i--){
		if(isarray(v)){
			FL(stack)[FL(sp)-i-1] = v;
			v = cvalue_array_aref(&FL(stack)[FL(sp)-i-1]);
			continue;
		}
		e = FL(stack)[FL(sp)-i];
		isz = tosize(e);
		if(isvector(v)){
			if(__unlikely(isz >= vector_size(v)))
				bounds_error(v, e);
			v = vector_elt(v, isz);
			continue;
		}
		if(!iscons(v) && v != FL_nil)
			type_error("sequence", v);
		for(value_t v0 = v;; isz--){
			if(isz == 0){
				v = car_(v);
				break;
			}
			v = cdr_(v);
			if(__unlikely(!iscons(v)))
				bounds_error(v0, e);
		}
	}
	POPN(n);
	PUSH(v);
	NEXT_OP;

OP(OP_ATOMP)
	FL(stack)[FL(sp)-1] = iscons(FL(stack)[FL(sp)-1]) ? FL_f : FL_t;
	NEXT_OP;

OP(OP_BRT)
	ip += POP() != FL_f ? GET_INT16(ip) : 2;
	NEXT_OP;

OP(OP_BRNN)
	ip += POP() != FL_nil ? GET_INT16(ip) : 2;
	NEXT_OP;

OP(OP_LOAD1)
	PUSH(fixnum(1));
	NEXT_OP;

OP(OP_LT)
	{
		value_t a = FL(stack)[FL(sp)-2], b = FL(stack)[FL(sp)-1];
		POPN(1);
		if(bothfixnums(a, b)){
			FL(stack)[FL(sp)-1] = (fixnum_t)a < (fixnum_t)b ? FL_t : FL_f;
		}else{
			x = numeric_compare(a, b, false, false, false);
			if(x > 1)
				x = numval(fl_compare(a, b));
			FL(stack)[FL(sp)-1] = x < 0 ? FL_t : FL_f;
		}
	}
	NEXT_OP;

OP(OP_ADD2)
LABEL(do_add2):
	FL(stack)[ipd] = (uintptr_t)ip;
	if(0){
OP(OP_SUB2)
LABEL(do_sub2):
		FL(stack)[ipd] = (uintptr_t)ip;
		FL(stack)[FL(sp)-1] = fl_neg(FL(stack)[FL(sp)-1]);
	}
	{
		fixnum_t a, b, c;
		a = FL(stack)[FL(sp)-2];
		b = FL(stack)[FL(sp)-1];
		if(bothfixnums(a, b) && !sadd_overflow(numval(a), numval(b), &c) && fits_fixnum(c)){
			v = fixnum(c);
		}else{
			v = fl_add_any(&FL(stack)[FL(sp)-2], 2);
		}
	}
	POPN(1);
	FL(stack)[FL(sp)-1] = v;
	NEXT_OP;

OP(OP_SETCDR)
	v = FL(stack)[FL(sp)-2];
	if(__unlikely(!iscons(v))){
		FL(stack)[ipd] = (uintptr_t)ip;
		type_error("cons", v);
	}
	cdr_(v) = FL(stack)[FL(sp)-1];
	POPN(1);
	NEXT_OP;

OP(OP_LOADF)
	PUSH(FL_f);
	NEXT_OP;

OP(OP_CONS)
	if(FL(curheap) > FL(lim))
		gc(0);
	c = (cons_t*)FL(curheap);
	FL(curheap) += sizeof(cons_t);
	c->car = FL(stack)[FL(sp)-2];
	c->cdr = FL(stack)[FL(sp)-1];
	FL(stack)[FL(sp)-2] = tagptr(c, TAG_CONS);
	POPN(1);
	NEXT_OP;

OP(OP_EQ)
	FL(stack)[FL(sp)-2] = FL(stack)[FL(sp)-2] == FL(stack)[FL(sp)-1] ? FL_t : FL_f;
	POPN(1);
	NEXT_OP;

OP(OP_SYMBOLP)
	FL(stack)[FL(sp)-1] = issymbol(FL(stack)[FL(sp)-1]) ? FL_t : FL_f;
	NEXT_OP;

OP(OP_NOT)
	FL(stack)[FL(sp)-1] = FL(stack)[FL(sp)-1] == FL_f ? FL_t : FL_f;
	NEXT_OP;

OP(OP_CADR)
	v = FL(stack)[FL(sp)-1];
	if(__likely(iscons(v))){
		v = cdr_(v);
		if(__likely(iscons(v)))
			v = car_(v);
		else
			goto LABEL(cadr_nil);
	}else{
LABEL(cadr_nil):
		if(__unlikely(v != FL_nil)){
			FL(stack)[ipd] = (uintptr_t)ip;
			type_error("cons", v);
		}
	}
	FL(stack)[FL(sp)-1] = v;
	NEXT_OP;

OP(OP_NEG)
LABEL(do_neg):
	FL(stack)[ipd] = (uintptr_t)ip;
	FL(stack)[FL(sp)-1] = fl_neg(FL(stack)[FL(sp)-1]);
	NEXT_OP;

OP(OP_NULLP)
	FL(stack)[FL(sp)-1] = FL(stack)[FL(sp)-1] == FL_nil ? FL_t : FL_f;
	NEXT_OP;

OP(OP_BOOLEANP)
	v = FL(stack)[FL(sp)-1];
	FL(stack)[FL(sp)-1] = (v == FL_t || v == FL_f) ? FL_t : FL_f;
	NEXT_OP;

OP(OP_NUMBERP)
	v = FL(stack)[FL(sp)-1];
	FL(stack)[FL(sp)-1] = fl_isnumber(v) ? FL_t : FL_f;
	NEXT_OP;

OP(OP_FIXNUMP)
	FL(stack)[FL(sp)-1] = isfixnum(FL(stack)[FL(sp)-1]) ? FL_t : FL_f;
	NEXT_OP;

OP(OP_BOUNDP)
	FL(stack)[ipd] = (uintptr_t)ip;
	sym = tosymbol(FL(stack)[FL(sp)-1]);
	FL(stack)[FL(sp)-1] = sym->binding == UNBOUND ? FL_f : FL_t;
	NEXT_OP;

OP(OP_BUILTINP)
	v = FL(stack)[FL(sp)-1];
	FL(stack)[FL(sp)-1] = (isbuiltin(v) || iscbuiltin(v)) ? FL_t : FL_f;
	NEXT_OP;

OP(OP_FUNCTIONP)
	v = FL(stack)[FL(sp)-1];
	FL(stack)[FL(sp)-1] =
		((tag(v) == TAG_FUNCTION &&
		  (isbuiltin(v) || v>(N_BUILTINS<<3))) ||
		 iscbuiltin(v)) ? FL_t : FL_f;
	NEXT_OP;

OP(OP_VECTORP)
	FL(stack)[FL(sp)-1] = isvector(FL(stack)[FL(sp)-1]) ? FL_t : FL_f;
	NEXT_OP;

OP(OP_JMPL)
	ip += GET_INT32(ip);
	NEXT_OP;

OP(OP_BRFL)
	ip += POP() == FL_f ? GET_INT32(ip) : 4;
	NEXT_OP;

OP(OP_BRTL)
	ip += POP() != FL_f ? GET_INT32(ip) : 4;
	NEXT_OP;

OP(OP_BRNEL)
	ip += FL(stack)[FL(sp)-2] != FL(stack)[FL(sp)-1] ? GET_INT32(ip) : 4;
	POPN(2);
	NEXT_OP;

OP(OP_BRNNL)
	ip += POP() != FL_nil ? GET_INT32(ip) : 4;
	NEXT_OP;

OP(OP_BRN)
	ip += POP() == FL_nil ? GET_INT16(ip) : 2;
	NEXT_OP;

OP(OP_BRNL)
	ip += POP() == FL_nil ? GET_INT32(ip) : 4;
	NEXT_OP;

OP(OP_EQV)
	if(FL(stack)[FL(sp)-2] == FL(stack)[FL(sp)-1])
		v = FL_t;
	else if(!leafp(FL(stack)[FL(sp)-2]) || !leafp(FL(stack)[FL(sp)-1]))
		v = FL_f;
	else
		v = compare_(FL(stack)[FL(sp)-2], FL(stack)[FL(sp)-1], 1) == 0 ? FL_t : FL_f;
	FL(stack)[FL(sp)-2] = v;
	POPN(1);
	NEXT_OP;

OP(OP_EQUAL)
	if(FL(stack)[FL(sp)-2] == FL(stack)[FL(sp)-1])
		v = FL_t;
	else
		v = compare_(FL(stack)[FL(sp)-2], FL(stack)[FL(sp)-1], 1) == 0 ? FL_t : FL_f;
	FL(stack)[FL(sp)-2] = v;
	POPN(1);
	NEXT_OP;

OP(OP_SETCAR)
	v = FL(stack)[FL(sp)-2];
	if(__unlikely(!iscons(v))){
		FL(stack)[ipd] = (uintptr_t)ip;
		type_error("cons", v);
	}
	car_(v) = FL(stack)[FL(sp)-1];
	POPN(1);
	NEXT_OP;

OP(OP_LIST)
	n = *ip++;
LABEL(apply_list):
	if(n > 0){
		v = list(&FL(stack)[FL(sp)-n], n, 0);
		POPN(n);
		PUSH(v);
	}else{
		PUSH(FL_nil);
	}
	NEXT_OP;

OP(OP_TAPPLY)
	tail = true;
	if(0){
OP(OP_APPLY)
		tail = false;
	}
	n = *ip++;
LABEL(apply_apply):
	v = POP();	 // arglist
	n = FL(sp)-(n-2);  // n-2 == # leading arguments not in the list
	while(iscons(v)){
		if(FL(sp) >= FL(nstack))
			grow_stack();
		PUSH(car_(v));
		v = cdr_(v);
	}
	if(v != FL_nil){
		FL(stack)[ipd] = (uintptr_t)ip;
		lerrorf(FL(ArgError), "apply: last argument: not a list");
	}
	n = FL(sp)-n;
	goto LABEL(do_call);

OP(OP_ADD)
	n = *ip++;
	if(n == 2)
		goto LABEL(do_add2);
LABEL(apply_add):
	FL(stack)[ipd] = (uintptr_t)ip;
	v = fl_add_any(&FL(stack)[FL(sp)-n], n);
	POPN(n);
	PUSH(v);
	NEXT_OP;

OP(OP_SUB)
	n = *ip++;
LABEL(apply_sub):
	if(n == 2)
		goto LABEL(do_sub2);
	if(n == 1)
		goto LABEL(do_neg);
	FL(stack)[ipd] = (uintptr_t)ip;
	i = FL(sp)-n;
	// we need to pass the full arglist on to fl_add_any
	// so it can handle rest args properly
	PUSH(FL(stack)[i]);
	FL(stack)[i] = fixnum(0);
	FL(stack)[i+1] = fl_neg(fl_add_any(&FL(stack)[i], n));
	FL(stack)[i] = POP();
	v = fl_add_any(&FL(stack)[i], 2);
	POPN(n);
	PUSH(v);
	NEXT_OP;

OP(OP_MUL)
	n = *ip++;
LABEL(apply_mul):
	FL(stack)[ipd] = (uintptr_t)ip;
	v = fl_mul_any(&FL(stack)[FL(sp)-n], n);
	POPN(n);
	PUSH(v);
	NEXT_OP;

OP(OP_DIV)
	n = *ip++;
LABEL(apply_div):
	FL(stack)[ipd] = (uintptr_t)ip;
	i = FL(sp)-n;
	if(n == 1){
		FL(stack)[FL(sp)-1] = fl_div2(fixnum(1), FL(stack)[i]);
	}else{
		if(n > 2){
			PUSH(FL(stack)[i]);
			FL(stack)[i] = fixnum(1);
			FL(stack)[i+1] = fl_mul_any(&FL(stack)[i], n);
			FL(stack)[i] = POP();
		}
		v = fl_div2(FL(stack)[i], FL(stack)[i+1]);
		POPN(n);
		PUSH(v);
	}
	NEXT_OP;

OP(OP_IDIV)
	FL(stack)[ipd] = (uintptr_t)ip;
	v = FL(stack)[FL(sp)-2];
	e = FL(stack)[FL(sp)-1];
	if(bothfixnums(v, e)){
		if(e == 0)
			DivideByZeroError();
		v = fixnum(numval(v) / numval(e));
	}else{
		v = fl_idiv2(v, e);
	}
	POPN(1);
	FL(stack)[FL(sp)-1] = v;
	NEXT_OP;

OP(OP_NUMEQ)
	v = FL(stack)[FL(sp)-2]; e = FL(stack)[FL(sp)-1];
	if(bothfixnums(v, e))
		v = v == e ? FL_t : FL_f;
	else{
		FL(stack)[ipd] = (uintptr_t)ip;
		v = numeric_compare(v, e, true, false, true) == 0 ? FL_t : FL_f;
	}
	POPN(1);
	FL(stack)[FL(sp)-1] = v;
	NEXT_OP;

OP(OP_COMPARE)
	FL(stack)[FL(sp)-2] = compare_(FL(stack)[FL(sp)-2], FL(stack)[FL(sp)-1], 0);
	POPN(1);
	NEXT_OP;

OP(OP_ARGC)
	n = *ip++;
	if(0){
OP(OP_LARGC)
		n = GET_INT32(ip);
		ip += 4;
	}
	FL(stack)[ipd] = (uintptr_t)ip;
	argcount(nargs, n);
	NEXT_OP;

OP(OP_VECTOR)
	n = *ip++;
LABEL(apply_vector):
	v = alloc_vector(n, 0);
	if(n){
		memcpy(&vector_elt(v, 0), &FL(stack)[FL(sp)-n], n*sizeof(value_t));
		POPN(n);
	}
	PUSH(v);
	NEXT_OP;

OP(OP_ASET)
	FL(stack)[ipd] = (uintptr_t)ip;
	v = FL(stack)[FL(sp)-3];
	n = 3;
	if(0){
LABEL(apply_aset):
		v = FL(stack)[FL(sp)-n];
		for(i = n-1; i >= 3; i--){
			if(isarray(v)){
				FL(stack)[FL(sp)-i-1] = v;
				v = cvalue_array_aref(&FL(stack)[FL(sp)-i-1]);
				continue;
			}
			e = FL(stack)[FL(sp)-i];
			isz = tosize(e);
			if(isvector(v)){
				if(__unlikely(isz >= vector_size(v)))
					bounds_error(v, e);
				v = vector_elt(v, isz);
				continue;
			}
			if(!iscons(v) && v != FL_nil)
				type_error("sequence", v);
			for(value_t v0 = v;; isz--){
				if(isz == 0){
					v = car_(v);
					break;
				}
				v = cdr_(v);
				if(__unlikely(!iscons(v)))
					bounds_error(v0, e);
			}
		}
		FL(stack)[FL(sp)-3] = v;
	}
	e = FL(stack)[FL(sp)-2];
	isz = tosize(e);
	if(isvector(v)){
		if(__unlikely(isz >= vector_size(v)))
			bounds_error(v, e);
		vector_elt(v, isz) = (e = FL(stack)[FL(sp)-1]);
	}else if(iscons(v) || v == FL_nil){
		for(value_t v0 = v;; isz--){
			if(isz == 0){
				car_(v) = (e = FL(stack)[FL(sp)-1]);
				break;
			}
			v = cdr_(v);
			if(__unlikely(!iscons(v)))
				bounds_error(v0, e);
		}
	}else if(isarray(v)){
		e = cvalue_array_aset(&FL(stack)[FL(sp)-3]);
	}else{
		type_error("sequence", v);
	}
	POPN(n);
	PUSH(e);
	NEXT_OP;

OP(OP_FOR)
	FL(stack)[ipd] = (uintptr_t)ip;
	s  = tofixnum(FL(stack)[FL(sp)-3]);
	hi = tofixnum(FL(stack)[FL(sp)-2]);
	v = FL_void;
	FL(sp) += 2;
	n = FL(sp);
	for(; s <= hi; s++){
		FL(stack)[FL(sp)-2] = FL(stack)[FL(sp)-3];
		FL(stack)[FL(sp)-1] = fixnum(s);
		v = _applyn(1);
		FL(sp) = n;
	}
	POPN(4);
	FL(stack)[FL(sp)-1] = v;
	NEXT_OP;

OP(OP_LOADNIL)
	PUSH(FL_nil);
	NEXT_OP;

OP(OP_LOADI8)
	s = (int8_t)*ip++;
	PUSH(fixnum(s));
	NEXT_OP;

OP(OP_LOADVL)
	v = fn_vals(FL(stack)[bp-1]);
	v = vector_elt(v, GET_INT32(ip));
	ip += 4;
	PUSH(v);
	NEXT_OP;

OP(OP_SETGL)
	v = fn_vals(FL(stack)[bp-1]);
	v = vector_elt(v, GET_INT32(ip));
	ip += 4;
	if(0){
OP(OP_SETG)
		v = fn_vals(FL(stack)[bp-1]);
		assert(*ip < vector_size(v));
		v = vector_elt(v, *ip);
		ip++;
	}
	assert(issymbol(v));
	sym = (symbol_t*)ptr(v);
	v = FL(stack)[FL(sp)-1];
	if(!isconstant(sym))
		sym->binding = v;
	NEXT_OP;

OP(OP_LOADAL)
	assert(nargs > 0);
	i = GET_INT32(ip);
	ip += 4;
	v = FL(stack)[bp+i];
	PUSH(v);
	NEXT_OP;

OP(OP_SETAL)
	v = FL(stack)[FL(sp)-1];
	i = GET_INT32(ip);
	ip += 4;
	FL(stack)[bp+i] = v;
	NEXT_OP;

OP(OP_LOADCL)
	i = GET_INT32(ip);
	ip += 4;
	v = FL(stack)[bp+nargs];
	PUSH(vector_elt(v, i));
	NEXT_OP;

OP(OP_VARGC)
	i = *ip++;
	if(0){
OP(OP_LVARGC)
		i = GET_INT32(ip);
		ip += 4;
	}
	s = (fixnum_t)nargs - (fixnum_t)i;
	if(s > 0){
		v = list(&FL(stack)[bp+i], s, 0);
		FL(stack)[bp+i] = v;
		if(s > 1){
			FL(stack)[bp+i+1] = FL(stack)[bp+nargs+0];
			FL(stack)[bp+i+2] = FL(stack)[bp+nargs+1];
			FL(stack)[bp+i+3] = i+1;
			FL(stack)[bp+i+4] = 0;
			FL(sp) =  bp+i+5;
			FL(curr_frame) = FL(sp);
		}
	}else if(__unlikely(s < 0)){
		FL(stack)[ipd] = (uintptr_t)ip;
		lerrorf(FL(ArgError), "too few arguments");
	}else{
		FL(sp)++;
		FL(stack)[FL(sp)-2] = i+1;
		FL(stack)[FL(sp)-3] = FL(stack)[FL(sp)-4];
		FL(stack)[FL(sp)-4] = FL(stack)[FL(sp)-5];
		FL(stack)[FL(sp)-5] = FL_nil;
		FL(curr_frame) = FL(sp);
	}
	ipd = FL(sp)-1;
	nargs = i+1;
	NEXT_OP;

OP(OP_TRYCATCH)
	FL(stack)[ipd] = (uintptr_t)ip;
	v = do_trycatch();
	POPN(1);
	FL(stack)[FL(sp)-1] = v;
	NEXT_OP;

OP(OP_OPTARGS)
	i = GET_INT32(ip);
	ip += 4;
	n = GET_INT32(ip);
	ip += 4;
	if(__unlikely(nargs < i)){
		FL(stack)[ipd] = (uintptr_t)ip;
		lerrorf(FL(ArgError), "too few arguments");
	}
	if((int32_t)n > 0){
		if(__unlikely(nargs > n)){
			FL(stack)[ipd] = (uintptr_t)ip;
			lerrorf(FL(ArgError), "too many arguments");
		}
	}else
		n = -n;
	if(__likely(n > nargs)){
		n -= nargs;
		FL(sp) += n;
		FL(stack)[FL(sp)-1] = FL(stack)[FL(sp)-n-1];
		FL(stack)[FL(sp)-2] = nargs+n;
		FL(stack)[FL(sp)-3] = FL(stack)[FL(sp)-n-3];
		FL(stack)[FL(sp)-4] = FL(stack)[FL(sp)-n-4];
		FL(curr_frame) = FL(sp);
		ipd = FL(sp)-1;
		for(i = 0; i < n; i++)
			FL(stack)[bp+nargs+i] = UNBOUND;
		nargs += n;
	}
	NEXT_OP;

OP(OP_BRBOUND)
	i = GET_INT32(ip);
	ip += 4;
	v = FL(stack)[bp+i];
	PUSH(v != UNBOUND ? FL_t : FL_f);
	NEXT_OP;

OP(OP_KEYARGS)
	v = fn_vals(FL(stack)[bp-1]);
	v = vector_elt(v, 0);
	i = GET_INT32(ip);
	ip += 4;
	n = GET_INT32(ip);
	ip += 4;
	s = GET_INT32(ip);
	ip += 4;
	FL(stack)[ipd] = (uintptr_t)ip;
	nargs = process_keys(v, i, n, labs(s)-(i+n), bp, nargs, s<0);
	ipd = FL(sp)-1;
	NEXT_OP;