/* jit.h Copyright (C) 2006-2007 J O'Connell & Codemist Ltd */ #ifndef header_jit_h #define header_jit_h 1 /* * This code may be used and modified, and redistributed in binary * or source form, subject to the "CCL Public License", which should * accompany it. This license is a variant on the BSD license, and thus * permits use of code derived from this in either open and commercial * projects: but it does require that updates to this code be made * available back to the originators of the package. * Before merging other code in with this or linking this code * with other packages or libraries please check that the license terms * of the other material are compatible with those of this. */ /* Signature: 4e53f50d 18-Jan-2007 */ /* * At present the CSL JIT only supports the Intel/AMD x86 architecture. * Attempts to use it on other sorts of machine may have really bad * confusing consequences! */ #define x86arch 1 /* * Debug switch for the JIT */ #define JDEBUG 1 /* register, eg EAX */ #define EAX 0x0 #define ECX 0x1 #define EDX 0x2 #define EBX 0x3 #define ESP 0x4 #define EBP 0x5 #define ESI 0x6 #define EDI 0x7 /* memory indirection, eg [EAX] */ #define EAXM 0x8 #define ECXM 0x9 #define EDXM 0xa #define EBXM 0xb #define ESPM 0xc #define EBPM 0xd #define ESIM 0xe #define EDIM 0xf /* memory offset */ #define DISP32 0x10 /* * At some stage it may be good to arrange that the JIT assembler can decide * whether it needs a long-form branch or if a short one will suffice. At this * stage the choice is made globally. Define JUMPREL8 if you guarantee * all functions are tiny and you want the shortest code, or leave it * undefined for safer treatment of bigger examples. */ #ifdef JUMPREL8 /* Conditional branches with rel8 offset */ #define JA 0x77 #define JAE 0x73 #define JB 0x72 #define JBE 0x76 #define JC 0x72 #define JCXZ 0xe3 #define JECXZ 0xe3 #define JRCXZ 0xe3 #define JE 0x74 #define JG 0x7f #define JGE 0x7d #define JL 0x7c #define JLE 0x7e #define JNA 0x76 #define JNAE 0x72 #define JNB 0x73 #define JNBE 0x77 #define JNC 0x73 #define JNE 0x75 #define JNG 0x7e #define JNGE 0x7c #define JNL 0x7d #define JNLE 0x7f #define JNO 0x71 #define JNP 0x7b #define JNS 0x79 #define JNZ 0x75 #define JO 0x70 #define JP 0x7a #define JPE 0x7a #define JPO 0x7b #define JS 0x78 #define JZ 0x74 #else /* Conditional branches with rel32 offset */ #define JA 0x0f87 #define JAE 0x0f83 #define JB 0x0f82 #define JBE 0x0f86 #define JC 0x0f82 #define JE 0x0f84 #define JG 0x0f8f #define JGE 0x0f8d #define JL 0x0f8c #define JLE 0x0f8e #define JNA 0x0f86 #define JNAE 0x0f82 #define JNB 0x0f83 #define JNBE 0x0f87 #define JNC 0x0f83 #define JNE 0x0f85 #define JNG 0x0f8e #define JNGE 0x0f8c #define JNL 0x0f8d #define JNLE 0x0f8f #define JNO 0x0f81 #define JNP 0x0f8b #define JNS 0x0f89 #define JNZ 0x0f85 #define JO 0x0f80 #define JP 0x0f8a #define JPE 0x0f8a #define JPO 0x0f8b #define JS 0x0f88 #define JZ 0x0f84 #endif /* JUMPREL */ /* Function defintions */ /* jitx86.h */ extern void inc_reg(int reg); extern void dec_reg(int reg); extern void sub_imm8_rm32(int size, int reg); extern void sub_imm32_rm32(int size, int reg); extern void add_imm8_addr(int size, void *addr); extern void sub_imm8_addr(int size, void *addr); extern void add_imm8_rm32(int size, int reg); extern void add_imm32_rm32(int size, int reg); extern void and_imm_rm32(int size, int reg); extern void mov_rm32_rm32(int dest, int source); extern void mov_rm32_rm32_disp(int dest, int source, int disp); extern void cmp_imm_r32(int size, int reg); extern void cmp_rm32_rm32(int dest, int source); extern void cmp_rm32_rm32_disp(int dest, int source, int disp); extern void mov_r32_addr(int dest, void *source); extern void mov_addr_r32(void *dest, int source); extern void lea_m32_r32_disp(int source, int dest, int disp); extern void lea_m32_r32_disp(int source, int dest, int disp); extern void MS_CDECL Jpush(int nargs, ...); extern void MS_CDECL Jpop(int nargs, ...); /* jit2.c */ typedef struct reloc_table_struct { char *label; unsigned long pos; struct reloc_table_struct *next; } reloc_table; typedef struct variables_table_struct { int addr; unsigned long pos; struct variables_table_struct *next; } variables_table; extern reloc_table *labels_table; extern reloc_table *callers_table; extern reloc_table *jumpers_table; extern variables_table *vars_table; extern reloc_table *disassembler_labels; extern unsigned char codebuffer[8192]; /* rather arbitrary size! */ extern unsigned long codep; extern void free_labels_table(reloc_table *head); extern void free_var_table(variables_table *head); extern void reloc_calls(); extern void reloc_jumps(); extern void reloc_vars(); extern void startcode(); extern void putbyte(int c); extern void put2bytes(int c); extern void put3bytes(int c); extern void put4bytes(int c); extern void put5bytes(long long c); extern void put_little_endian(Lisp_Object c); extern void put_addr(void *c); extern int isreg(int reg); extern void call_rel_fn(char *label); extern void jump(char *label); extern void cond_jump(char *label, int cond); extern void add_label(char *label); extern void add_disassembler_label(char *label); extern void Jcall_abs_fn(void *addr_big_endian); /* jit3.c */ #define init_stack_pointers() { put3bytes(0x5589e5); } #define exit_stack_pointers() { put4bytes(0x89ec5dc3); } #define exit_bytecode() exit_stack_pointers(); #define Jpush_all() { putbyte(0x60); } #define Jpop_all() { putbyte(0x61); } #undef stack #define stack &C_stack /* * 83 ec 28 sub $0x28,%esp * a1 xx xx xx xx mov 0x0, %eax * 89 45 f8 mov %eax, 0xfffffff8(%ebp) */ #define Jsetup_nil() { put4bytes(0x83ec38a1); \ put_addr(&C_nil); \ mov_rm32_rm32_disp(EAX,EBPM,-2); } #define Jnil_eq_C_nil() { putbyte(0xa1); \ put_addr(&C_nil); \ mov_rm32_rm32_disp(EAX,EBPM,-2); } #define Jresult() { put3bytes(0x8b45f4); } /* * used in bytecode compiler: */ #define load_stack_into(REG) mov_rm32_rm32_disp(EBPM,REG,-2); #define load_stackaddr_into(REG) lea_m32_r32_disp(EBPM,REG,-2); #define store_stack_from(REG) mov_rm32_rm32_disp(REG,EBPM,-2); #define load_nil_into(REG) mov_rm32_rm32_disp(EBPM,REG,-1); #define store_nil_from(REG) mov_rm32_rm32_disp(REG,EBPM,-1); #define load_entry_stack_into(REG) mov_rm32_rm32_disp(EBPM,REG,4); #define store_entry_stack_from(REG) mov_rm32_rm32_disp(REG,EBPM,4); #define store_result_from(REG) mov_rm32_rm32_disp(REG,EBPM,-15); /* * OPTIMISE_REG is a pending enhancement! */ #ifndef OPTIMISE_REG #define load_A_reg_into(REG) mov_rm32_rm32_disp(EBPM,REG,-17); #define store_A_reg_from(REG) mov_rm32_rm32_disp(REG,EBPM,-17); #define load_B_reg_into(REG) { load_nil_into(REG); \ add_imm32_rm32(B_REG,REG); } #else #define load_A_reg_into(REG) mov_rm32_rm32(EDI,REG); #define store_A_reg_from(REG) mov_rm32_rm32(REG,EDI); #define load_B_reg_into(REG) { load_nil_into(REG); \ add_imm32_rm32(B_REG,REG); } #endif /* OPTIMISE_REG */ #define push_A_reg() mov_rm32_rm32_disp(EDI,EBPM,-17); #define pop_A_reg() mov_rm32_rm32_disp(EBPM,EDI,-17); #define load_fringe_into(REG) { load_nil_into(REG); \ add_imm32_rm32(FRINGE,REG); } #define load_heaplimit_into(REG) { load_nil_into(REG); \ add_imm32_rm32(HEAPLIMIT,REG); } #define load_codevec_into(REG) { load_nil_into(REG); \ add_imm32_rm32(CODEVEC,REG); } #ifdef LITVEC_FROM_NIL #define load_litvec_into(REG) { load_nil_into(REG); \ add_imm32_rm32(LITVEC,REG); } #else /* * Loads litvec into REG from qcdr(def) which is passed as arg * to bytestream_interpret in 12(ebp) */ #define load_litvec_into(REG) mov_rm32_rm32_disp(EBPM,REG,3); #endif #define FRINGE 0x48 /* FIXME only works for x86 */ #define HEAPLIMIT 0x4c #define B_REG 0xd4 #define CODEVEC 0xd8 #define LITVEC 0xdc #define make_bc_label() sprintf(label,"BC%x",*ppc+bytecodes+1); #define make_bc_label_backwards() sprintf(label,"BC%x",bytecodes-*ppc+1); #define make_label(label,op,num) sprintf(label,"%s%i%i",op,num,bytecodes); #endif /* header_jit_h */ /* end of jit.h */