ref: 5acf222abf7bd65e3ccfe19b30fedd361d92cd7c
dir: /src/vm.inc/
#define fixnum_neg(x) ( \ i64 = -(int64_t)(numval(x)), \ i64 == INT64_MIN \ ? mk_mpint(uvtomp((uint64_t)INT64_MAX+1, nil)) \ : (fits_fixnum(i64) ? fixnum(i64) : mk_mpint(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_INT32(ip); ip += 4; } LABEL(do_call): *ipd = (uintptr_t)ip; value_t v = sp[-n-1]; if(tag(v) == TAG_FUNCTION){ if(v > (N_BUILTINS<<3)){ nargs = n; if(tail){ FL(curr_frame) = (value_t*)FL(curr_frame)[-3]; for(fixnum_t s = -1; s < (fixnum_t)n; s++) bp[s] = sp[s-n]; sp = bp+n; }else{ LABEL(apply_func): bp = sp-nargs; } function_t *fn = (function_t*)ptr(bp[-1]); ip = cvalue_data(fn->bcode); assert(!ismanaged((uintptr_t)ip)); *sp++ = fn->env; *sp++ = (value_t)FL(curr_frame); *sp++ = nargs; ipd = sp++; FL(curr_frame) = sp; NEXT_OP; } int i = uintval(v); assert(isbuiltin(v)); fixnum_t s = builtins[i].nargs; if(s >= 0){ FL(sp) = sp; argcount(n, s); }else if(s != ANYARGS && n < -s){ FL(sp) = sp; argcount(n, -s); } // remove function arg for(value_t *p = sp-n-1; p < sp-1; p++) p[0] = p[1]; sp--; switch(i){ case OP_VECTOR: goto LABEL(apply_vector); 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_NUMEQ: goto LABEL(apply_numeq); default: #if defined(COMPUTED_GOTO) goto *ops[i]; #else op = i; continue; #endif } }else if(fl_likely(iscbuiltin(v))){ value_t *p = sp - n; FL(sp) = sp; v = ((cvalue_t*)ptr(v))->cbuiltin(p, n); sp = p; p[-1] = v; NEXT_OP; } FL(sp) = sp; type_error("function", v); } OP(OP_ARGC) { int na = *ip++; if(0){ OP(OP_ARGCL) na = GET_INT32(ip); ip += 4; } if(fl_unlikely(nargs != na)){ *ipd = (uintptr_t)ip; FL(sp) = sp; arity_error(nargs, na); } NEXT_OP; } OP(OP_LOADA1) *sp++ = bp[1]; NEXT_OP; OP(OP_RET) { value_t v = *(--sp); sp = FL(curr_frame); FL(curr_frame) = (value_t*)sp[-3]; if(FL(curr_frame) == top_frame){ FL(sp) = sp; return v; } sp -= 4+nargs; ipd = FL(curr_frame)-1; ip = (uint8_t*)*ipd; nargs = FL(curr_frame)[-2]; bp = FL(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) == FL_nil ? GET_INT16(ip) : 2; NEXT_OP; OP(OP_LOADG) { value_t v = fn_vals(bp[-1]); assert(*ip < vector_size(v)); v = vector_elt(v, *ip); ip++; if(0){ OP(OP_LOADGL) v = fn_vals(bp[-1]); v = vector_elt(v, GET_INT32(ip)); ip += 4; } assert(issymbol(v)); symbol_t *sym = ptr(v); if(fl_unlikely(sym->binding == UNBOUND)){ *ipd = (uintptr_t)ip; FL(sp) = sp; unbound_error(v); } *sp++ = sym->binding; NEXT_OP; } OP(OP_LT) n = *ip++; LABEL(apply_lt): { int i = n; value_t a = sp[-i], b, v; for(v = FL_t; i > 1; a = b){ i--; b = sp[-i]; if(bothfixnums(a, b)){ if((fixnum_t)a >= (fixnum_t)b){ v = FL_nil; break; } }else{ int 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; } } } sp -= n; *sp++ = v; } NEXT_OP; OP(OP_LOADV) { value_t v = fn_vals(bp[-1]); assert(*ip < vector_size(v)); *sp++ = vector_elt(v, *ip++); NEXT_OP; } OP(OP_ADD2) { fixnum_t a, b, q; value_t v; LABEL(do_add2): *ipd = (uintptr_t)ip; if(0){ OP(OP_SUB2) LABEL(do_sub2): *ipd = (uintptr_t)ip; v = sp[-1]; int64_t i64; b = isfixnum(v) ? fixnum_neg(v) : fl_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 = fl_add_any(sp-2, 2); } sp--; sp[-1] = v; NEXT_OP; } OP(OP_LOADI8) *sp++ = fixnum((int8_t)*ip++); NEXT_OP; OP(OP_POP) sp--; NEXT_OP; OP(OP_BRNN) ip += *(--sp) != FL_nil ? GET_INT16(ip) : 2; NEXT_OP; OP(OP_DUP) sp[0] = sp[-1]; sp++; NEXT_OP; OP(OP_LOADC0) *sp++ = vector_elt(bp[nargs], 0); NEXT_OP; OP(OP_CAR) { value_t v = sp[-1]; if(fl_likely(iscons(v))) v = car_(v); else if(fl_unlikely(v != FL_nil)){ *ipd = (uintptr_t)ip; FL(sp) = sp; type_error("cons", v); } sp[-1] = v; NEXT_OP; } OP(OP_CLOSURE) { int x = *ip++; assert(x > 0); FL(sp) = sp; value_t *pv = alloc_words( 1+x+ #if !defined(BITS64) !(x&1)+ #endif sizeof(function_t)/sizeof(value_t)); value_t v = tagptr(pv, TAG_VECTOR); *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 function_t *f = (function_t*)pv; value_t e = sp[-2]; // closure to copy assert(isfunction(e)); f->bcode = fn_bcode(e); f->vals = fn_vals(e); f->env = sp[-1]; f->name = fn_name(e); sp--; sp[-1] = tagptr(f, TAG_FUNCTION); NEXT_OP; } OP(OP_CONS) { if(FL(curheap) > FL(lim)){ FL(sp) = sp; fl_gc(0); } cons_t *c = (cons_t*)FL(curheap); FL(curheap) += sizeof(cons_t); 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_INT16(ip) : 2; sp -= 2; NEXT_OP; OP(OP_CDR) { value_t v = sp[-1]; if(fl_likely(iscons(v))) v = cdr_(v); else if(fl_unlikely(v != FL_nil)){ *ipd = (uintptr_t)ip; FL(sp) = sp; type_error("cons", v); } sp[-1] = v; NEXT_OP; } OP(OP_LOADVOID) *sp++ = FL_void; NEXT_OP; OP(OP_NOT) sp[-1] = sp[-1] == FL_nil ? FL_t : FL_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_INT32(ip); ip += 4; } fixnum_t s = (fixnum_t)nargs - (fixnum_t)i; if(s > 0){ value_t 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; FL(curr_frame) = sp; } }else if(fl_unlikely(s < 0)){ *ipd = (uintptr_t)ip; FL(sp) = sp; lerrorf(FL_ArgError, "too few arguments"); }else{ sp++; sp[-2] = i+1; sp[-3] = sp[-4]; sp[-4] = sp[-5]; sp[-5] = FL_nil; FL(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) { value_t v = sp[-2]; if(fl_unlikely(!iscons(v))){ *ipd = (uintptr_t)ip; FL(sp) = sp; type_error("cons", v); } car_(v) = sp[-1]; sp--; NEXT_OP; } OP(OP_LOADNIL) *sp++ = FL_nil; NEXT_OP; OP(OP_BOX) { int i = *ip++; FL(sp) = sp; value_t v = mk_cons(); car_(v) = bp[i]; cdr_(v) = FL_nil; bp[i] = v; NEXT_OP; } OP(OP_JMP) ip += GET_INT16(ip); NEXT_OP; OP(OP_ATOMP) sp[-1] = iscons(sp[-1]) ? FL_nil : FL_t; NEXT_OP; OP(OP_AREF2) { n = 2; if(0){ OP(OP_AREF) *ipd = (uintptr_t)ip; n = 3 + *ip++; } LABEL(apply_aref):; value_t v = sp[-n]; for(int i = n-1; i > 0; i--){ if(isarray(v)){ sp[-i-1] = v; v = cvalue_array_aref(sp-i-1); continue; } value_t e = sp[-i]; size_t isz = tosize(e); if(isvector(v)){ if(fl_unlikely(isz >= vector_size(v))){ FL(sp) = sp; bounds_error(v, e); } v = vector_elt(v, isz); continue; } if(!iscons(v) && v != FL_nil){ FL(sp) = sp; 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))){ FL(sp) = sp; bounds_error(v0, e); } } } sp -= n; *sp++ = v; NEXT_OP; } OP(OP_NANP) { value_t v = sp[-1]; if(!iscprim(v)) v = FL_nil; else{ void *p = ptr(v); switch(cp_numtype(p)){ case T_DOUBLE: v = isnan(*(double*)cp_data(p)) ? FL_t : FL_nil; break; case T_FLOAT: v = isnan(*(float*)cp_data(p)) ? FL_t : FL_nil; break; default: v = FL_nil; break; } } sp[-1] = v; NEXT_OP; } OP(OP_LOAD0) *sp++ = fixnum(0); NEXT_OP; OP(OP_SETCDR) { value_t v = sp[-2]; if(fl_unlikely(!iscons(v))){ *ipd = (uintptr_t)ip; FL(sp) = sp; type_error("cons", v); } cdr_(v) = sp[-1]; sp--; NEXT_OP; } OP(OP_LOADC1) *sp++ = vector_elt(bp[nargs], 1); NEXT_OP; OP(OP_ASET) { *ipd = (uintptr_t)ip; value_t v = sp[-3]; n = 3; if(0){ LABEL(apply_aset): v = sp[-n]; for(int i = n-1; i >= 3; i--){ if(isarray(v)){ sp[-i-1] = v; v = cvalue_array_aref(sp-i-1); continue; } value_t e = sp[-i]; size_t isz = tosize(e); if(isvector(v)){ if(fl_unlikely(isz >= vector_size(v))){ FL(sp) = sp; bounds_error(v, e); } v = vector_elt(v, isz); continue; } if(!iscons(v) && v != FL_nil){ FL(sp) = sp; 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))){ FL(sp) = sp; bounds_error(v0, e); } } } sp[-3] = v; } value_t e = sp[-2]; size_t isz = tosize(e); if(isvector(v)){ if(fl_unlikely(isz >= vector_size(v))){ FL(sp) = sp; bounds_error(v, e); } vector_elt(v, isz) = (e = sp[-1]); }else if(iscons(v) || v == FL_nil){ for(value_t v0 = v;; isz--){ if(isz == 0){ car_(v) = (e = sp[-1]); break; } v = cdr_(v); if(fl_unlikely(!iscons(v))){ FL(sp) = sp; bounds_error(v0, e); } } }else if(isarray(v)){ e = cvalue_array_aset(sp-3); }else{ FL(sp) = sp; type_error("sequence", v); } sp -= n; *sp++ = e; NEXT_OP; } OP(OP_EQUAL) { value_t v; if(sp[-2] == sp[-1]) v = FL_t; else v = fl_compare(sp[-2], sp[-1], true) == 0 ? FL_t : FL_nil; sp[-2] = v; sp--; NEXT_OP; } OP(OP_CONSP) sp[-1] = iscons(sp[-1]) ? FL_t : FL_nil; NEXT_OP; OP(OP_LOADC) { value_t v = bp[nargs]; int i = *ip++; assert(isvector(v)); assert(i < (int)vector_size(v)); *sp++ = vector_elt(v, i); NEXT_OP; } OP(OP_SYMBOLP) sp[-1] = issymbol(sp[-1]) ? FL_t : FL_nil; NEXT_OP; OP(OP_NUMBERP) sp[-1] = fl_isnumber(sp[-1]) ? FL_t : FL_nil; NEXT_OP; OP(OP_BRBOUND) *sp++ = bp[GET_INT32(ip)] != UNBOUND ? FL_t : FL_nil; ip += 4; NEXT_OP; OP(OP_OPTARGS) { int i = GET_INT32(ip); ip += 4; int x = GET_INT32(ip); ip += 4; if(fl_unlikely(nargs < i)){ *ipd = (uintptr_t)ip; FL(sp) = sp; lerrorf(FL_ArgError, "too few arguments"); } if(x > 0){ if(fl_unlikely(nargs > x)){ *ipd = (uintptr_t)ip; FL(sp) = sp; lerrorf(FL_ArgError, "too many arguments"); } }else x = -x; if(fl_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]; FL(curr_frame) = sp; ipd = sp-1; for(i = 0; i < x; i++) bp[nargs+i] = UNBOUND; nargs += x; } NEXT_OP; } OP(OP_EQ) sp[-2] = sp[-2] == sp[-1] ? FL_t : FL_nil; sp--; NEXT_OP; OP(OP_LIST) { n = *ip++; LABEL(apply_list):; value_t v; v = list(sp-n, n, false); sp -= n; *sp++ = v; NEXT_OP; } OP(OP_BOUNDP) { *ipd = (uintptr_t)ip; symbol_t *sym = tosymbol(sp[-1]); sp[-1] = sym->binding == UNBOUND ? FL_nil : FL_t; NEXT_OP; } OP(OP_NUMEQ) { n = *ip++; LABEL(apply_numeq):; int i = n; value_t a = sp[-i], b, v; for(v = FL_t; i > 1; a = b){ i--; b = 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; } } sp -= n; *sp++ = v; NEXT_OP; } OP(OP_CADR) { value_t v = 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)){ *ipd = (uintptr_t)ip; FL(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):; value_t v = *(--sp); // arglist value_t *p = sp-(n-2); // n-2 == # leading arguments not in the list while(iscons(v)){ *sp++ = car_(v); v = cdr_(v); } if(v != FL_nil){ *ipd = (uintptr_t)ip; FL(sp) = sp; lerrorf(FL_ArgError, "apply: last argument: not a list"); } n = sp-p; goto LABEL(do_call); } OP(OP_LOADT) *sp++ = FL_t; NEXT_OP; OP(OP_BUILTINP) { value_t v = sp[-1]; sp[-1] = (isbuiltin(v) || iscbuiltin(v)) ? FL_t : FL_nil; NEXT_OP; } OP(OP_NEG) { LABEL(do_neg): *ipd = (uintptr_t)ip; value_t v = sp[-1]; int64_t i64; sp[-1] = isfixnum(v) ? fixnum_neg(v) : fl_neg(v); NEXT_OP; } OP(OP_FIXNUMP) sp[-1] = isfixnum(sp[-1]) ? FL_t : FL_nil; NEXT_OP; OP(OP_MUL) { n = *ip++; LABEL(apply_mul): *ipd = (uintptr_t)ip; value_t v = fl_mul_any(sp-n, n); sp -= n; *sp++ = v; NEXT_OP; } OP(OP_IDIV) { value_t a = sp[-2]; value_t b = sp[-1]; if(fl_unlikely(b == 0)){ *ipd = (uintptr_t)ip; FL(sp) = sp; divide_by_0_error(); } value_t v; if(bothfixnums(a, b)) v = fixnum((fixnum_t)a / (fixnum_t)b); else{ *ipd = (uintptr_t)ip; v = fl_idiv2(a, b); } sp--; sp[-1] = v; NEXT_OP; } OP(OP_DIV) { n = *ip++; LABEL(apply_div): *ipd = (uintptr_t)ip; value_t *p = sp-n; if(n == 1){ sp[-1] = fl_div2(fixnum(1), *p); }else{ if(fl_unlikely(n > 2)){ *sp++ = *p; *p = fixnum(1); p[1] = fl_mul_any(p, n); *p = *(--sp); } value_t v = fl_div2(p[0], p[1]); sp -= n; *sp++ = v; } NEXT_OP; } OP(OP_VECTOR) { n = *ip++; LABEL(apply_vector):; FL(sp) = sp; value_t v = alloc_vector(n, 0); memcpy(&vector_elt(v, 0), sp-n, n*sizeof(value_t)); sp -= n; *sp++ = v; NEXT_OP; } OP(OP_COMPARE) sp[-2] = fl_compare(sp[-2], sp[-1], false); sp--; NEXT_OP; OP(OP_FOR) { *ipd = (uintptr_t)ip; value_t *p = sp; value_t v; fixnum_t s = tofixnum(p[-3]); fixnum_t hi = tofixnum(p[-2]); sp += 2; FL(sp) = sp; for(v = FL_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_INT32(ip); ip += 4; } value_t v = fn_vals(bp[-1]); assert(i < (int)vector_size(v)); v = vector_elt(v, i); assert(issymbol(v)); symbol_t *sym = ptr(v); v = sp[-1]; if(!isconstant(sym)) sym->binding = v; NEXT_OP; } OP(OP_VECTORP) sp[-1] = isvector(sp[-1]) ? FL_t : FL_nil; NEXT_OP; OP(OP_TRYCATCH) { *ipd = (uintptr_t)ip; FL(sp) = sp; value_t 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_t)ip; value_t v = fl_add_any(sp-n, n); sp -= n; *sp++ = v; NEXT_OP; } OP(OP_LOADAL) assert(nargs > 0); *sp++ = bp[GET_INT32(ip)]; ip += 4; NEXT_OP; OP(OP_EQV) { value_t v; if(sp[-2] == sp[-1]) v = FL_t; else if(!leafp(sp[-2]) || !leafp(sp[-1])) v = FL_nil; else v = fl_compare(sp[-2], sp[-1], true) == 0 ? FL_t : FL_nil; sp[-2] = v; sp--; NEXT_OP; } OP(OP_KEYARGS) { value_t v = fn_vals(bp[-1]); v = vector_elt(v, 0); int i = GET_INT32(ip); ip += 4; int x = GET_INT32(ip); ip += 4; fixnum_t s = GET_INT32(ip); ip += 4; *ipd = (uintptr_t)ip; FL(sp) = sp; nargs = process_keys(v, i, x, labs(s)-(i+x), bp, nargs, s<0); sp = FL(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_t)ip; value_t *p = sp-n; // we need to pass the full arglist on to fl_add_any // so it can handle rest args properly *sp++ = *p; *p = fixnum(0); value_t v = fl_add_any(p, n); int64_t i64; p[1] = isfixnum(v) ? fixnum_neg(v) : fl_neg(v); p[0] = *(--sp); v = fl_add_any(p, 2); sp -= n; *sp++ = v; NEXT_OP; } OP(OP_BRNL) ip += *(--sp) == FL_nil ? GET_INT32(ip) : 4; NEXT_OP; OP(OP_SETAL) bp[GET_INT32(ip)] = sp[-1]; ip += 4; NEXT_OP; OP(OP_BOXL) { int i = GET_INT32(ip); ip += 4; FL(sp) = sp; value_t v = mk_cons(); car_(v) = bp[i]; cdr_(v) = FL_nil; bp[i] = v; NEXT_OP; } OP(OP_FUNCTIONP) { value_t v = sp[-1]; sp[-1] = ((tag(v) == TAG_FUNCTION && (isbuiltin(v) || v>(N_BUILTINS<<3))) || iscbuiltin(v)) ? FL_t : FL_nil; NEXT_OP; } OP(OP_JMPL) ip += GET_INT32(ip); NEXT_OP; OP(OP_BRNEL) ip += sp[-2] != sp[-1] ? GET_INT32(ip) : 4; sp -= 2; NEXT_OP; OP(OP_BRNNL) ip += *(--sp) != FL_nil ? GET_INT32(ip) : 4; NEXT_OP; OP(OP_LOADCL) ip += 4; *sp++ = vector_elt(bp[nargs], GET_INT32(ip)); ip += 4; NEXT_OP; OP(OP_LOADVL) { value_t v = fn_vals(bp[-1]); v = vector_elt(v, GET_INT32(ip)); ip += 4; *sp++ = v; NEXT_OP; }