shithub: sl

Download patch

ref: fdd1fd39e3a616139e48dae992ebc5d5cd710fb7
parent: 377087f52df398745bee200286c38cc0177b1632
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Tue Feb 11 21:40:51 EST 2025

vm: rearrange ops logic from most frequent to least frequent hit

Based on coverage reports when running tests.

--- a/src/vm.inc
+++ b/src/vm.inc
@@ -2,24 +2,6 @@
 	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_BRN)
-	ip += POP() == FL_nil ? GET_INT16(ip) : 2;
-	NEXT_OP;
-
-OP(OP_POP)
-	POPN(1);
-	NEXT_OP;
-
 OP(OP_TCALLL)
 	tail = true;
 	if(0){
@@ -63,10 +45,10 @@
 			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_LIST:   goto LABEL(apply_list);
+		case OP_APPLY:  goto LABEL(apply_apply);
 		case OP_SUB:	goto LABEL(apply_sub);
 		case OP_MUL:	goto LABEL(apply_mul);
 		case OP_DIV:	goto LABEL(apply_div);
@@ -91,6 +73,51 @@
 	}
 	type_error("function", v);
 
+OP(OP_ARGC)
+	n = *ip++;
+	if(0){
+OP(OP_ARGCL)
+		n = GET_INT32(ip);
+		ip += 4;
+	}
+	if(fl_unlikely(nargs != n)){
+		FL(stack)[ipd] = (uintptr_t)ip;
+		arity_error(nargs, n);
+	}
+	NEXT_OP;
+
+OP(OP_LOADA1)
+	PUSH(FL(stack)[bp+1]);
+	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_LOAD1)
+	PUSH(fixnum(1));
+	NEXT_OP;
+
+OP(OP_LOADA)
+	i = *ip++;
+	v = FL(stack)[bp+i];
+	PUSH(v);
+	NEXT_OP;
+
+OP(OP_BRN)
+	ip += POP() == FL_nil ? GET_INT16(ip) : 2;
+	NEXT_OP;
+
 OP(OP_LOADGL)
 	v = fn_vals(FL(stack)[bp-1]);
 	v = vector_elt(v, GET_INT32(ip));
@@ -111,54 +138,75 @@
 	PUSH(sym->binding);
 	NEXT_OP;
 
-OP(OP_LOADA)
-	i = *ip++;
-	v = FL(stack)[bp+i];
-	PUSH(v);
+OP(OP_LT)
+	n = *ip++;
+LABEL(apply_lt):
+	{
+		i = n;
+		value_t a = FL(stack)[FL(sp)-i], b;
+		for(v = FL_t; i > 1; a = b){
+			i--;
+			b = FL(stack)[FL(sp)-i];
+			if(bothfixnums(a, b)){
+				if((fixnum_t)a >= (fixnum_t)b){
+					v = FL_nil;
+					break;
+				}
+			}else{
+				x = numeric_compare(a, b, false, false, false);
+				if(x > 1)
+					x = numval(fl_compare(a, b, false));
+				if(x >= 0){
+					v = FL_nil;
+					break;
+				}
+			}
+		}
+		POPN(n);
+		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));
+OP(OP_LOADV)
+	v = fn_vals(FL(stack)[bp-1]);
+	assert(*ip < vector_size(v));
+	PUSH(vector_elt(v, *ip++));
 	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;
+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]);
+	}
+	{
+		value_t a, b, q;
+		a = FL(stack)[FL(sp)-2];
+		b = FL(stack)[FL(sp)-1];
+		if(bothfixnums(a, b) && !sadd_overflow(numval(a), numval(b), &q) && fits_fixnum(q)){
+			v = fixnum(q);
+		}else{
+			v = fl_add_any(&FL(stack)[FL(sp)-2], 2);
+		}
+	}
+	POPN(1);
+	FL(stack)[FL(sp)-1] = 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;
+OP(OP_LOADI8)
+	s = (int8_t)*ip++;
+	PUSH(fixnum(s));
 	NEXT_OP;
 
-OP(OP_SHIFT)
-	i = *ip++;
-	FL(stack)[FL(sp)-1-i] = FL(stack)[FL(sp)-1];
-	FL(sp) -= i;
+OP(OP_POP)
+	POPN(1);
 	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;
+OP(OP_BRNN)
+	ip += POP() != FL_nil ? GET_INT16(ip) : 2;
 	NEXT_OP;
 
 OP(OP_DUP)
@@ -166,6 +214,10 @@
 	FL(sp)++;
 	NEXT_OP;
 
+OP(OP_LOADC0)
+	PUSH(vector_elt(FL(stack)[bp+nargs], 0));
+	NEXT_OP;
+
 OP(OP_CAR)
 	v = FL(stack)[FL(sp)-1];
 	if(fl_likely(iscons(v)))
@@ -177,17 +229,6 @@
 	FL(stack)[FL(sp)-1] = v;
 	NEXT_OP;
 
-OP(OP_CDR)
-	v = FL(stack)[FL(sp)-1];
-	if(fl_likely(iscons(v)))
-		v = cdr_(v);
-	else if(fl_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);
@@ -215,6 +256,42 @@
 	FL(stack)[FL(sp)-1] = tagptr(pv, TAG_FUNCTION);
 	NEXT_OP;
 
+OP(OP_CONS)
+	if(FL(curheap) > FL(lim))
+		fl_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_BRNE)
+	ip += FL(stack)[FL(sp)-2] != FL(stack)[FL(sp)-1] ? GET_INT16(ip) : 2;
+	POPN(2);
+	NEXT_OP;
+
+OP(OP_CDR)
+	v = FL(stack)[FL(sp)-1];
+	if(fl_likely(iscons(v)))
+		v = cdr_(v);
+	else if(fl_unlikely(v != FL_nil)){
+		FL(stack)[ipd] = (uintptr_t)ip;
+		type_error("cons", v);
+	}
+	FL(stack)[FL(sp)-1] = v;
+	NEXT_OP;
+
+OP(OP_LOADVOID)
+	PUSH(FL_void);
+	NEXT_OP;
+
+OP(OP_NOT)
+	v = FL(stack)[FL(sp)-1];
+	FL(stack)[FL(sp)-1] = v == FL_nil ? FL_t : FL_nil;
+	NEXT_OP;
+
 OP(OP_SETA)
 	v = FL(stack)[FL(sp)-1];
 	i = *ip++;
@@ -221,39 +298,76 @@
 	FL(stack)[bp+i] = v;
 	NEXT_OP;
 
-OP(OP_JMP)
-	ip += GET_INT16(ip);
+OP(OP_VARGC)
+	i = *ip++;
+	if(0){
+OP(OP_VARGCL)
+		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(fl_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_LOADC0)
-	PUSH(vector_elt(FL(stack)[bp+nargs], 0));
+OP(OP_SHIFT)
+	i = *ip++;
+	FL(stack)[FL(sp)-1-i] = FL(stack)[FL(sp)-1];
+	FL(sp) -= i;
 	NEXT_OP;
 
-OP(OP_CONSP)
-	FL(stack)[FL(sp)-1] = iscons(FL(stack)[FL(sp)-1]) ? FL_t : FL_nil;
+OP(OP_SETCAR)
+	v = FL(stack)[FL(sp)-2];
+	if(fl_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_BRNE)
-	ip += FL(stack)[FL(sp)-2] != FL(stack)[FL(sp)-1] ? GET_INT16(ip) : 2;
-	POPN(2);
+OP(OP_LOADNIL)
+	PUSH(FL_nil);
 	NEXT_OP;
 
-OP(OP_LOADT)
-	PUSH(FL_t);
+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_LOADVOID)
-	PUSH(FL_void);
+OP(OP_JMP)
+	ip += GET_INT16(ip);
 	NEXT_OP;
 
-OP(OP_LOAD0)
-	PUSH(fixnum(0));
+OP(OP_ATOMP)
+	FL(stack)[FL(sp)-1] = iscons(FL(stack)[FL(sp)-1]) ? FL_nil : FL_t;
 	NEXT_OP;
 
-OP(OP_LOADC1)
-	PUSH(vector_elt(FL(stack)[bp+nargs], 1));
-	NEXT_OP;
-
 OP(OP_AREF2)
 	n = 2;
 	if(0){
@@ -293,129 +407,6 @@
 	PUSH(v);
 	NEXT_OP;
 
-OP(OP_ATOMP)
-	FL(stack)[FL(sp)-1] = iscons(FL(stack)[FL(sp)-1]) ? FL_nil : FL_t;
-	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)
-	n = *ip++;
-LABEL(apply_lt):
-	{
-		i = n;
-		value_t a = FL(stack)[FL(sp)-i], b;
-		for(v = FL_t; i > 1; a = b){
-			i--;
-			b = FL(stack)[FL(sp)-i];
-			if(bothfixnums(a, b)){
-				if((fixnum_t)a >= (fixnum_t)b){
-					v = FL_nil;
-					break;
-				}
-			}else{
-				x = numeric_compare(a, b, false, false, false);
-				if(x > 1)
-					x = numval(fl_compare(a, b, false));
-				if(x >= 0){
-					v = FL_nil;
-					break;
-				}
-			}
-		}
-		POPN(n);
-		PUSH(v);
-	}
-	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]);
-	}
-	{
-		value_t a, b, q;
-		a = FL(stack)[FL(sp)-2];
-		b = FL(stack)[FL(sp)-1];
-		if(bothfixnums(a, b) && !sadd_overflow(numval(a), numval(b), &q) && fits_fixnum(q)){
-			v = fixnum(q);
-		}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(fl_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_CONS)
-	if(FL(curheap) > FL(lim))
-		fl_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_nil;
-	POPN(1);
-	NEXT_OP;
-
-OP(OP_SYMBOLP)
-	FL(stack)[FL(sp)-1] = issymbol(FL(stack)[FL(sp)-1]) ? FL_t : FL_nil;
-	NEXT_OP;
-
-OP(OP_NOT)
-	v = FL(stack)[FL(sp)-1];
-	FL(stack)[FL(sp)-1] = v == FL_nil ? FL_t : FL_nil;
-	NEXT_OP;
-
-OP(OP_CADR)
-	v = FL(stack)[FL(sp)-1];
-	if(fl_likely(iscons(v))){
-		v = cdr_(v);
-		if(fl_likely(iscons(v)))
-			v = car_(v);
-		else
-			goto LABEL(cadr_nil);
-	}else{
-LABEL(cadr_nil):
-		if(fl_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_NANP)
 	{
 		value_t q = FL(stack)[FL(sp)-1];
@@ -439,85 +430,157 @@
 	}
 	NEXT_OP;
 
-OP(OP_NUMBERP)
-	v = FL(stack)[FL(sp)-1];
-	FL(stack)[FL(sp)-1] = fl_isnumber(v) ? FL_t : FL_nil;
+OP(OP_LOAD0)
+	PUSH(fixnum(0));
 	NEXT_OP;
 
-OP(OP_FIXNUMP)
-	FL(stack)[FL(sp)-1] = isfixnum(FL(stack)[FL(sp)-1]) ? FL_t : FL_nil;
+OP(OP_SETCDR)
+	v = FL(stack)[FL(sp)-2];
+	if(fl_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_BOUNDP)
-	FL(stack)[ipd] = (uintptr_t)ip;
-	sym = tosymbol(FL(stack)[FL(sp)-1]);
-	FL(stack)[FL(sp)-1] = sym->binding == UNBOUND ? FL_nil : FL_t;
+OP(OP_LOADC1)
+	PUSH(vector_elt(FL(stack)[bp+nargs], 1));
 	NEXT_OP;
 
-OP(OP_BUILTINP)
-	v = FL(stack)[FL(sp)-1];
-	FL(stack)[FL(sp)-1] = (isbuiltin(v) || iscbuiltin(v)) ? FL_t : FL_nil;
+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(fl_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(fl_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(fl_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(fl_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_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_nil;
+OP(OP_EQUAL)
+	if(FL(stack)[FL(sp)-2] == FL(stack)[FL(sp)-1])
+		v = FL_t;
+	else
+		v = fl_compare(FL(stack)[FL(sp)-2], FL(stack)[FL(sp)-1], true) == 0 ? FL_t : FL_nil;//FL_nil
+	FL(stack)[FL(sp)-2] = v;
+	POPN(1);
 	NEXT_OP;
 
-OP(OP_VECTORP)
-	FL(stack)[FL(sp)-1] = isvector(FL(stack)[FL(sp)-1]) ? FL_t : FL_nil;
+OP(OP_CONSP)
+	FL(stack)[FL(sp)-1] = iscons(FL(stack)[FL(sp)-1]) ? FL_t : FL_nil;
 	NEXT_OP;
 
-OP(OP_JMPL)
-	ip += GET_INT32(ip);
+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_BRNEL)
-	ip += FL(stack)[FL(sp)-2] != FL(stack)[FL(sp)-1] ? GET_INT32(ip) : 4;
-	POPN(2);
+OP(OP_SYMBOLP)
+	FL(stack)[FL(sp)-1] = issymbol(FL(stack)[FL(sp)-1]) ? FL_t : FL_nil;
 	NEXT_OP;
 
-OP(OP_BRNNL)
-	ip += POP() != FL_nil ? GET_INT32(ip) : 4;
+OP(OP_NUMBERP)
+	v = FL(stack)[FL(sp)-1];
+	FL(stack)[FL(sp)-1] = fl_isnumber(v) ? FL_t : FL_nil;
 	NEXT_OP;
 
-OP(OP_BRNL)
-	ip += POP() == FL_nil ? GET_INT32(ip) : 4;
+OP(OP_BRBOUND)
+	i = GET_INT32(ip);
+	ip += 4;
+	v = FL(stack)[bp+i];
+	PUSH(v != UNBOUND ? FL_t : FL_nil);
 	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_nil;
-	else
-		v = fl_compare(FL(stack)[FL(sp)-2], FL(stack)[FL(sp)-1], true) == 0 ? FL_t : FL_nil;//FL_nil
-	FL(stack)[FL(sp)-2] = v;
-	POPN(1);
+OP(OP_OPTARGS)
+	i = GET_INT32(ip);
+	ip += 4;
+	n = GET_INT32(ip);
+	ip += 4;
+	if(fl_unlikely(nargs < i)){
+		FL(stack)[ipd] = (uintptr_t)ip;
+		lerrorf(FL_ArgError, "too few arguments");
+	}
+	if((int32_t)n > 0){
+		if(fl_unlikely(nargs > n)){
+			FL(stack)[ipd] = (uintptr_t)ip;
+			lerrorf(FL_ArgError, "too many arguments");
+		}
+	}else
+		n = -n;
+	if(fl_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_EQUAL)
-	if(FL(stack)[FL(sp)-2] == FL(stack)[FL(sp)-1])
-		v = FL_t;
-	else
-		v = fl_compare(FL(stack)[FL(sp)-2], FL(stack)[FL(sp)-1], true) == 0 ? FL_t : FL_nil;//FL_nil
-	FL(stack)[FL(sp)-2] = v;
+OP(OP_EQ)
+	FL(stack)[FL(sp)-2] = FL(stack)[FL(sp)-2] == FL(stack)[FL(sp)-1] ? FL_t : FL_nil;
 	POPN(1);
 	NEXT_OP;
 
-OP(OP_SETCAR)
-	v = FL(stack)[FL(sp)-2];
-	if(fl_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):
@@ -530,6 +593,54 @@
 	}
 	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_nil : FL_t;
+	NEXT_OP;
+
+OP(OP_NUMEQ)
+	n = *ip++;
+LABEL(apply_numeq):
+	{
+		i = n;
+		value_t a = FL(stack)[FL(sp)-i], b;
+		for(v = FL_t; i > 1; a = b){
+			i--;
+			b = FL(stack)[FL(sp)-i];
+			if(bothfixnums(a, b)){
+				if(a != b){
+					v = FL_nil;
+					break;
+				}
+			}else if(numeric_compare(a, b, true, false, true) != 0){
+				v = FL_nil;
+				break;
+			}
+		}
+		POPN(n);
+		PUSH(v);
+	}
+	NEXT_OP;
+
+OP(OP_CADR)
+	v = FL(stack)[FL(sp)-1];
+	if(fl_likely(iscons(v))){
+		v = cdr_(v);
+		if(fl_likely(iscons(v)))
+			v = car_(v);
+		else
+			goto LABEL(cadr_nil);
+	}else{
+LABEL(cadr_nil):
+		if(fl_unlikely(v != FL_nil)){
+			FL(stack)[ipd] = (uintptr_t)ip;
+			type_error("cons", v);
+		}
+	}
+	FL(stack)[FL(sp)-1] = v;
+	NEXT_OP;
+
 OP(OP_TAPPLY)
 	tail = true;
 	if(0){
@@ -551,37 +662,25 @@
 	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);
+OP(OP_LOADT)
+	PUSH(FL_t);
 	NEXT_OP;
 
-OP(OP_SUB)
-	n = *ip++;
-LABEL(apply_sub):
-	if(n == 2)
-		goto LABEL(do_sub2);
-	if(n == 1)
-		goto LABEL(do_neg);
+OP(OP_BUILTINP)
+	v = FL(stack)[FL(sp)-1];
+	FL(stack)[FL(sp)-1] = (isbuiltin(v) || iscbuiltin(v)) ? FL_t : FL_nil;
+	NEXT_OP;
+
+OP(OP_NEG)
+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);
+	FL(stack)[FL(sp)-1] = fl_neg(FL(stack)[FL(sp)-1]);
 	NEXT_OP;
 
+OP(OP_FIXNUMP)
+	FL(stack)[FL(sp)-1] = isfixnum(FL(stack)[FL(sp)-1]) ? FL_t : FL_nil;
+	NEXT_OP;
+
 OP(OP_MUL)
 	n = *ip++;
 LABEL(apply_mul):
@@ -591,26 +690,6 @@
 	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)
 	{
 		value_t a = FL(stack)[FL(sp)-2];
@@ -630,48 +709,26 @@
 	}
 	NEXT_OP;
 
-OP(OP_NUMEQ)
+OP(OP_DIV)
 	n = *ip++;
-LABEL(apply_numeq):
-	{
-		i = n;
-		value_t a = FL(stack)[FL(sp)-i], b;
-		for(v = FL_t; i > 1; a = b){
-			i--;
-			b = FL(stack)[FL(sp)-i];
-			if(bothfixnums(a, b)){
-				if(a != b){
-					v = FL_nil;
-					break;
-				}
-			}else if(numeric_compare(a, b, true, false, true) != 0){
-				v = FL_nil;
-				break;
-			}
+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_COMPARE)
-	FL(stack)[FL(sp)-2] = fl_compare(FL(stack)[FL(sp)-2], FL(stack)[FL(sp)-1], false);
-	POPN(1);
-	NEXT_OP;
-
-OP(OP_ARGC)
-	n = *ip++;
-	if(0){
-OP(OP_ARGCL)
-		n = GET_INT32(ip);
-		ip += 4;
-	}
-	if(fl_unlikely(nargs != n)){
-		FL(stack)[ipd] = (uintptr_t)ip;
-		arity_error(nargs, n);
-	}
-	NEXT_OP;
-
 OP(OP_VECTOR)
 	n = *ip++;
 LABEL(apply_vector):
@@ -683,64 +740,9 @@
 	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(fl_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(fl_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(fl_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(fl_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);
+OP(OP_COMPARE)
+	FL(stack)[FL(sp)-2] = fl_compare(FL(stack)[FL(sp)-2], FL(stack)[FL(sp)-1], false);
+	POPN(1);
 	NEXT_OP;
 
 OP(OP_FOR)
@@ -760,22 +762,6 @@
 	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));
@@ -794,6 +780,28 @@
 		sym->binding = v;
 	NEXT_OP;
 
+OP(OP_VECTORP)
+	FL(stack)[FL(sp)-1] = isvector(FL(stack)[FL(sp)-1]) ? FL_t : FL_nil;
+	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_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_LOADAL)
 	assert(nargs > 0);
 	i = GET_INT32(ip);
@@ -802,6 +810,55 @@
 	PUSH(v);
 	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_nil;
+	else
+		v = fl_compare(FL(stack)[FL(sp)-2], FL(stack)[FL(sp)-1], true) == 0 ? FL_t : FL_nil;//FL_nil
+	FL(stack)[FL(sp)-2] = v;
+	POPN(1);
+	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;
+
+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_BRNL)
+	ip += POP() == FL_nil ? GET_INT32(ip) : 4;
+	NEXT_OP;
+
 OP(OP_SETAL)
 	v = FL(stack)[FL(sp)-1];
 	i = GET_INT32(ip);
@@ -809,102 +866,45 @@
 	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));
+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_VARGC)
-	i = *ip++;
-	if(0){
-OP(OP_VARGCL)
-		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(fl_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;
+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_nil;
 	NEXT_OP;
 
-OP(OP_TRYCATCH)
-	FL(stack)[ipd] = (uintptr_t)ip;
-	v = do_trycatch();
-	POPN(1);
-	FL(stack)[FL(sp)-1] = v;
+OP(OP_JMPL)
+	ip += GET_INT32(ip);
 	NEXT_OP;
 
-OP(OP_OPTARGS)
-	i = GET_INT32(ip);
-	ip += 4;
-	n = GET_INT32(ip);
-	ip += 4;
-	if(fl_unlikely(nargs < i)){
-		FL(stack)[ipd] = (uintptr_t)ip;
-		lerrorf(FL_ArgError, "too few arguments");
-	}
-	if((int32_t)n > 0){
-		if(fl_unlikely(nargs > n)){
-			FL(stack)[ipd] = (uintptr_t)ip;
-			lerrorf(FL_ArgError, "too many arguments");
-		}
-	}else
-		n = -n;
-	if(fl_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;
-	}
+OP(OP_BRNEL)
+	ip += FL(stack)[FL(sp)-2] != FL(stack)[FL(sp)-1] ? GET_INT32(ip) : 4;
+	POPN(2);
 	NEXT_OP;
 
-OP(OP_BRBOUND)
+OP(OP_BRNNL)
+	ip += POP() != FL_nil ? GET_INT32(ip) : 4;
+	NEXT_OP;
+
+OP(OP_LOADCL)
 	i = GET_INT32(ip);
 	ip += 4;
-	v = FL(stack)[bp+i];
-	PUSH(v != UNBOUND ? FL_t : FL_nil);
+	v = FL(stack)[bp+nargs];
+	PUSH(vector_elt(v, i));
 	NEXT_OP;
 
-OP(OP_KEYARGS)
+OP(OP_LOADVL)
 	v = fn_vals(FL(stack)[bp-1]);
-	v = vector_elt(v, 0);
-	i = GET_INT32(ip);
+	v = vector_elt(v, 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;
+	PUSH(v);
 	NEXT_OP;