/* jit1.c Copyright (C) 2006-2007, Codemist Ltd */ /* and J O'Connell */ /* * Just in time compiler interfaces. The ideal is that this file does not * depend on the architecture of the machine being compiled for. At present * there is a bit of system-specific stuff here about allocating memory that * can be written to and then executed. But mostly what happens here is an * interface between the main CSL interpreter and the JIT system. */ /* * 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: 49ece4ba 18-Jan-2007 */ #include "headers.h" #ifdef WIN32 #include #else #include #endif #ifdef X86 #include "distorm.h" #endif extern int codep; extern void *jit_space_p, *jit_space; #define name_from(def) elt(qcdr(def), 0) int set_jit_mem(char *jitcode) { #ifndef WIN32 /* Check if mmap worked ok */ if (jit_space==(caddr_t)-1) { printf("dead"); return -1; } #endif /* Check if enough space, if not try to get more or die nicely */ while (codep > (jit_size - ((unsigned long)jit_space_p-(unsigned long)jit_space))) { err_printf("\nJIT SPACE IS FULL. TRYING TO ALLOC MORE...\n"); jit_size *= 2; #ifndef WIN32 jit_space = mremap(jit_space, jit_size/2, jit_size, 0); if (jit_space==(caddr_t)-1) { /* * I probably want to use strerror not perror here so that I can then * direct the diagnostic to the CSL error destination, which may sometimes * be a window rather than "stdout". */ perror("mmap failed"); return -1; } err_printf("SUCCESSFUL. ALLOCATED %d\n", jit_size); #endif } /* copy over jit compiled function */ memcpy(jit_space_p, jitcode, codep); return 0; } Lisp_Object MS_CDECL jitcompileme0(Lisp_Object def, int nargs, ...) { Lisp_Object name = name_from(def); char *jitcode; if (nargs != 0) return error(2, err_wrong_no_args, name_from(def), fixnum_of_int((int32)nargs)); jitcode = Jcompile(def, 0); if (jitcode != NULL) { if (set_jit_mem(jitcode)==0) { ifnn(name) = (intptr_t)jit_space_p; jit_space_p += codep; } else ifnn(name) = (intptr_t)bytecoded0; } else ifnn(name) = (intptr_t)bytecoded0; return qfnn(name)(qenv(name), 0); } Lisp_Object jitcompileme1(Lisp_Object def, Lisp_Object a) { Lisp_Object name = name_from(def); /* * Jcompile does not have to do anything that could provoke a garbage * collection, so I am in the happy position that I do not need to * stack anything here or fuss in any way about the Lisp-ness of my * environment. */ char *jitcode = Jcompile(def, 1); /* * At present Jcompile builds its generated code in a private buffer * (probably of limited length) and I copy if to executable memory here. * The "copy" operation would have bad consequences for any code that * was location sensitive! */ if (jitcode != NULL) { if (set_jit_mem(jitcode)==0) { ifn1(name) = (intptr_t)jit_space_p; jit_space_p += codep; } else ifn1(name) = (intptr_t)bytecoded1; } else ifn1(name) = (intptr_t)bytecoded1; /* * remember to pass the compiled code its "environment" of literals. */ return qfn1(name)(qenv(name), a); } Lisp_Object jitcompileme2(Lisp_Object def, Lisp_Object a, Lisp_Object b) { Lisp_Object name = name_from(def); char *jitcode = Jcompile(def, 2); if (jitcode != NULL) { if (set_jit_mem(jitcode)==0) { ifn2(name) = (intptr_t)jit_space_p; jit_space_p += codep; } else ifn2(name) = (intptr_t)bytecoded2; } else ifn2(name) = (intptr_t)bytecoded2; return qfn2(name)(qenv(name), a, b); } Lisp_Object MS_CDECL jitcompileme3(Lisp_Object def, int nargs, ...) { Lisp_Object name = name_from(def); char *jitcode; va_list aa; Lisp_Object a, b, c; if (nargs != 3) return error(2, err_wrong_no_args, name_from(def), fixnum_of_int((int32)nargs)); jitcode = Jcompile(def, 3); if (jitcode != NULL) { if (set_jit_mem(jitcode)==0) { ifnn(name) = (intptr_t)jit_space_p; jit_space_p += codep; } else ifnn(name) = (intptr_t)bytecoded3; } else ifnn(name) = (intptr_t)bytecoded3; va_start(aa, nargs); a = va_arg(aa, Lisp_Object); b = va_arg(aa, Lisp_Object); c = va_arg(aa, Lisp_Object); va_end(aa); return qfnn(name)(qenv(name), 3, a, b, c); } Lisp_Object MS_CDECL jitcompilemen(Lisp_Object def, int nargs, ...) { Lisp_Object name = name_from(def); va_list a; /* * Ought I to check the number of args here? Quite probably!!!! */ char *jitcode = Jcompile(def, nargs); if (jitcode != NULL) { if (set_jit_mem(jitcode)==0) { ifnn(name) = (intptr_t)jit_space_p; jit_space_p += codep; } else ifnn(name) = (intptr_t)bytecodedn; } else ifnn(name) = (intptr_t)bytecodedn; /* * I have a feeling that nargs should never be zero here.... */ if (nargs != 0) { va_start(a, nargs); push_args(a, nargs); /* FIXME stack ok? or pushed too much */ } return apply(name, nargs, qenv(name), name); } /* end of jit1.c */