void as_3_function::compile_stack_resize( int count ) { #ifdef __GAMESWF_ENABLE_JIT__ jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 1 ) ); jit_this_call( m_compiled_code, &array<as_value>::size ); jit_subi( m_compiled_code, jit_eax, count ); jit_pusharg( m_compiled_code, jit_eax ); jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 1 ) ); jit_this_call( m_compiled_code, &array<as_value>::resize ); jit_popargs( m_compiled_code, 1 ); #endif }
void as_3_function::compile() { #define var_stack jit_getarg( 1 ) #define var_scope jit_getarg( 2 ) #ifdef __GAMESWF_ENABLE_JIT__ int ip = 0; jit_prologue( m_compiled_code ); if( m_code.size() == 0 ) return; do { Uint8 opcode = m_code[ip++]; switch (opcode) { case 0x24: // pushbyte { int byte_value; ip += read_vu30(byte_value, &m_code[ip]); //stack.push_back(byte_value); jit_pushargi( m_compiled_code, byte_value ); jit_load( m_compiled_code, jit_eax, jit_getarg( 1 ) ); jit_pusharg( m_compiled_code, jit_eax ); jit_call( m_compiled_code, stack_int_function(stack_push_back_value) ); jit_popargs( m_compiled_code, 2 ); //IF_VERBOSE_ACTION(log_msg("EX: pushbyte\t %d\n", byte_value)); break; } case 0x2D: // pushint { int index; ip += read_vu30(index, &m_code[ip]); int val = m_abc->get_integer(index); //stack.push_back(val); jit_pushargi( m_compiled_code, val ); jit_load( m_compiled_code, jit_eax, jit_getarg( 1 ) ); jit_pusharg( m_compiled_code, jit_eax ); jit_call( m_compiled_code, stack_int_function(stack_push_back_value) ); jit_popargs( m_compiled_code, 2 ); //IF_VERBOSE_ACTION(log_msg("EX: pushint\t %d\n", val)); break; } case 0x2C: // pushstring { int index; ip += read_vu30(index, &m_code[ip]); const char* val = m_abc->get_string(index); //stack.push_back(val); jit_pushargi( m_compiled_code, val ); jit_load( m_compiled_code, jit_eax, jit_getarg( 1 ) ); jit_pusharg( m_compiled_code, jit_eax ); jit_call( m_compiled_code, stack_charp_function( &stack_push_back_value ) ); jit_popargs( m_compiled_code, 2 ); //IF_VERBOSE_ACTION(log_msg("EX: pushstring\t '%s'\n", val)); break; } case 0x2F: // pushdouble { int index; ip += read_vu30(index, &m_code[ip]); double val = m_abc->get_double(index); jit_pushargi( m_compiled_code, val ); jit_load( m_compiled_code, jit_esi, var_stack ); jit_pusharg( m_compiled_code, jit_esi ); jit_call( m_compiled_code, &(stack_push_back_value<double>) ); jit_popargs( m_compiled_code, 3 ); //double counts for 2; //stack.push_back(val); //IF_VERBOSE_ACTION(log_msg("EX: pushdouble\t %f\n", val)); break; } case 0x30: // pushscope { //as_value& val = stack.back(); typedef as_value& ( array<as_value>::*back_function )(); jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 1 ) ); jit_this_call( m_compiled_code, (back_function)&array<as_value>::back ); jit_load( m_compiled_code, jit_this_pointer, var_scope ); jit_push( m_compiled_code, jit_result ); jit_call( m_compiled_code, (push_value_function)&array<as_value>::push_back ); jit_popargs( m_compiled_code, 1 ); //IF_VERBOSE_ACTION(log_msg("EX: pushscope\t %s\n", val.to_xstring())); //TODO: Ecx is caller-saved, copy it to esi or edi before calling to prevent reload from memory //stack.resize(stack.size() - 1); compile_stack_resize( 1 ); break; } case 0x47: // returnvoid { //IF_VERBOSE_ACTION(log_msg("EX: returnvoid\t\n")); //result->set_undefined(); jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 3 ) ); jit_this_call( m_compiled_code, &as_value::set_undefined ); break; } case 0x49: // constructsuper { // stack: object, arg1, arg2, ..., argn int arg_count; ip += read_vu30(arg_count, &m_code[ip]); struct constructsuper { static void call( array<as_value> & stack, int arg_count ) { as_object* obj = stack.back().to_object(); stack.resize(stack.size() - 1); for (int i = 0; i < arg_count; i++) { as_value& val = stack.back(); stack.resize(stack.size() - 1); } //TODO: construct super of obj IF_VERBOSE_ACTION(log_msg("EX: constructsuper\t 0x%p(args:%d)\n", obj, arg_count)); } }; jit_pushi( m_compiled_code, arg_count ); jit_load( m_compiled_code, jit_esi, var_stack ); jit_push( m_compiled_code, jit_esi ); jit_call( m_compiled_code, &constructsuper::call ); jit_popargs( m_compiled_code, 2 ); break; } case 0x4F: // callpropvoid, Call a property, discarding the return value. // Stack: …, obj, [ns], [name], arg1,...,argn => … { int index; ip += read_vu30(index, &m_code[ip]); const char* name = m_abc->get_multiname(index); int arg_count; ip += read_vu30(arg_count, &m_code[ip]); jit_load( m_compiled_code, jit_esi, var_stack ); jit_pusharg( m_compiled_code, jit_esi ); jit_pushargi( m_compiled_code, arg_count ); jit_pushargi( m_compiled_code, name ); jit_pushargi( m_compiled_code, this ); jit_call( m_compiled_code, &callpropvoid::call ); jit_popargs( m_compiled_code, 4 ); /* struct local { static void construct_env( as_environment *env, player * player ) { new( env ) as_environment( player ); } static void destruct_env( as_environment *env ) { env->~as_environment(); } }; //as_environment env(get_player()); int env_offset = jit_allocate_stack_object_memory( m_compiled_code, sizeof( as_environment ) ); //Do we query it each it or it won't change? I decided it won't change jit_mov( m_compiled_code, jit_edi, jit_stack_pointer ); jit_pushi( m_compiled_code, (uint32)get_player() ); jit_push( m_compiled_code, jit_edi ); jit_call( m_compiled_code, &local::construct_env ); jit_popargs( m_compiled_code, 2 ); //as_value* val = stack.back(); jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 1 ) ); typedef as_value& ( array<as_value>::*back_function )(); jit_this_call( m_compiled_code, (back_function)&array<as_value>::back ); jit_mov( m_compiled_code, jit_esi, jit_result ); for (int i = 0; i < arg_count; i++) { //env.push( *val); jit_mov( m_compiled_code, jit_this_pointer, jit_edi ); jit_push( m_compiled_code, jit_esi ); jit_this_call( m_compiled_code, & as_environment::push<as_value&> ); //val--; jit_subi( m_compiled_code, jit_esi, sizeof( as_value ) ); } //stack.resize(stack.size() - arg_count); compile_stack_resize( arg_count ); //as_object* obj = stack.back().to_object(); jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 1 ) ); typedef as_value& ( array<as_value>::*back_function )(); jit_this_call( m_compiled_code, (back_function)&array<as_value>::back ); jit_mov( m_compiled_code, jit_this_pointer, jit_result ); jit_this_call( m_compiled_code, &as_value::to_object ); jit_mov( m_compiled_code, jit_esi, jit_result ); //stack.resize(stack.size() - 1); compile_stack_resize( 1 ); //as_value func; //if (obj && obj->get_member(name, &func)) //{ // call_method(func, &env, obj, arg_count, env.get_top_index()); //} // Destruct env jit_getaddress( m_compiled_code, jit_result, jit_stack_pointer, env_offset ); jit_push( m_compiled_code ,jit_result ); jit_call( m_compiled_code, &local::destruct_env ); jit_popargs( m_compiled_code, 1 ); //IF_VERBOSE_ACTION(log_msg("EX: callpropvoid\t 0x%p.%s(args:%d)\n", obj, name, arg_count)); */ break; } case 0x5D: // findpropstrict { int index; ip += read_vu30(index, &m_code[ip]); const char* name = m_abc->get_multiname(index); // search property in scope // TODO: inline struct findpropstrict { static as_object * call( char* name, array<as_value> & scope ) { for (int i = scope.size() - 1; i >= 0; i--) { as_value val; if (scope[i].find_property(name, &val)) { return scope[i].to_object(); } } return NULL; } }; jit_load( m_compiled_code, jit_esi, var_scope ); jit_push( m_compiled_code, jit_esi ); jit_pushi( m_compiled_code, name); jit_call( m_compiled_code, &findpropstrict::call ); jit_popargs( m_compiled_code, 2 ); //IF_VERBOSE_ACTION(log_msg("EX: findpropstrict\t %s, obj=0x%p\n", name, obj)); //stack.push_back(obj); jit_load( m_compiled_code, jit_esi, var_stack ); jit_push( m_compiled_code, jit_result ); jit_push( m_compiled_code, jit_esi ); jit_call( m_compiled_code, &stack_push_back_value<as_object*> ); jit_popargs( m_compiled_code, 2 ); break; } case 0x5E: // findproperty, Search the scope stack for a property { int index; ip += read_vu30(index, &m_code[ip]); const char* name = m_abc->get_multiname(index); struct findproperty { static void call( const char* name, array<as_value> & scope, array<as_value> & stack ) { as_object* obj = NULL; for (int i = scope.size() - 1; i >= 0; i--) { as_value val; if (scope[i].find_property(name, &val)) { obj = scope[i].to_object(); break; } } IF_VERBOSE_ACTION(log_msg("EX: findproperty\t %s, obj=0x%p\n", name, obj)); stack.push_back(obj); } }; jit_load( m_compiled_code, jit_esi, var_stack ); jit_push( m_compiled_code, jit_esi ); jit_load( m_compiled_code, jit_esi, var_scope ); jit_push( m_compiled_code, jit_esi ); jit_pushi( m_compiled_code, name ); jit_call( m_compiled_code, &findproperty::call ); jit_popargs( m_compiled_code, 3 ); break; } case 0x60: // getlex, Find and get a property. { int index; ip += read_vu30(index, &m_code[ip]); const char* name = m_abc->get_multiname(index); struct getlex { static void call( const char* name, array<as_value> & scope, array<as_value> &stack ) { // search property in scope as_value val; for (int i = scope.size() - 1; i >= 0; i--) { if (scope[i].find_property(name, &val)) { break; } } IF_VERBOSE_ACTION(log_msg("EX: getlex\t %s, value=%s\n", name, val.to_xstring())); stack.push_back(val); } }; jit_load( m_compiled_code, jit_esi, var_stack ); jit_push( m_compiled_code, jit_esi ); jit_load( m_compiled_code, jit_esi, var_scope ); jit_push( m_compiled_code, jit_esi ); jit_pushi( m_compiled_code, name ); jit_call( m_compiled_code, &getlex::call ); jit_popargs( m_compiled_code, 2 ); break; } case 0x66: // getproperty { // int index; // ip += read_vu30(index, &m_code[ip]); // const char* name = m_abc->get_multiname(index); // // as_object* obj = stack.back().to_object(); // if (obj) // { // obj->get_member(name, &stack.back()); // } // else // { // stack.back().set_undefined(); // } // // IF_VERBOSE_ACTION(log_msg("EX: getproperty\t %s, value=%s\n", name, stack.back().to_xstring())); // break; } case 0x68: // initproperty, Initialize a property. { int index; ip += read_vu30(index, &m_code[ip]); const char* name = m_abc->get_multiname(index); struct initproperty { static void call( const char * name, array<as_value> & stack ) { as_value& val = stack[stack.size() - 1]; as_object* obj = stack[stack.size() - 2].to_object(); if (obj) { obj->set_member(name, val); } IF_VERBOSE_ACTION(log_msg("EX: initproperty\t 0x%p.%s=%s\n", obj, name, val.to_xstring())); stack.resize(stack.size() - 2); } }; jit_load( m_compiled_code, jit_esi, var_stack ); jit_push( m_compiled_code, jit_esi ); jit_pushi( m_compiled_code, name ); jit_call( m_compiled_code, &initproperty::call ); jit_popargs( m_compiled_code, 2 ); break; } case 0xD0: // getlocal_0 case 0xD1: // getlocal_1 case 0xD2: // getlocal_2 case 0xD3: // getlocal_3 { //as_value& val = lregister[opcode & 0x03]; jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 0 ) ); jit_pushi( m_compiled_code, opcode & 0x03 ); jit_this_call( m_compiled_code, (index_function)&array<as_value>::operator[] ); jit_popargs( m_compiled_code, 1 ); //stack.push_back(val); jit_push( m_compiled_code, jit_result ); jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 1 ) ); jit_this_call( m_compiled_code, (push_value_function) &array<as_value>::push_back ); jit_popargs( m_compiled_code, 1 ); //IF_VERBOSE_ACTION(log_msg("EX: getlocal_%d\t %s\n", opcode & 0x03, val.to_xstring())); break; } default: log_msg("TODO opcode 0x%02X\n", opcode); break; } } while (ip < m_code.size()); jit_return( m_compiled_code ); m_compiled_code.initialize(); #else assert( false ); #endif }
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; } }