#include "inc/priv.h" #include "inc/equal.h" #include "inc/cvalues.h" #include "inc/io.h" #define ENTER do{ \ sl.stack[ipd] = (uintptr)ip; \ }while(0) sl_v sl_vm_apply_cl(int nargs) { usize obp, ipd, top_frame = sl.curr_frame; const u8int *ip; bool tail; int n; goto apply_func; #if defined(COMPUTED_GOTO) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" static const void * const ops[] = { #define GOTO_OP_OFFSET(op) [op] = &&op_##op #include "vm_jmptbl.h" #undef GOTO_OP_OFFSET }; #define NEXT_OP do{ goto *ops[*ip++]; }while(0) #define LABEL(x) x #define OP(x) op_##x: #else /* just a usual (portable) switch/case */ u8int op; while(1){ switch(op){ #define NEXT_OP break #define LABEL(x) x #define OP(x) case x: #endif OP(OP_CALL) { tail = false; if(0){ OP(OP_TCALL) tail = true; } n = *ip++; // nargs if(0){ OP(OP_TCALLL) tail = true; if(0){ OP(OP_CALLL) tail = false; } n = GET_S32(ip); ip += 4; } LABEL(do_call): ENTER; sl_v v = sl.sp[-n-1]; if(tag(v) == TAG_FN){ if(sl_likely(!isfnbuiltin(v))){ nargs = n; if(tail){ sl.curr_frame = sl.stack[sl.curr_frame-3]; for(sl_fx s = -1; s < (sl_fx)n; s++) sl.stack[obp+s] = sl.sp[s-n]; sl.sp = &sl.stack[obp+n]; }else{ LABEL(apply_func): obp = sl.sp-sl.stack-nargs; } sl_fn *fn = ptr(sl_fn, sl.stack[obp-1]); assert(ismanaged(fn)); stack_for(fn->maxstack); ip = cvalue_data(fn->bcode); assert(!ismanaged((uintptr)ip)); PUSH(fn->env); PUSH(sl.curr_frame); PUSH(nargs); ipd = sl.sp++ - sl.stack; sl.curr_frame = ipd + 1; NEXT_OP; } assert(isbuiltin(v)); int i = u32numval(v), s = builtins[i].nargs; if(n != s && s != ANYARGS && (s >= 0 || n < -s)) cthrow(arity_error(n, s, sl_nil), nargs); // remove function arg for(sl_v *p = sl.sp-n-1; p < sl.sp-1; p++) p[0] = p[1]; POPN(1); switch(i){ case OP_LT: goto LABEL(apply_lt); case OP_LIST: goto LABEL(apply_list); case OP_VEC: goto LABEL(apply_vec); case OP_ADD: goto LABEL(apply_add); 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); case OP_AREF: goto LABEL(apply_aref); case OP_ASET: goto LABEL(apply_aset); case OP_NUMEQP: goto LABEL(apply_numeqp); default: #if defined(COMPUTED_GOTO) goto *ops[i]; #else op = i; continue; #endif } }else if(iscbuiltin(v)){ sl_builtinfn f = ptr(sl_cv, v)->cbuiltin; stack_for(4); PUSH(sl_nil); // fn->env; PUSH(sl.curr_frame); PUSH(n); PUSH(f); // ip sl.curr_frame = sl.sp - sl.stack; v = f(sl.sp-n-4, n); sl.sp = sl.stack + sl.curr_frame; sl.curr_frame = sl.sp[-3]; POPN(4+n); sl.sp[-1] = v; NEXT_OP; } cthrow(type_error(tail ? "tcall" : "call", "fn", v), nargs); } OP(OP_ARGC) { int na = *ip++; if(0){ OP(OP_ARGCL) na = GET_S32(ip); ip += 4; } if(sl_unlikely(nargs != na)){ ENTER; cthrow(arity_error(nargs, na, sl_nil), nargs); } NEXT_OP; } OP(OP_RET) { sl_v v = POP(); sl.sp = sl.stack + sl.curr_frame; sl.curr_frame = sl.sp[-3]; if(sl.curr_frame == top_frame) return v; POPN(4+nargs); ipd = sl.curr_frame-1; ip = (u8int*)sl.stack[ipd]; nargs = sl.stack[sl.curr_frame-2]; obp = sl.curr_frame-4-nargs; sl.sp[-1] = v; NEXT_OP; } OP(OP_LOAD1) PUSH(fixnum(1)); NEXT_OP; OP(OP_LOADA) PUSH(sl.stack[obp + *ip++]); NEXT_OP; OP(OP_BRN) ip += POP() == sl_nil ? GET_S16(ip) : 2; NEXT_OP; OP(OP_LOADG) { sl_v v = fn_vals(sl.stack[obp-1]); assert(*ip < vec_size(v)); v = vec_elt(v, *ip); ip++; if(0){ OP(OP_LOADGL) v = fn_vals(sl.stack[obp-1]); v = vec_elt(v, GET_S32(ip)); ip += 4; } assert(issym(v)); sl_sym *sym = ptr(sl_sym, v); if(sl_unlikely(sym->binding == sl_unbound)){ ENTER; cthrow(unbound_error(v), nargs); } PUSH(sym->binding); NEXT_OP; } OP(OP_LT) { n = *ip++; LABEL(apply_lt):; int i = n; sl_v a = sl.sp[-i], b, v; for(v = sl_t; i > 1; a = b){ i--; b = sl.sp[-i]; if(sl_likely(bothfixnums(a, b))){ if((sl_fx)a >= (sl_fx)b){ v = sl_nil; break; } }else{ int x = numeric_compare(a, b, false); if(x > 1) x = numval(sl_compare(a, b, false)); if(sl_unlikely(x >= 0)){ v = sl_nil; break; } } } POPN(n); PUSH(v); NEXT_OP; } OP(OP_LOADV) { sl_v v = fn_vals(sl.stack[obp-1]); assert(*ip < vec_size(v)); PUSH(vec_elt(v, *ip++)); assert(sl.sp < sl.stackend); NEXT_OP; } OP(OP_ADD2) { sl_fx a, b, q; sl_v v; ENTER; if(0){ OP(OP_SUB2) LABEL(do_sub2): ENTER; v = sl.sp[-1]; s64int i64; b = isfixnum(v) ? fixnum_neg(v) : sl_neg(v); }else{ b = sl.sp[-1]; } a = sl.sp[-2]; if(sl_likely(bothfixnums(a, b) && !sadd_overflow(a, b, &q))) v = q; else{ sl.sp[-1] = b; v = sl_add_any(sl.sp-2, 2); } POPN(1); sl.sp[-1] = v; NEXT_OP; } OP(OP_LOADI8) PUSH(fixnum((s8int)*ip++)); NEXT_OP; OP(OP_POP) POPN(1); NEXT_OP; OP(OP_BRNN) ip += POP() != sl_nil ? GET_S16(ip) : 2; NEXT_OP; OP(OP_DUP) sl.sp[0] = sl.sp[-1]; sl.sp++; NEXT_OP; OP(OP_CAR) { sl_v v = sl.sp[-1]; if(sl_likely(iscons(v))) v = car_(v); else if(sl_unlikely(v != sl_nil)){ ENTER; cthrow(type_error("car", "cons", v), nargs); } sl.sp[-1] = v; NEXT_OP; } OP(OP_CLOSURE) { int x = *ip++; assert(x > 0); ENTER; sl_v v = alloc_vec(x, false); for(int i = 0; i < x; i++) vec_elt(v, i) = sl.sp[-x+i]; POPN(x); PUSH(v); sl_fn *fn = (sl_fn*)alloc_words(sizeof(sl_fn)/sizeof(sl_v)); sl_v e = sl.sp[-2]; // closure to copy assert(isfn(e)); fn->vals = fn_vals(e); fn->bcode = fn_bcode(e); fn->env = sl.sp[-1]; fn->name = fn_name(e); fn->maxstack = fn_maxstack(e); POPN(1); sl.sp[-1] = tagptr(fn, TAG_FN); NEXT_OP; } OP(OP_CONS) { if(sl_unlikely((sl_v*)slvm.curheap > (sl_v*)slvm.lim)) sl_gc(false); sl_cons *c = (sl_cons*)slvm.curheap; slvm.curheap += sizeof(sl_cons); c->car = sl.sp[-2]; c->cdr = sl.sp[-1]; sl.sp[-2] = tagptr(c, TAG_CONS); POPN(1); NEXT_OP; } OP(OP_BRNE) ip += sl.sp[-2] != sl.sp[-1] ? GET_S16(ip) : 2; POPN(2); NEXT_OP; OP(OP_CDR) { sl_v v = sl.sp[-1]; if(sl_likely(iscons(v))) v = cdr_(v); else if(sl_unlikely(v != sl_nil)){ ENTER; cthrow(type_error("cdr", "cons", v), nargs); } sl.sp[-1] = v; NEXT_OP; } OP(OP_NOT) sl.sp[-1] = sl.sp[-1] == sl_nil ? sl_t : sl_nil; NEXT_OP; OP(OP_SETA) sl.stack[obp + *ip++] = sl.sp[-1]; NEXT_OP; OP(OP_VARGC) { int i = *ip++; if(0){ OP(OP_VARGCL) i = GET_S32(ip); ip += 4; } sl_fx s = (sl_fx)nargs - (sl_fx)i; ENTER; if(s > 0){ sl_v v = sl_list(&sl.stack[obp+i], s, false); sl.stack[obp+i] = v; if(s > 1){ sl.stack[obp+i+1] = sl.stack[obp+nargs+0]; sl.stack[obp+i+2] = sl.stack[obp+nargs+1]; sl.stack[obp+i+3] = i+1; sl.stack[obp+i+4] = 0; sl.sp = sl.stack+obp+i+5; sl.curr_frame = sl.sp - sl.stack; } }else if(sl_unlikely(s < 0)){ cthrow(arity_error(nargs, i, sl_minsym), nargs); }else{ sl.sp++; sl.sp[-2] = i+1; sl.sp[-3] = sl.sp[-4]; sl.sp[-4] = sl.sp[-5]; sl.sp[-5] = sl_nil; sl.curr_frame = sl.sp - sl.stack; } ipd = sl.curr_frame-1; nargs = i+1; NEXT_OP; } OP(OP_SHIFT) { int i = *ip++; sl.sp[-1-i] = sl.sp[-1]; POPN(i); NEXT_OP; } OP(OP_SETCAR) { sl_v v = sl.sp[-2]; if(sl_unlikely(!iscons(v))){ ENTER; cthrow(type_error("set-car!", "cons", v), nargs); } car_(v) = sl.sp[-1]; POPN(1); NEXT_OP; } OP(OP_BOX) { int i = *ip++; ENTER; sl_v v = alloc_cons(); car_(v) = sl.stack[obp+i]; cdr_(v) = sl_nil; sl.stack[obp+i] = v; NEXT_OP; } OP(OP_JMP) ip += GET_S16(ip); NEXT_OP; OP(OP_ATOMP) sl.sp[-1] = iscons(sl.sp[-1]) ? sl_nil : sl_t; NEXT_OP; OP(OP_AREF2) { ENTER; n = 2; if(0){ OP(OP_AREF) ENTER; n = 3 + *ip++; } LABEL(apply_aref):; sl_v v = sl.sp[-n]; for(int i = n-1; i > 0; i--){ sl_v e = sl.sp[-i]; usize isz = tosize(e); if(sl_unlikely(isarr(v))){ sl.sp[-i-1] = v; v = cvalue_arr_aref(sl.sp-i-1); continue; } if(isvec(v)){ if(sl_unlikely(isz >= (usize)vec_size(v))) cthrow(bounds_error(v, e), nargs); v = vec_elt(v, isz); continue; } if(sl_unlikely(!iscons(v))){ if(isio(v)){ ios *s = toio(v, true, true, false); if(sl_unlikely(s->bm != IOS_BUF_MEM)) cthrow(error(sl_errarg, "requires in-memory io"), nargs); if(isz >= s->size) cthrow(bounds_error(v, e), nargs); v = mk_u8(s->buf[isz]); continue; }else cthrow(type_error("aref", "sequence", v), nargs); } for(sl_v v0 = v;; isz--){ if(isz == 0){ v = car_(v); break; } v = cdr_(v); if(sl_unlikely(!iscons(v))) cthrow(bounds_error(v0, e), nargs); } } POPN(n); PUSH(v); NEXT_OP; } OP(OP_NANP) { sl_v v = sl.sp[-1]; if(sl_likely(!iscvalue(v))) v = sl_nil; else{ sl_cv *p = ptr(sl_cv, v); switch(cv_numtype(p)){ case T_F64: v = isnan(*(double*)cv_data(p)) ? sl_t : sl_nil; break; case T_F32: v = isnan(*(float*)cv_data(p)) ? sl_t : sl_nil; break; default: v = sl_nil; break; } } sl.sp[-1] = v; NEXT_OP; } OP(OP_LOAD0) PUSH(fixnum(0)); NEXT_OP; OP(OP_SETCDR) { sl_v v = sl.sp[-2]; if(sl_unlikely(!iscons(v))){ ENTER; cthrow(type_error("set-cdr!", "cons", v), nargs); } cdr_(v) = sl.sp[-1]; POPN(1); NEXT_OP; } OP(OP_ASET) { ENTER; sl_v v = sl.sp[-3]; n = 3; if(0){ LABEL(apply_aset): v = sl.sp[-n]; for(int i = n-1; i >= 3; i--){ if(sl_unlikely(isarr(v))){ sl.sp[-i-1] = v; v = cvalue_arr_aref(sl.sp-i-1); continue; } sl_v e = sl.sp[-i]; sl_fx isz = tosize(e); if(isvec(v)){ if(sl_unlikely(isz >= vec_size(v))) cthrow(bounds_error(v, e), nargs); v = vec_elt(v, isz); continue; } if(sl_unlikely(!iscons(v))) cthrow(type_error("aset!", "sequence", v), nargs); for(sl_v v0 = v;; isz--){ if(isz == 0){ v = car_(v); break; } v = cdr_(v); if(sl_unlikely(!iscons(v))) cthrow(bounds_error(v0, e), nargs); } } sl.sp[-3] = v; } sl_v e = sl.sp[-2]; usize isz = tosize(e); if(sl_likely(isvec(v))){ if(sl_unlikely(isz >= (usize)vec_size(v))) cthrow(bounds_error(v, e), nargs); vec_elt(v, isz) = (e = sl.sp[-1]); }else if(iscons(v)){ for(sl_v v0 = v;; isz--){ if(isz == 0){ car_(v) = (e = sl.sp[-1]); break; } v = cdr_(v); if(sl_unlikely(!iscons(v))) cthrow(bounds_error(v0, e), nargs); } }else if(isarr(v)){ e = cvalue_arr_aset(sl.sp-3); }else if(isio(v)){ ios *s = toio(v, true, false, true); if(sl_unlikely(s->bm != IOS_BUF_MEM)) cthrow(error(sl_errarg, "requires in-memory io"), nargs); if(isz >= s->size) cthrow(bounds_error(v, e), nargs); s->buf[isz] = tou32(sl.sp[-1]); e = mk_u8(s->buf[isz]); }else{ cthrow(type_error("aset!", "sequence", v), nargs); } POPN(n); PUSH(e); NEXT_OP; } OP(OP_EQUALP) { sl_v a = sl.sp[-2], b = sl.sp[-1]; POPN(1); sl.sp[-1] = (a == b || sl_compare(a, b, true) == 0) ? sl_t : sl_nil; NEXT_OP; } OP(OP_CONSP) sl.sp[-1] = iscons(sl.sp[-1]) ? sl_t : sl_nil; NEXT_OP; OP(OP_LOADC) { sl_v v = sl.stack[obp+nargs]; int i = *ip++; assert(isvec(v)); assert(i < (int)vec_size(v)); PUSH(vec_elt(v, i)); NEXT_OP; } OP(OP_SYMP) sl.sp[-1] = issym(sl.sp[-1]) ? sl_t : sl_nil; NEXT_OP; OP(OP_NUMP) sl.sp[-1] = sl_isnum(sl.sp[-1]) ? sl_t : sl_nil; NEXT_OP; OP(OP_BOUNDA) PUSH(sl.stack[obp+GET_S32(ip)] != sl_unbound ? sl_t : sl_nil); ip += 4; NEXT_OP; OP(OP_OPTARGS) { int i = GET_S32(ip); ip += 4; int x = GET_S32(ip); ip += 4; if(sl_unlikely(nargs < i)){ ENTER; cthrow(arity_error(nargs, i, sl_minsym), nargs); } if(sl_likely(x > 0)){ if(sl_unlikely(nargs > x)){ ENTER; cthrow(arity_error(nargs, x, sl_maxsym), nargs); } }else x = -x; if(sl_likely(x > nargs)){ x -= nargs; sl.sp += x; sl.sp[-1] = sl.sp[-x-1]; sl.sp[-2] = nargs+x; sl.sp[-3] = sl.sp[-x-3]; sl.sp[-4] = sl.sp[-x-4]; sl.curr_frame = sl.sp - sl.stack; ipd = sl.curr_frame - 1; for(i = 0; i < x; i++) sl.stack[obp+nargs+i] = sl_unbound; nargs += x; } NEXT_OP; } OP(OP_EQP) sl.sp[-2] = sl.sp[-2] == sl.sp[-1] ? sl_t : sl_nil; POPN(1); NEXT_OP; OP(OP_LIST) { n = *ip++; LABEL(apply_list):; ENTER; sl_v v = sl_list(sl.sp-n, n, false); POPN(n); PUSH(v); NEXT_OP; } OP(OP_MUL) { n = *ip++; LABEL(apply_mul): ENTER; sl_v v = sl_mul_any(sl.sp-n, n); POPN(n); PUSH(v); NEXT_OP; } OP(OP_BOUNDP) { ENTER; sl_v v = sl.sp[-1]; if(sl_unlikely(v == sl_nil || v == sl_t)) sl.sp[-1] = sl_t; else{ sl_sym *sym = tosym(v); sl.sp[-1] = sym->binding == sl_unbound ? sl_nil : sl_t; } NEXT_OP; } OP(OP_NUMEQP) { n = *ip++; LABEL(apply_numeqp):; ENTER; int i = n; sl_v a = sl.sp[-i], b, v; for(v = sl_t; i > 1; a = b){ i--; b = sl.sp[-i]; if(bothfixnums(a, b)){ if(a != b){ v = sl_nil; break; } }else if(numeric_compare(a, b, true) != 0){ v = sl_nil; break; } } POPN(n); PUSH(v); NEXT_OP; } OP(OP_CADR) { sl_v v = sl.sp[-1]; if(sl_likely(iscons(v))){ v = cdr_(v); if(sl_likely(iscons(v))) v = car_(v); else goto LABEL(cadr_nil); }else{ LABEL(cadr_nil): if(sl_unlikely(v != sl_nil)){ ENTER; cthrow(type_error("cadr", "cons", v), nargs); } } sl.sp[-1] = v; NEXT_OP; } OP(OP_TAPPLY) { tail = true; if(0){ OP(OP_APPLY) tail = false; } n = *ip++; LABEL(apply_apply):; sl_v v = POP(); // arglist n -= 2; // n-2 == # leading arguments not in the list if(v == sl_nil || iscons(v)){ while(iscons(v)){ n++; PUSH_SAFE(car_(v)); v = cdr_(v); } if(sl_unlikely(v != sl_nil)){ ENTER; cthrow(type_error("apply", "null", v), nargs); } }else if(isvec(v)){ usize s = vec_size(v); stack_for(s); memcpy(sl.sp, &vec_elt(v, 0), s*sizeof(sl_v)); sl.sp += s; n += s; }else{ ENTER; cthrow(type_error("apply", "(or list vec)", v), nargs); } goto LABEL(do_call); } OP(OP_LOADE8) PUSH(*ip++); NEXT_OP; OP(OP_BUILTINP) { sl_v v = sl.sp[-1]; sl.sp[-1] = (isbuiltin(v) || iscbuiltin(v)) ? sl_t : sl_nil; NEXT_OP; } OP(OP_NEG) { ENTER; sl_v v = sl.sp[-1]; s64int i64; sl.sp[-1] = sl_likely(isfixnum(v)) ? fixnum_neg(v) : sl_neg(v); NEXT_OP; } OP(OP_EQVP) { sl_v a = sl.sp[-2], b = sl.sp[-1]; sl.sp[-2] = (a == b || (leafp(a) && leafp(b) && sl_compare(a, b, true) == 0)) ? sl_t : sl_nil; POPN(1); NEXT_OP; } OP(OP_FIXNUMP) sl.sp[-1] = isfixnum(sl.sp[-1]) ? sl_t : sl_nil; NEXT_OP; OP(OP_FNP) sl.sp[-1] = isfn(sl.sp[-1]) ? sl_t : sl_nil; NEXT_OP; OP(OP_DIV0) { sl_v a = sl.sp[-2]; sl_v b = sl.sp[-1]; if(sl_unlikely(b == 0)){ ENTER; cthrow(divide_by_0_error(), nargs); } sl_v v; if(sl_likely(bothfixnums(a, b))) v = fixnum((sl_fx)a / (sl_fx)b); else{ ENTER; v = sl_idiv2(a, b); } POPN(1); sl.sp[-1] = v; NEXT_OP; } OP(OP_DIV) { n = *ip++; LABEL(apply_div): ENTER; sl_v *p = sl.sp-n; if(sl_unlikely(n == 1)){ sl.sp[-1] = sl_div2(fixnum(1), *p); }else{ if(sl_unlikely(n > 2)){ PUSH(*p); *p = fixnum(1); p[1] = sl_mul_any(p, n); *p = POP(); } sl_v v = sl_div2(p[0], p[1]); POPN(n); PUSH(v); } NEXT_OP; } OP(OP_VEC) { n = *ip++; LABEL(apply_vec):; ENTER; sl_v v; if(sl.sp[-n] == sl_vecstructsym){ if(sl_unlikely(n < 2)) cthrow(arity_error(n, 2, sl_minsym), nargs); v = alloc_vec(n-1, false); vec_setsize(v, vec_size(v), VEC_STRUCT); for(int i = 0; i < n-1; i++) vec_elt(v, i) = sl.sp[-n+1+i]; }else{ v = alloc_vec(n, false); for(int i = 0; i < n; i++) vec_elt(v, i) = sl.sp[-n+i]; } POPN(n); PUSH(v); NEXT_OP; } OP(OP_COMPARE) sl.sp[-2] = sl_compare(sl.sp[-2], sl.sp[-1], false); POPN(1); NEXT_OP; OP(OP_SETG) { int i = *ip++; if(0){ OP(OP_SETGL) i = GET_S32(ip); ip += 4; } sl_v v = fn_vals(sl.stack[obp-1]); assert(i < (int)vec_size(v)); v = vec_elt(v, i); assert(issym(v)); sl_sym *sym = ptr(sl_sym, v); sl_v nb = sl.sp[-1]; if(sl_unlikely(isconst(sym))){ if(sym->binding != nb && (!leafp(sym->binding) || !leafp(nb) || fn_builtin_type_of(&sym->binding, 1) != fn_builtin_type_of(&nb, 1) || sl_compare(sym->binding, nb, true) != 0)){ ENTER; cthrow(const_error(v), nargs); } } sym->binding = nb; if(sym->name[0] == '+' && sym->name[1] != 0 && sym->name[strlen(sym->name)-1] == '+') sym->flags |= FLAG_CONST; NEXT_OP; } OP(OP_VECP) sl.sp[-1] = isvec(sl.sp[-1]) && !isstruct(sl.sp[-1]) ? sl_t : sl_nil; NEXT_OP; OP(OP_TRYCATCH) { ENTER; sl_v v = sl_do_trycatch(); POPN(1); sl.sp[-1] = v; NEXT_OP; } OP(OP_ADD) { n = *ip++; assert(n != 2); LABEL(apply_add): ENTER; sl_v v = sl_add_any(sl.sp-n, n); POPN(n); PUSH(v); NEXT_OP; } OP(OP_LOADAL) assert(nargs > 0); PUSH(sl.stack[obp+GET_S32(ip)]); ip += 4; NEXT_OP; OP(OP_KEYARGS) { sl_v v = fn_vals(sl.stack[obp-1]); v = vec_elt(v, 0); int i = GET_S32(ip); ip += 4; int x = GET_S32(ip); ip += 4; sl_fx s = GET_S32(ip); ip += 4; ENTER; nargs = sl_process_keys(v, i, x, labs(s)-(i+x), obp, nargs, s<0); ipd = sl.sp-sl.stack-1; NEXT_OP; } OP(OP_SUB) { n = *ip++; LABEL(apply_sub): if(n == 2) goto LABEL(do_sub2); assert(n != 1); ENTER; sl_v *p = sl.sp-n; // we need to pass the full arglist on to sl_add_any // so it can handle rest args properly PUSH(*p); *p = fixnum(0); sl_v v = sl_add_any(p, n); s64int i64; p[1] = isfixnum(v) ? fixnum_neg(v) : sl_neg(v); p[0] = POP(); v = sl_add_any(p, 2); POPN(n); PUSH(v); NEXT_OP; } OP(OP_BRNL) ip += POP() == sl_nil ? GET_S32(ip) : 4; NEXT_OP; OP(OP_SETAL) sl.stack[obp+GET_S32(ip)] = sl.sp[-1]; ip += 4; NEXT_OP; OP(OP_BOXL) { int i = GET_S32(ip); ip += 4; ENTER; sl_v v = alloc_cons(); car_(v) = sl.stack[obp+i]; cdr_(v) = sl_nil; sl.stack[obp+i] = v; NEXT_OP; } OP(OP_JMPL) ip += GET_S32(ip); NEXT_OP; OP(OP_BRNEL) ip += sl.sp[-2] != sl.sp[-1] ? GET_S32(ip) : 4; POPN(2); NEXT_OP; OP(OP_BRNNL) ip += POP() != sl_nil ? GET_S32(ip) : 4; NEXT_OP; OP(OP_LOADCL) ip += 4; PUSH(vec_elt(sl.stack[obp+nargs], GET_S32(ip))); ip += 4; NEXT_OP; OP(OP_LOADVL) { sl_v v = fn_vals(sl.stack[obp-1]); int i = GET_S32(ip); assert(*ip < vec_size(v)); v = vec_elt(v, i); ip += 4; PUSH(v); NEXT_OP; } #if defined(COMPUTED_GOTO) #pragma GCC diagnostic pop #else } op = *ip++; } #endif }