shithub: femtolisp

Download patch

ref: df5ad841ec2f08c3f924229cd76581e439d37558
parent: c2cff341a39d3182820a0fc1f5462207cf78a6c2
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Thu Dec 26 16:20:46 EST 2024

vm: take the op table out to separate files

--- a/flisp.c
+++ b/flisp.c
@@ -895,1002 +895,27 @@
 #if defined(COMPUTED_GOTO)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wpedantic"
-#define OP(x) op_##x:
-#define NEXT_OP goto *ops[*ip++]
-#define GOTO_OP_OFFSET(op) [op] = &&op_##op
 	static const void *ops[] = {
-		GOTO_OP_OFFSET(OP_LOADA0),
-		GOTO_OP_OFFSET(OP_LOADA1),
-		GOTO_OP_OFFSET(OP_LOADV),
-		GOTO_OP_OFFSET(OP_BRF),
-		GOTO_OP_OFFSET(OP_POP),
-		GOTO_OP_OFFSET(OP_CALL),
-		GOTO_OP_OFFSET(OP_TCALL),
-		GOTO_OP_OFFSET(OP_LOADG),
-		GOTO_OP_OFFSET(OP_LOADA),
-		GOTO_OP_OFFSET(OP_LOADC),
-		GOTO_OP_OFFSET(OP_RET),
-		GOTO_OP_OFFSET(OP_DUP),
-		GOTO_OP_OFFSET(OP_CAR),
-		GOTO_OP_OFFSET(OP_CDR),
-		GOTO_OP_OFFSET(OP_CLOSURE),
-		GOTO_OP_OFFSET(OP_SETA),
-		GOTO_OP_OFFSET(OP_JMP),
-		GOTO_OP_OFFSET(OP_LOADC0),
-		GOTO_OP_OFFSET(OP_CONSP),
-		GOTO_OP_OFFSET(OP_BRNE),
-		GOTO_OP_OFFSET(OP_LOADT),
-		GOTO_OP_OFFSET(OP_LOAD0),
-		GOTO_OP_OFFSET(OP_LOADC1),
-		GOTO_OP_OFFSET(OP_AREF2),
-		GOTO_OP_OFFSET(OP_AREF),
-		GOTO_OP_OFFSET(OP_ATOMP),
-		GOTO_OP_OFFSET(OP_BRT),
-		GOTO_OP_OFFSET(OP_BRNN),
-		GOTO_OP_OFFSET(OP_LOAD1),
-		GOTO_OP_OFFSET(OP_LT),
-		GOTO_OP_OFFSET(OP_ADD2),
-		GOTO_OP_OFFSET(OP_SETCDR),
-		GOTO_OP_OFFSET(OP_LOADF),
-		GOTO_OP_OFFSET(OP_CONS),
-		GOTO_OP_OFFSET(OP_EQ),
-		GOTO_OP_OFFSET(OP_SYMBOLP),
-		GOTO_OP_OFFSET(OP_NOT),
-		GOTO_OP_OFFSET(OP_CADR),
-		GOTO_OP_OFFSET(OP_NEG),
-		GOTO_OP_OFFSET(OP_NULLP),
-		GOTO_OP_OFFSET(OP_BOOLEANP),
-		GOTO_OP_OFFSET(OP_NUMBERP),
-		GOTO_OP_OFFSET(OP_FIXNUMP),
-		GOTO_OP_OFFSET(OP_BOUNDP),
-		GOTO_OP_OFFSET(OP_BUILTINP),
-		GOTO_OP_OFFSET(OP_FUNCTIONP),
-		GOTO_OP_OFFSET(OP_VECTORP),
-		GOTO_OP_OFFSET(OP_SETCAR),
-		GOTO_OP_OFFSET(OP_JMPL),
-		GOTO_OP_OFFSET(OP_BRFL),
-		GOTO_OP_OFFSET(OP_BRTL),
-		GOTO_OP_OFFSET(OP_EQV),
-		GOTO_OP_OFFSET(OP_EQUAL),
-		GOTO_OP_OFFSET(OP_LIST),
-		GOTO_OP_OFFSET(OP_APPLY),
-		GOTO_OP_OFFSET(OP_ADD),
-		GOTO_OP_OFFSET(OP_SUB),
-		GOTO_OP_OFFSET(OP_MUL),
-		GOTO_OP_OFFSET(OP_DIV),
-		GOTO_OP_OFFSET(OP_IDIV),
-		GOTO_OP_OFFSET(OP_NUMEQ),
-		GOTO_OP_OFFSET(OP_COMPARE),
-		GOTO_OP_OFFSET(OP_ARGC),
-		GOTO_OP_OFFSET(OP_VECTOR),
-		GOTO_OP_OFFSET(OP_ASET),
-		GOTO_OP_OFFSET(OP_LOADNIL),
-		GOTO_OP_OFFSET(OP_LOADI8),
-		GOTO_OP_OFFSET(OP_LOADVL),
-		GOTO_OP_OFFSET(OP_LOADGL),
-		GOTO_OP_OFFSET(OP_LOADAL),
-		GOTO_OP_OFFSET(OP_LOADCL),
-		GOTO_OP_OFFSET(OP_SETG),
-		GOTO_OP_OFFSET(OP_SETGL),
-		GOTO_OP_OFFSET(OP_SETAL),
-		GOTO_OP_OFFSET(OP_VARGC),
-		GOTO_OP_OFFSET(OP_TRYCATCH),
-		GOTO_OP_OFFSET(OP_FOR),
-		GOTO_OP_OFFSET(OP_TAPPLY),
-		GOTO_OP_OFFSET(OP_SUB2),
-		GOTO_OP_OFFSET(OP_LARGC),
-		GOTO_OP_OFFSET(OP_LVARGC),
-		GOTO_OP_OFFSET(OP_CALLL),
-		GOTO_OP_OFFSET(OP_TCALLL),
-		GOTO_OP_OFFSET(OP_BRNEL),
-		GOTO_OP_OFFSET(OP_BRNNL),
-		GOTO_OP_OFFSET(OP_BRN),
-		GOTO_OP_OFFSET(OP_BRNL),
-		GOTO_OP_OFFSET(OP_OPTARGS),
-		GOTO_OP_OFFSET(OP_BRBOUND),
-		GOTO_OP_OFFSET(OP_KEYARGS),
-		GOTO_OP_OFFSET(OP_BOX),
-		GOTO_OP_OFFSET(OP_BOXL),
-		GOTO_OP_OFFSET(OP_SHIFT),
-		GOTO_OP_OFFSET(OP_LOADVOID),
+#define GOTO_OP_OFFSET(op) [op] = &&op_##op
+#include "vm_goto.inc"
+#undef GOTO_OP_OFFSET
 	};
+#define NEXT_OP goto *ops[*ip++]
+#define OP(x) op_##x:
 	NEXT_OP;
-#else
-#define OP(x) case x:
-#define NEXT_OP break
+#include "vm.inc"
+#undef OP
+#undef NEXT_OP
+#pragma GCC diagnostic pop
+#else /* just a usual (portable) switch/case */
 	uint8_t op = *ip++;
 	while(1){
 		switch(op){
-#endif
-		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
-			}
-		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 apply_list;
-						case OP_VECTOR: goto apply_vector;
-						case OP_APPLY:  goto apply_apply;
-						case OP_ADD:	goto apply_add;
-						case OP_SUB:	goto apply_sub;
-						case OP_MUL:	goto apply_mul;
-						case OP_DIV:	goto apply_div;
-						case OP_AREF:	goto apply_aref;
-						case OP_ASET:	goto 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++;
-			}
-		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)
-		do_add2:
-			FL(stack)[ipd] = (uintptr_t)ip;
-			if(0){
-		OP(OP_SUB2)
-		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 cadr_nil;
-			}else{
-			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)
-		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++;
-		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++;
-		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 do_call;
-
-		OP(OP_ADD)
-			n = *ip++;
-			if(n == 2)
-				goto do_add2;
-		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++;
-		apply_sub:
-			if(n == 2)
-				goto do_sub2;
-			if(n == 1)
-				goto 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++;
-		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++;
-		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++;
-		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){
-		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;
-
-#if defined(COMPUTED_GOTO)
-#pragma GCC diagnostic pop
-#else
+#define NEXT_OP break
+#define OP(x) case x:
+#include "vm.inc"
+#undef OP
+#undef NEXT_OP
 		}
 		op = *ip++;
 	}
--- a/mkfile
+++ b/mkfile
@@ -56,7 +56,7 @@
 		`{ls `{echo $OFILES | sed 's/\.'$O'/.c/g'} >[2]/dev/null} | sort >$target
 
 cvalues.$O: fl_arith_any.inc
-flisp.$O: maxstack.inc
+flisp.$O: maxstack.inc vm.inc
 
 plan9/flisp.boot.s:D: flisp.boot
 	aux/data2s boot <flisp.boot >$target
--- /dev/null
+++ b/vm.inc
@@ -1,0 +1,885 @@
+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
+	}
+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 apply_list;
+				case OP_VECTOR: goto apply_vector;
+				case OP_APPLY:  goto apply_apply;
+				case OP_ADD:	goto apply_add;
+				case OP_SUB:	goto apply_sub;
+				case OP_MUL:	goto apply_mul;
+				case OP_DIV:	goto apply_div;
+				case OP_AREF:	goto apply_aref;
+				case OP_ASET:	goto 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++;
+	}
+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)
+do_add2:
+	FL(stack)[ipd] = (uintptr_t)ip;
+	if(0){
+OP(OP_SUB2)
+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 cadr_nil;
+	}else{
+	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)
+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++;
+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++;
+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 do_call;
+
+OP(OP_ADD)
+	n = *ip++;
+	if(n == 2)
+		goto do_add2;
+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++;
+apply_sub:
+	if(n == 2)
+		goto do_sub2;
+	if(n == 1)
+		goto 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++;
+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++;
+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++;
+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){
+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;
--- /dev/null
+++ b/vm_goto.inc
@@ -1,0 +1,94 @@
+GOTO_OP_OFFSET(OP_LOADA0),
+GOTO_OP_OFFSET(OP_LOADA1),
+GOTO_OP_OFFSET(OP_LOADV),
+GOTO_OP_OFFSET(OP_BRF),
+GOTO_OP_OFFSET(OP_POP),
+GOTO_OP_OFFSET(OP_CALL),
+GOTO_OP_OFFSET(OP_TCALL),
+GOTO_OP_OFFSET(OP_LOADG),
+GOTO_OP_OFFSET(OP_LOADA),
+GOTO_OP_OFFSET(OP_LOADC),
+GOTO_OP_OFFSET(OP_RET),
+GOTO_OP_OFFSET(OP_DUP),
+GOTO_OP_OFFSET(OP_CAR),
+GOTO_OP_OFFSET(OP_CDR),
+GOTO_OP_OFFSET(OP_CLOSURE),
+GOTO_OP_OFFSET(OP_SETA),
+GOTO_OP_OFFSET(OP_JMP),
+GOTO_OP_OFFSET(OP_LOADC0),
+GOTO_OP_OFFSET(OP_CONSP),
+GOTO_OP_OFFSET(OP_BRNE),
+GOTO_OP_OFFSET(OP_LOADT),
+GOTO_OP_OFFSET(OP_LOAD0),
+GOTO_OP_OFFSET(OP_LOADC1),
+GOTO_OP_OFFSET(OP_AREF2),
+GOTO_OP_OFFSET(OP_AREF),
+GOTO_OP_OFFSET(OP_ATOMP),
+GOTO_OP_OFFSET(OP_BRT),
+GOTO_OP_OFFSET(OP_BRNN),
+GOTO_OP_OFFSET(OP_LOAD1),
+GOTO_OP_OFFSET(OP_LT),
+GOTO_OP_OFFSET(OP_ADD2),
+GOTO_OP_OFFSET(OP_SETCDR),
+GOTO_OP_OFFSET(OP_LOADF),
+GOTO_OP_OFFSET(OP_CONS),
+GOTO_OP_OFFSET(OP_EQ),
+GOTO_OP_OFFSET(OP_SYMBOLP),
+GOTO_OP_OFFSET(OP_NOT),
+GOTO_OP_OFFSET(OP_CADR),
+GOTO_OP_OFFSET(OP_NEG),
+GOTO_OP_OFFSET(OP_NULLP),
+GOTO_OP_OFFSET(OP_BOOLEANP),
+GOTO_OP_OFFSET(OP_NUMBERP),
+GOTO_OP_OFFSET(OP_FIXNUMP),
+GOTO_OP_OFFSET(OP_BOUNDP),
+GOTO_OP_OFFSET(OP_BUILTINP),
+GOTO_OP_OFFSET(OP_FUNCTIONP),
+GOTO_OP_OFFSET(OP_VECTORP),
+GOTO_OP_OFFSET(OP_SETCAR),
+GOTO_OP_OFFSET(OP_JMPL),
+GOTO_OP_OFFSET(OP_BRFL),
+GOTO_OP_OFFSET(OP_BRTL),
+GOTO_OP_OFFSET(OP_EQV),
+GOTO_OP_OFFSET(OP_EQUAL),
+GOTO_OP_OFFSET(OP_LIST),
+GOTO_OP_OFFSET(OP_APPLY),
+GOTO_OP_OFFSET(OP_ADD),
+GOTO_OP_OFFSET(OP_SUB),
+GOTO_OP_OFFSET(OP_MUL),
+GOTO_OP_OFFSET(OP_DIV),
+GOTO_OP_OFFSET(OP_IDIV),
+GOTO_OP_OFFSET(OP_NUMEQ),
+GOTO_OP_OFFSET(OP_COMPARE),
+GOTO_OP_OFFSET(OP_ARGC),
+GOTO_OP_OFFSET(OP_VECTOR),
+GOTO_OP_OFFSET(OP_ASET),
+GOTO_OP_OFFSET(OP_LOADNIL),
+GOTO_OP_OFFSET(OP_LOADI8),
+GOTO_OP_OFFSET(OP_LOADVL),
+GOTO_OP_OFFSET(OP_LOADGL),
+GOTO_OP_OFFSET(OP_LOADAL),
+GOTO_OP_OFFSET(OP_LOADCL),
+GOTO_OP_OFFSET(OP_SETG),
+GOTO_OP_OFFSET(OP_SETGL),
+GOTO_OP_OFFSET(OP_SETAL),
+GOTO_OP_OFFSET(OP_VARGC),
+GOTO_OP_OFFSET(OP_TRYCATCH),
+GOTO_OP_OFFSET(OP_FOR),
+GOTO_OP_OFFSET(OP_TAPPLY),
+GOTO_OP_OFFSET(OP_SUB2),
+GOTO_OP_OFFSET(OP_LARGC),
+GOTO_OP_OFFSET(OP_LVARGC),
+GOTO_OP_OFFSET(OP_CALLL),
+GOTO_OP_OFFSET(OP_TCALLL),
+GOTO_OP_OFFSET(OP_BRNEL),
+GOTO_OP_OFFSET(OP_BRNNL),
+GOTO_OP_OFFSET(OP_BRN),
+GOTO_OP_OFFSET(OP_BRNL),
+GOTO_OP_OFFSET(OP_OPTARGS),
+GOTO_OP_OFFSET(OP_BRBOUND),
+GOTO_OP_OFFSET(OP_KEYARGS),
+GOTO_OP_OFFSET(OP_BOX),
+GOTO_OP_OFFSET(OP_BOXL),
+GOTO_OP_OFFSET(OP_SHIFT),
+GOTO_OP_OFFSET(OP_LOADVOID),