static int ktap_lib_len(ktap_state *ks) { int len = kp_objlen(ks, kp_arg(ks, 1)); if (len < 0) return -1; set_number(ks->top, len); incr_top(ks); return 1; }
static int ktap_lib_len(ktap_State *ks) { int len = kp_objlen(ks, GetArg(ks, 1)); if (len < 0) return -1; setnvalue(ks->top, len); incr_top(ks); return 1; }
static void ktap_execute(ktap_state *ks) { int exec_count = 0; ktap_callinfo *ci; ktap_lclosure *cl; ktap_value *k; unsigned int instr, opcode; StkId base; /* stack pointer */ StkId ra; /* register pointer */ int res, nresults; /* temp varible */ ci = ks->ci; newframe: cl = CLVALUE(ci->func); k = cl->p->k; base = ci->u.l.base; mainloop: /* main loop of interpreter */ /* dead loop detaction */ if (exec_count++ == 10000) { if (G(ks)->mainthread != ks) { kp_error(ks, "non-mainthread executing too much, " "please try to enlarge execution limit\n"); return; } cond_resched(); if (signal_pending(current)) { flush_signals(current); return; } exec_count = 0; } instr = *(ci->u.l.savedpc++); opcode = GET_OPCODE(instr); /* ra is target register */ ra = RA(instr); switch (opcode) { case OP_MOVE: setobj(ra, base + GETARG_B(instr)); break; case OP_LOADK: setobj(ra, k + GETARG_Bx(instr)); break; case OP_LOADKX: setobj(ra, k + GETARG_Ax(*ci->u.l.savedpc++)); break; case OP_LOADBOOL: setbvalue(ra, GETARG_B(instr)); if (GETARG_C(instr)) ci->u.l.savedpc++; break; case OP_LOADNIL: { int b = GETARG_B(instr); do { setnilvalue(ra++); } while (b--); break; } case OP_GETUPVAL: { int b = GETARG_B(instr); setobj(ra, cl->upvals[b]->v); break; } case OP_GETTABUP: { int b = GETARG_B(instr); gettable(ks, cl->upvals[b]->v, RKC(instr), ra); base = ci->u.l.base; break; } case OP_GETTABLE: gettable(ks, RB(instr), RKC(instr), ra); base = ci->u.l.base; break; case OP_SETTABUP: { int a = GETARG_A(instr); settable(ks, cl->upvals[a]->v, RKB(instr), RKC(instr)); base = ci->u.l.base; break; } case OP_SETUPVAL: { ktap_upval *uv = cl->upvals[GETARG_B(instr)]; setobj(uv->v, ra); break; } case OP_SETTABLE: settable(ks, ra, RKB(instr), RKC(instr)); base = ci->u.l.base; break; case OP_NEWTABLE: { int b = GETARG_B(instr); int c = GETARG_C(instr); ktap_table *t = kp_table_new(ks); sethvalue(ra, t); if (b != 0 || c != 0) kp_table_resize(ks, t, fb2int(b), fb2int(c)); break; } case OP_SELF: { StkId rb = RB(instr); setobj(ra+1, rb); gettable(ks, rb, RKC(instr), ra); base = ci->u.l.base; break; } case OP_ADD: arith_op(ks, NUMADD); break; case OP_SUB: arith_op(ks, NUMSUB); break; case OP_MUL: arith_op(ks, NUMMUL); break; case OP_DIV: /* divide 0 checking */ if (!nvalue(RKC(instr))) { kp_error(ks, "divide 0 arith operation\n"); return; } arith_op(ks, NUMDIV); break; case OP_MOD: /* divide 0 checking */ if (!nvalue(RKC(instr))) { kp_error(ks, "mod 0 arith operation\n"); return; } arith_op(ks, NUMMOD); break; case OP_POW: kp_error(ks, "ktap don't support pow arith in kernel\n"); return; case OP_UNM: { ktap_value *rb = RB(instr); if (ttisnumber(rb)) { ktap_number nb = nvalue(rb); setnvalue(ra, NUMUNM(nb)); } break; } case OP_NOT: res = isfalse(RB(instr)); setbvalue(ra, res); break; case OP_LEN: { int len = kp_objlen(ks, RB(instr)); if (len < 0) return; setnvalue(ra, len); break; } case OP_CONCAT: { int b = GETARG_B(instr); int c = GETARG_C(instr); ktap_concat(ks, b, c); break; } case OP_JMP: dojump(ci, instr, 0); break; case OP_EQ: { ktap_value *rb = RKB(instr); ktap_value *rc = RKC(instr); if ((int)equalobj(ks, rb, rc) != GETARG_A(instr)) ci->u.l.savedpc++; else donextjump(ci); base = ci->u.l.base; break; } case OP_LT: if (lessthan(ks, RKB(instr), RKC(instr)) != GETARG_A(instr)) ci->u.l.savedpc++; else donextjump(ci); base = ci->u.l.base; break; case OP_LE: if (lessequal(ks, RKB(instr), RKC(instr)) != GETARG_A(instr)) ci->u.l.savedpc++; else donextjump(ci); base = ci->u.l.base; break; case OP_TEST: if (GETARG_C(instr) ? isfalse(ra) : !isfalse(ra)) ci->u.l.savedpc++; else donextjump(ci); break; case OP_TESTSET: { ktap_value *rb = RB(instr); if (GETARG_C(instr) ? isfalse(rb) : !isfalse(rb)) ci->u.l.savedpc++; else { setobj(ra, rb); donextjump(ci); } break; } case OP_CALL: { int b = GETARG_B(instr); int ret; nresults = GETARG_C(instr) - 1; if (b != 0) ks->top = ra + b; ret = precall(ks, ra, nresults); if (ret) { /* C function */ if (nresults >= 0) ks->top = ci->top; base = ci->u.l.base; break; } else { /* ktap function */ ci = ks->ci; /* this flag is used for return time, see OP_RETURN */ ci->callstatus |= CIST_REENTRY; goto newframe; } break; } case OP_TAILCALL: { int b = GETARG_B(instr); if (b != 0) ks->top = ra+b; if (precall(ks, ra, -1)) /* C function? */ base = ci->u.l.base; else { int aux; /* * tail call: put called frame (n) in place of * caller one (o) */ ktap_callinfo *nci = ks->ci; /* called frame */ ktap_callinfo *oci = nci->prev; /* caller frame */ StkId nfunc = nci->func; /* called function */ StkId ofunc = oci->func; /* caller function */ /* last stack slot filled by 'precall' */ StkId lim = nci->u.l.base + CLVALUE(nfunc)->p->numparams; /* close all upvalues from previous call */ if (cl->p->sizep > 0) function_close(ks, oci->u.l.base); /* move new frame into old one */ for (aux = 0; nfunc + aux < lim; aux++) setobj(ofunc + aux, nfunc + aux); /* correct base */ oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct top */ oci->top = ks->top = ofunc + (ks->top - nfunc); oci->u.l.savedpc = nci->u.l.savedpc; /* remove new frame */ ci = ks->ci = oci; /* restart ktap_execute over new ktap function */ goto newframe; } break; } case OP_RETURN: { int b = GETARG_B(instr); if (b != 0) ks->top = ra+b-1; if (cl->p->sizep > 0) function_close(ks, base); b = poscall(ks, ra); /* if it's called from external invocation, just return */ if (!(ci->callstatus & CIST_REENTRY)) return; ci = ks->ci; if (b) ks->top = ci->top; goto newframe; } case OP_FORLOOP: { ktap_number step = nvalue(ra+2); /* increment index */ ktap_number idx = NUMADD(nvalue(ra), step); ktap_number limit = nvalue(ra+1); if (NUMLT(0, step) ? NUMLE(idx, limit) : NUMLE(limit, idx)) { ci->u.l.savedpc += GETARG_sBx(instr); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } break; } case OP_FORPREP: { const ktap_value *init = ra; const ktap_value *plimit = ra + 1; const ktap_value *pstep = ra + 2; if (!ktap_tonumber(init, ra)) { kp_error(ks, KTAP_QL("for") " initial value must be a number\n"); return; } else if (!ktap_tonumber(plimit, ra + 1)) { kp_error(ks, KTAP_QL("for") " limit must be a number\n"); return; } else if (!ktap_tonumber(pstep, ra + 2)) { kp_error(ks, KTAP_QL("for") " step must be a number\n"); return; } setnvalue(ra, NUMSUB(nvalue(ra), nvalue(pstep))); ci->u.l.savedpc += GETARG_sBx(instr); break; } case OP_TFORCALL: { StkId cb = ra + 3; /* call base */ setobj(cb + 2, ra + 2); setobj(cb + 1, ra + 1); setobj(cb, ra); ks->top = cb + 3; /* func. + 2 args (state and index) */ kp_call(ks, cb, GETARG_C(instr)); base = ci->u.l.base; ks->top = ci->top; instr = *(ci->u.l.savedpc++); /* go to next instruction */ ra = RA(instr); } /*go through */ case OP_TFORLOOP: if (!ttisnil(ra + 1)) { /* continue loop? */ setobj(ra, ra + 1); /* save control variable */ ci->u.l.savedpc += GETARG_sBx(instr); /* jump back */ } break; case OP_SETLIST: { int n = GETARG_B(instr); int c = GETARG_C(instr); int last; ktap_table *h; if (n == 0) n = (int)(ks->top - ra) - 1; if (c == 0) c = GETARG_Ax(*ci->u.l.savedpc++); h = hvalue(ra); last = ((c - 1) * LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ kp_table_resizearray(ks, h, last); for (; n > 0; n--) { ktap_value *val = ra+n; kp_table_setint(ks, h, last--, val); } /* correct top (in case of previous open call) */ ks->top = ci->top; break; } case OP_CLOSURE: { /* need to use closure cache? (multithread contention issue)*/ ktap_proto *p = cl->p->p[GETARG_Bx(instr)]; pushclosure(ks, p, cl->upvals, base, ra); break; } case OP_VARARG: { int b = GETARG_B(instr) - 1; int j; int n = (int)(base - ci->func) - cl->p->numparams - 1; if (b < 0) { /* B == 0? */ b = n; /* get all var. arguments */ checkstack(ks, n); /* previous call may change the stack */ ra = RA(instr); ks->top = ra + n; } for (j = 0; j < b; j++) { if (j < n) { setobj(ra + j, base - n + j); } else setnilvalue(ra + j); } break; } case OP_EXTRAARG: return; case OP_EVENT: { struct ktap_event *e = ks->current_event; if (unlikely(!e)) { kp_error(ks, "invalid event context\n"); return; } setevalue(ra, e); break; } case OP_EVENTNAME: { struct ktap_event *e = ks->current_event; if (unlikely(!e)) { kp_error(ks, "invalid event context\n"); return; } setsvalue(ra, kp_tstring_new(ks, e->call->name)); break; } case OP_EVENTARG: if (unlikely(!ks->current_event)) { kp_error(ks, "invalid event context\n"); return; } kp_event_getarg(ks, ra, GETARG_B(instr)); break; case OP_LOAD_GLOBAL: { ktap_value *cfunc = cfunction_cache_get(ks, GETARG_C(instr)); setobj(ra, cfunc); } break; case OP_EXIT: return; } goto mainloop; }