int main() { pifi nfibs; int in; /* offset of the argument */ jit_insn *ref; /* to patch the forward reference */ jit_insn *mref; /* ref of move to backpatch */ jit_insn *tp; /* location to patch */ codeBuffer = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); if (codeBuffer == MAP_FAILED) { perror("mmap"); exit(0); } nfibs = (pifi) (jit_set_ip(codeBuffer).iptr); jit_prolog (1); in = jit_arg_ui (); jit_getarg_ui(JIT_V0, in); /* V0 = n */ mref= jit_movi_p(JIT_V2,jit_forward ()); /* Generate a dumb movi */ jit_jmpr(JIT_V2); /* generate some dump filler that will never be executed!*/ jit_addi_ui(JIT_V0,JIT_V0,1); jit_addi_ui(JIT_V0,JIT_V0,1); jit_addi_ui(JIT_V0,JIT_V0,1); jit_addi_ui(JIT_V0,JIT_V0,1); tp = jit_get_label (); ref = jit_blti_ui (jit_forward(), JIT_V0, 2); jit_subi_ui (JIT_V1, JIT_V0, 1); /* V1 = n-1 */ jit_subi_ui (JIT_V2, JIT_V0, 2); /* V2 = n-2 */ jit_prepare (1); jit_pusharg_ui(JIT_V1); jit_finish(nfibs); jit_retval(JIT_V1); /* V1 = nfibs(n-1) */ jit_prepare(1); jit_pusharg_ui(JIT_V2); jit_finish(nfibs); jit_retval(JIT_V2); /* V2 = nfibs(n-2) */ jit_addi_ui(JIT_V1, JIT_V1, 1); jit_addr_ui(JIT_RET, JIT_V1, JIT_V2); /* RET = V1 + V2 + 1 */ jit_ret(); jit_patch(ref); /* patch jump */ jit_movi_i(JIT_RET, 1); /* RET = 1 */ jit_ret(); jit_patch_movi(mref,tp); /* Ok. Do the back-patching */ /* call the generated code, passing 32 as an argument */ jit_flush_code(codeBuffer, jit_get_ip().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, (char *)codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS printf("nfibs(%d) = %d\n", 32, nfibs(32)); #endif return 0; }
floatFunc makeCallFloatFunc (floatFunc theFunc) { floatFunc retVal; int dbl1, dbl2; retVal = (floatFunc) jit_get_ip ().iptr; jit_prolog (2); dbl1 = jit_arg_f (); dbl2 = jit_arg_f (); jit_prepare_f (2); jit_getarg_f (JIT_FPR0, dbl1); jit_getarg_f (JIT_FPR1, dbl2); jit_mulr_f (JIT_FPR1, JIT_FPR1, JIT_FPR0); jit_pusharg_f (JIT_FPR1); jit_pusharg_f (JIT_FPR0); jit_finish ((void *) theFunc); jit_retval_f (JIT_FPRET); jit_ret (); jit_flush_code ((char *) retVal, jit_get_ip ().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble (stderr, (char *) retVal, jit_get_ip ().ptr); #endif return retVal; }
static divider_t generate_divider (int operand, unsigned int *size) { divider_t result; int arg; buffer = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); if (buffer == MAP_FAILED) { perror("mmap"); exit(0); } result = (divider_t)(jit_set_ip (buffer).iptr); jit_leaf (1); arg = jit_arg_i (); jit_getarg_i (JIT_R1, arg); jit_divi_i (JIT_R2, JIT_R1, operand); jit_movr_i (JIT_RET, JIT_R2); jit_ret (); jit_flush_code (buffer, jit_get_ip ().ptr); *size = (jit_insn *)jit_get_ip ().ptr - buffer; return result; }
mod_t generate_modi (int operand) { mod_t result; int arg; buffer = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); if (buffer == MAP_FAILED) { perror("mmap"); exit(0); } result = (mod_t)(jit_set_ip (buffer).iptr); jit_leaf (1); arg = jit_arg_i (); jit_getarg_i (JIT_R1, arg); jit_modi_i (JIT_R2, JIT_R1, operand); jit_movr_i (JIT_RET, JIT_R2); jit_ret (); jit_flush_code (buffer, jit_get_ip ().ptr); return result; }
int main() { static jit_insn codeBuffer[1024]; static jit_state _jit; pvfi myFunction; /* ptr to generated code */ char *start, *end; /* a couple of labels */ int ofs; /* to get the argument */ myFunction = (pvfi) (jit_set_ip(codeBuffer).vptr); start = jit_get_ip().ptr; jit_prolog(1); ofs = jit_arg_i(); jit_movi_p(JIT_R0, "looks like %d bytes sufficed\n"); jit_getarg_i(JIT_R1, ofs); jit_prepare_i(2); jit_pusharg_i(JIT_R1); /* push in reverse order */ jit_pusharg_p(JIT_R0); jit_finish(display_message); jit_ret(); end = jit_get_ip().ptr; jit_flush_code(codeBuffer, end); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, codeBuffer, end); #endif #ifndef LIGHTNING_CROSS /* call the generated code, passing its size as argument */ myFunction(sizeof(codeBuffer)); #endif return 0; }
static int_return_int_t generate_function_proxy (int_return_int_t func) { static jit_insn buffer[1024]; static jit_state _jit; int_return_int_t result; int arg; result = (int_return_int_t)(jit_set_ip (buffer).ptr); jit_prolog (1); arg = jit_arg_i (); jit_getarg_i (JIT_R1, arg); /* Reset `JIT_RET'. */ jit_movi_i (JIT_RET, -1); /* Invoke a FUNC. */ jit_prepare (1); jit_pusharg_i (JIT_R1); (void)jit_finish (func); /* Copy the result of FUNC from `JIT_RET' into our own result register. */ jit_retval_i (JIT_RET); jit_ret (); jit_flush_code (buffer, jit_get_ip ().ptr); return result; }
void _jit_retr_d(jit_state_t *_jit, jit_int32_t u) { if (JIT_FRET != u) jit_movr_d(JIT_FRET, u); else jit_live(JIT_FRET); jit_ret(); }
static stakumilo_t generate_push_pop (void) { static const char msg[] = "we got %i\n"; stakumilo_t result; int arg; int retval; buffer = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); if (buffer == MAP_FAILED) { perror("mmap"); exit(0); } result = (stakumilo_t)(jit_set_ip (buffer).ptr); jit_prolog (1); arg = jit_arg_i (); jit_getarg_i (JIT_R1, arg); /* Save R1 on the stack. */ jit_pushr_i (JIT_R1); /* Save two other registers just for the sake of using the stack. */ jit_movi_i (JIT_R0, -1); jit_movi_i (JIT_R2, -1); jit_pushr_i (JIT_R0); jit_pushr_i (JIT_R2); /* most likely need stack aligned at 16 bytes, dummy push to force align */ jit_pushr_i (JIT_R2); jit_movr_i (JIT_R0, JIT_R1); jit_movi_p (JIT_R1, msg); /* Invoke a function that may modify R1. */ jit_prepare (2); jit_pusharg_i (JIT_R0); jit_pusharg_p (JIT_R1); (void)jit_finish (display_message); /* dummy pop for the sake of calling function with 16 byte aligned stack */ jit_popr_i (JIT_R2); /* Restore the dummy registers. */ jit_popr_i (JIT_R2); jit_popr_i (JIT_R0); /* Restore R1. */ jit_popr_i (JIT_R1); jit_movr_i (JIT_RET, JIT_R1); jit_ret (); jit_flush_code (buffer, jit_get_ip ().ptr); return result; }
static stakumilo_t generate_push_pop (void) { static const char msg[] = "we got %i\n"; static char buffer[1024]; stakumilo_t result; int arg; result = (stakumilo_t)(jit_set_ip (buffer).ptr); jit_prolog (1); arg = jit_arg_i (); jit_getarg_i (JIT_R1, arg); /* Save R1 on the stack. */ jit_pushr_i (JIT_R1); /* Save two other registers just for the sake of using the stack. */ jit_movi_i (JIT_R0, -1); jit_movi_i (JIT_R2, -1); jit_pushr_i (JIT_R0); jit_pushr_i (JIT_R2); jit_movr_i (JIT_R0, JIT_R1); jit_movi_p (JIT_R1, msg); /* Invoke a function that may modify R1. */ jit_prepare (2); jit_pusharg_i (JIT_R0); jit_pusharg_p (JIT_R1); (void)jit_finish (display_message); /* Restore the dummy registers. */ jit_popr_i (JIT_R2); jit_popr_i (JIT_R0); /* Restore R1. */ jit_popr_i (JIT_R1); jit_movr_i (JIT_RET, JIT_R1); jit_ret (); jit_flush_code (buffer, jit_get_ip ().ptr); return result; }
static mover_t generate_movi (const void *operand) { static char buffer[1024]; mover_t result; /* printf ("si?=%i ui?=%i\n", _siP (16, operand), _uiP (16, operand)); */ result = (mover_t)(jit_set_ip (buffer).iptr); jit_leaf (1); jit_movi_p (JIT_R0, operand); jit_movr_p (JIT_RET, JIT_R0); jit_ret (); jit_flush_code (buffer, jit_get_ip ().ptr); return result; }
mod_t generate_modi (int operand) { static char buffer[1024]; mod_t result; int arg; result = (mod_t)(jit_set_ip (buffer).iptr); jit_leaf (1); arg = jit_arg_i (); jit_getarg_i (JIT_R1, arg); jit_modi_i (JIT_R2, JIT_R1, operand); jit_movr_i (JIT_RET, JIT_R2); jit_ret (); jit_flush_code (buffer, jit_get_ip ().ptr); return result; }
int JIT_evaluate(ASTNode *root) { #ifdef __APPLE__ // Mac OS X hack codeBuffer = mmap (NULL, 4096, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); #endif pifi function = (pifi) (jit_set_ip(codeBuffer).iptr); jit_leaf(1); int regs[MAX_REG] = {0}; int ret = alloc_reg(regs); JIT_visit(root, regs, ret); jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); return function(); }
int main() { pifi myFunction= (pifi) (jit_set_ip(codeBuffer).iptr); int ofs; /* offset of the argument */ jit_leaf(1); ofs = jit_arg_i(); jit_getarg_i(JIT_R0, ofs); jit_addi_i(JIT_RET, JIT_R0, 1); jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); /* call the generated code, passing its size as argument */ #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS printf("%d + 1 = %d\n", 5, myFunction(5)); #endif return 0; }
/* Generate a function that computes and returns the sum of its two double arguments (return an int) i.e., double foo(double x,double y) { return x + y;} */ floatFunc makeFloatFunc () { floatFunc retVal; int dbl1, dbl2; retVal = (floatFunc) jit_get_ip ().iptr; jit_prolog (2); dbl1 = jit_arg_f (); dbl2 = jit_arg_f (); jit_getarg_f (JIT_FPR0, dbl1); jit_getarg_f (JIT_FPR1, dbl2); jit_addr_f (JIT_FPR0, JIT_FPR0, JIT_FPR1); jit_movr_f (JIT_FPRET, JIT_FPR0); jit_ret (); jit_flush_code ((char *) retVal, jit_get_ip ().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble (stderr, (char *) retVal, jit_get_ip ().ptr); #endif return retVal; }
int main() { pifi nfibs = (pifi) (jit_set_ip(codeBuffer).iptr); int in; /* offset of the argument */ jit_insn *ref; /* to patch the forward reference */ jit_insn *loop; /* start of the loop */ jit_prolog (1); in = jit_arg_ui (); jit_getarg_ui(JIT_R2, in); /* V0 = n */ jit_movi_ui (JIT_R1, 1); ref = jit_blti_ui (jit_forward(), JIT_R2, 2); jit_subi_ui (JIT_R2, JIT_R2, 1); jit_movi_ui (JIT_R0, 1); loop= jit_get_label(); jit_subi_ui (JIT_R2, JIT_R2, 1); /* we'll calculate one more */ jit_addr_ui (JIT_V0, JIT_R0, JIT_R1); /* V0 = R0 + R1 */ jit_movr_ui (JIT_R0, JIT_R1); /* R0 = R1 */ jit_addi_ui (JIT_R1, JIT_V0, 1); /* R1 = V0 + 1 */ jit_bnei_ui (loop, JIT_R2, 0); /* if (R2) goto loop; */ jit_patch(ref); /* patch forward jump */ jit_movr_ui (JIT_RET, JIT_R1); /* RET = R1 */ jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, (char *) codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS /* call the generated code, passing 36 as an argument */ printf("nfibs(%d) = %d\n", 36, nfibs(36)); #endif return 0; }
int main() { pvfi myFunction; /* ptr to generated code */ char *start, *end; /* a couple of labels */ int ofs; /* to get the argument */ codeBuffer = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); if (codeBuffer == MAP_FAILED) { perror("mmap"); exit(0); } myFunction = (pvfi) (jit_set_ip(codeBuffer).vptr); start = jit_get_ip().ptr; jit_prolog(1); ofs = jit_arg_i(); jit_movi_p(JIT_R0, "looks like %d bytes sufficed\n"); jit_getarg_i(JIT_R1, ofs); jit_prepare_i(2); jit_pusharg_i(JIT_R1); /* push in reverse order */ jit_pusharg_p(JIT_R0); jit_finish(display_message); jit_ret(); end = jit_get_ip().ptr; jit_flush_code(codeBuffer, end); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, codeBuffer, end); #endif #ifndef LIGHTNING_CROSS /* call the generated code, with a dummy argument */ myFunction(1024); #endif return 0; }
int main() { jit_code code; volatile double x = 0.0; code.ptr = (char *) codeBuffer; jit_set_ip(codeBuffer); jit_leaf(0); jit_ldi_d(JIT_FPR0, &a); jit_movi_d(JIT_FPR1, 0.0); jit_gtr_d(JIT_R0, JIT_FPR0, JIT_FPR1); jit_ltr_d(JIT_R1, JIT_FPR0, JIT_FPR1); jit_subr_i(JIT_RET, JIT_R0, JIT_R1); /* [greater] - [less] = -1/0/1 */ jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, (char *)codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS int_test("compare", code, -2.6, -2.4, 0, 2.4, 2.6); #endif #ifdef __GNUC__ jit_set_ip(codeBuffer); jit_leaf(0); jit_ldi_d(JIT_FPR0, &a); jit_movi_d(JIT_FPR1, 0.0); jit_eqr_d(JIT_R0, JIT_FPR0, JIT_FPR1); jit_ltgtr_d(JIT_R1, JIT_FPR0, JIT_FPR1); jit_lshi_i(JIT_R1, JIT_R1, 1); jit_orr_i(JIT_RET, JIT_R0, JIT_R1); jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, (char *)codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS int_test("nans", code, x / x, 1 / (a - a), -1 / (a - a), 0.0, -2.0); #endif #else printf ("nans\t\t1 3 3 0 3\n"); #endif jit_set_ip(codeBuffer); jit_leaf(0); jit_ldi_d(JIT_FPR0, &a); jit_truncr_d_i(JIT_RET, JIT_FPR0); jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, (char *)codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS int_test("trunc", code, -2.6, -2.4, 0, 2.4, 2.6); int_test("trunc", code, -3, -2, 0, 2, 3); #endif jit_set_ip(codeBuffer); jit_leaf(0); jit_ldi_d(JIT_FPR0, &a); jit_ceilr_d_i(JIT_RET, JIT_FPR0); jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, (char *)codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS int_test("ceil", code, -2.6, -2.4, 0, 2.4, 2.6); int_test("ceil", code, -3, -2, 0, 2, 3); #endif jit_set_ip(codeBuffer); jit_leaf(0); jit_ldi_d(JIT_FPR0, &a); jit_floorr_d_i(JIT_RET, JIT_FPR0); jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, (char *)codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS int_test("floor", code, -2.6, -2.4, 0, 2.4, 2.6); int_test("floor", code, -3, -2, 0, 2, 3); #endif jit_set_ip(codeBuffer); jit_leaf(0); jit_ldi_d(JIT_FPR0, &a); jit_roundr_d_i(JIT_RET, JIT_FPR0); jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, (char *)codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS int_test("round", code, -2.6, -2.4, 0, 2.4, 2.6); int_test("round", code, -3, -2, 0, 2, 3); #endif #if 0 && defined JIT_TRANSCENDENTAL jit_set_ip(codeBuffer); jit_leaf(0); jitfp_sti_d(&a, jitfp_log( jitfp_exp(jitfp_imm(1.0)) ) ); jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); code.vptr(); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, (char *)codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS printf("log e = \t%f\n", a); #endif jit_set_ip(codeBuffer); jit_leaf(0); jitfp_sti_d(&a, jitfp_atn( jitfp_imm(1.732050807657) ) ); jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); code.vptr(); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, (char *)codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS printf("pi = \t%f\n", a*3); #endif jit_set_ip(codeBuffer); jit_leaf(0); jitfp_sti_d(&a, jitfp_tan( jitfp_ldi_d(&a) ) ); jit_ret(); jit_flush_code(codeBuffer, jit_get_ip().ptr); code.vptr(); #ifdef LIGHTNING_DISASSEMBLE disassemble(stderr, (char *)codeBuffer, jit_get_ip().ptr); #endif #ifndef LIGHTNING_CROSS printf("tan^2 pi/3 = \t%f\n", a*a); #endif #endif /* JIT_TRANSCEDENTAL */ return (0); }
pdfd compile_rpn (char *expr) { pdfd fn; int ofs, sp = 1; fn = (pdfd) (jit_get_ip ().dptr); jit_leaf (1); ofs = jit_arg_d (); jit_getarg_d (regs[0], ofs); while (*expr) { char buf[32]; int n; /* This scanner is much less advanced than the one in rpn.c. */ if (sscanf (expr, "%[0-9]%n", buf, &n)) { double d = strtod (buf, NULL); expr += n - 1; jit_movi_d (regs[sp], d); sp++; } else if (*expr == '+') { jit_addr_d (regs[sp - 2], regs[sp - 2], regs[sp - 1]); sp--; } else if (*expr == '-') { jit_subr_d (regs[sp - 2], regs[sp - 2], regs[sp - 1]); sp--; } else if (*expr == '*') { jit_mulr_d (regs[sp - 2], regs[sp - 2], regs[sp - 1]); sp--; } else if (*expr == '/') { jit_divr_d (regs[sp - 2], regs[sp - 2], regs[sp - 1]); sp--; } else { fprintf (stderr, "cannot compile: %s\n", expr); abort (); } ++expr; } jit_movr_d (JIT_FPRET, regs[0]); jit_ret (); jit_flush_code ((char *) fn, jit_get_ip ().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble (stderr, (char *) fn, jit_get_ip ().ptr); #endif return fn; }
jit_pointer_t compile(const std::vector<Oper>& ops, jit_word_t *memory, const bool flush = true) { jit_prolog(); jit_movi(JIT_V0, reinterpret_cast<jit_word_t>(memory)); jit_movi(JIT_V1, 0); std::stack<Loop> loops; jit_node_t* start = jit_note(__FILE__, __LINE__); for ( size_t n=0; n<ops.size(); ++n ) { switch ( ops[n].code ) { case '<': jit_str(JIT_V0, JIT_V1); jit_subi(JIT_V0, JIT_V0, ops[n].count * sizeof(jit_word_t)); jit_ldr(JIT_V1, JIT_V0); break; case '>': jit_str(JIT_V0, JIT_V1); jit_addi(JIT_V0, JIT_V0, ops[n].count * sizeof(jit_word_t)); jit_ldr(JIT_V1, JIT_V0); break; case 'z': jit_movi(JIT_V1, 0); break; case '+': jit_addi(JIT_V1, JIT_V1, ops[n].count); break; case '-': jit_subi(JIT_V1, JIT_V1, ops[n].count); break; case '.': jit_prepare(); jit_pushargr(JIT_V1); jit_finishi(reinterpret_cast<jit_pointer_t>(putchar)); if ( flush ) { jit_prepare(); jit_pushargi(reinterpret_cast<jit_word_t>(stdout)); jit_finishi(reinterpret_cast<jit_pointer_t>(fflush)); } break; case ',': jit_prepare(); jit_finishi(reinterpret_cast<jit_pointer_t>(getchar)); jit_retval(JIT_V1); break; case '[': { Loop loop; loop.end = jit_forward(); jit_node_t *j = jit_beqi(JIT_V1, 0); jit_patch_at(j, loop.end); loop.body = jit_label(); loops.push(loop); } break; case ']': { Loop loop = loops.top(); jit_node_t *j = jit_bnei(JIT_V1, 0); jit_patch_at(j, loop.body); jit_link(loop.end); loops.pop(); break; } default: break; } } jit_node_t* stop = jit_note(__FILE__, __LINE__); jit_ret(); jit_epilog(); jit_pointer_t r = jit_emit(); fprintf(stderr, "compiled to %zu bytes\n", (char*)jit_address(stop) - (char*)jit_address(start)); return r; }
errno_t jit_compile_method(struct pvm_code_handler *code) { struct jit_out jo; struct jit_out *j = &jo; //struct data_area_4_thread *da = (struct data_area_4_thread *)&(current_thread.data->da); // TODO: check for current_thread to be thread for real // JITted code supposed to be called with da in BX //jit_gen_push( j, JIT_R_BX ); //jit_gen_call( j, JIT_F_LOAD_F_ACC ); //pvm_exec_load_fast_acc(da); // For any case { #warning resleep? // Thread was snapped sleeping - resleep it //if(da->sleep_flag) phantom_thread_sleep_worker( da ); /* jit_load_thread_field( j, offsetof(da->sleep_flag) ); // to AX, gen flags jit_label jl = jit_get_label( j ); jit_jz( jl ); jit_gen_push( j, JIT_R_BX ); jit_gen_call( j, JIT_F_THREAD_SLEEP_WORKER ); jit_mark_label( j, jl ); */ } while(1) { /* if(phantom_virtual_machine_snap_request) { pvm_exec_save_fast_acc(da); // Before snap phantom_thread_wait_4_snap(); //pvm_exec_load_fast_acc(da); // We don't need this, if we die, we will enter again from above :) } */ { jit_check_snap_request( j ); /* jit_label jl = jit_get_label( j ); jit_jz( jl ); //jit_gen_push( j, JIT_R_BX ); jit_gen_call( j, JIT_F_WAIT_SNAP ); jit_mark_label( j, jl ); */ } jit_mark_possible_label(j); unsigned char instruction = pvm_code_get_byte(code); //printf("instr 0x%02X ", instruction); switch(instruction) { case opcode_nop: //if( debug_print_instr ) printf("nop; "); break; case opcode_debug: { int type = pvm_code_get_byte(code); //cf->cs.get_instr( cf->IP ); //printf("\n\nDebug 0x%02X", type ); if( type & 0x80 ) { //printf(" (" ); pvm_object_t o = pvm_code_get_string(code); //pvm_object_print(o); ref_dec_o(o); //printf(")" ); } if( type & 0x01 ) debug_print_instr = 1; if( type & 0x02 ) debug_print_instr = 0; /* if( is_empty() ) printf(", istack empty"); else printf(",\n\tistack top = %d", is_top() ); if( os_empty() ) printf(", ostack empty"); else { printf(",\n\tostack top = {" ); pvm_object_print( os_top() ); printf("}" ); } printf(";\n\n"); */ } break; // int stack ops --------------------------------------- case opcode_is_dup: if( debug_print_instr ) printf("is dup; "); jit_is_push( j, jit_is_top( j ) ); break; case opcode_is_drop: if( debug_print_instr ) printf("is drop; "); jit_is_pop( j ); break; case opcode_iconst_0: if( debug_print_instr ) printf("iconst 0; "); jit_is_push( j, jit_iconst( j, 0 ) ); break; case opcode_iconst_1: if( debug_print_instr ) printf("iconst 1; "); jit_is_push( j, jit_iconst( j, 1 ) ); break; case opcode_iconst_8bit: { int v = pvm_code_get_byte(code); jit_is_push( j, jit_iconst( j, v ) ); if( debug_print_instr ) printf("iconst8 = %d; ", v); break; } case opcode_iconst_32bit: { int v = pvm_code_get_int32(code); jit_is_push( j, jit_iconst( j, v ) ); if( debug_print_instr ) printf("iconst32 = %d; ", v); break; } case opcode_isum: if( debug_print_instr ) printf("isum; "); jit_binary_op( j, jit_gen_add ); break; case opcode_imul: if( debug_print_instr ) printf("imul; "); { //int mul = is_pop(); //is_push( is_pop() * mul ); jit_binary_op( j, jit_gen_mul ); } break; case opcode_isubul: if( debug_print_instr ) printf("isubul; "); { jit_value_t u = jit_is_pop( j ); jit_value_t l = jit_is_pop( j ); jit_value_t r = jit_gen_sub( j, u, l ); jit_is_push( j, r ); } break; case opcode_isublu: if( debug_print_instr ) printf("isublu; "); { jit_value_t u = jit_is_pop( j ); jit_value_t l = jit_is_pop( j ); jit_value_t r = jit_gen_sub( j, l, u ); jit_is_push( j, r ); } break; case opcode_idivul: if( debug_print_instr ) printf("idivul; "); { jit_value_t u = jit_is_pop( j ); jit_value_t l = jit_is_pop( j ); jit_value_t r = jit_gen_div( j, u, l ); jit_is_push( j, r ); } break; case opcode_idivlu: if( debug_print_instr ) printf("idivlu; "); { jit_value_t u = jit_is_pop( j ); jit_value_t l = jit_is_pop( j ); jit_value_t r = jit_gen_div( j, l, u ); jit_is_push( j, r ); } break; case opcode_ior: if( debug_print_instr ) printf("ior; "); //{ int operand = is_pop(); is_push( is_pop() | operand ); } jit_binary_op( j, jit_gen_binor ); break; case opcode_iand: if( debug_print_instr ) printf("iand; "); //{ int operand = is_pop(); is_push( is_pop() & operand ); } jit_binary_op( j, jit_gen_binand ); break; case opcode_ixor: if( debug_print_instr ) printf("ixor; "); //{ int operand = is_pop(); is_push( is_pop() ^ operand ); } jit_binary_op( j, jit_gen_binxor ); break; case opcode_inot: if( debug_print_instr ) printf("inot; "); jit_unary_op( j, jit_gen_binnot ); break; case opcode_log_or: if( debug_print_instr ) printf("lor; "); jit_binary_op( j, jit_gen_logor ); break; case opcode_log_and: if( debug_print_instr ) printf("land; "); jit_binary_op( j, jit_gen_logand ); break; case opcode_log_xor: if( debug_print_instr ) printf("lxor; "); jit_binary_op( j, jit_gen_logxor ); break; case opcode_log_not: if( debug_print_instr ) printf("lnot; "); jit_unary_op( j, jit_gen_lognot ); break; case opcode_ige: // >= if( debug_print_instr ) printf("ige; "); jit_binary_op( j, jit_gen_ige ); break; case opcode_ile: // <= if( debug_print_instr ) printf("ile; "); jit_binary_op( j, jit_gen_ile ); break; case opcode_igt: // > if( debug_print_instr ) printf("igt; "); jit_binary_op( j, jit_gen_igt ); break; case opcode_ilt: // < if( debug_print_instr ) printf("ilt; "); jit_binary_op( j, jit_gen_ilt ); break; case opcode_i2o: if( debug_print_instr ) printf("i2o; "); jit_push_arg( j, jit_is_pop( j ) ); jit_os_push( j, jit_gen_call( j, JIT_F_CREATE_INT_OBJ ) ); break; case opcode_o2i: if( debug_print_instr ) printf("o2i; "); { jit_is_push( j, jit_o2int( j, jit_os_pop( j ) ) );// push AX //jit_refdec( j ); // TODO jit_o2int must refdec? } break; case opcode_os_eq: if( debug_print_instr ) printf("os eq; "); { jit_value_t v1 = jit_os_pop( j ); jit_value_t v2 = jit_os_pop( j ); jit_is_push( j, jit_gen_cmp( j, v1, v2 ) ); jit_refdec( j, v1 ); jit_refdec( j, v2 ); break; } case opcode_os_neq: if( debug_print_instr ) printf("os neq; "); { jit_value_t v1 = jit_os_pop( j ); jit_value_t v2 = jit_os_pop( j ); jit_is_push( j, jit_gen_lognot( j, jit_gen_cmp( j, v1, v2 )) ); jit_refdec( j, v1 ); jit_refdec( j, v2 ); break; } case opcode_os_isnull: if( debug_print_instr ) printf("isnull; "); { jit_value_t o1 = jit_os_pop( j ); jit_is_push( j, jit_is_null( j, o1 ) ); jit_refdec( j, o1 ); break; } case opcode_os_push_null: case opcode_summon_null: if( debug_print_instr ) printf("push null; "); { jit_os_push( j, jit_get_null( j ) ); break; } // summoning, special ---------------------------------------------------- case opcode_summon_thread: if( debug_print_instr ) printf("summon thread; "); jit_os_push( j, jit_get_thread( j ) ); break; case opcode_summon_this: if( debug_print_instr ) printf("summon this; "); jit_os_push( j, jit_refinc( j, jit_get_this( j ) ) ); break; case opcode_summon_class_class: if( debug_print_instr ) printf("summon class class; "); jit_os_push( j, jit_get_class_class( j ) ); break; case opcode_summon_interface_class: if( debug_print_instr ) printf("summon interface class; "); // locked refcnt jit_os_push( j, jit_get_iface_class( j ) ); break; case opcode_summon_code_class: if( debug_print_instr ) printf("summon code class; "); // locked refcnt jit_os_push( j, jit_get_code_class( j ) ); break; case opcode_summon_int_class: if( debug_print_instr ) printf("summon int class; "); // locked refcnt jit_os_push( j, jit_get_int_class( j ) ); break; case opcode_summon_string_class: if( debug_print_instr ) printf("summon string class; "); // locked refcnt jit_os_push( j, jit_get_string_class( j ) ); break; case opcode_summon_array_class: if( debug_print_instr ) printf("summon array class; "); // locked refcnt jit_os_push( j, jit_get_array_class( j ) ); break; // TODO we can turn class to const, but the we have to keep refcount for it in // const space and release when we release compiled code // TODO const list is just an array? easy to release all case opcode_summon_by_name: { if( debug_print_instr ) printf("summon by name; "); struct pvm_object name = pvm_code_get_string(code); struct pvm_object cl = pvm_exec_lookup_class_by_name( name ); // TODO XXX must inc ref ref_dec_o(name); // Need throw here? if( pvm_is_null( cl ) ) { printf("JIT: summon by name: null class\n"); return ENOENT; // TODO XXX generate summon in run time? } int cid = jit_alloc_const( j, cl ); jit_os_push( j, jit_get_const( j, cid ) ); } break; /** * A BIG NOTE for object creation * * We must be SURE that it is NOT ever possible to pass * non-internal object as init data to internal and vice versa! * It would be a securily hole! * **/ case opcode_new: if( debug_print_instr ) printf("new; "); { //pvm_object_t cl = os_pop(); //os_push( pvm_create_object( cl ) ); //ref_dec_o( cl ); // object keep class ref jit_os_pop( j );// pop AX, DX jit_os_push( j, jit_gen_call( j, JIT_F_CREATE_OBJ ) );// push AX, DX } break; case opcode_copy: if( debug_print_instr ) printf("copy; "); { jit_push_arg( j, jit_os_pop( j ) ); jit_os_push( j, jit_gen_call( j, JIT_F_COPY_OBJ ) ); // jit_refdec( j, JIT_R_CX ); XXX TODO need? } break; // if you want to enable these, work out refcount // and security issues first! // compose/decompose #if 0 case opcode_os_compose32: if( debug_print_instr ) printf(" compose32; "); { int num = pvm_code_get_int32(code); struct pvm_object in_class = os_pop(); os_push( pvm_exec_compose_object( in_class, da->_ostack, num ) ); } break; case opcode_os_decompose: if( debug_print_instr ) printf(" decompose; "); { struct pvm_object to_decomp = os_pop(); int num = da_po_limit(to_decomp.data); is_push( num ); while( num ) { num--; struct pvm_object o = pvm_get_ofield( to_decomp, num); os_push( ref_inc_o( o ) ); } os_push(to_decomp.data->_class); } break; #endif // string ---------------------------------------------------------------- case opcode_sconst_bin: if( debug_print_instr ) printf("sconst bin; "); //os_push(pvm_code_get_string(code)); { int constid = jit_alloc_const( j, pvm_code_get_string( code ) ); jit_os_push( j, jit_get_const( j, constid ) ); } break; // flow ------------------------------------------------------------------ case opcode_jmp: { int newip = pvm_code_get_rel_IP_as_abs(code); if( debug_print_instr ) printf("jmp %d; ", newip ); //da->code.IP = pvm_code_get_rel_IP_as_abs(code); jit_jump( j, newip ); } break; case opcode_djnz: { if( debug_print_instr ) printf("djnz " ); int newip = pvm_code_get_rel_IP_as_abs(code); //is_push( is_pop() - 1 ); jit_decrement( j, jit_is_top(j) ); jit_jnz( j, newip, jit_is_top(j) ); //if( debug_print_instr ) printf("(%d) -> %d; ", is_top() , new_IP ); } break; case opcode_jz: { if( debug_print_instr ) printf("jz " ); int newip = pvm_code_get_rel_IP_as_abs(code); jit_jz( j, newip, jit_is_pop(j) ); } break; case opcode_switch: { #warning impl /* if( debug_print_instr ) printf("switch "); unsigned int tabsize = pvm_code_get_int32(code); int shift = pvm_code_get_int32(code); unsigned int divisor = pvm_code_get_int32(code); int stack_top = is_pop(); if( debug_print_instr ) printf("(%d+%d)/%d, ", stack_top, shift, divisor ); unsigned int start_table_IP = da->code.IP; unsigned int displ = (stack_top+shift)/divisor; unsigned int new_IP = start_table_IP+(tabsize*4); // default if( debug_print_instr ) printf("displ %d, etab addr %d ", displ, new_IP ); if( displ < tabsize ) { da->code.IP = start_table_IP+(displ*4); // BUG! 4! if( debug_print_instr ) printf("load from %d, ", da->code.IP ); new_IP = pvm_code_get_rel_IP_as_abs(code); } da->code.IP = new_IP; if( debug_print_instr ) printf("switch(%d) ->%d; ", displ, new_IP ); */ printf("no switch yet"); return ENXIO; } break; case opcode_ret: { if( debug_print_instr ) printf( "\nret\n" ); jit_ret(j); } break; // exceptions are like ret --------------------------------------------------- case opcode_throw: if( debug_print_instr ) printf( "\nthrow\n" ); jit_throw(j, jit_os_pop(j) ); break; case opcode_push_catcher: { unsigned addr = pvm_code_get_rel_IP_as_abs(code); if( debug_print_instr ) printf("push catcher %u; ", addr ); jit_es_push( j, jit_os_pop(j), addr ); } break; case opcode_pop_catcher: if( debug_print_instr ) printf("pop catcher; "); jit_refdec( j, jit_es_pop(j) ); break; // ok, now method calls ------------------------------------------------------ // these 4 are parameter-less calls! case opcode_short_call_0: jit_os_push( j, jit_call_method( j, 0, 0, 1) ); break; case opcode_short_call_1: jit_os_push( j, jit_call_method( j, 1, 0, 1) ); break; case opcode_short_call_2: jit_os_push( j, jit_call_method( j, 2, 0, 1) ); break; case opcode_short_call_3: jit_os_push( j, jit_call_method( j, 3, 0, 1) ); break; case opcode_call_8bit: { unsigned int method_index = pvm_code_get_byte(code); unsigned int n_param = pvm_code_get_int32(code); jit_os_push( j, jit_call_method( j, method_index, n_param, 1) ); // optimization for soon return } break; case opcode_call_32bit: { unsigned int method_index = pvm_code_get_int32(code); unsigned int n_param = pvm_code_get_int32(code); jit_os_push( j, jit_call_method( j, method_index, n_param, 1) ); // optimization for soon return } break; // object stack -------------------------------------------------------------- case opcode_os_dup: if( debug_print_instr ) printf("os dup; "); jit_os_push( j, jit_refinc( j, jit_os_top( j ) ) ); break; case opcode_os_drop: if( debug_print_instr ) printf("os drop; "); jit_refdec( j, jit_os_pop( j ) ); break; case opcode_os_pull32: if( debug_print_instr ) printf("os pull; "); { int pos = pvm_code_get_int32(code); jit_os_push( j, jit_refinc( j, jit_os_pull( j, pos ) ) ); // TODO XXX load must refinc! } break; case opcode_os_load8: { int slot = pvm_code_get_byte(code); jit_os_push( j, jit_os_load( j, slot ) ); // TODO XXX load must refinc! } break; case opcode_os_load32: { int slot = pvm_code_get_int32(code); jit_os_push( j, jit_os_load( j, slot ) ); // TODO XXX load must refinc! break; } case opcode_os_save8: { int slot = pvm_code_get_byte(code); jit_os_save( j, slot, jit_os_pop( j ) ); } break; case opcode_os_save32: { int slot = pvm_code_get_int32(code); jit_os_save( j, slot, jit_os_pop( j ) ); } break; case opcode_is_load8: //pvm_exec_iload(da, pvm_code_get_byte(code)); { int slot = pvm_code_get_byte(code); jit_value_t ov = jit_os_load( j, slot ); jit_value_t iv = jit_o2int( j, ov ); // TODO XXX jit_o2int must gen refdec jit_is_push( j, iv ); } break; case opcode_is_save8: { int slot = pvm_code_get_byte(code); jit_push_arg( j, jit_is_pop( j ) ); // TODO arg is int? // pvm_create_int_object jit_os_save( j, slot, jit_gen_call( j, JIT_F_CREATE_INT_OBJ ) ); } break; case opcode_os_get32: { int pos = pvm_code_get_int32(code); jit_value_t v = jit_os_absget( j, pos ); // AX, DX = obj //jit_refinc( j, v ); // TODO XXX must not be needed - absget must inc! jit_os_push( j, v ); } break; case opcode_os_set32: { int pos = pvm_code_get_int32(code); jit_os_absset( j, pos, jit_os_pop( j ) ); } break; case opcode_is_get32: { int pos = pvm_code_get_int32(code); jit_is_push( j, jit_is_absget( j, pos ) ); } break; case opcode_is_set32: { int pos = pvm_code_get_int32(code); jit_is_absset( j, pos, jit_is_pop( j ) ); } break; default: if( (instruction & 0xF0 ) == opcode_sys_0 ) { jit_sys( j, instruction & 0x0F); /* sys_sleep: // Only sys can put thread asleep // If we are snapped here we, possibly, will continue from // the entry to this func. So save fasc acc and recheck // sleep condition on the func entry. if(da->sleep_flag) { pvm_exec_save_fast_acc(da); // Before snap phantom_thread_sleep_worker( da ); } break; */ } if( instruction == opcode_sys_8bit ) { jit_sys( j, pvm_code_get_byte(code)); //goto sys_sleep; break; } if( (instruction & 0xE0 ) == opcode_call_00 ) { unsigned int n_param = pvm_code_get_byte(code); jit_os_push( j, jit_call_method( j, instruction & 0x1F, n_param, 0) ); //no optimization for soon return break; } printf("JIT: Unknown op code 0x%X\n", instruction ); return ENOENT; } } }
/* This function does all of lexing, parsing, and picking a good order of evaluation... Needless to say, this is not the best possible design, but it avoids cluttering everything with globals. */ pifi compile_rpn (char *expr) { struct stack_element stack[32]; int sp = 0; int curr_tos = -1; /* stack element currently in R0 */ int spill_base, spill_sp; pifi fn; int ofs; fn = (pifi) (jit_get_ip ().iptr); jit_leaf (1); ofs = jit_arg_i (); spill_sp = spill_base = jit_allocai (32 * sizeof (int)); while (*expr) { int with_imm; int imm; int tok; int src1, src2; /* This is the lexer. */ switch (*expr) { case ' ': case '\t': expr++; continue; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': stack[sp].kind = IMM; stack[sp++].imm = strtol (expr, &expr, 0); continue; case 'x': expr++; stack[sp++].kind = ARG; continue; case '~': /* NOT. Implemented as a XOR with -1. */ stack[sp].kind = IMM; stack[sp++].imm = ~0; tok = '^'; break; case '_': /* Unary minus. Transform to 0 - X and go on. Also used to enter negative constants (32_ = -32). */ expr++; stack[sp] = stack[sp - 1]; /* Ensure CURR_TOS is correct. */ if (curr_tos == sp - 1) curr_tos = sp; stack[sp - 1].kind = IMM; stack[sp - 1].imm = 0; sp++; tok = '-'; break; case '+': case '-': case '*': case '/': case '%': case '&': case '|': case '^': case '=': tok = *expr++; break; case '!': /* Get != */ expr++; assert (*expr == '='); tok = NE; break; case '<': /* Get <, <<, <= */ if (expr[1] == '=') expr += 2, tok = LE; else if (expr[1] == '<') expr += 2, tok = LSH; else expr++, tok = '<'; break; case '>': /* Get >, >>, >>>, >= */ if (expr[1] == '=') expr += 2, tok = GE; else if (expr[1] == '>' && expr[2] == '>') expr += 3, tok = RSHU; else if (expr[1] == '>') expr += 2, tok = RSH; else expr++, tok = '>'; break; default: abort (); } assert (sp >= 2); /* Constant folding. */ if (stack[sp - 1].kind == IMM && stack[sp - 2].kind == IMM) { stack[sp - 2].imm = fold (stack[sp - 2].imm, stack[sp - 1].imm, tok); sp--; continue; } /* If possible, ensure that the constant is the RHS, possibly by changing TOK (if it is a comparison). */ if (stack[sp - 2].kind == IMM) { int swapped_operation = swap_op (tok); if (swapped_operation) { tok = swapped_operation; stack[sp - 2].kind = stack[sp - 1].kind; stack[sp - 1].kind = IMM; stack[sp - 1].imm = stack[sp - 2].imm; /* Ensure CURR_TOS is correct. */ if (curr_tos == sp - 1) curr_tos = sp - 2; } } /* Get the second argument into a register, if not an immediate. Also decide which argument will be prepared into JIT_R0 and which will be prepared into JIT_V0. */ with_imm = 0; src1 = JIT_R0; src2 = JIT_V0; switch (stack[sp - 1].kind) { case IMM: /* RHS is an immediate, use an immediate instruction. */ with_imm = 1; imm = stack[sp - 1].imm; break; case EXPR: /* RHS is an expression, check if it is already in JIT_R0. */ if (curr_tos == sp - 1) { /* Invert the two sources. */ src1 = JIT_V0; src2 = JIT_R0; } else popr (JIT_V0, &spill_sp); curr_tos = -1; break; case ARG: jit_getarg_i (JIT_V0, ofs); break; } /* Get the first argument into a register indicated by SRC1. */ switch (stack[sp - 2].kind) { case IMM: /* LHS is an immediate, check if we must spill the top of stack. */ if (curr_tos != -1) { pushr (JIT_R0, &spill_sp); curr_tos = -1; } jit_movi_i (src1, stack[sp - 2].imm); break; case EXPR: /* LHS is an expression, check if it is already in JIT_R0. */ if (curr_tos != sp - 2) { popr (src1, &spill_sp); curr_tos = -1; } else assert (src1 == JIT_R0); break; case ARG: if (curr_tos != -1) { pushr (JIT_R0, &spill_sp); curr_tos = -1; } jit_getarg_i (src1, ofs); break; } /* Set up the new stack entry, which is cached in R0. */ sp -= 2; curr_tos = sp; stack[sp++].kind = EXPR; /* Perform the computation. */ if (with_imm) gen_reg_imm (src1, imm, tok); else gen_reg_reg (src1, src2, tok); } assert (sp == 1); switch (stack[0].kind) { case IMM: jit_movi_i (JIT_RET, stack[0].imm); break; case EXPR: assert (curr_tos == 0); jit_movr_i (JIT_RET, JIT_R0); break; case ARG: jit_getarg_i (JIT_V0, ofs); break; } jit_ret (); jit_flush_code ((char *) fn, jit_get_ip ().ptr); #ifdef LIGHTNING_DISASSEMBLE disassemble (stderr, (char *) fn, jit_get_ip ().ptr); #endif return fn; }
void run_gnulightning(void) { struct bfi * n = bfprog; int maxstack = 0, stackptr = 0; char *strbuf = 0; size_t maxstrlen = 0; #ifdef GNULIGHTv1 jit_insn** loopstack = 0; jit_insn *codeBuffer; void * startptr; int argp; #endif #ifdef GNULIGHTv2 jit_node_t *start, *end; /* For size of code */ jit_node_t** loopstack = 0; jit_node_t *argp; #endif if (cell_size == 8) tape_step = 1; else tape_step = sizeof(int); #ifdef GNULIGHTv1 /* TODO: Use mmap for allocating memory, the x86 execute protection * bit is on the segment so Linux has to say thay everything below * a specific address is executable. If you ask mmap for executable * memory it can put it below the current value. The mprotect() * function can't do this. */ if (total_nodes < 4096) codeBuffer = malloc(65536); else codeBuffer = malloc(16 * total_nodes); save_ptr_for_free(codeBuffer); codeptr = (codeptr_t) jit_set_ip(codeBuffer).vptr; startptr = jit_get_ip().ptr; /* Function call prolog */ jit_prolog(1); /* Get the data area pointer */ argp = jit_arg_p(); jit_getarg_p(REG_P, argp); #endif #ifdef GNULIGHTv2 init_jit(NULL); // argv[0]); _jit = jit_new_state(); start = jit_note(__FILE__, __LINE__); jit_prolog(); /* Get the data area pointer */ argp = jit_arg(); jit_getarg(REG_P, argp); #endif while(n) { switch(n->type) { case T_MOV: if (acc_loaded) acc_offset -= n->count; jit_addi(REG_P, REG_P, n->count * tape_step); break; case T_ADD: load_acc_offset(n->offset); set_acc_offset(n->offset); jit_addi(REG_ACC, REG_ACC, n->count); break; case T_SET: set_acc_offset(n->offset); if (acc_const && acc_const_val == n->count) { ; } else if (acc_const && acc_const_val+1 == n->count) { jit_addi(REG_ACC, REG_ACC, 1); } else if (acc_const && acc_const_val-1 == n->count) { jit_addi(REG_ACC, REG_ACC, -1); } else { jit_movi(REG_ACC, n->count); } acc_const = 1; acc_const_val = n->count; break; case T_CALC: if (n->offset == n->offset2 && n->count2 == 1) { load_acc_offset(n->offset); set_acc_offset(n->offset); if (n->count) jit_addi(REG_ACC, REG_ACC, n->count); } else if (n->count2 != 0) { load_acc_offset(n->offset2); set_acc_offset(n->offset); if (n->count2 == -1) jit_negr(REG_ACC, REG_ACC); else if (n->count2 != 1) jit_muli(REG_ACC, REG_ACC, n->count2); if (n->count) jit_addi(REG_ACC, REG_ACC, n->count); } else { clean_acc(); set_acc_offset(n->offset); jit_movi(REG_ACC, n->count); if (n->count2 != 0) { if (tape_step > 1) jit_ldxi_i(REG_A1, REG_P, n->offset2 * tape_step); else jit_ldxi_uc(REG_A1, REG_P, n->offset2); if (n->count2 == -1) jit_negr(REG_A1, REG_A1); else if (n->count2 != 1) jit_muli(REG_A1, REG_A1, n->count2); jit_addr(REG_ACC, REG_ACC, REG_A1); } } if (n->count3 != 0) { if (tape_step > 1) jit_ldxi_i(REG_A1, REG_P, n->offset3 * tape_step); else jit_ldxi_uc(REG_A1, REG_P, n->offset3); if (n->count3 == -1) jit_negr(REG_A1, REG_A1); else if (n->count3 != 1) jit_muli(REG_A1, REG_A1, n->count3); jit_addr(REG_ACC, REG_ACC, REG_A1); } break; case T_IF: case T_MULT: case T_CMULT: case T_WHL: load_acc_offset(n->offset); clean_acc(); acc_const = acc_loaded = 0; if (stackptr >= maxstack) { loopstack = realloc(loopstack, ((maxstack+=32)+2)*sizeof(*loopstack)); if (loopstack == 0) { perror("loop stack realloc failure"); exit(1); } } if (cell_mask > 0 && acc_hi_dirty) { if (cell_mask == 0xFF) jit_extr_uc(REG_ACC,REG_ACC); else jit_andi(REG_ACC, REG_ACC, cell_mask); } #ifdef GNULIGHTv1 loopstack[stackptr] = jit_beqi_i(jit_forward(), REG_ACC, 0); loopstack[stackptr+1] = jit_get_label(); #endif #ifdef GNULIGHTv2 loopstack[stackptr] = jit_beqi(REG_ACC, 0); loopstack[stackptr+1] = jit_label(); #endif stackptr += 2; break; case T_END: load_acc_offset(n->offset); clean_acc(); stackptr -= 2; if (stackptr < 0) { fprintf(stderr, "Code gen failure: Stack pointer negative.\n"); exit(1); } if (cell_mask > 0 && acc_hi_dirty) { if (cell_mask == 0xFF) jit_extr_uc(REG_ACC,REG_ACC); else jit_andi(REG_ACC, REG_ACC, cell_mask); } #ifdef GNULIGHTv1 jit_bnei_i(loopstack[stackptr+1], REG_ACC, 0); jit_patch(loopstack[stackptr]); #endif #ifdef GNULIGHTv2 { jit_node_t *ref; ref = jit_bnei(REG_ACC, 0); jit_patch_at(ref, loopstack[stackptr+1]); jit_patch(loopstack[stackptr]); } #endif break; case T_ENDIF: clean_acc(); acc_const = acc_loaded = 0; stackptr -= 2; if (stackptr < 0) { fprintf(stderr, "Code gen failure: Stack pointer negative.\n"); exit(1); } jit_patch(loopstack[stackptr]); break; case T_PRT: clean_acc(); load_acc_offset(n->offset); acc_loaded = 0; #ifdef GNULIGHTv1 jit_prepare_i(1); jit_pusharg_i(REG_ACC); jit_finish(putch); #endif #ifdef GNULIGHTv2 jit_prepare(); jit_pushargr(REG_ACC); jit_finishi(putch); #endif break; case T_CHR: clean_acc(); acc_const = acc_loaded = 0; if (n->count <= 0 || (n->count >= 127 && iostyle == 1) || !n->next || n->next->type != T_CHR) { jit_movi(REG_ACC, n->count); #ifdef GNULIGHTv1 jit_prepare_i(1); jit_pusharg_i(REG_ACC); jit_finish(putch); #endif #ifdef GNULIGHTv2 jit_prepare(); jit_pushargr(REG_ACC); jit_finishi(putch); #endif } else { unsigned i = 0; struct bfi * v = n; char *s; while(v->next && v->next->type == T_CHR && v->next->count > 0 && (v->next->count < 127 || iostyle != 1)) { if (i+2 > maxstrlen) { if (maxstrlen) maxstrlen *= 2; else maxstrlen = 4096; strbuf = realloc(strbuf, maxstrlen); if (!strbuf) { fprintf(stderr, "Reallocate of string buffer failed\n"); exit(42); } } strbuf[i++] = (char) /*GCC -Wconversion*/ v->count; n = v; v = v->next; } strbuf[i] = 0; s = strdup(strbuf); if (!s) { fprintf(stderr, "Save of string failed\n"); exit(43); } save_ptr_for_free(s); #ifdef GNULIGHTv1 jit_movi_p(REG_ACC, s); jit_prepare_i(1); jit_pusharg_i(REG_ACC); jit_finish(puts_without_nl); #endif #ifdef GNULIGHTv2 jit_prepare(); jit_pushargi((jit_word_t) s); jit_finishi(puts_without_nl); #endif } break; case T_INP: load_acc_offset(n->offset); set_acc_offset(n->offset); #ifdef GNULIGHTv1 jit_prepare_i(1); jit_pusharg_i(REG_ACC); jit_finish(getch); jit_retval_i(REG_ACC); #endif #ifdef GNULIGHTv2 jit_prepare(); jit_pushargr(REG_ACC); jit_finishi(getch); jit_retval(REG_ACC); #endif break; case T_STOP: #ifdef GNULIGHTv1 jit_prepare_i(0); jit_finish(failout); #endif #ifdef GNULIGHTv2 jit_prepare(); jit_finishi(failout); #endif break; case T_NOP: case T_DUMP: fprintf(stderr, "Warning on code generation: " "%s node: ptr+%d, cnt=%d, @(%d,%d).\n", tokennames[n->type], n->offset, n->count, n->line, n->col); break; default: fprintf(stderr, "Code gen error: " "%s\t" "%d:%d, %d:%d, %d:%d\n", tokennames[n->type], n->offset, n->count, n->offset2, n->count2, n->offset3, n->count3); exit(1); } n=n->next; #if 0 /*def GNULIGHTv2 */ if(n && enable_trace) { char *p, buf[250]; clean_acc(); acc_loaded = 0; sprintf(buf, "@(%d,%d)\n", n->line, n->col); p = strdup(buf); save_ptr_for_free(p); jit_prepare(); jit_pushargi((jit_word_t) p); jit_finishi(puts_without_nl); } #endif #ifdef GNULIGHTv1 /* TODO -- Check for codeBuffer overflow (add jmp to new) */ #endif } jit_ret(); if (strbuf) { maxstrlen = 0; free(strbuf); strbuf = 0; } delete_tree(); #ifdef GNULIGHTv1 jit_flush_code(startptr, jit_get_ip().ptr); if (verbose) fprintf(stderr, "Generated %d bytes of V1 GNU Lightning code, running\n", (int)(jit_get_ip().ptr - (char*)startptr)); start_runclock(); codeptr(map_hugeram()); finish_runclock(&run_time, &io_time); #endif #ifdef GNULIGHTv2 jit_epilog(); end = jit_note(__FILE__, __LINE__); codeptr = jit_emit(); if (verbose) fprintf(stderr, "Generated %d bytes of V2 GNU Lightning code, running\n", (int)((char*)jit_address(end) - (char*)jit_address(start))); jit_clear_state(); // jit_disassemble(); start_runclock(); codeptr(map_hugeram()); finish_runclock(&run_time, &io_time); #endif #if 0 /* This code writes the generated instructions to a file * so we can disassemble it using: ndisasm -b 32/64 code.bin */ { #ifdef GNULIGHTv1 char *p = startptr; int s = jit_get_ip().ptr - p; #endif #ifdef GNULIGHTv2 char *p = (char*)jit_address(start); int s = (char*)jit_address(end) - p; #endif FILE *fp = fopen("code.bin", "w"); int i; for (i = 0; i < s; ++i) { fputc(p[i], fp); } fclose(fp); } #endif #ifdef GNULIGHTv2 jit_destroy_state(); finish_jit(); #endif codeptr = 0; if (loopstack) { free(loopstack); loopstack = 0; } free_saved_memory(); }
void outrun(int ch, int count) { jit_node_t *argp; switch(ch) { case '!': if (bytecell) tape_step = 1; else tape_step = sizeof(int); init_jit(NULL); // argv[0]); _jit = jit_new_state(); start = jit_note(__FILE__, __LINE__); jit_prolog(); /* Get the data area pointer */ argp = jit_arg(); jit_getarg(REG_P, argp); break; case '~': jit_ret(); jit_epilog(); end = jit_note(__FILE__, __LINE__); codeptr = jit_emit(); jit_clear_state(); codeptr(calloc(tape_step, tapelen)); jit_destroy_state(); finish_jit(); codeptr = 0; if (loopstack) { free(loopstack); loopstack = 0; } break; case '>': jit_addi(REG_P, REG_P, count * tape_step); break; case '<': jit_subi(REG_P, REG_P, count * tape_step); break; case '+': if (tape_step>1) jit_ldr_i(REG_ACC, REG_P); else jit_ldr_uc(REG_ACC, REG_P); jit_addi(REG_ACC, REG_ACC, count); if (tape_step>1) jit_str_i(REG_P, REG_ACC); else jit_str_c(REG_P, REG_ACC); break; case '-': if (tape_step>1) jit_ldr_i(REG_ACC, REG_P); else jit_ldr_uc(REG_ACC, REG_P); jit_subi(REG_ACC, REG_ACC, count); if (tape_step>1) jit_str_i(REG_P, REG_ACC); else jit_str_c(REG_P, REG_ACC); break; case '[': if (tape_step>1) jit_ldr_i(REG_ACC, REG_P); else jit_ldr_uc(REG_ACC, REG_P); if (stackptr >= maxstack) { loopstack = realloc(loopstack, ((maxstack+=32)+2)*sizeof(*loopstack)); if (loopstack == 0) { perror("loop stack realloc failure"); exit(1); } } loopstack[stackptr] = jit_beqi(REG_ACC, 0); loopstack[stackptr+1] = jit_label(); stackptr += 2; break; case ']': if (tape_step>1) jit_ldr_i(REG_ACC, REG_P); else jit_ldr_uc(REG_ACC, REG_P); stackptr -= 2; if (stackptr < 0) { fprintf(stderr, "Code gen failure: Stack pointer negative.\n"); exit(1); } { jit_node_t *ref; ref = jit_bnei(REG_ACC, 0); jit_patch_at(ref, loopstack[stackptr+1]); jit_patch(loopstack[stackptr]); } break; case '.': if (tape_step>1) jit_ldr_i(REG_ACC, REG_P); else jit_ldr_uc(REG_ACC, REG_P); jit_prepare(); jit_pushargr(REG_ACC); jit_finishi(putchar); break; case ',': jit_prepare(); jit_pushargr(REG_ACC); jit_finishi(getchar); jit_retval(REG_ACC); if (tape_step>1) jit_str_i(REG_P, REG_ACC); else jit_str_c(REG_P, REG_ACC); break; } }
void _jit_reti_d(jit_state_t *_jit, jit_float64_t u) { jit_movi_d(JIT_FRET, u); jit_ret(); }
int compile_for_platform(Cell* expr, Cell** res) { jit_out = fopen("/tmp/jit_out.s","w"); jit_init(); register void* sp asm ("sp"); Frame empty_frame = {NULL, 0, 0, sp}; int success = compile_expr(expr, &empty_frame, TAG_ANY); jit_ret(); if (!success) { printf("<compile_expr failed: %d>\r\n",success); } if (success) { int codesz = 1024; fclose(jit_out); struct stat src_stat; stat("/tmp/jit_out.s", &src_stat); off_t generated_sz = src_stat.st_size; FILE* asm_f = fopen("/tmp/jit_out.s","r"); uint32_t* jit_asm = malloc(generated_sz); memset(jit_asm,0,generated_sz); fread(jit_asm,1,generated_sz,asm_f); fclose(asm_f); #ifdef DEBUG printf("\nJIT ---------------------\n%s-------------------------\n\n",jit_asm); #endif free(jit_asm); // prefix with arm-none-eabi- on ARM -mlittle-endian system("as -L /tmp/jit_out.s -o /tmp/jit_out.o"); #if defined(__APPLE__) && defined(__MACH__) system("gobjcopy /tmp/jit_out.o -O binary /tmp/jit_out.bin"); #else system("objcopy /tmp/jit_out.o -O binary /tmp/jit_out.bin"); #endif stat("/tmp/jit_out.bin", &src_stat); generated_sz = src_stat.st_size; while (generated_sz>codesz) { codesz*=2; printf ("<compiler: doubling code block size to %d>\r\n",codesz); } FILE* binary_f = fopen("/tmp/jit_out.bin","r"); uint32_t* jit_binary = mmap(0, codesz, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); int bytes_read = fread(jit_binary,1,codesz,binary_f); fclose(binary_f); #ifdef DEBUG printf("<assembled bytes: %d at: %p>\n",bytes_read,jit_binary); char cmd[256]; sprintf(cmd,"cp /tmp/jit_out.o /tmp/jit_%p.o",jit_binary); system(cmd); sprintf(cmd,"cp /tmp/jit_out.s /tmp/jit_%p.s",jit_binary); system(cmd); #endif if (bytes_read>codesz) { printf("<error: max assembly size of %d exhausted. aborting>\n",codesz); munmap(jit_binary,codesz); return 0; } // read symbols for linking lambdas #if defined(__APPLE__) && defined(__MACH__) system("gnm /tmp/jit_out.o > /tmp/jit_out.syms 2> /dev/null"); #else system("nm /tmp/jit_out.o > /tmp/jit_out.syms"); #endif FILE* link_f = fopen("/tmp/jit_out.syms","r"); if (link_f) { char* link_line=malloc(128); while(fgets(link_line, 128, link_f)) { if (strlen(link_line)>22) { char ida=link_line[19]; char idb=link_line[20]; char idc=link_line[21]; //printf("link_line: %s %c %c %c\n",link_line,ida,idb,idc); if (ida=='L' && idc=='_') { Cell* lambda = (Cell*)strtoul(&link_line[24], NULL, 16); if (idb=='0') { // function entrypoint // TODO: 64/32 bit unsigned long long offset = strtoul(link_line, NULL, 16); void* binary = ((uint8_t*)jit_binary) + offset; //printf("function %p entrypoint: %p (+%ld)\n",lambda,binary,offset); if (lambda->tag == TAG_LAMBDA) { lambda->dr.next = binary; } else { printf("fatal error: no lambda found at %p!\n",lambda); } } else if (idb=='1') { // function exit unsigned long long offset = strtoul(link_line, NULL, 16); //printf("function exit point: %p\n",offset); } } } } free(link_line); } int mp_res = mprotect(jit_binary, codesz, PROT_EXEC|PROT_READ); if (!mp_res) { *res = execute_jitted(jit_binary); success = 1; } else { printf("<mprotect result: %d\n>",mp_res); *res = NULL; success = 0; } } return success; }
void _jit_reti_f(jit_state_t *_jit, jit_float32_t u) { jit_movi_f(JIT_FRET, u); jit_ret(); }
void _jit_reti(jit_state_t *_jit, jit_word_t u) { jit_movi(JIT_RET, u); jit_ret(); }