Index: src/frame_builder.c =================================================================== --- src/frame_builder.c (revision 41833) +++ src/frame_builder.c (working copy) @@ -7,99 +7,8 @@ /* HEADERIZER STOP */ #include "parrot/parrot.h" -#include "pmc/pmc_fixedintegerarray.h" -#include "pmc/pmc_unmanagedstruct.h" -#include "pmc/pmc_managedstruct.h" #include "frame_builder.h" -/* - -=over 4 - -=item C - -This is a callback to implement the proper freeing semantics. It is called by -the ManagedStruct PMC as it is garbage collected. - -=cut - -*/ - -void -Parrot_jit_free_buffer(PARROT_INTERP, void *ptr, void *priv) -{ - const struct jit_buffer_private_data * const jit = (struct jit_buffer_private_data*)priv; - mem_free_executable(ptr, jit->size); - free(priv); -} - -/* - -=item C - -This is a callback to implement the proper cloning semantics for jit buffers. -It is called by the ManagedStruct PMC's clone() function. - -=back - -=cut - -*/ - -PMC * -Parrot_jit_clone_buffer(PARROT_INTERP, PMC *pmc, void *priv) -{ - PMC * const rv = pmc_new(interp, pmc->vtable->base_type); - - VTABLE_init(interp, rv); - /* copy the attributes */ - { - void (*tmpfreefunc)(PARROT_INTERP, void*, void*); - GETATTR_ManagedStruct_custom_free_func(interp, pmc, tmpfreefunc); - SETATTR_ManagedStruct_custom_free_func(interp, rv , tmpfreefunc); - } - { - PMC* (*tmpclonefunc)(PARROT_INTERP, PMC*, void*); - GETATTR_ManagedStruct_custom_clone_func(interp, pmc, tmpclonefunc); - SETATTR_ManagedStruct_custom_clone_func(interp, rv , tmpclonefunc); - } - - { - void *freepriv, *clonepriv; - GETATTR_ManagedStruct_custom_free_priv(interp , pmc, freepriv); - GETATTR_ManagedStruct_custom_clone_priv(interp, pmc, clonepriv); - if (freepriv) { - void *tmp = mem_sys_allocate(sizeof (struct jit_buffer_private_data)); - memcpy(tmp, freepriv, sizeof (struct jit_buffer_private_data)); - SETATTR_ManagedStruct_custom_free_priv(interp, rv , tmp); - if (clonepriv == freepriv) { - /* clonepriv is a copy of freepriv, make it a copy in the clone too. */ - SETATTR_ManagedStruct_custom_clone_priv(interp, rv , tmp); - clonepriv = NULL; /* disable the clonepriv copying below */ - } - } - if (clonepriv) { - void *tmp = mem_sys_allocate(sizeof (struct jit_buffer_private_data)); - memcpy(tmp, clonepriv, sizeof (struct jit_buffer_private_data)); - SETATTR_ManagedStruct_custom_clone_priv(interp, rv , tmp); - } - } - - /* copy the execmem buffer */ - if (PARROT_MANAGEDSTRUCT(pmc)->ptr) { - struct jit_buffer_private_data *jit = (struct jit_buffer_private_data*)priv; - void *ptr = PARROT_MANAGEDSTRUCT(pmc)->ptr; - void *newptr = mem_alloc_executable(jit->size); - if (!newptr) - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Cannot allocate executable memory"); - memcpy(newptr, ptr, jit->size); - PARROT_MANAGEDSTRUCT(rv)->ptr = newptr; - } - - return rv; -} - INTVAL get_nci_I(PARROT_INTERP, ARGMOD(call_state *st), int n) { @@ -224,515 +133,7 @@ } } -int -emit_is8bit(long disp) -{ - return disp >= -128 && disp <= 127; -} - -char * -emit_disp8_32(char *pc, int disp) -{ - if (emit_is8bit(disp)) { - *(pc++) = (char)disp; - return pc; - } - else { - *(long *)pc = disp; - return pc + 4; - } -} - -void -emit_sib(PARROT_INTERP, char *pc, int scale, int i, int base) -{ - int scale_byte; - - switch (scale) { - case 1: - scale_byte = emit_Scale_1; - break; - case 2: - scale_byte = emit_Scale_2; - break; - case 4: - scale_byte = emit_Scale_4; - break; - case 8: - scale_byte = emit_Scale_8; - break; - default: - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Invalid scale factor %d\n", scale); - return; - } - - *pc = (char)(scale_byte | (i == emit_None ? emit_Index_None : emit_reg_Index(i)) | - emit_reg_Base(base)); -} - -char * -emit_r_X(PARROT_INTERP, char *pc, int reg_opcode, int base, int i, int scale, long disp) -{ - if (i && !scale) - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "emit_r_X passed invalid scale+index combo\n"); - - if (base == emit_EBP) { - /* modrm disp */ - if (i == emit_None) { - *(pc++) = (char)((emit_is8bit(disp) ? emit_Mod_b01 : emit_Mod_b10) - | reg_opcode | emit_reg_rm(emit_EBP)); - return emit_disp8_32(pc, disp); - } - /* modrm sib disp */ - else { - *(pc++) = (char)((emit_is8bit(disp) ? emit_Mod_b01 : emit_Mod_b10) - | reg_opcode | emit_b100); - emit_sib(interp, pc++, scale, i, base); - return emit_disp8_32(pc, disp); - } - } - - /* modrm sib disp */ - if (base == emit_ESP) { - *(pc++) = (char)((emit_is8bit(disp) ? emit_Mod_b01 : emit_Mod_b10) - | reg_opcode | emit_rm_b100); - emit_sib(interp, pc++, scale, i, emit_ESP); - return emit_disp8_32(pc, disp); - } - - /* modrm disp32 */ - if (!base && !(i && scale)) { - *(pc++) = (char)(emit_Mod_b00 | reg_opcode | emit_rm_b101); - *(long *)pc = disp; - return pc + 4; - } - - /* Ok, everything should be more regular here */ - *(pc++) = (char)((disp == 0 ? emit_Mod_b00 : - (emit_is8bit(disp) ? - emit_Mod_b01 : emit_Mod_b10)) | - reg_opcode | - (!base || (scale && i) ? emit_rm_b100 : emit_reg_rm(base))); - - if (!base || (scale && i)) { - emit_sib(interp, pc++, scale, i, base); - } - if (disp) - pc = emit_disp8_32(pc, disp); - - return pc; -} - -char * -emit_shift_i_r(PARROT_INTERP, char *pc, int opcode, int imm, int reg) -{ - if (opcode == emit_b000 && imm < 0) { - opcode = emit_b001; /* -rol => 32 + ror */ - imm = -imm; - } - - if (imm == 0) { - /* noop */ - } - else if (imm == 1) { - *(pc++) = (char) 0xd1; - *(pc++) = (char) emit_alu_X_r(opcode, reg); - } - else if (imm > 1 && imm < 33) { - *(pc++) = (char) 0xc1; - *(pc++) = (char) emit_alu_X_r(opcode, reg); - *(pc++) = (char)imm; - } - else { - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "emit_shift_i_r passed invalid shift\n"); - } - - return pc; -} - -char * -emit_popl_r(char *pc, int reg) -{ - *(pc++) = (char)(0x58 | (reg - 1)); - return pc; -} - -unsigned char *lastpc; - -size_t -calc_signature_needs(const char *sig, int *strings) -{ - size_t stack_size = 0; - while (*sig) { - switch (*sig) { - case 't': - (*strings)++; - stack_size +=4; - break; - case 'd': - stack_size +=8; - break; - default: - stack_size +=4; - break; - } - sig++; - } - return stack_size; - -} - /* - * The function generated here is called as func(interp, nci_info) - * interp ... 8(%ebp) - * nci_info ... 12(%ebp) - * - * The generate function for a specific signature looks quite similar to - * an optimized compile of src/nci.c:pcf_x_yy(). In case of any troubles - * just compare the disassembly. - * - * If a non-NULL sizeptr is passed, the integer it points to will be written - * with the size of the allocated execmem buffer. - */ - -void * -Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci, STRING *signature, int *sizeptr) -{ - char *pc; - char *execmem; - int i = 0; - int arg_count = 0; - int string_buffer_count = 0; - const int ST_SIZE_OF = 124; - const int JIT_ALLOC_SIZE = 1024; - - char *signature_str = Parrot_str_to_cstring(interp, signature); - /* skip over the result */ - char *sig = signature_str + 1; - size_t stack_space_needed = calc_signature_needs(sig, - &string_buffer_count); - - int base_offset = 0; - int strings_offset = base_offset - (sizeof (char *) * string_buffer_count); - int st_offset = strings_offset - ST_SIZE_OF; - int args_offset = st_offset - stack_space_needed; - int temp_calls_offset = args_offset - 16; - int total_stack_needed = -temp_calls_offset; - - /* - * ESP - * 0-15, 16 bytes for utility calls - * stack_space_needed for actual NCI call - * st - * STRINGS -> char * holding space - * EBP - */ - - /* this ought to be enough - the caller of this function - * should free the function pointer returned here - */ - pc = execmem = (char *)mem_alloc_executable(JIT_ALLOC_SIZE); - if (! pc) - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Cannot allocate executable memory"); - - - /* this generated jit function will be called as (INTERP (EBP 8), func_ptr - * (ESP 12), args signature (ESP 16)) */ - - /* make stack frame, preserve %ebx */ - jit_emit_stack_frame_enter(pc); - - emitm_subl_i_r(pc, total_stack_needed, emit_ESP); - - /* Parrot_init_arg_nci(interp, &st, "S"); */ - /* args signature "S" */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 16); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - - /*&st*/ - emitm_lea_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, st_offset); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - /*interpreter*/ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 8); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 0); - - if (sig && *sig) - emitm_call_cfunc(pc, Parrot_init_arg_nci); - - while (*sig) { - emitm_movl_i_m(pc, arg_count, emit_EBP, 0, 1, temp_calls_offset + 8); - - switch (*sig) { - case '0': /* null ptr or such - doesn't consume a reg */ - jit_emit_bxor_rr_i(interp, pc, emit_EAX, emit_EAX); - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'f': - emitm_call_cfunc(pc, get_nci_N); - emitm_fstps(interp, pc, emit_EBP, 0, 1, args_offset); - break; - case 'N': - case 'd': - emitm_call_cfunc(pc, get_nci_N); - emitm_fstpl(interp, pc, emit_EBP, 0, 1, args_offset); - args_offset += 4; - break; - case 'I': /* INTVAL */ - case 'l': /* long */ - case 'i': /* int */ - emitm_call_cfunc(pc, get_nci_I); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 't': /* string, pass a cstring */ - emitm_call_cfunc(pc, get_nci_S); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - emitm_call_cfunc(pc, string_to_cstring_nullable); - - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - /* save off temporary allocation address */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, strings_offset); - strings_offset += 4; - - /* reset ESP(4) */ - emitm_lea_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, st_offset); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - break; - case 's': /* short: movswl intreg_o(base), %eax */ - emitm_call_cfunc(pc, get_nci_I); - emitm_movswl_r_r(pc, emit_EAX, emit_EAX); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'c': /* char: movsbl intreg_o(base), %eax */ - emitm_call_cfunc(pc, get_nci_I); - emitm_movsbl_r_r(pc, emit_EAX, emit_EAX); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'J': /* interpreter */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 8); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - arg_count--; - break; - case 'p': /* push pmc->data */ - emitm_call_cfunc(pc, get_nci_p); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'O': /* push PMC * object in P2 */ - case 'P': /* push PMC * */ - case '@': - emitm_call_cfunc(pc, get_nci_P); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'v': - break; - case 'b': /* buffer (void*) pass Buffer_bufstart(SReg) */ - emitm_call_cfunc(pc, get_nci_S); - emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, - (size_t) &Buffer_bufstart((STRING *) NULL)); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'B': /* buffer (void**) pass &Buffer_bufstart(SReg) */ - emitm_call_cfunc(pc, get_nci_S); - emitm_lea_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, - (size_t) &Buffer_bufstart((STRING *) NULL)); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'S': - emitm_call_cfunc(pc, get_nci_S); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - - - /* I have no idea how to handle these */ - case '2': - case '3': - case '4': - case 'V': - mem_free_executable(execmem, JIT_ALLOC_SIZE); - Parrot_str_free_cstring(signature_str); - return NULL; - break; - default: - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Unknown arg Signature %c\n", *sig); - /* - * oops unknown signature: - * cleanup and try nci.c - */ - mem_free_executable(execmem, JIT_ALLOC_SIZE); - Parrot_str_free_cstring(signature_str); - return NULL; - } - args_offset +=4; - arg_count++; - sig++; - } - - /* prepare to call VTABLE_get_pointer, set up args */ - /* interpreter - movl 8(%ebp), %eax */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 8); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 0); - - /* pmc - movl 12(%ebp), %eax */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 12); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - /* get the get_pointer() pointer from the pmc's vtable */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, offsetof(PMC, vtable)); - emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, offsetof(VTABLE, get_pointer)); - - /* call get_pointer(), result goes into eax */ - emitm_callr(pc, emit_EAX); - emitm_addl_i_r(pc, 16, emit_ESP); - - /* call the resulting function pointer */ - emitm_callr(pc, emit_EAX); - emitm_subl_i_r(pc, 16, emit_ESP); - - /* SAVE OFF EAX */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - - /*&st*/ - emitm_lea_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, st_offset); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - /*interpreter*/ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 8); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 0); - - /* RESTORE BACK EAX */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - - /* now place return value in registers */ - /* first in signature is the return value */ - sig = signature_str; /* the result */ - switch (*sig) { - /* I have no idea how to handle these */ - case '2': - case '3': - case '4': - /* get integer from pointer - untested */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, 0); - if (*sig == 2) /* short */ - emitm_movswl_r_r(pc, emit_EAX, emit_EAX); - emitm_call_cfunc(pc, set_nci_I); - break; - case 'f': - case 'd': - jit_emit_fstore_mb_n(interp, pc, emit_EBP, temp_calls_offset + 8); - emitm_call_cfunc(pc, set_nci_N); - /* pop num from st(0) and mov to reg */ - break; - case 's': - /* movswl %ax, %eax */ - emitm_movswl_r_r(pc, emit_EAX, emit_EAX); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - emitm_call_cfunc(pc, set_nci_I); - break; - case 'c': - /* movsbl %al, %eax */ - emitm_movsbl_r_r(pc, emit_EAX, emit_EAX); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - emitm_call_cfunc(pc, set_nci_I); - break; - case 'I': /* INTVAL */ - case 'l': - case 'i': - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - emitm_call_cfunc(pc, set_nci_I); - break; - case 'v': /* void - do nothing */ - break; - case 'P': - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - emitm_call_cfunc(pc, set_nci_P); - break; - case 'p': /* make a new unmanaged struct */ - /* save return value on stack */ - - /* save pointer p */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 12); - - /* make new pmc */ - emitm_movl_i_m(pc, enum_class_UnManagedStruct, emit_EBP, 0, 1, temp_calls_offset + 4); - emitm_call_cfunc(pc, pmc_new); - - /* restore pointer p to EDX */ - emitm_movl_m_r(interp, pc, emit_EDX, emit_EBP, 0, 1, temp_calls_offset + 12); - - /* copy UnManagedStruct to stack for set_nci_P call */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - - /* eax = PMC, get return value into edx */ - /* mov data(%eax), %eax - mov %edx, ptr(%eax) */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, offsetof(struct PMC, data)); - emitm_movl_r_m(interp, pc, emit_EDX, emit_EAX, 0, 1, - offsetof(struct Parrot_UnManagedStruct_attributes, ptr)); - - /* reset EBP(4) */ - emitm_lea_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, st_offset); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - emitm_call_cfunc(pc, set_nci_P); - break; - case 'S': - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - emitm_call_cfunc(pc, set_nci_S); - break; - case 't': /* string */ - /* EAX is char* */ - emitm_movl_i_m(pc, 0, emit_EBP, 0, 1, temp_calls_offset + 8); /* len */ - - /* overwrites address of st in EBP(4) */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - emitm_call_cfunc(pc, Parrot_str_new); - - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - - /* reset EBP(4) */ - emitm_lea_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, st_offset); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - emitm_call_cfunc(pc, set_nci_S); - break; - default: - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Unknown return Signature %c\n", *sig); - /* - * oops unknown signature: - * cleanup and try nci.c - */ - Parrot_str_free_cstring(signature_str); - mem_free_executable(execmem, JIT_ALLOC_SIZE); - return NULL; - } - - /* free temporary strings */ - strings_offset = st_offset + ST_SIZE_OF; - for (i=0; i #include "parrot/parrot.h" -#include "parrot/hash.h" -#include "parrot/oplib/ops.h" /* * NCI interface */ + void * -Parrot_jit_build_call_func(Interp *, PMC *, STRING *, int *); +Parrot_jit_build_call_func(Interp *, PMC *, STRING *, void **); /* custom pmc callback functions */ void @@ -37,22 +32,6 @@ PMC* Parrot_jit_clone_buffer(PARROT_INTERP, PMC *pmc, void *priv); -struct jit_buffer_private_data { - int size; -}; - -/* Scale factor values */ -#define emit_Scale(scale) ((scale) << 6) -#define emit_Scale_1 emit_Scale(0) -#define emit_Scale_2 emit_Scale(1) -#define emit_Scale_4 emit_Scale(2) -#define emit_Scale_8 emit_Scale(3) - -/* ESIB byte */ -#define emit_reg_Index(x) (((x)-1) << 3) -#define emit_reg_Base(x) ((x)-1) -#define emit_Index_None ((emit_b100) << 3) - /* * helper funcs - get argument n */ @@ -92,1310 +71,9 @@ void set_nci_P(PARROT_INTERP, ARGOUT(call_state *st), PMC* val); -/* - * if we have a delegated method like typeof_i_p, that returns an INTVAL - * and that is all in a sequence of JITted opcodes, and when these INTVAL - * is MAPped, we got a problem. So the EXT_CALL flag is disabled - mapped - * registers are saved/restored around vtable calls. - */ -#define JIT_VTABLE_OPS 1 +#endif /* PARROT_FRAME_BUILDER_H_GUARD */ -/* EXEC_SHARED generates code to be used with libparrot.so - * It grabs the real address of cgp_core from the gcc generated code - * x/1i cgp_code - * jmp *0xXXXX - * x/1wx 0xXXXX - * real address of cpg_core - * s. exec_emit_end - * XXX This should be a command line option. - */ -#undef EXEC_SHARED - -extern UINTVAL ld(UINTVAL); - -#define NEG_MINUS_ZERO -/* #define NEG_ZERO_SUB */ - -/* Register codes */ -#define emit_None 0 - -/* These are + 1 the real values */ -#define emit_EAX 1 -#define emit_ECX 2 -#define emit_EDX 3 -#define emit_EBX 4 -#define emit_ESP 5 -#define emit_EBP 6 -#define emit_ESI 7 -#define emit_EDI 8 - -/* Scratch register. */ - -#define ISR1 emit_EAX -#define FSR1 0 - -#define emit_b00 0 -#define emit_b01 1 -#define emit_b10 2 -#define emit_b11 3 - -#define emit_b000 0 -#define emit_b001 1 -#define emit_b010 2 -#define emit_b011 3 -#define emit_b100 4 -#define emit_b101 5 -#define emit_b110 6 -#define emit_b111 7 - -/* Mod R/M byte */ -#define emit_reg(x) ((x) << 3) -#define emit_Mod(Mod) ((Mod) << 6) -#define emit_reg_rm(x) ((x)-1) - -/* Mod values for Mod R/M Byte */ -#define emit_Mod_b00 emit_Mod(emit_b00) -#define emit_Mod_b01 emit_Mod(emit_b01) -#define emit_Mod_b10 emit_Mod(emit_b10) - -/* special R/M values */ -#define emit_rm_b101 emit_b101 -#define emit_rm_b100 emit_b100 - -#define emit_r_m(interp, pc, reg1, b, i, s, d) \ - emit_r_X((interp), (pc), emit_reg((reg1)-1), (b), (i), (s), (d)) - -#define emit_alu_X_r(X, reg) ((emit_b11 << 6) | ((X) << 3) | ((reg) - 1)) - -#define emit_alu_r_r(reg1, reg2) emit_alu_X_r(((reg1) - 1), (reg2)) - -int emit_is8bit(long disp); - -char * emit_disp8_32(char *pc, int disp); - -void emit_sib(PARROT_INTERP, char *pc, int scale, int i, int base); - -char * emit_r_X(PARROT_INTERP, char *pc, int reg_opcode, int base, int i, - int scale, long disp); - -char * emit_shift_i_r(PARROT_INTERP, char *pc, int opcode, int imm, int reg); - -char * emit_shift_i_m(PARROT_INTERP, char *pc, int opcode, int imm, - int base, int i, int scale, long disp); - -char * emit_shift_r_r(PARROT_INTERP, char *pc, int opcode, int reg1, int reg2); - -char * emit_shift_r_m(PARROT_INTERP, char *pc, int opcode, int reg, - int base, int i, int scale, long disp); - -/* CDQ - need this to do multiply */ -#define emitm_cdq(pc) *((pc)++) = (char) 0x99 - -/* RET */ -#define emitm_ret(pc) *((pc)++) = (char) 0xc3 - -/* NOP */ -#define emit_nop(pc) *((pc)++) = (char) 0x90 - -/* PUSHes */ - -#define emitm_pushl_r(pc, reg) \ - *((pc)++) = (char) 0x50 | ((reg) - 1) - -#define emitm_pushl_i(pc, imm) { \ - *((pc)++) = (char) 0x68; \ - *(long *)(pc) = (long)(imm); \ - (pc) += 4; } - -#define emitm_pushl_m(pc, mem) { \ - *((pc)++) = (char) 0xff; \ - *((pc)++) = (char) 0x35; \ - *(long *)(pc) = (long)(mem); \ - (pc) += 4; } - -char * emit_pushl_m(PARROT_INTERP, char *pc, int base, int i, int scale, - long disp); - -/* POPs */ - -char * emit_popl_r(char *pc, int reg); - -# define emitm_popl_r(pc, reg) \ - (pc) = emit_popl_r((pc), (reg)) - -char * emit_popl_m(PARROT_INTERP, char *pc, int base, int i, int scale, - long disp); - -/* MOVes */ - -char * emit_movb_r_r(char *pc, int reg1, int reg2); - -# define jit_emit_mov_rr_i(pc, reg2, reg1) if ((reg1) != (reg2)) { \ - *((pc)++) = (char) 0x89; \ - *((pc)++) = (char) emit_alu_r_r((reg1), (reg2)); } - -# define jit_emit_mov_ri_i(interp, pc, reg, imm) { \ - *((pc)++) = (char)(0xb8 | ((reg) - 1)); \ - *(long *)(pc) = (long)(imm); (pc) += 4; } - -# define emitm_movX_Y_Z(interp, op, pc, reg1, b, i, s, d) { \ - *((pc)++) = (char) (op); \ - (pc) = emit_r_m((interp), (pc), (reg1), (b), (i), (s), (long)(d)); } - -# define emitm_movb_r_m(interp, pc, reg1, b, i, s, d) \ - emitm_movX_Y_Z((interp), 0x88, (pc), (reg1), (b), (i), (s), (d)) - -# define emitm_movl_r_m(interp, pc, reg1, b, i, s, d) \ - emitm_movX_Y_Z((interp), 0x89, (pc), (reg1), (b), (i), (s), (d)) - -/* move byte/word with sign extension */ -# define emitm_movsbl_r_m(interp, pc, reg1, b, i, s, d) { \ - *((pc)++) = (char) 0x0f; \ - emitm_movX_Y_Z((interp), 0xBE, (pc), (reg1), (b), (i), (s), (d)); \ -} - -# define emitm_movswl_r_m(interp, pc, reg1, b, i, s, d) { \ - *((pc)++) = (char) 0x0f; \ - emitm_movX_Y_Z((interp), 0xBF, (pc), (reg1), (b), (i), (s), (d)); \ -} - -# define emitm_movsbl_r_r(pc, reg1, reg2) { \ - *((pc)++) = (char) 0x0f; \ - *((pc)++) = (char) 0xbe; \ - *((pc)++) = (char) emit_alu_r_r((reg1), (reg2)); \ -} - -# define emitm_movswl_r_r(pc, reg1, reg2) { \ - *((pc)++) = (char) 0x0f; \ - *((pc)++) = (char) 0xbf; \ - *((pc)++) = (char) emit_alu_r_r((reg1), (reg2)); \ -} - -# define emitm_movb_m_r(interp, pc, reg1, b, i, s, d) \ - emitm_movX_Y_Z((interp), 0x8a, (pc), (reg1), (b), (i), (s), (d)) - -# define emitm_movl_m_r(interp, pc, reg1, b, i, s, d) \ - emitm_movX_Y_Z((interp), 0x8b, (pc), (reg1), (b), (i), (s), (d)) - -# define emitm_lea_m_r(interp, pc, reg1, b, i, s, d) \ - emitm_movX_Y_Z((interp), 0x8d, (pc), (reg1), (b), (i), (s), (d)) - -char * emit_movb_i_m(PARROT_INTERP, char *pc, char imm, int base, int i, - int scale, long disp); - -# define emitm_movl_i_m(pc, imm, b, i, s, d) { \ - *((pc)++) = (char) 0xc7; \ - (pc) = emit_r_X((interp), (pc), emit_reg(emit_b000), (b), (i), (s), (long)(d)); \ - *(long *)(pc) = (long)(imm); (pc) += 4; } - -/* Various ALU formats */ - -# define emitm_alul_r_r(pc, op, reg1, reg2) { \ - *((pc)++) = (char) (op); *((pc)++) = (char) emit_alu_r_r((reg1), (reg2)); } - -# define emitm_alub_i_r(pc, op1, op2, imm, reg) { \ - *((pc)++) = (char) (op1); *((pc)++) = (char) emit_alu_X_r((op2), (reg)); *((pc)++) = (char)(imm); } - -# define emitm_alul_i_r(pc, op1, op2, imm, reg) { \ - *((pc)++) = (char) (op1); \ - *((pc)++) = (char) emit_alu_X_r((op2), (reg)); \ - *(long *)((pc)) = (long)(imm); (pc) += 4; } - -# define emitm_alul_i_m(pc, op1, op2, imm, b, i, s, d) { \ - *((pc)++) = (char) (op1); \ - (pc) = emit_r_X((interp), (pc), emit_reg(op2), (b), (i), (s), (d)); \ - *(long *)(pc) = (long)(imm); (pc) += 4; } - -# define emitm_alul_r_m(pc, op, reg, b, i, s, d) { \ - *((pc)++) = (char) (op); \ - (pc) = emit_r_X((interp), (pc), emit_reg((reg)-1), (b), (i), (s), (long)(d)); } - -/* ADDs */ - -# define emitm_addb_r_r(pc, reg1, reg2) \ - emitm_alul_r_r((pc), 0x00, (reg1), (reg2)) - -# define emitm_addb_i_r(pc, imm, reg) \ - emitm_alub_i_r((pc), 0x83, emit_b000, (imm), (reg)) - -# define jit_emit_add_rr_i(interp, pc, reg1, reg2) \ - emitm_alul_r_r((pc), 0x01, (reg2), (reg1)) - -# define jit_emit_add_ri_i(interp, pc, reg, imm) \ - emitm_alul_i_r((pc), 0x81, emit_b000, (imm), (reg)) - -# define emitm_addl_i_r(pc, imm, reg) \ - emitm_alul_i_r((pc), 0x81, emit_b000, (imm), (reg)) - -# define emitm_addl_i_m(pc, imm, b, i, s, d) \ - emitm_alul_i_m((pc), 0x81, emit_b000, (imm), (b), (i), (s), (d)) - -# define emitm_addl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x01, (reg), (b), (i), (s), (d)) - -# define emitm_addl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x03, (reg), (b), (i), (s), (d)) - -/* SUBs */ - -# define jit_emit_sub_rr_i(interp, pc, reg1, reg2) \ - emitm_alul_r_r((pc), 0x29, (reg2), (reg1)) - -# define emitm_subl_i_r(pc, imm, reg) \ - emitm_alul_i_r((pc), 0x81, emit_b101, (imm), (reg)) - -# define jit_emit_sub_ri_i(interp, pc, r, i) emitm_subl_i_r((pc), (i), (r)) - -# define emitm_subl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x29, (reg), (b), (i), (s), (d)) - -# define emitm_subl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x2b, (reg), (b), (i), (s), (d)) - -# define emitm_subl_i_m(pc, imm, b, i, s, d) \ - emitm_alul_i_m((pc), 0x81, emit_b101, (imm), (b), (i), (s), (d)) - -/* These are used by both signed and unsigned EDIV, but only unsigned MUL */ -# define emitm_alu_imp_r(pc, op, reg) { \ - *((pc)++) = (char) 0xf7; \ - *((pc)++) = (char) emit_alu_X_r((op), (reg)); } - -# define emitm_alu_imp_m(pc, op, b, i, s, d) { \ - *((pc)++) = (char) 0xf7; \ - (pc) = emit_r_X((interp), (pc), emit_reg(op), (b), (i), (s), (d)); } - -/* Unsigned MUL and EDIV */ -/* EAX implicit destination in multiply and divide */ - -# define emitm_umull_r(pc, reg2) emitm_alu_imp_r((pc), emit_b100, (reg2)) - -# define emitm_udivl_r(pc, reg2) emitm_alu_imp_r((pc), emit_b110, (reg2)) - -# define emitm_umull_m(pc, b, i, s, d) \ - emitm_alu_imp_m((pc), emit_b100, (b), (i), (s), (d)) - -# define emitm_udivl_m(pc, b, i, s, d) \ - emitm_alu_imp_m((pc), emit_b110, (b), (i), (s), (d)) - -/* Signed MUL and EDIV */ - -# define emitm_sdivl_r(pc, reg2) emitm_alu_imp_r((pc), emit_b111, (reg2)) - -# define emitm_sdivl_m(pc, b, i, s, d) \ - emitm_alu_imp_m((pc), emit_b111, (b), (i), (s), (d)) - -# define jit_emit_cdq(pc) *(pc)++ = 0x99 - -/* TEST for zero */ -# define jit_emit_test_r_i(pc, reg1) emitm_alul_r_r((pc), 0x85, (reg1), (reg1)) - -# define emitm_smull_r(pc, reg2) emitm_alu_imp_r((pc), emit_b101, (reg2)) - -# define jit_emit_mul_rr_i(interp, pc, reg1, reg2) { \ - *(pc)++ = 0xf; \ - emitm_alul_r_r((pc), 0xaf, (reg1), (reg2)); } - -# define emitm_smull_r_m(pc, reg1, b, i, s, d) { \ - *(pc)++ = 0xf; \ - emitm_alul_r_m((pc), 0xaf, (reg1), (b), (i), (s), (d)); } - -char * opt_mul(PARROT_INTERP, char *pc, int dest, INTVAL imm, int src); - -# define jit_emit_mul_rir_i(pc, dest, imm, src) \ - (pc) = opt_mul(interp, (pc), (dest), (imm), (src)) - - -# define jit_emit_mul_ri_i(pc, r, imm) jit_emit_mul_rir_i((pc), (r), (imm), (r)) - -# define jit_emit_mul_RIM_ii(pc, reg, imm, ofs) \ - emitm_alul_r_m((pc), 0x69, (reg), emit_EBX, emit_None, 1, (ofs)); \ - *(long *)(pc) = (long)(imm); \ - (pc) += 4; - -/* NEG */ - -# define jit_emit_neg_r_i(pc, reg) emitm_alu_imp_r((pc), emit_b011, (reg)) - -# define emitm_negl_m(pc, b, i, s, d) \ - emitm_alu_imp_m((pc), emit_b011, (b), (i), (s), (d)) - -/* AND */ - -# define emit_andl_r_r(pc, reg1, reg2) emitm_alul_r_r((pc), 0x21, (reg1), (reg2)) -# define jit_emit_band_rr_i(interp, pc, r1, r2) emit_andl_r_r((pc), (r2), (r1)) - -# define jit_emit_band_ri_i(interp, pc, reg, imm) \ - emitm_alul_i_r((pc), 0x81, emit_b100, (imm), (reg)) - -# define emitm_andl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x21, (reg), (b), (i), (s), (d)) - -# define emitm_andl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x23, (reg), (b), (i), (s), (d)) - -# define emitm_andl_i_m(pc, imm, b, i, s, d) \ - emitm_alul_i_m((pc), 0x81, emit_b100, (imm), (b), (i), (s), (d)) - -/* TEST op */ -# define jit_emit_test_rr_i(pc, r1, r2) emitm_alul_r_r((pc), 0x85, (r1), (r2)) - -# define jit_emit_test_ri_i(pc, r, im) \ - emitm_alul_i_r((pc), 0xF7, emit_b000, (im), (r)) - -# define jit_emit_test_RM_i(pc, r, offs) \ - emitm_alul_r_m((pc), 0x85, (r), emit_EBX, 0, 1, (offs)) - -/* OR */ - -# define jit_emit_bor_rr_i(interp, pc, reg1, reg2) emitm_alul_r_r((pc), 0x9, (reg2), (reg1)) - -# define jit_emit_bor_ri_i(interp, pc, reg, imm) \ - emitm_alul_i_r((pc), 0x81, emit_b001, (imm), (reg)) - -# define emitm_orl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x09, (reg), (b), (i), (s), (d)) - -# define emitm_orl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x0b, (reg), (b), (i), (s), (d)) - -# define emitm_orl_i_m(pc, imm, b, i, s, d) \ - emitm_alul_i_m((pc), 0x81, emit_b001, (imm), (b), (i), (s), (d)) - -/* XOR */ - -# define jit_emit_bxor_rr_i(interp, pc, reg1, reg2) \ - emitm_alul_r_r((pc), 0x31, (reg2), (reg1)) - -# define jit_emit_bxor_ri_i(intepr, pc, reg, imm) \ - emitm_alul_i_r((pc), 0x81, emit_b110, (imm), (reg)) - -# define emitm_xorl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x31, (reg), (b), (i), (s), (d)) - -# define emitm_xorl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x33, (reg), (b), (i), (s), (d)) - -# define emitm_xorl_i_m(pc, imm, b, i, s, d) \ - emitm_alul_i_m((pc), 0x81, emit_b110, (imm), (b), (i), (s), (d)) - -/* NOT */ - -# define jit_emit_not_r_i(pc, reg) emitm_alu_imp_r((pc), emit_b010, (reg)) -# define emitm_notl_m(pc, b, i, s, d) \ - emitm_alu_imp_m((pc), emit_b010, (b), (i), (s), (d)) - -# define jit_emit_not_M_i(interp, pc, offs) emitm_notl_m((pc), emit_EBX, 0, 1, (offs)) - -/* XCHG */ -# define jit_emit_xchg_rr_i(interp, pc, r1, r2) { \ - if ((r1) != (r2)) { \ - *((pc)++) = (char) 0x87; \ - *((pc)++) = (char) emit_alu_r_r((r1), (r2)); \ - } \ -} - -# define jit_emit_xchg_rm_i(pc, r, m) { \ - emitm_alul_r_m((pc), 0x87, (r), emit_None, emit_None, emit_None, (m)) \ -} -# define jit_emit_xchg_RM_i(interp, pc, r, offs) { \ - emitm_alul_r_m((pc), 0x87, (r), emit_EBX, emit_None, 1, (offs)) \ -} -# define jit_emit_xchg_MR_i(interp, pc, offs, r) jit_emit_xchg_RM_i((interp), (pc), (r), (offs)) - -/* SHL */ - -# define jit_emit_shl_ri_i(interp, pc, reg, imm) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b100, (imm), (reg)); } - -# define emitm_shll_i_m(pc, imm, b, i, s, d) \ - { (pc) = emit_shift_i_m((pc), emit_b100, (imm), (b), (i), (s), (d)); } - -# define emitm_shll_r_r(interp, pc, reg1, reg2) \ - { (pc) = emit_shift_r_r((interp), (pc), emit_b100, (reg1), (reg2)); } - -# define emitm_shll_r_m(pc, reg, b, i, s, d) \ - { (pc) = emit_shift_r_m((pc), emit_b100, (reg), (b), (i), (s), (d)); } - -/* SHR */ - -# define jit_emit_lsr_ri_i(interp, pc, reg, imm) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b101, (imm), (reg)); } - -# define emitm_shrl_i_m(pc, imm, b, i, s, d) \ - { (pc) = emit_shift_i_m((pc), emit_b101, (imm), (b), (i), (s), (d)); } - -# define emitm_shrl_r_r(interp, pc, reg1, reg2) \ - { (pc) = emit_shift_r_r((interp), (pc), emit_b101, (reg1), (reg2)); } - -# define emitm_shrl_r_m(pc, reg, b, i, s, d) \ - { (pc) = emit_shift_r_m((pc), emit_b101, (reg), (b), (i), (s), (d)); } - -/* SAL */ - -# define emitm_sall_i_r(interp, pc, imm, reg) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b100, (imm), (reg)); } - -# define emitm_sall_i_m(pc, imm, b, i, s, d) \ - { (pc) = emit_shift_i_m((pc), emit_b100, (imm), (b), (i), (s), (d)); } - -# define emitm_sall_r_r(interp, pc, reg1, reg2) \ - { (pc) = emit_shift_r_r((interp), (pc), emit_b100, (reg1), (reg2)); } - -# define emitm_sall_r_m(pc, reg, b, i, s, d) \ - { (pc) = emit_shift_r_m((pc), emit_b100, (reg), (b), (i), (s), (d)); } - -/* SAR */ - -# define jit_emit_shr_ri_i(interp, pc, reg, imm) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b111, (imm), (reg)); } - - -# define emitm_sarl_i_m(pc, imm, b, i, s, d) \ - { (pc) = emit_shift_i_m((pc), emit_b111, (imm), (b), (i), (s), (d)); } - -# define emitm_sarl_r_r(interp, pc, reg1, reg2) \ - { (pc) = emit_shift_r_r((interp), (pc), emit_b111, (reg1), (reg2)); } - -# define emitm_sarl_r_m(pc, reg, b, i, s, d) \ - { (pc) = emit_shift_r_m((pc), emit_b111, (reg), (b), (i), (s), (d)); } - -/* rotate */ - -# define jit_emit_rol_ri_i(interp, pc, reg, imm) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b000, (imm), (reg)); } - -# define jit_emit_ror_ri_i(interp, pc, reg, imm) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b001, (imm), (reg)); } - -/* interface, shift r1 by r2 bits */ - -# define jit_emit_shl_rr_i(interp, pc, r1, r2) \ - (pc) = opt_shift_rr((interp), jit_info, (r1), (r2), emit_b100) - -# define jit_emit_shl_RM_i(interp, pc, r1, offs) \ - (pc) = opt_shift_rm((interp), jit_info, (r1), (offs), emit_b100) - -/* shr seems to be the arithmetic shift */ -# define jit_emit_shr_rr_i(interp, pc, r1, r2) \ - (pc) = opt_shift_rr((interp), jit_info, (r1), (r2), emit_b111) - -# define jit_emit_shr_RM_i(interp, pc, r1, offs) \ - (pc) = opt_shift_rm((interp), jit_info, (r1), (offs), emit_b111) - -# define jit_emit_lsr_rr_i(interp, pc, r1, r2) \ - (pc) = opt_shift_rr((interp), jit_info, (r1), (r2), emit_b101) - -# define jit_emit_lsr_RM_i(interp, pc, r1, offs) \ - (pc) = opt_shift_rm((interp), jit_info, (r1), (offs), emit_b101) - -/* MOV (reg), reg */ -# define emit_movm_r_r(pc, src, dest) \ - *((pc)++) = (char) 0x8b; \ - *((pc)++) = (char) (src) | (dest) << 3 - -/* MOV X(reg), reg */ -# define emit_movb_i_r_r(pc, imm, src, dest) \ - *((pc)++) = (char)(0x8b); \ - *((p)c++) = (char)(0x40 | ((src) - 1) | ((dest) - 1) << 3); \ - *((pc)++) = (imm) - -/* INC / DEC */ -# define jit_emit_inc_r_i(pc, reg) *((pc)++) = (char)(0x40 | ((reg) - 1)) -# define jit_emit_dec_r_i(pc, reg) *((pc)++) = (char)(0x48 | ((reg) - 1)) - -/* Floating point ops */ - -# define emitm_floatop 0xd8 /* 11011000 */ -# define jit_emit_dec_fsp(pc) { *((pc)++) = (char) 0xD9; *((pc)++) = (char) 0xF6; } -# define jit_emit_inc_fsp(pc) { *((pc)++) = (char) 0xD9; *((pc)++) = (char) 0xF7; } - -# define emitm_fl_2(interp, pc, mf, opa, opb, b, i, s, d) { \ - *((pc)++) = (char)(emitm_floatop | ((mf) << 1) | (opa)); \ - (pc) = emit_r_X((interp), (pc), emit_reg(opb), (b), (i), (s), (long)(d)); } - -# define emitm_fl_3(pc, d_p_opa, opb_r, sti) { \ - *((pc)++) = (char)(emitm_floatop | (d_p_opa)); \ - *((pc)++) = (char)(0xc0 | ((opb_r) << 3) | (sti)); } - -# define emitm_fl_4(pc, op) { \ - *((pc)++) = (char)(emitm_floatop | emit_b001); \ - *((pc)++) = (char)(0xe0 | (op)); } - -/* Integer loads and stores */ -# define emitm_fildl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 1, emit_b000, (b), (i), (s), (d)) - -# define emitm_fistpl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 1, emit_b011, (b), (i), (s), (d)) - -# define emitm_fistl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 1, emit_b010, (b), (i), (s), (d)) - -/* long long integer load/store */ -# define emitm_fildll(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b11, 1, emit_b101, (b), (i), (s), (d)) - -# define emitm_fistpll(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b11, 1, emit_b111, (b), (i), (s), (d)) - -/* Double loads and stores */ -# define emitm_fldl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 1, emit_b000, (b), (i), (s), (d)) - -# define emitm_fstpl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 1, emit_b011, (b), (i), (s), (d)) - -# define emitm_fstl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 1, emit_b010, (b), (i), (s), (d)) - -/* long double load / store */ -# define emitm_fldt(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 1, emit_b101, (b), (i), (s), (d)) - -# define emitm_fstpt(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 1, emit_b111, (b), (i), (s), (d)) - -/* short float load / store */ -# define emitm_flds(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b00, 1, emit_b000, (b), (i), (s), (d)) - -# define emitm_fstps(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b00, 1, emit_b010, (b), (i), (s), (d)) - -#if NUMVAL_SIZE == 8 - -# define jit_emit_fload_m_n(interp, pc, address) \ - emitm_fldl((interp), (pc), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_fload_mb_n(interp, pc, base, offs) \ - emitm_fldl((interp), (pc), (base), emit_None, 1, (offs)) - -# define jit_emit_fstore_m_n(interp, pc, address) \ - emitm_fstpl((interp), (pc), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_fstore_mb_n(interp, pc, base, offs) \ - emitm_fstpl((interp), (pc), (base), emit_None, 1, (offs)) - -# define jit_emit_fst_mb_n(interp, pc, base, offs) \ - emitm_fstl((interp), (pc), (base), emit_None, 1, (offs)) - -#else /* NUMVAL_SIZE */ - -# define jit_emit_fload_m_n(interp, pc, address) \ - emitm_fldt((pc), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_fload_mb_n(interp, pc, base, offs) \ - emitm_fldt((pc), (base), emit_None, 1, (offs)) - -# define jit_emit_fstore_m_n(pc, address) \ - emitm_fstpt((pc), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_fstore_mb_n(interp, pc, base, offs) \ - emitm_fstpt((pc), (base), emit_None, 1, (offs)) - -# define jit_emit_fst_mb_n(interp, pc, base, offs) \ - emitm_fstt((pc), (base), emit_None, 1, (offs)) - -#endif /* NUMVAL_SIZE */ - -#if INTVAL_SIZE == 4 - -# define jit_emit_fload_m_i(interp, pc, address) \ - emitm_fildl((interp), (pc), emit_None, emit_None, emit_None, (address)) -# define jit_emit_fload_mb_i(interp, pc, offs) \ - emitm_fildl((interp), (pc), emit_EBX, emit_None, 1, (offs)) -# define jit_emit_fstore_m_i(pc, m) \ - emitm_fistpl((pc), emit_None, emit_None, emit_None, (m)) - -#else /* INTVAL_SIZE */ - -# define jit_emit_fload_m_i(interp, pc, address) \ - emitm_fildll((interp), (pc), emit_None, emit_None, emit_None, (address)) -# define jit_emit_fload_mb_i(interp, pc, offs) \ - emitm_fildll((interp), (pc), emit_EBX, emit_None, 1, (offs)) -# define jit_emit_fstore_m_i(pc, m) \ - emitm_fistpll((pc), emit_None, emit_None, emit_None, (m)) - -#endif /* INTVAL_SIZE */ - -/* 0xD8 ops */ -# define emitm_fadd(pc, sti) emitm_fl_3((pc), emit_b000, emit_b000, (sti)) -# define emitm_fmul(pc, sti) emitm_fl_3((pc), emit_b000, emit_b001, (sti)) -# define emitm_fsub(pc, sti) emitm_fl_3((pc), emit_b000, emit_b100, (sti)) -# define emitm_fdiv(pc, sti) emitm_fl_3((pc), emit_b000, emit_b110, (sti)) - -/* 0xD9 ops */ -# define emitm_fldz(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xee; } -# define emitm_fld1(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xe8; } -# define emitm_fsqrt(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xfa; } -# define emitm_fsin(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xfe; } -# define emitm_fcos(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xff; } -# define emitm_fxam(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xe5; } - -/* FXCH ST, ST(i) , optimize 2 consecutive fxch with same reg */ -# define emitm_fxch(pc, sti) { \ - emitm_fl_3((pc), emit_b001, emit_b001, (sti)); \ -} - -/* FLD ST, ST(i), optimized FSTP(N+1);FLD(N) => FST(N+1) */ -extern unsigned char *lastpc; -# define emitm_fld(pc, sti) do { \ - if ((unsigned char *)(pc) == (lastpc + 2) && \ - (int)(*lastpc) == (int)0xDD && \ - (int)lastpc[1] == (int)(0xD8+(sti)+1)) \ - lastpc[1] = 0xD0+(sti)+1; \ - else \ - emitm_fl_3((pc), emit_b001, emit_b000, (sti)); \ - } while (0) - -/* 0xDA, 0xDB ops */ -/* FCMOV*, FCOMI PPRO */ - -/* 0xDC like 0xD8 with reversed operands */ -# define emitm_faddr(pc, sti) emitm_fl_3((pc), emit_b100, emit_b000, (sti)) -# define emitm_fmulr(pc, sti) emitm_fl_3((pc), emit_b100, emit_b001, (sti)) -# define emitm_fsubr(pc, sti) emitm_fl_3((pc), emit_b100, emit_b100, (sti)) - -/* 0xDD ops */ -/* FFree ST(i) */ -# define emitm_ffree(pc, sti) emitm_fl_3((pc), emit_b101, emit_b000, (sti)) - -/* FST ST(i) = ST */ -# define emitm_fst(pc, sti) emitm_fl_3((pc), emit_b101, emit_b010, (sti)) - -/* FSTP ST(i) = ST, POP */ -# define emitm_fstp(pc, sti) { \ - lastpc = (unsigned char*) (pc); \ - emitm_fl_3((pc), emit_b101, emit_b011, (sti)); \ -} - -/* FUCOM ST(i) <=> ST unordered compares */ -# define emitm_fucom(pc, sti) emitm_fl_3((pc), emit_b101, emit_b100, (sti)) - -/* FUCOMP ST(i) <=> ST, POP */ -# define emitm_fucomp(pc, sti) emitm_fl_3((pc), emit_b101, emit_b101, (sti)) - -/* 0xDE ops */ -/* FADDP Add ST(i) = ST + ST(i); POP */ -# define emitm_faddp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b000, (sti)) - -/* FMULP Mul ST(i) = ST * ST(i); POP */ -# define emitm_fmulp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b001, (sti)) - -/* FSUB ST = ST - ST(i) */ - -/* FSUBRP SubR ST(i) = ST - ST(i); POP */ -# define emitm_fsubrp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b100, (sti)) - -/* FSUBP Sub ST(i) = ST(i) - ST; POP */ -# define emitm_fsubp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b101, (sti)) - -/* FDIVRP DivR ST(i) = ST(i) / ST(0); POP */ -# define emitm_fdivrp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b110, (sti)) - -/* FDIVP Div ST(i) = ST(0) / ST(i); POP ST(0) */ -# define emitm_fdivp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b111, (sti)) - -/* 0xDF OPS: FCOMIP, FUCOMIP PPRO */ - -/* Negate - called change sign */ -# define emitm_fchs(pc) emitm_fl_4((pc), 0) - -/* ABS - ST(0) = ABS(ST(0)) */ -# define emitm_fabs(pc) emitm_fl_4((pc), 1) - -/* Comparisons */ - -# define emitm_fcom(pc, sti) emitm_fl_3((pc), emit_b000, emit_b010, (sti)) - -# define emitm_fcomp(pc, sti) emitm_fl_3((pc), emit_b000, emit_b011, (sti)) - -#ifdef PARROT_HAS_JIT_FCOMIP -# define emitm_fcomip(pc, sti) emitm_fl_3((pc), emit_b111, emit_b110, (sti)) -# define emitm_fcomi(pc, sti) emitm_fl_3((pc), emit_b011, emit_b110, (sti)) -#else -# define emitm_fcomip(pc, sti) do { \ - emitm_fcomp((pc), (sti)); \ - emitm_fstw(pc); \ - emitm_sahf(pc); \ - } while (0) -# define emitm_fcomi(pc, sti) do { \ - emitm_fcom((pc), (sti)); \ - emitm_fstw(pc); \ - emitm_sahf(pc); \ - } while (0) -#endif - -# define emitm_fcompp(pc) { *((pc)++) = (char) 0xde; *((pc)++) = (char) 0xd9; } - -# define emitm_fcom_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b010, (b), (i), (s), (d)) - -# define emitm_fcomp_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b011, (b), (i), (s), (d)) - -/* ST -= real64 */ -# define emitm_fsub_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b100, (b), (i), (s), (d)) - -/* ST -= int32_mem */ -# define emitm_fisub_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 0, emit_b100, (b), (i), (s), (d)) - -# define emitm_fadd_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b000, (b), (i), (s), (d)) - -/* ST += int32_mem */ -# define emitm_fiadd_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 0, emit_b000, (b), (i), (s), (d)) - -/* ST *= real64 */ -# define emitm_fmul_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b001, (b), (i), (s), (d)) - -/* ST *= int32_mem */ -# define emitm_fimul_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 0, emit_b001, (b), (i), (s), (d)) - -/* ST /= real64 */ -# define emitm_fdiv_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b110, (b), (i), (s), (d)) - -/* ST /= int32_mem */ -# define emitm_fidiv_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 0, emit_b110, (b), (i), (s), (d)) - -/* Ops Needed to support loading EFLAGs for conditional branches */ -# define emitm_fstw(pc) emitm_fl_3((pc), emit_b111, emit_b100, emit_b000) - -# define emitm_sahf(pc) *((pc)++) = (char) 0x9e - -/* misc float */ -# define emitm_ftst(pc) { *(pc)++ = 0xd9; *(pc)++ = 0xE4; } -# define emitm_fprem(pc) { *(pc)++ = 0xd9; *(pc)++ = 0xF8; } -# define emitm_fprem1(pc) { *(pc)++ = 0xd9; *(pc)++ = 0xF5; } - -# define emitm_fldcw(interp, pc, mem) \ - emitm_fl_2((interp), (pc), emit_b00, 1, emit_b101, 0, 0, 0, (mem)) - -#if defined(NEG_MINUS_ZERO) -# define jit_emit_neg_r_n(pc, r) { \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_fchs(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } \ - } - -# define jit_emit_neg_M_n(interp, pc, mem) { \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (mem)); \ - emitm_fchs(pc); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (mem)); \ - } - -#elif defined(NEG_ZERO_SUB) - -# define jit_emit_neg_r_n(pc, r) { \ - emitm_fldz(pc); \ - emitm_fsubrp((pc), ((r)+1)); \ - } - -# define jit_emit_neg_M_n(interp, pc, mem) { \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (mem)); \ - emitm_fldz(pc); \ - emitm_fsubrp((pc), 1); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (mem)); \ - } -#else - -# define jit_emit_neg_r_n(pc, r) { \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_ftst(pc); \ - emitm_fstw(pc); \ - emitm_sahf(pc); \ - emitm_jxs((pc), emitm_jz, 2); \ - emitm_fchs(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } \ - } - -# define jit_emit_neg_M_n(interp, pc, mem) { \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (mem)); \ - emitm_ftst(pc); \ - emitm_fstw(pc); \ - emitm_sahf(pc); \ - emitm_jxs((pc), emitm_jz, 2); \ - emitm_fchs(pc); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (mem)); \ - } -#endif - -# define jit_emit_sin_r_n(pc, r) \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_fsin(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } - -# define jit_emit_cos_r_n(pc, r) \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_fcos(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } - -# define jit_emit_sqrt_r_n(pc, r) \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_fsqrt(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } - -# define jit_emit_abs_r_n(pc, r) { \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_fabs(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } \ - } - -# define jit_emit_abs_r_i(pc, r) { \ - jit_emit_test_r_i((pc), (r)); \ - emitm_jxs((pc), emitm_jns, 3); \ - jit_emit_not_r_i((pc), (r)); \ - jit_emit_inc_r_i((pc), (r)); \ - } - -# define jit_emit_abs_m_n(interp, pc, mem) { \ - jit_emit_fload_m_n((interp), (pc), (mem)); \ - emitm_fabs(pc); \ - jit_emit_fstore_m_n((pc), (mem)); \ - } - -/* Integer comparisons */ -# define jit_emit_cmp_rr(pc, reg1, reg2) \ - emitm_alul_r_r((pc), 0x39, (reg2), (reg1)) -# define jit_emit_cmp_rr_i(pc, r1, r2) jit_emit_cmp_rr((pc), (r1), (r2)) - -# define emitm_cmpl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x3b, (reg), (b), (i), (s), (d)) - -# define emitm_cmpl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x39, (reg), (b), (i), (s), (d)) - -# define jit_emit_cmp_ri_i(interp, pc, reg, imm) \ - emitm_alul_i_r((pc), 0x81, emit_b111, (imm), (reg)) - -/* Unconditional Jump/Call */ - -# define emitm_call_cfunc(pc, func) emitm_calll((pc), (char *)(func) - (pc) - 4) - -# define emitm_calll(pc, disp) { \ - *((pc)++) = (char) 0xe8; \ - *(long *)(pc) = (disp); (pc) += 4; } - -# define emitm_callr(pc, reg) { \ - *((pc)++) = (char) 0xff; \ - *((pc)++) = (char) 0xd0 | ((reg) - 1); } - -# define emitm_callm(pc, b, i, s, d) { \ - *((pc)++) = (char) 0xff; \ - (pc) = emit_r_X((interp), (pc), emit_reg(emit_b010), (b), (i), (s), (d)); } - -# define emitm_jumps(pc, disp) { \ - *((pc)++) = (char) 0xeb; \ - *((pc)++) = (disp); } - -# define emitm_jumpl(pc, disp) { \ - *((pc)++) = (char) 0xe9; \ - *(long *)(pc) = (disp); (pc) += 4; } - -# define emitm_jumpr(pc, reg) { \ - *((pc)++) = (char) 0xff; \ - *((pc)++) = (char)(0xe0 | ((reg) - 1)); } - -# define emitm_jumpm(pc, b, i, s, d) { \ - *((pc)++) = (char) 0xff; \ - (pc) = emit_r_X((interp), (pc), emit_reg(emit_b100), (b), (i), (s), (d)); } - -/* Conditional jumps */ - -/* Short jump - 8 bit disp */ -# define emitm_jxs(pc, code, disp) { \ - *((pc)++) = (char)(0x70 | (code)); \ - *((pc)++) = (char)(disp); } - -/* Long jump - 32 bit disp */ -# define emitm_jxl(pc, code, disp) { \ - *((pc)++) = (char) 0x0f; \ - *((pc)++) = (char)(0x80 | (code)); \ - *(long *)(pc) = (disp); (pc) += 4; } - -# define emitm_jo 0 -# define emitm_jno 1 -# define emitm_jb 2 -# define emitm_jnb 3 -# define emitm_jz 4 -# define emitm_je emitm_jz -# define emitm_jnz 5 -# define emitm_jne emitm_jnz -# define emitm_jbe 6 -# define emitm_ja 7 -# define emitm_js 8 -# define emitm_jns 9 -# define emitm_jp 10 -# define emitm_jnp 11 -# define emitm_jl 12 -# define emitm_jnl 13 -# define emitm_jle 14 -# define emitm_jg 15 - -/* set byte conditional */ -# define jit_emit_setcc_r(pc, cc, r) \ - *(pc)++ = 0x0f; \ - *(pc)++ = 0x90 + (cc); \ - *(pc)++ = (char) emit_alu_X_r(0, (r)) - /* - * core.jit interface - * - * The new offset based versions have uppercase RM or MR inside - * That's probably only during transition time - */ - -# define jit_emit_mov_mi_i(pc, dest, immediate) \ - emitm_movl_i_m((pc), (immediate), emit_None, emit_None, emit_None, (dest)) - -# define jit_emit_mov_MI_i(interp, pc, offs, immediate) \ - emitm_movl_i_m((pc), (immediate), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_mov_rm_i(interp, pc, reg, address) \ - emitm_movl_m_r((interp), (pc), (reg), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_mov_RM_i(interp, pc, reg, offs) \ - emitm_movl_m_r((interp), (pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_mov_mr_i(interp, pc, address, reg) \ - emitm_movl_r_m((interp), (pc), (reg), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_mov_MR_i(interp, pc, offs, reg) \ - emitm_movl_r_m((interp), (pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_mul_RM_i(interp, pc, reg, offs) \ - emitm_smull_r_m((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_sub_RM_i(interp, pc, reg, offs) \ - emitm_subl_m_r((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_sub_MR_i(interp, pc, offs, reg) \ - emitm_subl_r_m((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_sub_MI_i(pc, offs, imm) \ - emitm_subl_i_m((pc), (imm), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_add_RM_i(interp, pc, reg, offs) \ - emitm_addl_m_r((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_add_MR_i(interp, pc, offs, reg) \ - emitm_addl_r_m((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_add_MI_i(pc, offs, imm) \ - emitm_addl_i_m((pc), (imm), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_cmp_rm_i(pc, reg, address) \ - emitm_cmpl_r_m((pc), (reg), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_cmp_RM_i(interp, pc, reg, offs) \ - emitm_cmpl_r_m((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_cmp_MR_i(interp, pc, offs, reg) \ - emitm_cmpl_m_r((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -/* high level routines, behave like real 2 register FP */ - -/* mapped float registers numbers are ST(1)-ST(4). - * scratch register is ST(0) - */ - -/* ST(i) <- numvar */ -# define jit_emit_mov_RM_n(interp, pc, r, d) { \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (d)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* ST(i) <= NUM_CONST */ -# define jit_emit_mov_ri_n(interp, pc, r, i) { \ - jit_emit_fload_m_n((interp), (pc), (i)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* ST(i) <= &INT_CONST */ -# define jit_emit_mov_ri_ni(interp, pc, r, i) { \ - jit_emit_fload_m_i((interp), (pc), (i)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* ST(i) <= INT_REG */ -# define jit_emit_mov_RM_ni(interp, pc, r, i) { \ - jit_emit_fload_mb_i((interp), (pc), (i)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* NUM_REG(i) <= &INT_CONST - * the int const i is loaded from the code memory - */ -# define jit_emit_mov_MI_ni(interp, pc, offs, i) { \ - jit_emit_fload_m_i((interp), (pc), (i)); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (offs)); \ -} - -/* INT_REG <= ST(i) */ -# define jit_emit_mov_mr_in(pc, mem, r) { \ - emitm_fld((pc), (r)); \ - jit_emit_fstore_m_i((pc), (mem)); \ -} - -/* numvar <- ST(i) */ -# define jit_emit_mov_mr_n(pc, d, r) { \ - emitm_fld((pc), (r)); \ - jit_emit_fstore_m_n((pc), (d)); \ -} - -# define jit_emit_mov_MR_n(interp, pc, d, r) { \ - if (r) { \ - emitm_fld((pc), (r)); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (d)); \ - } \ - else { \ - jit_emit_fst_mb_n((interp), (pc), emit_EBX, (d)); \ - } \ -} - -/* ST(r1) <= ST(r2) */ -# define jit_emit_mov_rr_n(pc, r1, r2) { \ - if ((r1) != (r2)) { \ - if (r2) { \ - emitm_fld((pc), (r2)); \ - emitm_fstp((pc), ((r1)+1)); \ - } \ - else { \ - emitm_fst((pc), (r1)); \ - } \ - } \ -} - -/* ST(r1) xchg ST(r2) */ -# define jit_emit_xchg_rr_n(interp, pc, r1, r2) { \ - if ((r1) != (r2)) { \ - emitm_fld((pc), (r1)); \ - emitm_fld((pc), ((r2)+1)); \ - emitm_fstp((pc), ((r1)+2)); \ - emitm_fstp((pc), ((r2)+1)); \ - } \ -} - -# define jit_emit_xchg_RM_n(interp, pc, r, offs) { \ - emitm_fld((pc), (r)); \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (offs)); \ - emitm_fstp((pc), ((r)+2)); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (offs)); \ -} - -# define jit_emit_xchg_MR_n(interp, pc, offs, r) { \ - emitm_fld((pc), (r)); \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (offs)); \ - emitm_fstp((pc), ((r)+2)); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (offs)); \ -} - -# define jit_emit_finit(pc) { *((pc)++) = (char) 0xdb; *((pc)++) = (char) 0xe3; } - -/* ST(i) op= MEM */ - -# define jit_emit_xxx_rm_n(interp, op, pc, r, m) { \ - jit_emit_fload_m_n((interp), (pc), (m)); \ - emitm_f ## op ## p((pc), ((r)+1)); \ -} - -# define jit_emit_xxx_RM_n(interp, op, pc, r, offs) { \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (offs)); \ - emitm_f ## op ## p((pc), ((r)+1)); \ -} - -/* - * float ops in two flavors: abs memory for constants, offsets for regs - */ - -# define jit_emit_add_ri_n(interp, pc, r, m) jit_emit_xxx_rm_n((interp), add, (pc), (r), (m)) -# define jit_emit_sub_ri_n(interp, pc, r, m) jit_emit_xxx_rm_n((interp), sub, (pc), (r), (m)) -# define jit_emit_mul_ri_n(interp, pc, r, m) jit_emit_xxx_rm_n((interp), mul, (pc), (r), (m)) - -# define jit_emit_add_RM_n(interp, pc, r, o) jit_emit_xxx_RM_n((interp), add, (pc), (r), (o)) -# define jit_emit_sub_RM_n(interp, pc, r, o) jit_emit_xxx_RM_n((interp), sub, (pc), (r), (o)) -# define jit_emit_mul_RM_n(interp, pc, r, o) jit_emit_xxx_RM_n((interp), mul, (pc), (r), (o)) - -/* ST(r1) += ST(r2) */ -/* r1 == 0: ST(0) <- ST(0) + ST(i) - * r2 == 0: ST(i) <- ST(0) + ST(i) - */ -# define jit_emit_add_rr_n(interp, pc, r1, r2) do { \ - if (!(r1)) { \ - emitm_fadd((pc), (r2)); \ - } \ - else if (!(r2)) { \ - emitm_faddr((pc), (r1)); \ - } \ - else { \ - emitm_fld((pc), (r2)); \ - emitm_faddp((pc), ((r1)+1)); \ - } \ - } \ - while (0) -/* - * ST(r) += INT_REG - */ -# define jit_emit_add_RM_ni(pc, r, offs) { \ - emitm_fld((pc), (r)); \ - emitm_fiadd_m((pc), emit_EBX, 0, 1, (offs)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* ST(r1) -= ST(r2) */ -/* r1 == 0: ST(0) <- ST(0) - ST(i) - * r2 == 0: ST(i) <- ST(i) - ST(0) - */ -# define jit_emit_sub_rr_n(interp, pc, r1, r2) do { \ - if (!(r1)) { \ - emitm_fsub((pc), (r2)); \ - } \ - else if (!(r2)) { \ - emitm_fsubr((pc), (r1)); \ - } \ - else { \ - emitm_fld((pc), (r2)); \ - emitm_fsubp((pc), ((r1)+1)); \ - } \ - } \ - while (0) - -/* - * ST(r) -= INT_REG - */ -# define jit_emit_sub_RM_ni(pc, r, offs) { \ - emitm_fld((pc), (r)); \ - emitm_fisub_m((pc), emit_EBX, 0, 1, (offs)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -# define jit_emit_inc_r_n(pc, r) { \ - emitm_fld1(pc); \ - emitm_faddp((pc), ((r)+1)); \ -} - -# define jit_emit_dec_r_n(pc, r) { \ - emitm_fld1(pc); \ - emitm_fsubp((pc), ((r)+1)); \ -} - -/* ST(r1) *= ST(r2) */ -/* r1 == 0: ST(0) <- ST(0) * ST(i) - * r2 == 0: ST(i) <- ST(0) * ST(i) - */ -# define jit_emit_mul_rr_n(interp, pc, r1, r2) do { \ - if (!(r1)) { \ - emitm_fmul((pc), (r2)); \ - } \ - else if (!(r2)) { \ - emitm_fmulr((pc), (r1)); \ - } \ - else { \ - emitm_fld((pc), (r2)); \ - emitm_fmulp((pc), ((r1)+1)); \ - } \ - } \ - while (0) - -/* - * ST(r) *= INT_REG - */ -# define jit_emit_mul_RM_ni(pc, r, offs) { \ - emitm_fld((pc), (r)); \ - emitm_fimul_m((pc), emit_EBX, 0, 1, (offs)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* - * ST(r) /= INT_REG - */ -# define jit_emit_div_RM_ni(pc, r, offs) { \ - emitm_fld((pc), (r)); \ - emitm_fidiv_m((pc), emit_EBX, 0, 1, (offs)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* test r for zero */ -# define jit_emit_test_r_n(pc, r) { \ - if (r) { \ - emitm_fxch((pc), (r)); \ - } \ - emitm_fxam(pc); \ - emitm_fstw(pc); \ - emitm_sahf(pc); \ - if (r) { \ - emitm_fxch((pc), (r)); \ - } \ -} - -enum { JIT_X86BRANCH, JIT_X86JUMP, JIT_X86CALL }; - -# define jit_emit_stack_frame_enter(pc) do { \ - emitm_pushl_r((pc), emit_EBP); \ - jit_emit_mov_rr_i((pc), emit_EBP, emit_ESP); \ -} while (0) - -# define jit_emit_stack_frame_leave(pc) do { \ - jit_emit_mov_rr_i((pc), emit_ESP, emit_EBP); \ - emitm_popl_r((pc), emit_EBP); \ -} while (0) - -# define jit_emit_end(pc) { \ - jit_emit_add_ri_i((interp), (pc), emit_ESP, 4); \ - emitm_popl_r((pc), emit_EDI); \ - emitm_popl_r((pc), emit_ESI); \ - emitm_popl_r((pc), emit_EBX); \ - emitm_popl_r((pc), emit_EBP); \ - emitm_ret(pc); \ - } - -size_t calc_signature_needs(const char *sig, int *strings); - -void * Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci, - STRING *signature, int *sizeptr); - -/* - * register usage - * %edi, %esi ... mapped, preserved - * %edx, %ecx ... mapped, not preserved - * %ebx ... base pointer for register access, preserved - * %eax ... scratch, return value register - */ - -#endif /* PARROT_I386_JIT_EMIT_H_GUARD */ - -/* * Local variables: * c-file-style: "parrot" * End: Index: src/nci_test.c =================================================================== --- src/nci_test.c (revision 41833) +++ src/nci_test.c (working copy) @@ -109,6 +109,8 @@ PARROT_EXPORT void nci_vfff(float, float, float); PARROT_EXPORT void nci_vV(const char **); PARROT_EXPORT void nci_vVVV(const char **, const char **, const char **); +PARROT_EXPORT int nci_i20(int, int, int, int, int, int, int, int, int, int, int, int, int, int, + int, int, int, int, int); /* Declarations for callback tests */ @@ -1190,6 +1192,50 @@ *ptr3 = "Go suck a lemon.\n"; } +/* + +=item C + +Prints and returns the nth value in a list of integers. First argument is the selector; subsequents, +the list. + +This function is designed to be outside of the range of the static frame builder as an excercise for +the dynamic frame builder. + +=cut + +*/ +PARROT_EXPORT int +nci_i20(int sel, int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9, int v10, + int v11, int v12, int v13, int v14, int v15, int v16, int v17, int v18) { + int *selected; + switch ((sel < 0 ? -sel : sel) % 18) { + case 0: selected = &v1; break; + case 1: selected = &v2; break; + case 2: selected = &v3; break; + case 3: selected = &v4; break; + case 4: selected = &v5; break; + case 5: selected = &v6; break; + case 6: selected = &v7; break; + case 7: selected = &v8; break; + case 8: selected = &v9; break; + case 9: selected = &v10; break; + case 10: selected = &v11; break; + case 11: selected = &v12; break; + case 12: selected = &v13; break; + case 13: selected = &v14; break; + case 14: selected = &v15; break; + case 15: selected = &v16; break; + case 16: selected = &v17; break; + case 17: selected = &v18; break; + default: printf("default case reached (should never happen)"); return -1; + } + printf("%d\n", *selected); + return *selected; +} + #ifdef TEST char l2 = 4; Index: tools/build/nativecall.pl =================================================================== --- tools/build/nativecall.pl (revision 41833) +++ tools/build/nativecall.pl (working copy) @@ -467,17 +467,13 @@ return F2DPTR(VTABLE_get_pointer(interp, b)); } else { - int jit_size; - void * const result = Parrot_jit_build_call_func(interp, pmc_nci, signature, &jit_size); + void *priv; + void * const result = Parrot_jit_build_call_func(interp, pmc_nci, signature, &priv); if (result) { - struct jit_buffer_private_data *priv; *jitted = 1; temp_pmc = pmc_new(interp, enum_class_ManagedStruct); VTABLE_set_pointer(interp, temp_pmc, (void *)result); #ifdef PARROT_HAS_EXEC_PROTECT - priv = (struct jit_buffer_private_data *) - mem_sys_allocate(sizeof(struct jit_buffer_private_data)); - priv->size = jit_size; SETATTR_ManagedStruct_custom_free_func(interp, temp_pmc, Parrot_jit_free_buffer); SETATTR_ManagedStruct_custom_free_priv(interp, temp_pmc, priv); SETATTR_ManagedStruct_custom_clone_func(interp, temp_pmc, Parrot_jit_clone_buffer); Index: lib/Parrot/Configure/Options/Conf.pm =================================================================== --- lib/Parrot/Configure/Options/Conf.pm (revision 41833) +++ lib/Parrot/Configure/Options/Conf.pm (working copy) @@ -105,6 +105,7 @@ --without-gmp Build parrot without GMP support --without-opengl Build parrot without OpenGL support (GL/GLU/GLUT) --without-pcre Build parrot without pcre support + --without-libjit Build parrot without LibJIT support ICU Options: Index: lib/Parrot/Configure/Options/Conf/Shared.pm =================================================================== --- lib/Parrot/Configure/Options/Conf/Shared.pm (revision 41833) +++ lib/Parrot/Configure/Options/Conf/Shared.pm (working copy) @@ -75,6 +75,7 @@ without-gettext without-gmp without-icu + without-libjit without-opengl without-pcre without-threads Index: lib/Parrot/Configure/Step/List.pm =================================================================== --- lib/Parrot/Configure/Step/List.pm (revision 41833) +++ lib/Parrot/Configure/Step/List.pm (working copy) @@ -64,6 +64,7 @@ auto::ctags auto::revision auto::icu + auto::libjit gen::config_h gen::core_pmcs gen::crypto @@ -73,6 +74,7 @@ gen::makefiles gen::platform gen::config_pm + gen::libjit ); sub get_steps_list { return @steps; } Index: t/pmc/nci.t =================================================================== --- t/pmc/nci.t (revision 41833) +++ t/pmc/nci.t (working copy) @@ -6,7 +6,7 @@ use warnings; use lib qw( . lib ../lib ../../lib ); use Test::More; -use Parrot::Test tests => 70; +use Parrot::Test tests => 71; use Parrot::Config qw(%PConfig); =head1 NAME @@ -2753,6 +2753,76 @@ Go suck a lemon. OUTPUT +my $test_code = <<'CODE'; +.sub test :main + .local pmc libnci_test + $S0 = 'libnci_test' + libnci_test = loadlib $S0 + + .local pmc nci_i20 + nci_i20 = dlfunc libnci_test, "nci_i20", "iiiiiiiiiiiiiiiiiiii" + + .local pmc args + args = new ['FixedIntegerArray'] + args = 18 + + $I0 = 2 + args[0] = 1 + args[1] = 1 + +LOOP1: + $I1 = $I0 - 1 + $I1 = args[$I1] + + $I2 = $I0 - 2 + $I2 = args[$I2] + + $I3 = $I1 + $I2 + args[$I0] = $I3 + inc $I0 + if $I0 < 18 goto LOOP1 + + $I0 = args + dec $I0 + + $I1 = args[0] + $I2 = args[1] + $I3 = args[2] + $I4 = args[3] + $I5 = args[4] + $I6 = args[5] + $I7 = args[6] + $I8 = args[7] + $I9 = args[8] + $I10 = args[9] + $I11 = args[10] + $I12 = args[11] + $I13 = args[12] + $I14 = args[13] + $I15 = args[14] + $I16 = args[15] + $I17 = args[16] + $I18 = args[17] + +LOOP2: + nci_i20($I0, $I1, $I2, $I3, $I4, $I5, $I6, $I7, $I8, $I9, $I10, $I11, $I12, $I13, $I14, $I15, $I16, $I17, $I18) + $I0 = $I0 / 2 + if $I0 > 0 goto LOOP2 +.end +CODE +if ($PConfig{cc_build_call_frames}) { + pir_output_is($test_code, < 9; + +use lib 'lib'; + +use Parrot::Configure; +use Parrot::Configure::Options 'process_options'; +use Parrot::Configure::Test qw( + test_step_thru_runstep + test_step_constructor_and_description +); + +use_ok('config::init::defaults'); +use_ok('config::auto::libjit'); + +########## _select_lib() ########## + +my ($args, $step_list_ref) = process_options( + { + argv => [], + mode => 'configure', + } +); + +my $conf = Parrot::Configure->new; + +test_step_thru_runstep( $conf, 'init::defaults', $args ); + +my $pkg = 'auto::libjit'; + +$conf->add_steps($pkg); +$conf->options->set(%$args); +my $stp = test_step_constructor_and_description($conf); + +################### DOCUMENTATION ################### + +=head1 NAME + +auto/libjit-01.t - test auto::libjit + +=head1 SYNOPSIS + + % prove t/steps/auto/libjit-01.t + +=head1 DESCRIPTION + +The files in this directory test functionality used by F. + +The tests in this file test auto::libjit. + +=head1 SEE ALSO + +config::auto::libjit, F. + +=cut + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: Index: t/steps/gen/libjit-01.t =================================================================== --- t/steps/gen/libjit-01.t (revision 0) +++ t/steps/gen/libjit-01.t (revision 0) @@ -0,0 +1,107 @@ +#! perl +# Copyright (C) 2009, Parrot Foundation. +# $Id$ +# gen/libjit-01.t + +use strict; +use warnings; + +use constant num_generated_files => 2; +use Test::More tests => 8 + 2*num_generated_files; + +use File::Copy 'move'; +use File::Temp 'tempfile'; + +use lib 'lib'; +use Parrot::Configure; +use Parrot::Configure::Options 'process_options'; +use Parrot::Configure::Test qw( + test_step_thru_runstep + rerun_defaults_for_testing + test_step_constructor_and_description +); + +use_ok('config::gen::libjit'); + +my ($args, $step_list_ref) = process_options( + { + argv => [], + mode => 'configure', + } +); + +my $conf = Parrot::Configure->new; + +my $serialized = $conf->pcfreeze(); + +my $pkg = 'gen::libjit'; +$conf->add_steps($pkg); +$conf->options->set( %$args ); +my $step = test_step_constructor_and_description($conf); + +is( scalar keys %{$step->{targets}}, num_generated_files, "Expected number of generated files"); +is_deeply([keys %{$step->{targets}}], [keys %{$step->{templates}}], "Templates match targets"); + +foreach (keys %{$step->{templates}}) { + ok(-f $step->{templates}{$_}, "Able to locate $_ template") +} + +my %orig_files; +foreach (keys %{$step->{targets}}) { + if (-f (my $targ_name = $step->{targets}{$_})) { + $orig_files{$_} = tempfile(); + move($targ_name, $orig_files{$_}); + } +} + +my %orig_conf = map { $_ => $conf->data->get($_) } qw[ iv nv ]; +$conf->data->set( iv => 'int', nv => 'float' ); +my $ret = $step->runstep($conf); +ok( $ret, "runstep() returned true value" ); +foreach (keys %{$step->{targets}}) { + ok(-f $step->{targets}{$_}, "$_ target generated"); +} + +# re-set for next test +$conf->data->set(%orig_conf); +$step->set_result( '' ); +foreach (keys %{$step->{targets}}) { + if (exists $orig_files{$_}) { + move( $orig_files{$_}, $step->{targets}{$_} ); + } else { + unlink $_; + } +} + +$conf->replenish($serialized); + +pass("Completed all tests in $0"); + +################### DOCUMENTATION ################### + +=head1 NAME + + gen/libjit-01.t - test gen::libjit + +=head1 SYNOPSIS + + % prove t/steps/gen/libjit-01.t + +=head1 DESCRIPTION + +The files in this directory test functionality used by F. + +The tests in this file test gen::libjit. + +=head1 SEE ALSO + +config::gen::libjit, F. + +=cut + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: Index: config/auto/libjit.pm =================================================================== --- config/auto/libjit.pm (revision 0) +++ config/auto/libjit.pm (revision 0) @@ -0,0 +1,97 @@ +# Copyright (C) 2009, Parrot Foundation. +# $Id$ + +=head1 NAME + +config/auto/libjit - Check whether LibJIT is installed + +=head1 DESCRIPTION + +Determines whether LibJIT is present is installed and +functional on the system. It is OK when it doesn't exist. + +=cut + +package auto::libjit; + +use strict; +use warnings; + +use base 'Parrot::Configure::Step'; + +use Parrot::Configure::Utils ':auto'; + +sub _init { + my $self = shift; + my %data = ( + description => 'Is LibJIT installed', + result => '', + ); + return \%data; +} + +sub runstep { + my ($self, $conf) = @_; + + my ($verbose, $without) = $conf->options->get( qw{ + verbose + without-libjit + }); + + if ($without) { + $conf->data->set( HAS_LIBJIT => 0 ); + $self->set_result('no'); + return 1; + } + + my $extra_libs = $self->_select_lib({ + conf => $conf, + osname => $conf->data->get_p5('OSNAME'), + cc => $conf->data->get('cc'), + win32_nongcc => 'libjit.lib', + default => '-ljit', + }); + + $conf->cc_gen('config/auto/libjit/libjit_c.in'); + eval {$conf->cc_build('', $extra_libs)}; + my $has_libjit = 0; + if (!$@) { + my $test = $conf->cc_run(); + $has_libjit = $self->_evaluate_cc_run($conf, $test, $has_libjit, $verbose); + } else { + die $@; + } + + $conf->data->set( HAS_LIBJIT => $has_libjit ); + $self->set_result( $has_libjit ? 'yes' : 'no' ); + + if ($has_libjit) { + $conf->data->set( + cc_build_call_frames => '-DCAN_BUILD_CALL_FRAMES', + has_exec_protect => 1, + ); + $conf->data->add( ' ', libs => $extra_libs ); + } + + return 1; +} + +sub _evaluate_cc_run { + my $self = shift; + my ($conf, $test, $has_libjit, $verbose) = @_; + if ($test =~ m/^USES INTERPRETER: \d+/ ) { + $has_libjit = 1; + print " (yes) " if $verbose; + $self->set_result("yes"); + } + return $has_libjit; +} + +1; + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: Index: config/auto/libjit/libjit_c.in =================================================================== --- config/auto/libjit/libjit_c.in (revision 0) +++ config/auto/libjit/libjit_c.in (revision 0) @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2009, Parrot Foundation. + * $Id$ + */ + +#include +#include +#include + +int +main(int argc, char *argv[]) { + jit_init(); + printf("USES INTERPRETER: %i\n", jit_uses_interpreter()); + return EXIT_SUCCESS; +} + +/* + * Local variables: + * c-file-style: "parrot" + * End: + * vim: expandtab shiftwidth=4: + */ Index: config/gen/libjit.pm =================================================================== --- config/gen/libjit.pm (revision 0) +++ config/gen/libjit.pm (revision 0) @@ -0,0 +1,199 @@ +# Copyright (C) 2009, Parrot Foundation. +# $Id$ + +=head1 NAME + +config/gen/libjit.pm - LibJIT Code Generation + +=head1 DESCRIPTION + +Populate F and +F with system appropriate +type information and automatically generated parrot function and +vtable jit wrappers. + +=cut + +package gen::libjit; + +use strict; +use warnings; + +use base 'Parrot::Configure::Step'; + +use Parrot::Configure::Utils ':gen'; + + +sub _init { + my $self = shift; + my %data = ( + description => 'Generate LibJIT specific code', + result => '', + targets => { + frame_builder_h => 'src/frame_builder_libjit.h', + frame_builder_c => 'src/frame_builder_libjit.c', + }, + templates => { + frame_builder_h => 'config/gen/libjit/frame_builder_libjit_h.in', + frame_builder_c => 'config/gen/libjit/frame_builder_libjit_c.in', + }, + wrapped_vtables => { + get_integer => [ () => 'INTVAL' ], + set_integer_native => [ ('INTVAL') => 'void' ], + get_pointer => [ () => 'void_ptr' ], + set_pointer => [ ('void_ptr') => 'void' ], + }, + wrapped_funcs => { + get_nci_I => [ qw(void_ptr void_ptr sys_int) => 'INTVAL' ], + get_nci_N => [ qw(void_ptr void_ptr sys_int) => 'FLOATVAL' ], + get_nci_S => [ qw(void_ptr void_ptr sys_int) => 'void_ptr' ], + get_nci_P => [ qw(void_ptr void_ptr sys_int) => 'void_ptr' ], + get_nci_p => [ qw(void_ptr void_ptr sys_int) => 'void_ptr' ], + + set_nci_I => [ qw(void_ptr void_ptr INTVAL) => 'void' ], + set_nci_N => [ qw(void_ptr void_ptr FLOATVAL) => 'void' ], + set_nci_S => [ qw(void_ptr void_ptr void_ptr) => 'void' ], + set_nci_P => [ qw(void_ptr void_ptr void_ptr) => 'void' ], + + Parrot_str_new => [ qw(void_ptr void_ptr UINTVAL) => 'void_ptr' ], + Parrot_str_to_cstring => [ qw(void_ptr void_ptr) => 'void_ptr' ], + Parrot_str_free_cstring => [ ('void_ptr') => 'void' ], + + Parrot_init_arg_nci => [ qw(void_ptr void_ptr void_ptr) => 'void_ptr' ], + pmc_new_noinit => [ qw(void_ptr INTVAL) => 'void_ptr' ], + }, + ); + return \%data; +} + +sub runstep { + my ($self, $conf) = @_; + + my ($libjit_iv, $libjit_uv) = @{ + my $iv = $conf->data->get('iv') || ''; + { + short => [ 'jit_type_sys_short' , 'jit_type_sys_ushort' ], + int => [ 'jit_type_sys_int' , 'jit_type_sys_uint' ], + long => [ 'jit_type_sys_long' , 'jit_type_sys_ulong' ], + 'long long' => [ 'jit_type_sys_longlong', 'jit_type_sys_ulonglong' ], + }->{$iv} + or die "Couldn't determine libjity type for intval of type '$iv'"; + }; + + my $libjit_nv = do { + my $nv = $conf->data->get('nv') || ''; + { + float => 'jit_type_sys_float', + double => 'jit_type_sys_double', + 'long double' => 'jit_type_sys_long_double', + }->{$nv} + or die "Couldn't determine libjity type for floatval of type '$nv'"; + }; + + $conf->data->set( libjit_iv => $libjit_iv, + libjit_uv => $libjit_uv, + libjit_nv => $libjit_nv, ); + + my @vtable_wrappers = map {gen_vtable_wrapper($self, $_)} keys %{$self->{wrapped_vtables}}; + my @function_wrappers = map {gen_function_wrapper($self, $_)} keys %{$self->{wrapped_funcs}}; + + $conf->data->set( TEMP_vtable_wrap_decls => (join "\n", map {$_->{decl}} @vtable_wrappers), + TEMP_vtable_wrap_defns => (join "\n", map {$_->{defn}} @vtable_wrappers), + TEMP_func_wrap_decls => (join "\n", map {$_->{decl}} @function_wrappers), + TEMP_func_wrap_defns => (join "\n", map {$_->{defn}} @function_wrappers) ); + + foreach (keys %{$self->{targets}}) { + $conf->genfile($self->{templates}{$_}, $self->{targets}{$_}); + } + + return 1; +} + +sub gen_vtable_wrapper { + my ($self, $entry_name) = @_; + + my $entry_sig = $self->{wrapped_vtables}{$entry_name}; + $_ = jit_prefix_type($_) for @$entry_sig; + + my $ret_t = pop @$entry_sig; + my $arg_t = join ", ", @$entry_sig; + + my $n_args = scalar @$entry_sig; + my $arg_decls_t = join ", ", map {'jit_value_t'} 1..$n_args; + my $arg_decls_v = join ", ", map {"jit_value_t v$_"} 1..$n_args; + my $arg_v = join ", ", map {"v$_"} 1..$n_args; + + my $_arg_decls_t = $n_args ? ", $arg_decls_t" : ""; + my $_arg_decls_v = $n_args ? ", $arg_decls_v" : ""; + my $_arg_t = $n_args ? ", $arg_t" : ""; + my $_arg_v = $n_args ? ", $arg_v" : ""; + + return { decl => < <{wrapped_funcs}{$func_name}; + $_ = jit_prefix_type($_) for @$func_sig; + + my $ret_t = pop @$func_sig; + my $arg_t = join ", ", @$func_sig; + + my $n_args = scalar @$func_sig; + my $arg_decls_t = join ", ", map {'jit_value_t'} 1..$n_args; + my $arg_decls_v = join ", ", map {"jit_value_t v$_"} 1..$n_args; + my $arg_v = join ", ", map {"v$_"} 1..$n_args; + + return { decl => < < + +Public interface to NCI function interface builder. + +=cut + +*/ + +void * +Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc, STRING *sig, void **priv) { + void *thunk; + char *sig_cstr; + + sig_cstr = Parrot_str_to_cstring(interp, sig); + *priv = mem_sys_allocate(sizeof (struct jit_buffer_private_data)); + + thunk = Parrot_jit_create_thunk(interp, sig_cstr, *priv); + + Parrot_str_free_cstring(sig_cstr); + + return thunk; +} + +/* + +=item C + +This is a callback to implement the proper freeing semantics. It is called by +the ManagedStruct PMC as it is garbage collected. + +=cut + +*/ + +void +Parrot_jit_free_buffer(PARROT_INTERP, void *ptr, void *priv) +{ + struct jit_buffer_private_data *jit = (struct jit_buffer_private_data*)priv; + jit_context_destroy(jit->ctx); + mem_sys_free(jit->sig); + mem_sys_free(priv); +} + +/* + +=item C + +This is a callback to implement the proper cloning semantics for jit buffers. +It is called by the ManagedStruct PMC's clone() function. + +=back + +=cut + +*/ + +PMC * +Parrot_jit_clone_buffer(PARROT_INTERP, PMC *pmc, void *priv) +{ + PMC * const rv = pmc_new(interp, pmc->vtable->base_type); + + VTABLE_init(interp, rv); + /* copy the attributes */ + { + void (*tmpfreefunc)(PARROT_INTERP, void*, void*); + GETATTR_ManagedStruct_custom_free_func(interp, pmc, tmpfreefunc); + SETATTR_ManagedStruct_custom_free_func(interp, rv , tmpfreefunc); + } + { + PMC* (*tmpclonefunc)(PARROT_INTERP, PMC*, void*); + GETATTR_ManagedStruct_custom_clone_func(interp, pmc, tmpclonefunc); + SETATTR_ManagedStruct_custom_clone_func(interp, rv , tmpclonefunc); + } + + /* compile a clone of the function */ + if (PARROT_MANAGEDSTRUCT(pmc)->ptr) { + void *rv_priv; + struct jit_buffer_private_data *jit = (struct jit_buffer_private_data*)priv; + STRING *sig = Parrot_str_new(interp, jit->sig, 0); + PARROT_MANAGEDSTRUCT(rv)->ptr = Parrot_jit_build_call_func(interp, rv, sig, &rv_priv); + } + + return rv; +} + +/* + * JIT functions + */ + +void * +Parrot_jit_create_thunk(PARROT_INTERP, char *sig, void *priv) { + struct jit_buffer_private_data *p; + jit_function_t f; + jit_value_t jit_interp, jit_func; + jit_type_t *jit_args_t; + jit_value_t *jit_args_v, *jit_regs; + + /* populate private data */ + p = (struct jit_buffer_private_data*)priv; + p->ctx = jit_context_create(); + p->sig = mem_sys_strdup(sig); + + /* start compiling */ + jit_context_build_start(p->ctx); + + /* start JIT function */ + { + jit_type_t arg_types[] = { + jit_type_void_ptr, /* interp */ + jit_type_void_ptr /* nci_info */ + }; + jit_type_t f_sig = jit_type_create_signature(jit_abi_cdecl, jit_type_void, arg_types, 2, 1); + f = jit_function_create(p->ctx, f_sig); + } + + /* get the incomming args */ + jit_interp = jit_value_get_param(f, 0); + jit_func = jit__vtable_get_pointer(f, jit_interp, jit_value_get_param(f, 1)); + + /* get the outgoing args */ + { + jit_value_t st; + int nargs; + + { + jit_value_t sizeof_call_state + = jit_value_create_nint_constant(f, jit_type_sys_int, sizeof (call_state)); + st = jit_insn_alloca(f, sizeof_call_state); + } + + nargs = Parrot_jit_parse_sig_args_pre(interp, sig, f, jit_interp, st, + &jit_args_t, &jit_args_v, &jit_regs); + + /* get the return type */ + { + jit_type_t ret_t; + jit_value_t ret_v; + + ret_t = Parrot_jit_parse_sig_ret_pre(interp, sig); + + /* make the call */ + { + jit_type_t jit_sig + = jit_type_create_signature(jit_abi_cdecl, ret_t, jit_args_t, nargs, 1); + ret_v = jit_insn_call_indirect(f, jit_func, jit_sig, jit_args_v, nargs, 0); + } + + /* get the incomming return */ + Parrot_jit_parse_sig_ret_post(interp, sig, f, jit_interp, st, ret_v); + } + + /* clean up args */ + Parrot_jit_parse_sig_args_post(interp, sig, nargs, f, jit_interp, jit_args_v, jit_regs); + } + + /* end JIT function */ + jit_insn_return(f, NULL); + + /* compile to native callable func poitner */ + jit_function_compile(f); + jit_context_build_end(p->ctx); + + mem_sys_free(jit_args_t); + mem_sys_free(jit_args_v); + mem_sys_free(jit_regs); + + return jit_function_to_closure(f); +} + +int +Parrot_jit_parse_sig_args_pre(PARROT_INTERP, char *sig, jit_function_t f, + jit_value_t jinterp, jit_value_t st, + jit_type_t **arg_types, + jit_value_t **arg_vals, jit_value_t **arg_regs) { + int nargs, nregs, i, j; + + sig += 1; /* ignore return character */ + + nargs = strlen(sig); + nregs = Parrot_jit_init_pcc(sig, nargs, f, jinterp, st); + + *arg_types = (jit_type_t *)mem_sys_allocate(nargs * sizeof (jit_type_t)); + *arg_vals = (jit_value_t *)mem_sys_allocate(nargs * sizeof (jit_value_t)); + *arg_regs = (jit_value_t *)mem_sys_allocate(nregs * sizeof (jit_value_t)); + + for (i = 0, j = 0; i < nargs; i++) { + char c; + jit_type_t t1; + jit_value_t v1, v2, v3, v4; + switch (c = sig[i]) { + case 'I': + t1 = JIT_TYPE_INTVAL; + read_int_reg: + (*arg_types)[i] = t1; + v1 = jit_value_create_nint_constant(f, jit_type_sys_int, j); + v2 = jit__get_nci_I(f, jinterp, st, v1); + (*arg_regs)[j++] = (*arg_vals)[i] = v2; + break; + case 'c': + t1 = jit_type_sys_char; + goto read_int_reg; + case 's': + t1 = jit_type_sys_short; + goto read_int_reg; + case 'i': + t1 = jit_type_sys_int; + goto read_int_reg; + case 'l': + t1 = jit_type_sys_long; + goto read_int_reg; + + case 'N': + t1 = JIT_TYPE_FLOATVAL; + read_float_reg: + (*arg_types)[i] = t1; + v1 = jit_value_create_nint_constant(f, jit_type_sys_int, j); + v2 = jit__get_nci_N(f, jinterp, st, v1); + (*arg_regs)[j++] = (*arg_vals)[i] = v2; + break; + case 'f': + t1 = jit_type_sys_float; + goto read_float_reg; + case 'd': + t1 = jit_type_sys_double; + goto read_float_reg; + + case 'S': + (*arg_types)[i] = jit_type_void_ptr; + v1 = jit_value_create_nint_constant(f, jit_type_sys_int, j); + v2 = jit__get_nci_S(f, jinterp, st, v1); + (*arg_regs)[j++] = (*arg_vals)[i] = v2; + break; + + case 't': + (*arg_types)[i] = jit_type_void_ptr; + v1 = jit_value_create_nint_constant(f, jit_type_sys_int, j); + v2 = jit__get_nci_S(f, jinterp, st, v1); + (*arg_regs)[j++] = v2; + (*arg_vals)[i] = jit__Parrot_str_to_cstring(f, jinterp, v2); + break; + + case 'b': + (*arg_types)[i] = jit_type_void_ptr; + v1 = jit_value_create_nint_constant(f, jit_type_sys_int, j); + v2 = jit__get_nci_S(f, jinterp, st, v1); + (*arg_regs)[j++] = v2; + (*arg_vals)[i] = jit__Buffer_bufstart(f, v2); + break; + case 'B': + (*arg_types)[i] = jit_type_void_ptr; + v1 = jit_value_create_nint_constant(f, jit_type_sys_int, j); + v2 = jit__get_nci_S(f, jinterp, st, v1); + (*arg_regs)[j++] = v2; + v3 = jit__Parrot_str_to_cstring(f, jinterp, v2); + jit_value_set_addressable(v3); + (*arg_vals)[i] = jit_insn_address_of(f, v3); + break; + + case 'p': + (*arg_types)[i] = jit_type_void_ptr; + v1 = jit_value_create_nint_constant(f, jit_type_sys_int, j); + v2 = jit__get_nci_p(f, jinterp, st, v1); + (*arg_regs)[j++] = (*arg_vals)[i] = v2; + break; + case 'P': + case 'O': + case '@': + (*arg_types)[i] = jit_type_void_ptr; + v1 = jit_value_create_nint_constant(f, jit_type_sys_int, j); + v2 = jit__get_nci_P(f, jinterp, st, v1); + (*arg_regs)[j++] = (*arg_vals)[i] = v2; + break; + case '2': + t1 = jit_type_sys_short; + goto call_get_integer; + case '3': + t1 = jit_type_sys_int; + goto call_get_integer; + case '4': + t1 = jit_type_sys_long; + call_get_integer: + (*arg_types)[i] = jit_type_void_ptr; + v1 = jit_value_create_nint_constant(f, jit_type_sys_int, j); + v2 = jit__get_nci_P(f, jinterp, st, v1); + (*arg_regs)[j++] = v2; + v3 = jit__vtable_get_integer(f, jinterp, v2); + v4 = jit_value_create(f, t1); + jit_value_set_addressable(v4); + jit_insn_store(f, v4, v3); + (*arg_vals)[i] = jit_insn_address_of(f, v4); + break; + + case 'V': + (*arg_types)[i] = jit_type_void_ptr; + v1 = jit_value_create_nint_constant(f, jit_type_sys_int, j); + v2 = jit__get_nci_P(f, jinterp, st, v1); + (*arg_regs)[j++] = v2; + v3 = jit__vtable_get_pointer(f, jinterp, v2); + v4 = jit_value_create(f, jit_type_void_ptr); + jit_value_set_addressable(v4); + jit_insn_store(f, v4, v3); + (*arg_vals)[i] = jit_insn_address_of(f, v4); + break; + + case '0': + (*arg_types)[i] = jit_type_void_ptr; + (*arg_vals)[i] = jit_value_create_nint_constant(f, jit_type_void_ptr, (jit_nint)NULL); + break; + + case 'J': + (*arg_types)[i] = jit_type_void_ptr; + (*arg_vals)[i] = jinterp; + break; + + case 'U': + /* TODO */ + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, + "arg type 'U' not yet implemented"); + return -1; + + default: + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, + "unkown arg type '%c'", c); + return -1; + } + } + + return nargs; +} + +int +Parrot_jit_init_pcc(char *sig, int nargs, jit_function_t f, jit_value_t interp, jit_value_t st) { + int i, j; + char pcc_sig[nargs]; + + for (i = 0, j = 0; i < nargs; i++) { + switch (sig[i]) { + case 'I': + case 'c': + case 's': + case 'i': + case 'l': + pcc_sig[j++] = 'I'; + break; + + case 'N': + case 'f': + case 'd': + pcc_sig[j++] = 'N'; + break; + + case 'S': + case 't': + case 'b': + case 'B': + pcc_sig[j++] = 'S'; + break; + + case 'p': + case 'P': + case 'O': + case 'V': + case '2': + case '3': + case '4': + pcc_sig[j++] = 'P'; + break; + + case '@': + pcc_sig[j++] = '@'; + break; + + default: + break; + } + } + pcc_sig[j] = '\0'; + + jit__Parrot_init_arg_nci(f, interp, st, + jit_value_create_string_constant(f, pcc_sig, j+1)); + + return j; +} + +jit_type_t +Parrot_jit_parse_sig_ret_pre(PARROT_INTERP, char *sig) { + char c; + switch (c = sig[0]) { + case 'v': + return jit_type_void; + + case 'I': + return JIT_TYPE_INTVAL; + case 'c': + return jit_type_sys_char; + case 's': + return jit_type_sys_short; + case 'i': + return jit_type_sys_int; + case 'l': + return jit_type_sys_long; + + case 'N': + return JIT_TYPE_FLOATVAL; + case 'f': + return jit_type_sys_float; + case 'd': + return jit_type_sys_double; + + case 'S': + case 't': + return jit_type_void_ptr; + + case 'p': + case 'P': + return jit_type_void_ptr; + + case 'U': + /* TODO */ + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, + "return type 'U' not yet implemented"); + return NULL; + default: + /* FAIL */ + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, + "unknown return type '%c'", c); + return NULL; + } +} + +void +Parrot_jit_parse_sig_ret_post(PARROT_INTERP, char *sig, + jit_function_t f, jit_value_t jinterp, jit_value_t st, + jit_value_t retval) { + jit_type_t t1; + jit_value_t v1, v2, v3; + switch (sig[0]) { + case 'v': + break; + + case 'I': + case 'c': + case 's': + case 'i': + case 'l': + jit__set_nci_I(f, jinterp, st, retval); + break; + + case 'N': + case 'f': + case 'd': + jit__set_nci_N(f, jinterp, st, retval); + break; + + case 'S': + jit__set_nci_S(f, jinterp, st, retval); + break; + case 't': + v1 = jit_value_create_nint_constant(f, jit_type_sys_int, 0); + v2 = jit__Parrot_str_new(f, jinterp, retval, v1); + jit__set_nci_S(f, jinterp, st, v2); + break; + + case 'P': + jit__set_nci_P(f, jinterp, st, retval); + break; + case 'p': + v1 = jit_value_create_intval_constant(f, enum_class_UnManagedStruct); + v2 = jit__pmc_new_noinit(f, jinterp, v1); + jit__vtable_set_pointer(f, jinterp, v2, retval); + jit__set_nci_P(f, jinterp, st, v2); + break; + case '2': + t1 = jit_type_sys_short; + goto create_int_pmc; + case '3': + t1 = jit_type_sys_int; + goto create_int_pmc; + case '4': + t1 = jit_type_sys_long; + create_int_pmc: + v1 = jit_insn_load_relative(f, retval, 0, t1); + v2 = jit_value_create_intval_constant(f, enum_class_Integer); + v3 = jit__pmc_new_noinit(f, jinterp, v2); + jit__vtable_set_integer_native(f, jinterp, v3, v1); + jit__set_nci_P(f, jinterp, st, v3); + break; + + case 'U': + /* ignore (failed elsewhere) */ + break; + + default: + /* ignore (failed elsewhere) */ + break; + } +} + +void +Parrot_jit_parse_sig_args_post(PARROT_INTERP, char *sig, int nargs, + jit_function_t f, jit_value_t jinterp, + jit_value_t *args, jit_value_t *regs) { + int i, j; + + sig += 1; + + for (i = 0, j = 0; i < nargs; i++) { + jit_type_t t1; + jit_value_t v1; + switch (sig[i]) { + case 't': + jit__Parrot_str_free_cstring(f, args[i]); + j++; + break; + + case 'B': + v1 = jit_insn_load_relative(f, args[i], 0, jit_type_void_ptr); + jit__Parrot_str_free_cstring(f, v1); + j++; + break; + + case '2': + t1 = jit_type_sys_short; + goto set_integer; + case '3': + t1 = jit_type_sys_int; + goto set_integer; + case '4': + t1 = jit_type_sys_long; + set_integer: + v1 = jit_insn_load_relative(f, args[i], 0, t1); + jit__vtable_set_integer_native(f, jinterp, regs[j], v1); + j++; + break; + + case 'V': + v1 = jit_insn_load_relative(f, args[i], 0, jit_type_void_ptr); + jit__vtable_set_pointer(f, jinterp, regs[j], v1); + j++; + break; + + case 'I': + case 'c': + case 'i': + case 'l': + case 'N': + case 'f': + case 'd': + case 'S': + case 'b': + case 'p': + case 'P': + case 'O': + case '@': + j++; + break; + + case 'U': + /* TODO */ + break; + default: + /* ignore */ + break; + } + } +} + +jit_value_t +jit_value_create_intval_constant(jit_function_t f, INTVAL i) { + return jit_value_create_nint_constant(f, JIT_TYPE_INTVAL, i); +} + +jit_value_t +jit_value_create_string_constant(jit_function_t f, char *str, int len) { + jit_value_t jit_len, jit_str; + int i; + + if (len < 1) { + len = strlen(str); + } + + jit_len = jit_value_create_nint_constant(f, jit_type_sys_int, len); + jit_str = jit_insn_alloca(f, jit_len); + + for (i = 0; i < len; i++) { + jit_value_t c = jit_value_create_nint_constant(f, jit_type_sys_char, str[i]); + jit_insn_store_relative(f, jit_str, i, c); + } + + return jit_str; +} + +/* + * JIT wrappers + */ + +/* custom wrappers */ +jit_value_t +jit__Buffer_bufstart(jit_function_t f, jit_value_t buf) { + return jit_insn_load_relative(f, buf, offsetof(Buffer, _bufstart), jit_type_void_ptr); +} + +/* vtable wrappers */ +@TEMP_vtable_wrap_defns@ + +/* function wrappers */ +@TEMP_func_wrap_defns@ + +#endif /* PARROT_HAS_LIBJIT */ + +/* + * Local variables: + * c-file-style: "parrot" + * End: + * vim: expandtab shiftwidth=4: + */ Index: config/gen/libjit/frame_builder_libjit_h.in =================================================================== --- config/gen/libjit/frame_builder_libjit_h.in (revision 0) +++ config/gen/libjit/frame_builder_libjit_h.in (revision 0) @@ -0,0 +1,91 @@ +/* frame_builder_libjit.h + * $Id$ + * Copyright (C) 2009, Parrot Foundation. + */ + +#ifndef PARROT_FRAME_BUILDER_LIBJIT_H_GUARD +#define PARROT_FRAME_BUILDER_LIBJIT_H_GUARD + + +#if defined(__cplusplus) +# define EXTERN extern "C" +#else +# define EXTERN +#endif + +#include +#include "parrot/parrot.h" +#include "frame_builder.h" + +#if PARROT_HAS_LIBJIT + +#include + +/* + * JITted function state data + */ +struct jit_buffer_private_data { + jit_context_t ctx; + char *sig; +}; + +/* + * JIT types + */ + +#define JIT_TYPE_UINTVAL @libjit_uv@ // jit_type_sys_ulong +#define JIT_TYPE_INTVAL @libjit_iv@ // jit_type_sys_long +#define JIT_TYPE_FLOATVAL @libjit_nv@ // jit_type_sys_double + +/* + * JIT functions + */ + +void * +Parrot_jit_create_thunk(Interp *, char *, void *); + +int +Parrot_jit_parse_sig_args_pre(Interp *, char *, jit_function_t, jit_value_t, jit_value_t, + jit_type_t **, jit_value_t **, jit_value_t **); + +int +Parrot_jit_init_pcc(char *, int, jit_function_t, jit_value_t, jit_value_t); + +jit_type_t +Parrot_jit_parse_sig_ret_pre(Interp *, char *); + +void +Parrot_jit_parse_sig_ret_post(Interp *, char *, jit_function_t, jit_value_t, jit_value_t, jit_value_t); + +void +Parrot_jit_parse_sig_args_post(Interp *, char *, int, jit_function_t, jit_value_t, jit_value_t *, jit_value_t *); + +jit_value_t +jit_value_create_intval_constant(jit_function_t, INTVAL); + +jit_value_t +jit_value_create_string_constant(jit_function_t, char *, int); + +/* + * JIT wrappers + */ + +/* custom wrappers */ +jit_value_t +jit__Buffer_bufstart(jit_function_t, jit_value_t); + +/* vtable wrappers */ +@TEMP_vtable_wrap_decls@ + +/* function wrappers */ +@TEMP_func_wrap_decls@ + +#endif /* PARROT_HAS_LIBJIT */ +#endif /* PARROT_FRAME_BUILDER_LIBJIT_H_GUARD */ + +/* + * Local variables: + * c-file-style: "parrot" + * End: + * vim: expandtab shiftwidth=4: + */