ref: a70379d7e4b822f532fb0a8ccdd1624a90b64a68
dir: /src/vm.h/
#define fixnum_neg(x) ( \ i64 = -(s64int)(numval(x)), \ i64 == INT64_MIN \ ? mk_mp(uvtomp((u64int)INT64_MAX+1, nil)) \ : (fits_fixnum(i64) ? fixnum(i64) : mk_mp(vtomp(i64, nil))) \ ) OP(OP_LOADA0) *sp++ = bp[0]; NEXT_OP; 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): *ipd = (uintptr)ip; sl_v v = sp[-n-1]; if(tag(v) == TAG_FN){ if(v > (N_BUILTINS<<3)){ nargs = n; if(tail){ sl.curr_frame = (sl_v*)sl.curr_frame[-3]; for(sl_fx s = -1; s < (sl_fx)n; s++) bp[s] = sp[s-n]; sp = bp+n; }else{ LABEL(apply_func): bp = sp-nargs; } sl_fn *fn = (sl_fn*)ptr(bp[-1]); ip = cvalue_data(fn->bcode); assert(!ismanaged((uintptr)ip)); *sp++ = fn->env; *sp++ = (sl_v)sl.curr_frame; *sp++ = nargs; ipd = sp++; sl.curr_frame = sp; NEXT_OP; } int i = uintval(v); assert(isbuiltin(v)); sl_fx s = builtins[i].nargs; if(s >= 0){ sl.sp = sp; argcount(n, s); }else if(s != ANYARGS && n < -s){ sl.sp = sp; argcount(n, -s); } // remove function arg for(sl_v *p = sp-n-1; p < sp-1; p++) p[0] = p[1]; sp--; switch(i){ case OP_VEC: goto LABEL(apply_vec); 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); case OP_AREF: goto LABEL(apply_aref); case OP_ASET: goto LABEL(apply_aset); case OP_LT: goto LABEL(apply_lt); case OP_NUMEQP: goto LABEL(apply_numeqp); default: #if defined(COMPUTED_GOTO) goto *ops[i]; #else op = i; continue; #endif } }else if(sl_likely(iscbuiltin(v))){ sl.sp = sp; sp -= n; sp[-1] = ((sl_cv*)ptr(v))->cbuiltin(sp, n); NEXT_OP; } sl.sp = sp; type_error("fn", v); } OP(OP_ARGC) { int na = *ip++; if(0){ OP(OP_ARGCL) na = GET_S32(ip); ip += 4; } if(sl_unlikely(nargs != na)){ *ipd = (uintptr)ip; sl.sp = sp; arity_error(nargs, na); } NEXT_OP; } OP(OP_LOADA1) *sp++ = bp[1]; NEXT_OP; OP(OP_RET) { sl_v v = *(--sp); sp = sl.curr_frame; sl.curr_frame = (sl_v*)sp[-3]; if(sl.curr_frame == top_frame){ sl.sp = sp; return v; } sp -= 4+nargs; ipd = sl.curr_frame-1; ip = (u8int*)*ipd; nargs = sl.curr_frame[-2]; bp = sl.curr_frame - 4 - nargs; sp[-1] = v; NEXT_OP; } OP(OP_LOAD1) *sp++ = fixnum(1); NEXT_OP; OP(OP_LOADA) *sp++ = bp[*ip++]; NEXT_OP; OP(OP_BRN) ip += *(--sp) == sl_nil ? GET_S16(ip) : 2; NEXT_OP; OP(OP_LOADG) { sl_v v = fn_vals(bp[-1]); assert(*ip < vec_size(v)); v = vec_elt(v, *ip); ip++; if(0){ OP(OP_LOADGL) v = fn_vals(bp[-1]); v = vec_elt(v, GET_S32(ip)); ip += 4; } assert(issym(v)); sl_sym *sym = ptr(v); if(sl_unlikely(sym->binding == UNBOUND)){ *ipd = (uintptr)ip; sl.sp = sp; unbound_error(v); } *sp++ = sym->binding; NEXT_OP; } OP(OP_LT) { n = *ip++; LABEL(apply_lt):; int i = n; sl_v a = sp[-i], b, v; for(v = sl_t; i > 1; a = b){ i--; b = sp[-i]; if(bothfixnums(a, b)){ if((sl_fx)a >= (sl_fx)b){ v = sl_nil; break; } }else{ int x = numeric_compare(a, b, false, false, false); if(x > 1) x = numval(sl_compare(a, b, false)); if(x >= 0){ v = sl_nil; break; } } } sp -= n; *sp++ = v; NEXT_OP; } OP(OP_LOADV) { sl_v v = fn_vals(bp[-1]); assert(*ip < vec_size(v)); *sp++ = vec_elt(v, *ip++); NEXT_OP; } OP(OP_ADD2) { sl_fx a, b, q; sl_v v; LABEL(do_add2): *ipd = (uintptr)ip; if(0){ OP(OP_SUB2) LABEL(do_sub2): *ipd = (uintptr)ip; v = sp[-1]; s64int i64; b = isfixnum(v) ? fixnum_neg(v) : sl_neg(v); }else{ b = sp[-1]; } a = sp[-2]; if(bothfixnums(a, b) && !sadd_overflow(a, b, &q)) v = q; else{ sp[-1] = b; v = sl_add_any(sp-2, 2); } sp--; sp[-1] = v; NEXT_OP; } OP(OP_LOADI8) *sp++ = fixnum((s8int)*ip++); NEXT_OP; OP(OP_POP) sp--; NEXT_OP; OP(OP_BRNN) ip += *(--sp) != sl_nil ? GET_S16(ip) : 2; NEXT_OP; OP(OP_DUP) sp[0] = sp[-1]; sp++; NEXT_OP; OP(OP_LOADC0) *sp++ = vec_elt(bp[nargs], 0); NEXT_OP; OP(OP_CAR) { sl_v v = sp[-1]; if(sl_likely(iscons(v))) v = car_(v); else if(sl_unlikely(v != sl_nil)){ *ipd = (uintptr)ip; sl.sp = sp; type_error("cons", v); } sp[-1] = v; NEXT_OP; } OP(OP_CLOSURE) { int x = *ip++; assert(x > 0); sl.sp = sp; sl_v *pv = alloc_words( 1+x+ #if !defined(BITS64) !(x&1)+ #endif sizeof(sl_fn)/sizeof(sl_v)); sl_v v = tagptr(pv, TAG_VEC); *pv++ = fixnum(x); for(int i = 0; i < x; i++) *pv++ = sp[-x+i]; sp -= x; *sp = v; #if !defined(BITS64) if((x & 1) == 0) pv++; #endif sl_fn *f = (sl_fn*)pv; sl_v e = sp[-1]; // closure to copy sp[-1] = tagptr(f, TAG_FN); assert(isfn(e)); f->vals = fn_vals(e); f->bcode = fn_bcode(e); f->env = sp[0]; f->name = fn_name(e); NEXT_OP; } OP(OP_CONS) { if(slg.curheap > slg.lim){ sl.sp = sp; sl_gc(0); } sl_cons *c = (sl_cons*)slg.curheap; slg.curheap += sizeof(sl_cons); c->car = sp[-2]; c->cdr = sp[-1]; sp[-2] = tagptr(c, TAG_CONS); sp--; NEXT_OP; } OP(OP_BRNE) ip += sp[-2] != sp[-1] ? GET_S16(ip) : 2; sp -= 2; NEXT_OP; OP(OP_CDR) { sl_v v = sp[-1]; if(sl_likely(iscons(v))) v = cdr_(v); else if(sl_unlikely(v != sl_nil)){ *ipd = (uintptr)ip; sl.sp = sp; type_error("cons", v); } sp[-1] = v; NEXT_OP; } OP(OP_LOADVOID) *sp++ = sl_void; NEXT_OP; OP(OP_NOT) sp[-1] = sp[-1] == sl_nil ? sl_t : sl_nil; NEXT_OP; OP(OP_SETA) bp[*ip++] = 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; if(s > 0){ sl_v v = list(bp+i, s, false); bp[i] = v; if(s > 1){ bp[i+1] = bp[nargs+0]; bp[i+2] = bp[nargs+1]; bp[i+3] = i+1; bp[i+4] = 0; sp = bp+i+5; sl.curr_frame = sp; } }else if(sl_unlikely(s < 0)){ *ipd = (uintptr)ip; sl.sp = sp; lerrorf(sl_errarg, "too few arguments"); }else{ sp++; sp[-2] = i+1; sp[-3] = sp[-4]; sp[-4] = sp[-5]; sp[-5] = sl_nil; sl.curr_frame = sp; } ipd = sp-1; nargs = i+1; NEXT_OP; } OP(OP_SHIFT) { int i = *ip++; sp[-1-i] = sp[-1]; sp -= i; NEXT_OP; } OP(OP_SETCAR) { sl_v v = sp[-2]; if(sl_unlikely(!iscons(v))){ *ipd = (uintptr)ip; sl.sp = sp; type_error("cons", v); } car_(v) = sp[-1]; sp--; NEXT_OP; } OP(OP_LOADNIL) *sp++ = sl_nil; NEXT_OP; OP(OP_BOX) { int i = *ip++; sl.sp = sp; sl_v v = alloc_cons(); car_(v) = bp[i]; cdr_(v) = sl_nil; bp[i] = v; NEXT_OP; } OP(OP_JMP) ip += GET_S16(ip); NEXT_OP; OP(OP_ATOMP) sp[-1] = iscons(sp[-1]) ? sl_nil : sl_t; NEXT_OP; OP(OP_AREF2) { n = 2; if(0){ OP(OP_AREF) *ipd = (uintptr)ip; n = 3 + *ip++; } LABEL(apply_aref):; sl_v v = sp[-n]; for(int i = n-1; i > 0; i--){ if(isarr(v)){ sp[-i-1] = v; v = cvalue_arr_aref(sp-i-1); continue; } sl_v e = sp[-i]; usize isz = tosize(e); if(isvec(v)){ if(sl_unlikely(isz >= vec_size(v))){ sl.sp = sp; bounds_error(v, e); } v = vec_elt(v, isz); continue; } if(!iscons(v)){ sl.sp = sp; type_error("sequence", v); } for(sl_v v0 = v;; isz--){ if(isz == 0){ v = car_(v); break; } v = cdr_(v); if(sl_unlikely(!iscons(v))){ sl.sp = sp; bounds_error(v0, e); } } } sp -= n; *sp++ = v; NEXT_OP; } OP(OP_NANP) { sl_v v = sp[-1]; if(!iscprim(v)) v = sl_nil; else{ void *p = ptr(v); switch(cp_numtype(p)){ case T_DOUBLE: v = isnan(*(double*)cp_data(p)) ? sl_t : sl_nil; break; case T_FLOAT: v = isnan(*(float*)cp_data(p)) ? sl_t : sl_nil; break; default: v = sl_nil; break; } } sp[-1] = v; NEXT_OP; } OP(OP_LOAD0) *sp++ = fixnum(0); NEXT_OP; OP(OP_SETCDR) { sl_v v = sp[-2]; if(sl_unlikely(!iscons(v))){ *ipd = (uintptr)ip; sl.sp = sp; type_error("cons", v); } cdr_(v) = sp[-1]; sp--; NEXT_OP; } OP(OP_LOADC1) *sp++ = vec_elt(bp[nargs], 1); NEXT_OP; OP(OP_ASET) { *ipd = (uintptr)ip; sl_v v = sp[-3]; n = 3; if(0){ LABEL(apply_aset): v = sp[-n]; for(int i = n-1; i >= 3; i--){ if(isarr(v)){ sp[-i-1] = v; v = cvalue_arr_aref(sp-i-1); continue; } sl_v e = sp[-i]; usize isz = tosize(e); if(isvec(v)){ if(sl_unlikely(isz >= vec_size(v))){ sl.sp = sp; bounds_error(v, e); } v = vec_elt(v, isz); continue; } if(sl_unlikely(!iscons(v))){ sl.sp = sp; type_error("sequence", v); } for(sl_v v0 = v;; isz--){ if(isz == 0){ v = car_(v); break; } v = cdr_(v); if(sl_unlikely(!iscons(v))){ sl.sp = sp; bounds_error(v0, e); } } } sp[-3] = v; } sl_v e = sp[-2]; usize isz = tosize(e); if(isvec(v)){ if(sl_unlikely(isz >= vec_size(v))){ sl.sp = sp; bounds_error(v, e); } vec_elt(v, isz) = (e = sp[-1]); }else if(iscons(v)){ for(sl_v v0 = v;; isz--){ if(isz == 0){ car_(v) = (e = sp[-1]); break; } v = cdr_(v); if(sl_unlikely(!iscons(v))){ sl.sp = sp; bounds_error(v0, e); } } }else if(isarr(v)){ e = cvalue_arr_aset(sp-3); }else{ sl.sp = sp; type_error("sequence", v); } sp -= n; *sp++ = e; NEXT_OP; } OP(OP_EQUALP) { sl_v a = sp[-2], b = sp[-1]; sp--; sp[-1] = (a == b || sl_compare(a, b, true) == 0) ? sl_t : sl_nil; NEXT_OP; } OP(OP_CONSP) sp[-1] = iscons(sp[-1]) ? sl_t : sl_nil; NEXT_OP; OP(OP_LOADC) { sl_v v = bp[nargs]; int i = *ip++; assert(isvec(v)); assert(i < (int)vec_size(v)); *sp++ = vec_elt(v, i); NEXT_OP; } OP(OP_SYMP) sp[-1] = issym(sp[-1]) ? sl_t : sl_nil; NEXT_OP; OP(OP_NUMP) sp[-1] = sl_isnum(sp[-1]) ? sl_t : sl_nil; NEXT_OP; OP(OP_BRBOUND) *sp++ = bp[GET_S32(ip)] != 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)){ *ipd = (uintptr)ip; sl.sp = sp; lerrorf(sl_errarg, "too few arguments"); } if(x > 0){ if(sl_unlikely(nargs > x)){ *ipd = (uintptr)ip; sl.sp = sp; lerrorf(sl_errarg, "too many arguments"); } }else x = -x; if(sl_likely(x > nargs)){ x -= nargs; sp += x; sp[-1] = sp[-x-1]; sp[-2] = nargs+x; sp[-3] = sp[-x-3]; sp[-4] = sp[-x-4]; sl.curr_frame = sp; ipd = sp-1; for(i = 0; i < x; i++) bp[nargs+i] = UNBOUND; nargs += x; } NEXT_OP; } OP(OP_EQP) sp[-2] = sp[-2] == sp[-1] ? sl_t : sl_nil; sp--; NEXT_OP; OP(OP_LIST) { n = *ip++; LABEL(apply_list):; sl_v v; v = list(sp-n, n, false); sp -= n; *sp++ = v; NEXT_OP; } OP(OP_BOUNDP) { *ipd = (uintptr)ip; sl_sym *sym = tosym(sp[-1]); sp[-1] = sym->binding == UNBOUND ? sl_nil : sl_t; NEXT_OP; } OP(OP_NUMEQP) { n = *ip++; LABEL(apply_numeqp):; int i = n; sl_v a = sp[-i], b, v; for(v = sl_t; i > 1; a = b){ i--; b = sp[-i]; if(bothfixnums(a, b)){ if(a != b){ v = sl_nil; break; } }else if(numeric_compare(a, b, true, false, true) != 0){ v = sl_nil; break; } } sp -= n; *sp++ = v; NEXT_OP; } OP(OP_CADR) { sl_v v = 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)){ *ipd = (uintptr)ip; sl.sp = sp; type_error("cons", v); } } 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 = *(--sp); // arglist sl_v *p = sp-(n-2); // n-2 == # leading arguments not in the list while(iscons(v)){ *sp++ = car_(v); v = cdr_(v); } if(v != sl_nil){ *ipd = (uintptr)ip; sl.sp = sp; lerrorf(sl_errarg, "apply: last argument: not a list"); } n = sp-p; goto LABEL(do_call); } OP(OP_LOADT) *sp++ = sl_t; NEXT_OP; OP(OP_BUILTINP) { sl_v v = sp[-1]; sp[-1] = (isbuiltin(v) || iscbuiltin(v)) ? sl_t : sl_nil; NEXT_OP; } OP(OP_NEG) { LABEL(do_neg): *ipd = (uintptr)ip; sl_v v = sp[-1]; s64int i64; sp[-1] = isfixnum(v) ? fixnum_neg(v) : sl_neg(v); NEXT_OP; } OP(OP_FIXNUMP) sp[-1] = isfixnum(sp[-1]) ? sl_t : sl_nil; NEXT_OP; OP(OP_MUL) { n = *ip++; LABEL(apply_mul): *ipd = (uintptr)ip; sl_v v = sl_mul_any(sp-n, n); sp -= n; *sp++ = v; NEXT_OP; } OP(OP_DIV0) { sl_v a = sp[-2]; sl_v b = sp[-1]; if(sl_unlikely(b == 0)){ *ipd = (uintptr)ip; sl.sp = sp; divide_by_0_error(); } sl_v v; if(bothfixnums(a, b)) v = fixnum((sl_fx)a / (sl_fx)b); else{ *ipd = (uintptr)ip; v = sl_idiv2(a, b); } sp--; sp[-1] = v; NEXT_OP; } OP(OP_DIV) { n = *ip++; LABEL(apply_div): *ipd = (uintptr)ip; sl_v *p = sp-n; if(n == 1){ sp[-1] = sl_div2(fixnum(1), *p); }else{ if(sl_unlikely(n > 2)){ *sp++ = *p; *p = fixnum(1); p[1] = sl_mul_any(p, n); *p = *(--sp); } sl_v v = sl_div2(p[0], p[1]); sp -= n; *sp++ = v; } NEXT_OP; } OP(OP_VEC) { n = *ip++; LABEL(apply_vec):; sl.sp = sp; sl_v v = alloc_vec(n, 0); memcpy(&vec_elt(v, 0), sp-n, n*sizeof(sl_v)); sp -= n; *sp++ = v; NEXT_OP; } OP(OP_COMPARE) sp[-2] = sl_compare(sp[-2], sp[-1], false); sp--; NEXT_OP; OP(OP_FOR) { *ipd = (uintptr)ip; sl_v *p = sp; sl_v v; sl_fx s = tofixnum(p[-3]); sl_fx hi = tofixnum(p[-2]); sp += 2; sl.sp = sp; for(v = sl_void; s <= hi; s++){ p[0] = p[-1]; p[1] = fixnum(s); v = _applyn(1); } sp -= 4; p[1] = v; NEXT_OP; } OP(OP_SETG) { int i = *ip++; if(0){ OP(OP_SETGL) i = GET_S32(ip); ip += 4; } sl_v v = fn_vals(bp[-1]); assert(i < (int)vec_size(v)); v = vec_elt(v, i); assert(issym(v)); sl_sym *sym = ptr(v); if(sl_unlikely(isconst(sym))) const_error(sym); sym->binding = sp[-1]; NEXT_OP; } OP(OP_VECP) sp[-1] = isvec(sp[-1]) ? sl_t : sl_nil; NEXT_OP; OP(OP_TRYCATCH) { *ipd = (uintptr)ip; sl.sp = sp; sl_v v = do_trycatch(); sp--; sp[-1] = v; NEXT_OP; } OP(OP_ADD) { n = *ip++; if(n == 2) goto LABEL(do_add2); LABEL(apply_add): *ipd = (uintptr)ip; sl_v v = sl_add_any(sp-n, n); sp -= n; *sp++ = v; NEXT_OP; } OP(OP_LOADAL) assert(nargs > 0); *sp++ = bp[GET_S32(ip)]; ip += 4; NEXT_OP; OP(OP_EQVP) { sl_v a = sp[-2], b = sp[-1]; sp[-2] = (a == b || (leafp(a) && leafp(b) && sl_compare(a, b, true) == 0)) ? sl_t : sl_nil; sp--; NEXT_OP; } OP(OP_KEYARGS) { sl_v v = fn_vals(bp[-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; *ipd = (uintptr)ip; sl.sp = sp; nargs = process_keys(v, i, x, labs(s)-(i+x), bp, nargs, s<0); sp = sl.sp; ipd = 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); *ipd = (uintptr)ip; sl_v *p = sp-n; // we need to pass the full arglist on to sl_add_any // so it can handle rest args properly *sp++ = *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] = *(--sp); v = sl_add_any(p, 2); sp -= n; *sp++ = v; NEXT_OP; } OP(OP_BRNL) ip += *(--sp) == sl_nil ? GET_S32(ip) : 4; NEXT_OP; OP(OP_SETAL) bp[GET_S32(ip)] = sp[-1]; ip += 4; NEXT_OP; OP(OP_BOXL) { int i = GET_S32(ip); ip += 4; sl.sp = sp; sl_v v = alloc_cons(); car_(v) = bp[i]; cdr_(v) = sl_nil; bp[i] = v; NEXT_OP; } OP(OP_FNP) { sl_v v = sp[-1]; sp[-1] = ((tag(v) == TAG_FN && (isbuiltin(v) || v>(N_BUILTINS<<3))) || iscbuiltin(v)) ? sl_t : sl_nil; NEXT_OP; } OP(OP_JMPL) ip += GET_S32(ip); NEXT_OP; OP(OP_BRNEL) ip += sp[-2] != sp[-1] ? GET_S32(ip) : 4; sp -= 2; NEXT_OP; OP(OP_BRNNL) ip += *(--sp) != sl_nil ? GET_S32(ip) : 4; NEXT_OP; OP(OP_LOADCL) ip += 4; *sp++ = vec_elt(bp[nargs], GET_S32(ip)); ip += 4; NEXT_OP; OP(OP_LOADVL) { sl_v v = fn_vals(bp[-1]); v = vec_elt(v, GET_S32(ip)); ip += 4; *sp++ = v; NEXT_OP; }