#define i_implement #include"vm.h" #undef i_implement #include"str.h" #include size_t lvm_run(LVM *L, LFunc *func, size_t arg_count, LValue *regs) { if(func->is_native) { return func->native_func(L, func->ud, arg_count, regs); } static void *dispatch_table[] = { [L_GETGLOBAL] = &&do_getglobal, [L_SETGLOBAL] = &&do_setglobal, [L_SETINT16] = &&do_setint16, [L_SETINT32] = &&do_setint32, [L_SETFLOAT] = &&do_setfloat, [L_SETSTR] = &&do_setstr, [L_SETTABLE] = &&do_settable, [L_SETBOOL] = &&do_setbool, [L_SETNIL] = &&do_setnil, [L_SETFUNC] = &&do_setfunc, [L_ADD] = &&do_add, [L_SUB] = &&do_sub, [L_MUL] = &&do_mul, [L_DIV] = &&do_div, [L_MOD] = &&do_mod, [L_RET] = &&do_ret, [L_JNOTCOND] = &&do_jnotcond, [L_MOVE] = &&do_move, [L_CALL] = &&do_call, [L_JUMP] = &&do_jump, [L_ADVANCETEST] = &&do_advancetest, [L_COND_EQ] = &&do_cond_eq, [L_COND_NEQ] = &&do_cond_neq, [L_SETFIELD] = &&do_setfield, [L_GETFIELD] = &&do_getfield, }; LUnit *unit = func->unit; LInst *inst = func->lua_instrs; #define DISPATCH() goto *dispatch_table[(++inst)->opcode] inst--; DISPATCH(); do_getglobal:; { uint8_t *area = unit->abyss + inst->bc; size_t len = *(uint16_t*) area; area += 2; LString *str = lstring_new(len, area); regs[inst->a] = ltable_get(func->env, lvalue_from_string(str)); lstring_free(str); } DISPATCH(); do_setglobal:; { uint8_t *area = unit->abyss + inst->bc; size_t len = *(uint16_t*) area; area += 2; LString *str = lstring_new(len, area); ltable_set(func->env, lvalue_from_string(str), regs[inst->a]); lvm_gc_add(L, lvalue_from_string(str)); } DISPATCH(); do_setint16:; regs[inst->a] = lvalue_from_int32((int16_t) inst->bc); DISPATCH(); do_setint32:; regs[inst->a] = lvalue_from_int32(*(int32_t*) &unit->abyss[inst->bc]); DISPATCH(); do_setfloat:; DISPATCH(); do_setstr:; { uint8_t *area = unit->abyss + inst->bc; size_t len = *(uint16_t*) area; area += 2; regs[inst->a] = lvalue_raw(LTAG_STRING, (uintptr_t) lstring_new(len, area)); lvm_gc_add(L, regs[inst->a]); } DISPATCH(); do_settable:; { LTable *tbl = ltable_new(inst->bc); lvm_gc_add(L, lvalue_from_table(tbl)); regs[inst->a] = lvalue_from_table(tbl); } DISPATCH(); do_setbool:; regs[inst->a] = lvalue_from_bool(inst->b); DISPATCH(); do_setnil:; regs[inst->a] = lvalue_from_nil(); DISPATCH(); do_setfunc:; regs[inst->a] = lvalue_from_func(&func->unit->funcs[inst->bc]); DISPATCH(); do_add:; { LValue x = regs[inst->b]; LValue y = regs[inst->c]; if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) { regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) + y.f); } else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) { regs[inst->a] = lvalue_from_double(x.f + lvalue_to_int32(y)); } else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) { regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) + lvalue_to_int32(y)); } else goto err; } DISPATCH(); do_sub:; { LValue x = regs[inst->b]; LValue y = regs[inst->c]; if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) { regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) - y.f); } else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) { regs[inst->a] = lvalue_from_double(x.f - lvalue_to_int32(y)); } else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) { regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) - lvalue_to_int32(y)); } else goto err; } DISPATCH(); do_mul:; { LValue x = regs[inst->b]; LValue y = regs[inst->c]; if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) { regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) * y.f); } else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) { regs[inst->a] = lvalue_from_double(x.f * lvalue_to_int32(y)); } else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) { regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) * lvalue_to_int32(y)); } else goto err; } DISPATCH(); do_div:; { LValue x = regs[inst->b]; LValue y = regs[inst->c]; if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) { regs[inst->a] = lvalue_from_double(lvalue_to_int32(x) / y.f); } else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) { regs[inst->a] = lvalue_from_double(x.f / lvalue_to_int32(y)); } else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) { int32_t yv = lvalue_to_int32(y); if(yv == 0) { regs[inst->a] = lvalue_from_nil(); } else { regs[inst->a] = lvalue_from_int32(lvalue_to_int32(x) / yv); } } else goto err; } DISPATCH(); do_mod:; { LValue x = regs[inst->b]; LValue y = regs[inst->c]; if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_FLOAT) { regs[inst->a] = lvalue_from_double(fmod(fmod(lvalue_to_int32(x), y.f) + y.f, y.f)); } else if(lvalue_tag(x) == LTAG_FLOAT && lvalue_tag(y) == LTAG_I32) { int32_t yv = lvalue_to_int32(y); regs[inst->a] = lvalue_from_double(fmod(fmod(x.f, yv) + yv, yv)); } else if(lvalue_tag(x) == LTAG_I32 && lvalue_tag(y) == LTAG_I32) { int32_t yv = lvalue_to_int32(y); if(yv == 0) { goto err; } else { regs[inst->a] = lvalue_from_int32((lvalue_to_int32(x) % yv + yv) % yv); } } else goto err; } DISPATCH(); do_jump:; inst += (int16_t) inst->bc; DISPATCH(); do_jnotcond:; { LValue v = regs[inst->a]; if(v.u == LTAG_NIL || v.u == LTAG_FALSE) { inst += (int16_t) inst->bc; } } DISPATCH(); do_call:; { if(lvalue_tag(regs[inst->a]) != LTAG_FUNCTION) { goto err; } uint8_t *abyss_data = unit->abyss + inst->bc; uint8_t ret_vreg = abyss_data[0]; uint8_t arg_count = abyss_data[1]; uint8_t *args = &abyss_data[2]; LValue regs2[256]; lvm_reset_regs(regs2); for(int i = 0; i < arg_count; i++) { regs2[i] = regs[args[i]]; } size_t returned_count = lvm_run(L, (LFunc*) (regs[inst->a].u & ~LTAG_MASK), arg_count, regs2); if(returned_count) { // TODO: more than 1 return regs[ret_vreg] = regs2[0]; } } DISPATCH(); do_move:; regs[inst->a] = regs[inst->b]; DISPATCH(); do_advancetest:; { int64_t a = lvalue_to_int32(regs[inst->a]); int64_t b = lvalue_to_int32(regs[inst->b]); int64_t c = lvalue_to_int32(regs[inst->c]); if(!((c >= 0 && a > b) || (c < 0 && a < b))) { inst++; } } DISPATCH(); do_cond_eq:; regs[inst->a] = lvalue_from_bool(lvalue_eq(regs[inst->b], regs[inst->c])); DISPATCH(); do_cond_neq:; regs[inst->a] = lvalue_from_bool(!lvalue_eq(regs[inst->b], regs[inst->c])); DISPATCH(); do_setfield:; { if(lvalue_tag(regs[inst->a]) != LTAG_TABLE) { goto err; } if(lvalue_tag(regs[inst->b]) == LTAG_NIL) { goto err; } LTable *tbl = (void*) (regs[inst->a].u & ~LTAG_MASK); ltable_set(tbl, regs[inst->b], regs[inst->c]); } DISPATCH(); do_getfield:; { if(lvalue_tag(regs[inst->a]) != LTAG_TABLE) { goto err; } LTable *tbl = (void*) (regs[inst->b].u & ~LTAG_MASK); regs[inst->a] = ltable_get(tbl, regs[inst->c]); } DISPATCH(); err:; do_ret:; return 0; } void lvm_gc_add(LVM *L, LValue lvalue) { set_LValueU_insert(&L->gc_objects, lvalue.u); } LFunc *lvm_func_from_native(LFuncCallback cb, void *ud) { LFunc *f = calloc(1, sizeof(*f)); f->is_native = true; f->ud = ud; f->native_func = cb; return f; } bool lvalue_eq(LValue a, LValue b) { if(a.u == b.u) { return true; } if(lvalue_tag(a) == LTAG_I32 && lvalue_tag(b) == LTAG_FLOAT) { return (a.u & ~LTAG_MASK) == b.f; } else if(lvalue_tag(a) == LTAG_FLOAT && lvalue_tag(b) == LTAG_I32) { return (b.u & ~LTAG_MASK) == a.f; } else if(lvalue_tag(a) == LTAG_STRING && lvalue_tag(b) == LTAG_STRING) { LString *sa = (LString*) (a.u & ~LTAG_MASK); LString *sb = (LString*) (b.u & ~LTAG_MASK); if(sa->length != sb->length) { return false; } return !memcmp(sa->data, sb->data, sa->length); } return false; }