├── .gitignore ├── LICENSE ├── Makefile ├── README.rst ├── basic_self_jit_x64.c ├── call_c_from_jit.c ├── call_puts_from_jit.c ├── gcd.c └── gcd_iter.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | 5 | # Libraries 6 | *.lib 7 | *.a 8 | 9 | # Shared objects (inc. Windows DLLs) 10 | *.dll 11 | *.so 12 | *.so.* 13 | *.dylib 14 | 15 | # Executables 16 | *.exe 17 | *.out 18 | *.app 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # Makefile for building the code samples. Read inline comments for 3 | # documentation. 4 | # 5 | # Eli Bendersky (eliben@gmail.com) 6 | # This code is in the public domain 7 | #------------------------------------------------------------------------------- 8 | 9 | LIBJIT_PATH = $$HOME/test/libjit 10 | LIBJIT_INCLUDE_PATH = $(LIBJIT_PATH)/include 11 | LIBJIT_LIB_PATH = $(LIBJIT_PATH)/jit/.libs 12 | LIBJIT_AR = $(LIBJIT_LIB_PATH)/libjit.a 13 | 14 | CC = gcc 15 | LD = gcc 16 | CCOPT = -g -O0 17 | CCFLAGS = -c $(CCOPT) 18 | LDFLAGS = -lpthread -lm -ldl -lrt 19 | 20 | all: gcd gcd_iter call_c_from_jit call_puts_from_jit \ 21 | basic_self_jit_x64 22 | 23 | gcd: gcd.o 24 | $(LD) $^ $(LIBJIT_AR) $(LDFLAGS) -o $@ 25 | 26 | gcd.o: gcd.c 27 | $(CC) -I$(LIBJIT_INCLUDE_PATH) -I. $(CCFLAGS) $^ -o $@ 28 | 29 | gcd_iter: gcd_iter.o 30 | $(LD) $^ $(LIBJIT_AR) $(LDFLAGS) -o $@ 31 | 32 | gcd_iter.o: gcd_iter.c 33 | $(CC) -I$(LIBJIT_INCLUDE_PATH) -I. $(CCFLAGS) $^ -o $@ 34 | 35 | call_c_from_jit: call_c_from_jit.o 36 | $(LD) $^ $(LIBJIT_AR) $(LDFLAGS) -o $@ 37 | 38 | call_c_from_jit.o: call_c_from_jit.c 39 | $(CC) -I$(LIBJIT_INCLUDE_PATH) -I. $(CCFLAGS) $^ -o $@ 40 | 41 | call_puts_from_jit: call_puts_from_jit.o 42 | $(LD) $^ $(LIBJIT_AR) $(LDFLAGS) -o $@ 43 | 44 | call_puts_from_jit.o: call_puts_from_jit.c 45 | $(CC) -I$(LIBJIT_INCLUDE_PATH) -I. $(CCFLAGS) $^ -o $@ 46 | 47 | basic_self_jit_x64: basic_self_jit_x64.c 48 | $(CC) $(CCOPT) $^ -o $@ 49 | 50 | clean: 51 | rm -rf *.o gcd gcd_iter call_c_from_jit call_puts_from_jit \ 52 | basic_self_jit_x64 53 | 54 | 55 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | libjit-samples 2 | ============== 3 | 4 | Code samples for using libjit and related APIs. 5 | 6 | -------------------------------------------------------------------------------- /basic_self_jit_x64.c: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // Simple JITing of code into memory. 3 | // 4 | // This example doesn't actually use libjit - it's much more basic. 5 | // 6 | // Eli Bendersky (eliben@gmail.com) 7 | // This code is in the public domain 8 | //------------------------------------------------------------------------------ 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | // Allocates RWX memory of given size and returns a pointer to it. On failure, 16 | // prints out the error and returns NULL. 17 | void* alloc_executable_memory(size_t size) { 18 | void* ptr = mmap(0, size, 19 | PROT_READ | PROT_WRITE | PROT_EXEC, 20 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 21 | if (ptr == (void*)-1) { 22 | perror("mmap"); 23 | return NULL; 24 | } 25 | return ptr; 26 | } 27 | 28 | // Allocates RW memory of given size and returns a pointer to it. On failure, 29 | // prints out the error and returns NULL. mmap is used to allocate, so 30 | // deallocation has to be done with munmap, and the memory is allocated 31 | // on a page boundary so it's suitable for calling mprotect. 32 | void* alloc_writable_memory(size_t size) { 33 | void* ptr = mmap(0, size, 34 | PROT_READ | PROT_WRITE, 35 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 36 | if (ptr == (void*)-1) { 37 | perror("mmap"); 38 | return NULL; 39 | } 40 | return ptr; 41 | } 42 | 43 | // Sets a RX permission on the given memory, which must be page-aligned. Returns 44 | // 0 on success. On failure, prints out the error and returns -1. 45 | int make_memory_executable(void* m, size_t size) { 46 | if (mprotect(m, size, PROT_READ | PROT_EXEC) == -1) { 47 | perror("mprotect"); 48 | return -1; 49 | } 50 | return 0; 51 | } 52 | 53 | // Emits code into the given memory, assuming enough was allocated. Returns the 54 | // number of bytes emitted. 55 | size_t emit_code_into_memory(unsigned char* m) { 56 | unsigned char code[] = { 57 | 0x48, 0x89, 0xf8, // mov %rdi, %rax 58 | 0x48, 0x83, 0xc0, 0x04, // add $4, %rax 59 | 0xc3 // ret 60 | }; 61 | memcpy(m, code, sizeof(code)); 62 | return sizeof(code); 63 | } 64 | 65 | const size_t SIZE = 1024; 66 | typedef long (*JittedFunc)(long); 67 | 68 | // Allocates RWX memory directly. 69 | void run_from_rwx() { 70 | void* m = alloc_executable_memory(SIZE); 71 | size_t n = emit_code_into_memory(m); 72 | 73 | const char* filename = "/tmp/jitout.bin"; 74 | FILE* outfile = fopen(filename, "wb"); 75 | if (outfile) { 76 | if (fwrite(m, 1, n, outfile) == n) { 77 | printf("Successfully emitted binary to %s\n", filename); 78 | } 79 | fclose(outfile); 80 | } 81 | 82 | JittedFunc func = m; 83 | int result = func(2); 84 | printf("result = %d\n", result); 85 | } 86 | 87 | // Allocates RW memory, emits the code into it and sets it to RX before 88 | // executing. 89 | void emit_to_rw_run_from_rx() { 90 | void* m = alloc_writable_memory(SIZE); 91 | emit_code_into_memory(m); 92 | make_memory_executable(m, SIZE); 93 | 94 | JittedFunc func = m; 95 | int result = func(2); 96 | printf("result = %d\n", result); 97 | } 98 | 99 | int main(int argc, char** argv) { 100 | run_from_rwx(); 101 | emit_to_rw_run_from_rx(); 102 | 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /call_c_from_jit.c: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // call_c_from_jit libjit sample. 3 | // 4 | // Eli Bendersky (eliben@gmail.com) 5 | // This code is in the public domain 6 | //------------------------------------------------------------------------------ 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | int native_mult(int a, int b) { 13 | return a * b; 14 | } 15 | 16 | // Builds this function, and returns an uncompiled jit_function_t: 17 | // 18 | // int jit_adder(int x, y) { 19 | // return x + y; 20 | // } 21 | jit_function_t build_jit_adder(jit_context_t context) { 22 | jit_context_build_start(context); 23 | 24 | // Create function signature and object. int (*)(int, int) 25 | jit_type_t params[2] = {jit_type_int, jit_type_int}; 26 | jit_type_t signature = jit_type_create_signature( 27 | jit_abi_cdecl, jit_type_int, params, 2, 1); 28 | jit_function_t F = jit_function_create(context, signature); 29 | 30 | // x, y are the parameters; sum is a temporary 31 | jit_value_t x = jit_value_get_param(F, 0); 32 | jit_value_t y = jit_value_get_param(F, 1); 33 | jit_value_t sum = jit_value_create(F, jit_type_int); 34 | 35 | // sum = x + y 36 | jit_value_t temp_sum = jit_insn_add(F, x, y); 37 | jit_insn_store(F, sum, temp_sum); 38 | 39 | // return sum 40 | jit_insn_return(F, sum); 41 | jit_context_build_end(context); 42 | return F; 43 | } 44 | 45 | // Builds this function: 46 | // 47 | // void foo(int x, int y, int* result) { 48 | // int t = jit_adder(x, y); 49 | // *result = native_mult(t, y); 50 | // } 51 | // 52 | // Returns an uncompiled jit_function_t 53 | // Note that jit_adder is a jit_function_t that's passed into this builder. 54 | jit_function_t build_foo(jit_context_t context, jit_function_t jit_adder) { 55 | jit_context_build_start(context); 56 | 57 | // Create function signature and object. void (*)(int, int, void*) 58 | // libjit treats all native pointers as void*. 59 | jit_type_t params[] = {jit_type_int, jit_type_int, jit_type_void_ptr}; 60 | jit_type_t signature = jit_type_create_signature( 61 | jit_abi_cdecl, jit_type_void, params, 3, 1); 62 | jit_function_t F = jit_function_create(context, signature); 63 | 64 | // x, y, result are the parameters; t is a temporary 65 | jit_value_t x = jit_value_get_param(F, 0); 66 | jit_value_t y = jit_value_get_param(F, 1); 67 | jit_value_t result = jit_value_get_param(F, 2); 68 | jit_value_t t = jit_value_create(F, jit_type_int); 69 | 70 | // t = jit_adder(x, y) 71 | jit_value_t adder_args[] = {x, y}; 72 | jit_value_t call_temp = jit_insn_call( 73 | F, "jit_adder", jit_adder, 0, adder_args, 2, 0); 74 | 75 | jit_insn_store(F, t, call_temp); 76 | 77 | // Prepare calling native_mult: create its signature 78 | jit_type_t mult_params[] = {jit_type_int, jit_type_int}; 79 | jit_type_t mult_signature = jit_type_create_signature( 80 | jit_abi_cdecl, jit_type_int, params, 2, 1); 81 | 82 | // x = native_mult(t, y) 83 | jit_value_t mult_args[] = {t, y}; 84 | jit_value_t res = jit_insn_call_native( 85 | F, "native_mult", native_mult, mult_signature, 86 | mult_args, sizeof(mult_args) / sizeof(jit_value_t), JIT_CALL_NOTHROW); 87 | jit_insn_store(F, x, res); 88 | 89 | // *result = x 90 | // Note that this creates a store of a value libjit considers to be a 91 | // jit_type_int, so the pointer must point to at least that size. 92 | jit_insn_store_relative(F, result, 0, x); 93 | 94 | jit_context_build_end(context); 95 | return F; 96 | } 97 | 98 | 99 | // Run foo with arguments and return its result 100 | int run_foo(jit_function_t jit_foo, int x, int y) { 101 | int result, *presult = &result; 102 | void* args[] = {&x, &y, &presult}; 103 | 104 | jit_function_apply(jit_foo, args, NULL); 105 | return result; 106 | } 107 | 108 | 109 | int main(int argc, char** argv) { 110 | jit_init(); 111 | jit_context_t context = jit_context_create(); 112 | jit_function_t jit_adder = build_jit_adder(context); 113 | jit_function_t foo = build_foo(context, jit_adder); 114 | 115 | // This will dump the uncompiled function, showing libjit opcodes 116 | jit_dump_function(stdout, jit_adder, "jit_adder [uncompiled]"); 117 | jit_dump_function(stdout, foo, "foo [uncompiled]"); 118 | 119 | // Compile (JIT) the functions to machine code 120 | jit_context_build_start(context); 121 | jit_function_compile(jit_adder); 122 | jit_function_compile(foo); 123 | jit_context_build_end(context); 124 | 125 | // This will dump the disassembly of the machine code for the function 126 | jit_dump_function(stdout, jit_adder, "jit_adder [compiled]"); 127 | jit_dump_function(stdout, foo, "foo [compiled]"); 128 | 129 | // Run the function on argv input 130 | if (argc > 2) { 131 | int u = atoi(argv[1]); 132 | int v = atoi(argv[2]); 133 | printf("foo(%d, %d) --> %d\n", u, v, run_foo(foo, u, v)); 134 | } 135 | 136 | jit_context_destroy(context); 137 | return 0; 138 | } 139 | 140 | 141 | -------------------------------------------------------------------------------- /call_puts_from_jit.c: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // call_puts_from_jit libjit sample. 3 | // 4 | // Eli Bendersky (eliben@gmail.com) 5 | // This code is in the public domain 6 | //------------------------------------------------------------------------------ 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | int main(int argc, char** argv) { 13 | jit_init(); 14 | jit_context_t context = jit_context_create(); 15 | 16 | // void foo() 17 | jit_function_t F = jit_function_create(context, 18 | jit_type_create_signature(jit_abi_cdecl, jit_type_void, NULL, 0, 1)); 19 | 20 | // Approach #1: allocate the string buffer on stack inside the jit-ed 21 | // function and store the desired characters into it. 22 | 23 | // char* bufptr 24 | #define CONST_BYTE(v) (jit_value_create_nint_constant(F, jit_type_ubyte, v)) 25 | jit_type_t type_cstring = jit_type_create_pointer(jit_type_sys_char, 1); 26 | jit_value_t bufptr = jit_value_create(F, type_cstring); 27 | 28 | // Make bufptr point to a 4-byte buffer allocated on the stack 29 | jit_insn_store(F, bufptr, jit_insn_alloca(F, CONST_BYTE(4))); 30 | 31 | // Store "abc" (with explicit terminating zero) into bufptr 32 | jit_insn_store_relative(F, bufptr, 0, CONST_BYTE('a')); 33 | jit_insn_store_relative(F, bufptr, 1, CONST_BYTE('b')); 34 | jit_insn_store_relative(F, bufptr, 2, CONST_BYTE('c')); 35 | jit_insn_store_relative(F, bufptr, 3, CONST_BYTE('\x00')); 36 | 37 | // Create the signature of puts: int (*)(char*) 38 | jit_type_t puts_signature = jit_type_create_signature( 39 | jit_abi_cdecl, jit_type_int, &type_cstring, 1, 1); 40 | 41 | // puts(bufptr); 42 | jit_insn_call_native( 43 | F, "puts", puts, puts_signature, &bufptr, 1, JIT_CALL_NOTHROW); 44 | 45 | // Approach #2: use the address of a string literal in the host code directly, 46 | // storing it into a constant. Note that this has to explicitly specify that 47 | // host pointers are 64-bit. 48 | 49 | jit_value_t hostmemptr = jit_value_create_long_constant( 50 | F, type_cstring, (long)"foobar"); 51 | 52 | jit_insn_call_native( 53 | F, "puts", puts, puts_signature, &hostmemptr, 1, JIT_CALL_NOTHROW); 54 | 55 | jit_dump_function(stdout, F, "F [uncompiled]"); 56 | jit_function_compile(F); 57 | jit_dump_function(stdout, F, "F [compiled]"); 58 | 59 | // Run 60 | jit_function_apply(F, NULL, NULL); 61 | 62 | jit_context_destroy(context); 63 | return 0; 64 | } 65 | 66 | 67 | -------------------------------------------------------------------------------- /gcd.c: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // gcd.c Taken from the libjit tutorial, part 2. 3 | // 4 | // The libjit license applies to this file. 5 | //------------------------------------------------------------------------------ 6 | /* 7 | * JITs this gcd function: 8 | * unsigned int gcd(unsigned int x, unsigned int y) { 9 | * if (x == y) 10 | * return x; 11 | * else if (x < y) 12 | * return gcd(x, y - x); 13 | * else 14 | * return gcd(x - y, y); 15 | * } 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | int main(int argc, char **argv) { 22 | jit_context_t context; 23 | jit_type_t params[2]; 24 | jit_type_t signature; 25 | jit_function_t function; 26 | jit_value_t x, y; 27 | jit_value_t temp1, temp2; 28 | jit_value_t temp3, temp4; 29 | jit_value_t temp_args[2]; 30 | jit_label_t label1 = jit_label_undefined; 31 | jit_label_t label2 = jit_label_undefined; 32 | jit_uint arg1, arg2; 33 | void *args[2]; 34 | jit_uint result; 35 | 36 | /* Create a context to hold the JIT's primary state */ 37 | context = jit_context_create(); 38 | 39 | /* Lock the context while we build and compile the function */ 40 | jit_context_build_start(context); 41 | 42 | /* Build the function signature */ 43 | params[0] = jit_type_uint; 44 | params[1] = jit_type_uint; 45 | signature = jit_type_create_signature 46 | (jit_abi_cdecl, jit_type_uint, params, 2, 1); 47 | 48 | /* Create the function object */ 49 | function = jit_function_create(context, signature); 50 | jit_type_free(signature); 51 | 52 | /* Check the condition "if(x == y)" */ 53 | x = jit_value_get_param(function, 0); 54 | y = jit_value_get_param(function, 1); 55 | temp1 = jit_insn_eq(function, x, y); 56 | jit_insn_branch_if_not(function, temp1, &label1); 57 | 58 | /* Implement "return x" */ 59 | jit_insn_return(function, x); 60 | 61 | /* Set "label1" at this position */ 62 | jit_insn_label(function, &label1); 63 | 64 | /* Check the condition "if(x < y)" */ 65 | temp2 = jit_insn_lt(function, x, y); 66 | jit_insn_branch_if_not(function, temp2, &label2); 67 | 68 | /* Implement "return gcd(x, y - x)" */ 69 | temp_args[0] = x; 70 | temp_args[1] = jit_insn_sub(function, y, x); 71 | temp3 = jit_insn_call 72 | (function, "gcd", function, 0, temp_args, 2, 0); 73 | jit_insn_return(function, temp3); 74 | 75 | /* Set "label2" at this position */ 76 | jit_insn_label(function, &label2); 77 | 78 | /* Implement "return gcd(x - y, y)" */ 79 | temp_args[0] = jit_insn_sub(function, x, y); 80 | temp_args[1] = y; 81 | temp4 = jit_insn_call 82 | (function, "gcd", function, 0, temp_args, 2, 0); 83 | jit_insn_return(function, temp4); 84 | 85 | /* Compile the function */ 86 | jit_function_compile(function); 87 | 88 | /* Unlock the context */ 89 | jit_context_build_end(context); 90 | 91 | /* Execute the function and print the result */ 92 | arg1 = 27; 93 | arg2 = 14; 94 | args[0] = &arg1; 95 | args[1] = &arg2; 96 | jit_function_apply(function, args, &result); 97 | printf("gcd(27, 14) = %u\n", (unsigned int)result); 98 | 99 | /* Clean up */ 100 | jit_context_destroy(context); 101 | 102 | /* Finished */ 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /gcd_iter.c: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // gcd_iter libjit sample. Iterative version of gcd.c 3 | // 4 | // Eli Bendersky (eliben@gmail.com) 5 | // This code is in the public domain 6 | //------------------------------------------------------------------------------ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // Native version for benchmarking 14 | int __attribute__ ((noinline)) gcd_iter_native(int u, int v) { 15 | int t; 16 | while (v) { 17 | t = u; 18 | u = v; 19 | v = t % v; 20 | } 21 | return u < 0 ? -u : u; /* abs(u) */ 22 | } 23 | 24 | // Compute difference between two timespecs, as a timespec. 25 | struct timespec timespec_diff(struct timespec start, struct timespec end) { 26 | const long SEC = 1000 * 1000 * 1000; // 1 sec in ns 27 | struct timespec diff; 28 | if (end.tv_nsec < start.tv_nsec) { 29 | diff.tv_sec = end.tv_sec - start.tv_sec - 1; 30 | diff.tv_nsec = SEC + end.tv_nsec - start.tv_nsec; 31 | } else { 32 | diff.tv_sec = end.tv_sec - start.tv_sec; 33 | diff.tv_nsec = end.tv_nsec - start.tv_nsec; 34 | } 35 | 36 | return diff; 37 | } 38 | 39 | void print_diff(struct timespec start, struct timespec end) { 40 | struct timespec diff = timespec_diff(start, end); 41 | printf("Elapsed %ld . %ld\n", diff.tv_sec, diff.tv_nsec); 42 | } 43 | 44 | // Run a benchmark 45 | void benchmark(jit_function_t jit_f) { 46 | int n1 = 49979687; 47 | int n2 = 982451653; 48 | const int N = 5 * 1000 * 1000; 49 | struct timespec t1, t2, d; 50 | typedef int (*FF)(int, int); 51 | int i, g; 52 | 53 | // Arguments for the JIT invocation 54 | void* args[] = {&n1, &n2}; 55 | jit_int result; 56 | 57 | printf("Native\n"); 58 | clock_gettime(CLOCK_REALTIME, &t1); 59 | for (i = 0; i < N; ++i) { 60 | g = gcd_iter_native(n1, n2); 61 | } 62 | clock_gettime(CLOCK_REALTIME, &t2); 63 | print_diff(t1, t2); 64 | 65 | printf("\nJIT apply\n"); 66 | clock_gettime(CLOCK_REALTIME, &t1); 67 | for (i = 0; i < N; ++i) { 68 | jit_function_apply(jit_f, args, &result); 69 | } 70 | clock_gettime(CLOCK_REALTIME, &t2); 71 | print_diff(t1, t2); 72 | 73 | printf("\nJIT closure\n"); 74 | FF clos = jit_function_to_closure(jit_f); 75 | clock_gettime(CLOCK_REALTIME, &t1); 76 | for (i = 0; i < N; ++i) { 77 | g = clos(n1, n2); 78 | } 79 | clock_gettime(CLOCK_REALTIME, &t2); 80 | print_diff(t1, t2); 81 | } 82 | 83 | 84 | // Builds a function that performs the iterative GCD computation, implementing 85 | // the following C code: 86 | // 87 | // int gcd_iter(int u, int v) { 88 | // int t; 89 | // while (v) { 90 | // t = u; 91 | // u = v; 92 | // v = t % v; 93 | // } 94 | // return u < 0 ? -u : u; /* abs(u) */ 95 | // } 96 | // 97 | // Returns an uncompiled jit_function_t. 98 | jit_function_t build_gcd_func(jit_context_t context) { 99 | jit_context_build_start(context); 100 | 101 | // Create function signature and object. int (*)(int, int) 102 | jit_type_t params[2] = {jit_type_int, jit_type_int}; 103 | jit_type_t signature = jit_type_create_signature( 104 | jit_abi_cdecl, jit_type_int, params, 2, 1); 105 | jit_function_t F = jit_function_create(context, signature); 106 | 107 | // u, v are function parameters; t is a temporary value. 108 | jit_value_t u, v, t; 109 | u = jit_value_get_param(F, 0); 110 | v = jit_value_get_param(F, 1); 111 | t = jit_value_create(F, jit_type_int); 112 | 113 | // Create the while (v) condition with a label that allows to loop back. 114 | // 115 | // label_while: 116 | // if (v == 0) goto label_after_while 117 | // .. contents of while loop 118 | // 119 | // label_after_while is created as undefined at this point, so that 120 | // instructions can have forward references to it. It will be placed later. 121 | jit_label_t label_while = jit_label_undefined; 122 | jit_label_t label_after_while = jit_label_undefined; 123 | jit_value_t const0 = jit_value_create_nint_constant(F, jit_type_int, 0); 124 | 125 | jit_insn_label(F, &label_while); 126 | jit_value_t cmp_v_0 = jit_insn_eq(F, v, const0); 127 | jit_insn_branch_if(F, cmp_v_0, &label_after_while); 128 | 129 | // t = u 130 | jit_insn_store(F, t, u); 131 | // u = v 132 | jit_insn_store(F, u, v); 133 | 134 | // v = t % v 135 | jit_value_t rem = jit_insn_rem(F, t, v); 136 | jit_insn_store(F, v, rem); 137 | 138 | // goto label_while 139 | // label_after_while: 140 | // ... 141 | jit_insn_branch(F, &label_while); 142 | jit_insn_label(F, &label_after_while); 143 | 144 | // if (u >= 0) goto label_positive 145 | // return -u 146 | // label_pos: 147 | // return u 148 | jit_label_t label_positive = jit_label_undefined; 149 | jit_value_t cmp_u_0 = jit_insn_ge(F, u, const0); 150 | jit_insn_branch_if(F, cmp_u_0, &label_positive); 151 | 152 | jit_value_t minus_u = jit_insn_neg(F, u); 153 | jit_insn_return(F, minus_u); 154 | jit_insn_label(F, &label_positive); 155 | jit_insn_return(F, u); 156 | 157 | jit_context_build_end(context); 158 | return F; 159 | } 160 | 161 | 162 | int main(int argc, char** argv) { 163 | jit_init(); 164 | jit_context_t context = jit_context_create(); 165 | jit_function_t gcd = build_gcd_func(context); 166 | 167 | // This will dump the uncompiled function, showing libjit opcodes 168 | jit_dump_function(stdout, gcd, "gcd [uncompiled]"); 169 | 170 | printf("Optimization level: %u\n", jit_function_get_optimization_level(gcd)); 171 | // Compile (JIT) the function to machine code 172 | jit_context_build_start(context); 173 | jit_function_compile(gcd); 174 | jit_context_build_end(context); 175 | 176 | // This will dump the disassembly of the machine code for the function 177 | jit_dump_function(stdout, gcd, "gcd [compiled]"); 178 | 179 | // Run the function on argv input 180 | if (argc > 2) { 181 | int u = atoi(argv[1]); 182 | int v = atoi(argv[2]); 183 | void* args[2] = {&u, &v}; 184 | 185 | printf("gcd(%d, %d) --> ", u, v); 186 | jit_int result; 187 | jit_function_apply(gcd, args, &result); 188 | /*typedef int (*FF)(int, int);*/ 189 | /*FF gcd_f = jit_function_to_closure(gcd);*/ 190 | /*int result = gcd_f(u, v);*/ 191 | printf("%d\n", (int)result); 192 | } 193 | 194 | /*benchmark(gcd);*/ 195 | 196 | jit_context_destroy(context); 197 | return 0; 198 | } 199 | 200 | --------------------------------------------------------------------------------