#include #include #include #include #include WIZER_DEFAULT_INIT(); WEVAL_DEFINE_GLOBALS(); enum Opcode { PushConst, Drop, Dup, GetLocal, SetLocal, Add, Sub, Print, Goto, GotoIf, Exit, }; struct Inst { Opcode opcode; uint32_t imm; explicit Inst(Opcode opcode_) : opcode(opcode_), imm(0) {} Inst(Opcode opcode_, uint32_t imm_) : opcode(opcode_), imm(imm_) {} }; #define OPSTACK_SIZE 32 #define LOCAL_SIZE 32 struct State { uint32_t opstack[OPSTACK_SIZE]; uint32_t locals[LOCAL_SIZE]; }; template uint32_t Interpret(const Inst* insts, uint32_t ninsts, State* state) { uint32_t pc = 0; uint32_t steps = 0; uint32_t* opstack = state->opstack; uint32_t* locals = state->locals; int sp = 0; if (Specialized) { weval::push_context(pc); } while (true) { steps++; const Inst* inst = &insts[pc]; pc++; if (Specialized) { weval::update_context(pc); } switch (inst->opcode) { case PushConst: if (sp + 1 > OPSTACK_SIZE) { return 0; } opstack[sp++] = inst->imm; break; case Drop: if (sp == 0) { return 0; } sp--; break; case Dup: if (sp + 1 > OPSTACK_SIZE) { return 0; } if (sp == 0) { return 0; } opstack[sp] = opstack[sp - 1]; sp++; break; case GetLocal: if (sp + 1 > OPSTACK_SIZE) { return 0; } if (inst->imm >= LOCAL_SIZE) { return 0; } opstack[sp++] = locals[inst->imm]; break; case SetLocal: if (sp == 0) { return 0; } if (inst->imm >= LOCAL_SIZE) { return 0; } locals[inst->imm] = opstack[--sp]; break; case Add: if (sp < 2) { return 0; } opstack[sp - 2] += opstack[sp - 1]; sp--; break; case Sub: if (sp < 2) { return 0; } opstack[sp - 2] -= opstack[sp - 1]; sp--; break; case Print: if (sp == 0) { return 0; } printf("%u\n", opstack[--sp]); break; case Goto: if (inst->imm >= ninsts) { return 0; } pc = inst->imm; if (Specialized) { weval::update_context(pc); } break; case GotoIf: if (sp == 0) { return 0; } if (inst->imm >= ninsts) { return 0; } sp--; if (opstack[sp] != 0) { pc = inst->imm; if (Specialized) { weval::update_context(pc); } continue; } break; case Exit: goto out; } } out: if (Specialized) { weval::pop_context(); } printf("Exiting after %d steps at PC %d.\n", steps, pc); return steps; } static const uint32_t kIters = 10000000; Inst prog[] = { Inst(PushConst, 0), Inst(Dup), Inst(PushConst, kIters), Inst(Sub), Inst(GotoIf, 6), Inst(Exit), Inst(PushConst, 1), Inst(Add), Inst(Goto, 1), }; static const uint32_t kExpectedSteps = 7*kIters + 6; typedef uint32_t (*InterpretFunc)(const Inst* insts, uint32_t ninsts, State* state); WEVAL_DEFINE_TARGET(1, Interpret); struct Func { const Inst* insts; uint32_t ninsts; InterpretFunc specialized; Func(const Inst* insts_, uint32_t ninsts_) : insts(insts_), ninsts(ninsts_), specialized(nullptr) { printf("ctor: ptr %p\n", &specialized); auto* req = weval::weval( &specialized, &Interpret, 1, 0, weval::SpecializeMemory(insts, ninsts * sizeof(Inst)), weval::Specialize(ninsts), weval::Runtime()); assert(req); } uint32_t invoke(State* state) { printf("Inspecting func ptr at: %p -> %p (size %lu)\n", &specialized, specialized, sizeof(specialized)); if (specialized) { printf("Calling specialized function: %p\n", specialized); return specialized(insts, ninsts, state); } return Interpret(insts, ninsts, state); } }; Func prog_func(prog, sizeof(prog)/sizeof(Inst)); int main(int argc, char** argv) { State* state = (State*)calloc(sizeof(State), 1); uint32_t steps = prog_func.invoke(state); assert(kExpectedSteps == steps); fflush(stdout); }