From: Aleksey Demakov Date: Fri, 19 Oct 2012 23:19:44 +0000 (+0400) Subject: Keep function start and end with memory manager again, also lots of cosmetic changes. X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=7d33e65ebc0885ab93d9cab5c622e45c53486274;p=francis%2Flibjit.git Keep function start and end with memory manager again, also lots of cosmetic changes. --- diff --git a/ChangeLog b/ChangeLog index d6d1876..fd8cd82 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-10-20 Aleksey Demakov + + * include/jit/jit-memory.h, jit/jit-internal.h, jit/jit-memory.c + * jit-cache.c: get back to the scheme where function start and end + addresses are kept by the memory manager, not in jit_function_t. + 2012-10-16 Aleksey Demakov * include/jit/jit-memory.h: add file that defines pluggable memory diff --git a/include/jit/jit-except.h b/include/jit/jit-except.h index 4010453..69084b5 100644 --- a/include/jit/jit-except.h +++ b/include/jit/jit-except.h @@ -41,7 +41,7 @@ extern "C" { #define JIT_RESULT_CALLED_NESTED (-7) #define JIT_RESULT_OUT_OF_BOUNDS (-8) #define JIT_RESULT_UNDEFINED_LABEL (-9) -#define JIT_RESULT_CACHE_FULL (-10000) +#define JIT_RESULT_MEMORY_FULL (-10000) /* * Exception handling function for builtin exceptions. diff --git a/include/jit/jit-memory.h b/include/jit/jit-memory.h index 1d8e68f..418b42b 100644 --- a/include/jit/jit-memory.h +++ b/include/jit/jit-memory.h @@ -49,6 +49,8 @@ struct jit_memory_manager void (*destroy)(jit_memory_context_t memctx); jit_function_t (*find_function)(jit_memory_context_t memctx, void *pc); + void * (*get_function_start)(jit_memory_context_t memctx, jit_function_t func); + void * (*get_function_end)(jit_memory_context_t memctx, jit_function_t func); jit_function_t (*alloc_function)(jit_memory_context_t memctx); void (*free_function)(jit_memory_context_t memctx, jit_function_t func); diff --git a/jit/jit-cache.c b/jit/jit-cache.c index 58ec608..319955a 100644 --- a/jit/jit-cache.c +++ b/jit/jit-cache.c @@ -60,6 +60,8 @@ struct jit_cache_method { jit_cache_method_t left; /* Left sub-tree and red/black bit */ jit_cache_method_t right; /* Right sub-tree */ + unsigned char *start; /* Start of the cache region */ + unsigned char *end; /* End of the cache region */ struct _jit_function func; /* Function */ }; @@ -208,7 +210,7 @@ AllocCachePage(jit_cache_t cache, int factor) static int CacheCompare(jit_cache_t cache, unsigned char *key, jit_cache_method_t node) { - if(node == &(cache->nil) || node == &(cache->head)) + if(node == &cache->nil || node == &cache->head) { /* Every key is greater than the sentinel nodes */ return 1; @@ -216,11 +218,11 @@ CacheCompare(jit_cache_t cache, unsigned char *key, jit_cache_method_t node) else { /* Compare a regular node */ - if(key < node->func.code_start) + if(key < node->start) { return -1; } - else if(key > node->func.code_start) + else if(key > node->start) { return 1; } @@ -300,7 +302,7 @@ CacheRotate(jit_cache_t cache, unsigned char *key, jit_cache_method_t around) static void AddToLookupTree(jit_cache_t cache, jit_cache_method_t method) { - unsigned char *key = method->func.code_start; + unsigned char *key = method->start; jit_cache_method_t temp; jit_cache_method_t greatGrandParent; jit_cache_method_t grandParent; @@ -536,8 +538,8 @@ _jit_cache_start_function(jit_cache_t cache, jit_function_t func) (((char *) func) - offsetof(struct jit_cache_method, func)); /* Initialize the function information */ - cache->method->func.code_start = cache->free_start; - cache->method->func.code_end = cache->free_start; + cache->method->start = cache->free_start; + cache->method->end = 0; cache->method->left = 0; cache->method->right = 0; @@ -554,7 +556,7 @@ _jit_cache_end_function(jit_cache_t cache, int result) } /* Determine if we ran out of space while writing the function */ - if(result != JIT_MEMORY_OK || cache->free_start >= cache->free_end) + if(result != JIT_MEMORY_OK) { /* Restore the saved cache position */ cache->free_start = cache->prev_start; @@ -564,7 +566,7 @@ _jit_cache_end_function(jit_cache_t cache, int result) } /* Update the method region block and then add it to the lookup tree */ - cache->method->func.code_end = cache->free_start; + cache->method->end = cache->free_start; AddToLookupTree(cache, cache->method); cache->method = 0; @@ -782,11 +784,11 @@ _jit_cache_get_function(jit_cache_t cache, void *pc) jit_cache_method_t node = cache->head.right; while(node != &(cache->nil)) { - if(((unsigned char *)pc) < node->func.code_start) + if(((unsigned char *)pc) < node->start) { node = GetLeft(node); } - else if(((unsigned char *)pc) >= node->func.code_end) + else if(((unsigned char *)pc) >= node->end) { node = GetRight(node); } @@ -798,25 +800,79 @@ _jit_cache_get_function(jit_cache_t cache, void *pc) return 0; } +void * +_jit_cache_get_function_start(jit_memory_context_t memctx, jit_function_t func) +{ + jit_cache_method_t method = (jit_cache_method_t) + (((char *) func) - offsetof(struct jit_cache_method, func)); + return method->start; +} + +void * +_jit_cache_get_function_end(jit_memory_context_t memctx, jit_function_t func) +{ + jit_cache_method_t method = (jit_cache_method_t) + (((char *) func) - offsetof(struct jit_cache_method, func)); + return method->end; +} + jit_memory_manager_t jit_default_memory_manager(void) { static const struct jit_memory_manager mm = { + + (jit_memory_context_t (*)(jit_context_t)) &_jit_cache_create, + + (void (*)(jit_memory_context_t)) &_jit_cache_destroy, + + (jit_function_t (*)(jit_memory_context_t, void *)) &_jit_cache_get_function, + + (void * (*)(jit_memory_context_t, jit_function_t)) + &_jit_cache_get_function_start, + + (void * (*)(jit_memory_context_t, jit_function_t)) + &_jit_cache_get_function_end, + + (jit_function_t (*)(jit_memory_context_t)) &_jit_cache_alloc_function, + + (void (*)(jit_memory_context_t, jit_function_t)) &_jit_cache_free_function, + + (int (*)(jit_memory_context_t, jit_function_t)) &_jit_cache_start_function, + + (int (*)(jit_memory_context_t, int)) &_jit_cache_end_function, + + (int (*)(jit_memory_context_t, int)) &_jit_cache_extend, + + (void * (*)(jit_memory_context_t)) &_jit_cache_get_code_limit, + + (void * (*)(jit_memory_context_t)) &_jit_cache_get_code_break, + + (void (*)(jit_memory_context_t, void *)) &_jit_cache_set_code_break, + + (void * (*)(jit_memory_context_t)) &_jit_cache_alloc_trampoline, + + (void (*)(jit_memory_context_t, void *)) &_jit_cache_free_trampoline, + + (void * (*)(jit_memory_context_t)) &_jit_cache_alloc_closure, + + (void (*)(jit_memory_context_t, void *)) &_jit_cache_free_closure, + + (void * (*)(jit_memory_context_t, jit_size_t, jit_size_t)) &_jit_cache_alloc_data }; return &mm; diff --git a/jit/jit-compile.c b/jit/jit-compile.c index 88b8946..a443b9e 100644 --- a/jit/jit-compile.c +++ b/jit/jit-compile.c @@ -36,15 +36,12 @@ typedef struct { jit_function_t func; - int cache_locked; - int cache_started; + int memory_locked; + int memory_started; int restart; int page_factor; - void *code_start; - void *code_end; - struct jit_gencode gen; } _jit_compile_t; @@ -156,7 +153,7 @@ jit_optimize(jit_function_t func) void mark_offset(jit_gencode_t gen, jit_function_t func, unsigned long offset) { - unsigned long native_offset = gen->ptr - func->code_start; + unsigned long native_offset = gen->ptr - gen->mem_start; if(!_jit_varint_encode_uint(&gen->offset_encoder, (jit_uint) offset)) { jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); @@ -380,10 +377,10 @@ cleanup_on_restart(jit_gencode_t gen, jit_function_t func) } /* - * Acquire the code cache. + * Acquire the memory context. */ static void -cache_acquire(_jit_compile_t *state) +memory_acquire(_jit_compile_t *state) { /* Store the function's context as codegen context */ state->gen.context = state->func->context; @@ -392,7 +389,7 @@ cache_acquire(_jit_compile_t *state) _jit_memory_lock(state->gen.context); /* Remember that the lock is acquired */ - state->cache_locked = 1; + state->memory_locked = 1; if(!_jit_memory_ensure(state->gen.context)) { @@ -401,16 +398,16 @@ cache_acquire(_jit_compile_t *state) } /* - * Release the code cache. + * Release the memory context. */ static void -cache_release(_jit_compile_t *state) +memory_release(_jit_compile_t *state) { /* Release the lock if it was previously acquired */ - if(state->cache_locked) + if(state->memory_locked) { _jit_memory_unlock(state->gen.context); - state->cache_locked = 0; + state->memory_locked = 0; } } @@ -421,7 +418,7 @@ cache_release(_jit_compile_t *state) * to pad unused bytes. */ static void -cache_align(_jit_compile_t *state, int align, int diff, int nop) +memory_align(_jit_compile_t *state, int align, int diff, int nop) { jit_nuint p, n; @@ -455,55 +452,69 @@ cache_align(_jit_compile_t *state, int align, int diff, int nop) } /* - * Allocate some space in the code cache. + * Prepare to start code generation with just allocated code space. */ static void -cache_alloc(_jit_compile_t *state) +memory_start(_jit_compile_t *state) +{ + /* Remember the memory context state */ + state->memory_started = 1; + + /* Store the bounds of the available space */ + state->gen.mem_start = _jit_memory_get_break(state->gen.context); + state->gen.mem_limit = _jit_memory_get_limit(state->gen.context); + + /* Align the function code start as required */ + state->gen.ptr = state->gen.mem_start; + memory_align(state, JIT_FUNCTION_ALIGNMENT, JIT_FUNCTION_ALIGNMENT, 0); + + /* Prepare the bytecode offset encoder */ + _jit_varint_init_encoder(&state->gen.offset_encoder); +} + +/* + * Allocate some amount of code space. + */ +static void +memory_alloc(_jit_compile_t *state) { int result; - /* First try with the current cache page */ + /* Try to allocate within the current memory limit */ result = _jit_memory_start_function(state->gen.context, state->func); if(result == JIT_MEMORY_RESTART) { - /* No space left on the current cache page. Allocate a new one. */ + /* Not enough space. Request to extend the limit and retry */ _jit_memory_extend_limit(state->gen.context, state->page_factor++); result = _jit_memory_start_function(state->gen.context, state->func); } if(result != JIT_MEMORY_OK) { - /* Failed to allocate any cache space */ + /* Failed to allocate any space */ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); } - state->gen.ptr = _jit_memory_get_break(state->gen.context); - state->gen.limit = _jit_memory_get_limit(state->gen.context); - - /* Align the function code. */ - cache_align(state, JIT_FUNCTION_ALIGNMENT, JIT_FUNCTION_ALIGNMENT, 0); - /* Prepare the bytecode offset encoder */ - _jit_varint_init_encoder(&state->gen.offset_encoder); - - /* On success remember the cache state */ - state->cache_started = 1; + /* Start with with allocated space */ + memory_start(state); } /* - * End function output to the cache. + * Finish code generation. */ static void -cache_flush(_jit_compile_t *state) +memory_flush(_jit_compile_t *state) { int result; - if(state->cache_started) + if(state->memory_started) { - state->cache_started = 0; + /* Reset the memory state */ + state->memory_started = 0; - /* Let the cache know where we are */ - _jit_memory_set_break(state->gen.context, state->gen.ptr); + /* Let the memory context know the address we ended at */ + _jit_memory_set_break(state->gen.context, state->gen.code_end); - /* End the function's output process */ + /* Finally end the function */ result = _jit_memory_end_function(state->gen.context, JIT_MEMORY_OK); if(result != JIT_MEMORY_OK) { @@ -512,7 +523,7 @@ cache_flush(_jit_compile_t *state) /* Throw an internal exception that causes a larger code space to be allocated and the code generation to restart */ - jit_exception_builtin(JIT_RESULT_CACHE_FULL); + jit_exception_builtin(JIT_RESULT_MEMORY_FULL); } else { @@ -524,8 +535,8 @@ cache_flush(_jit_compile_t *state) #ifndef JIT_BACKEND_INTERP /* On success perform a CPU cache flush, to make the code executable */ - _jit_flush_exec(state->code_start, - (unsigned int)(state->code_end - state->code_start)); + _jit_flush_exec(state->gen.code_start, + state->gen.code_end - state->gen.code_start); #endif /* Terminate the debug information and flush it */ @@ -538,16 +549,16 @@ cache_flush(_jit_compile_t *state) } /* - * Release the allocated cache space. + * Give back the allocated space in case of failure to generate the code. */ static void -cache_abort(_jit_compile_t *state) +memory_abort(_jit_compile_t *state) { - if(state->cache_started) + if(state->memory_started) { - state->cache_started = 0; + state->memory_started = 0; - /* Release the cache space */ + /* Release the code space */ _jit_memory_end_function(state->gen.context, JIT_MEMORY_RESTART); /* Free encoded bytecode offset data */ @@ -556,40 +567,31 @@ cache_abort(_jit_compile_t *state) } /* - * Allocate more space in the code cache. + * Allocate more code space. */ static void -cache_realloc(_jit_compile_t *state) +memory_realloc(_jit_compile_t *state) { int result; - /* Release the allocated cache space */ - cache_abort(state); + /* Release the previously allocated code space */ + memory_abort(state); - /* Allocate a new cache page with the size that grows - by factor of 2 on each reallocation */ + /* Request to extend memory limit and retry space allocation */ _jit_memory_extend_limit(state->gen.context, state->page_factor++); result = _jit_memory_start_function(state->gen.context, state->func); if(result != JIT_MEMORY_OK) { - /* Failed to allocate enough cache space */ + /* Failed to allocate enough space */ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); } - state->gen.ptr = _jit_memory_get_break(state->gen.context); - state->gen.limit = _jit_memory_get_limit(state->gen.context); - - /* Align the function code. */ - cache_align(state, JIT_FUNCTION_ALIGNMENT, JIT_FUNCTION_ALIGNMENT, 0); - - /* Prepare the bytecode offset encoder */ - _jit_varint_init_encoder(&state->gen.offset_encoder); - /* On success remember the cache state */ - state->cache_started = 1; + /* Start with with allocated space */ + memory_start(state); } /* - * Prepare data needed for code generation. + * Prepare function info needed for code generation. */ static void codegen_prepare(_jit_compile_t *state) @@ -623,7 +625,9 @@ codegen(_jit_compile_t *state) struct jit_gencode *gen = &state->gen; jit_block_t block; - state->code_start = gen->ptr; + /* Remember the start code address (due to alignment it may differ from + the available space start - gen->start) */ + gen->code_start = gen->ptr; #ifdef JIT_PROLOG_SIZE /* Output space for the function prolog */ @@ -657,11 +661,13 @@ codegen(_jit_compile_t *state) /* Output the function epilog. All return paths will jump to here */ _jit_gen_epilog(gen, func); - state->code_end = gen->ptr; + + /* Remember the end code address */ + gen->code_end = gen->ptr; #ifdef JIT_PROLOG_SIZE /* Back-patch the function prolog and get the real entry point */ - state->code_start = _jit_gen_prolog(gen, func, state->code_start); + gen->code_start = _jit_gen_prolog(gen, func, gen->code_start); #endif #if !defined(JIT_BACKEND_INTERP) && (!defined(jit_redirector_size) || !defined(jit_indirector_size)) @@ -703,15 +709,15 @@ compile(_jit_compile_t *state, jit_function_t func) if(setjmp(jbuf.buf)) { result = _JIT_RESULT_FROM_OBJECT(jit_exception_get_last_and_clear()); - if(result == JIT_RESULT_CACHE_FULL) + if(result == JIT_RESULT_MEMORY_FULL) { - /* Restart code generation after the cache-full condition */ + /* Restart code generation after the memory full condition */ state->restart = 1; goto restart; } - /* Release allocated cache space and exit */ - cache_abort(state); + /* Release allocated code space and exit */ + memory_abort(state); goto exit; } @@ -725,9 +731,9 @@ compile(_jit_compile_t *state, jit_function_t func) /* Prepare data needed for code generation */ codegen_prepare(state); - /* Allocate some cache */ - cache_acquire(state); - cache_alloc(state); + /* Allocate some space */ + memory_acquire(state); + memory_alloc(state); } else { @@ -736,8 +742,8 @@ compile(_jit_compile_t *state, jit_function_t func) /* Clean up the compilation state */ cleanup_on_restart(&state->gen, state->func); - /* Allocate more cache */ - cache_realloc(state); + /* Allocate more space */ + memory_realloc(state); } #ifdef _JIT_COMPILE_DEBUG @@ -768,14 +774,14 @@ compile(_jit_compile_t *state, jit_function_t func) #endif /* End the function's output process */ - cache_flush(state); + memory_flush(state); - /* Compilation done, no exceptions occured */ + /* Compilation done, no exceptions occurred */ result = JIT_RESULT_OK; exit: - /* Release the cache */ - cache_release(state); + /* Release the memory context */ + memory_release(state); /* Restore the "setjmp" context */ _jit_unwind_pop_setjmp(); @@ -833,7 +839,7 @@ jit_compile(jit_function_t func) result = compile(&state, func); if(result == JIT_RESULT_OK) { - func->entry_point = state.code_start; + func->entry_point = state.gen.code_start; func->is_compiled = 1; /* Free the builder structure, which we no longer require */ @@ -892,7 +898,7 @@ jit_compile_entry(jit_function_t func, void **entry_point) result = compile(&state, func); if(result == JIT_RESULT_OK) { - *entry_point = state.code_start; + *entry_point = state.gen.code_start; } return result; @@ -991,7 +997,7 @@ _jit_function_compile_on_demand(jit_function_t func) result = compile(&state, func); if(result == JIT_RESULT_OK) { - func->entry_point = state.code_start; + func->entry_point = state.gen.code_start; func->is_compiled = 1; } } @@ -1021,12 +1027,7 @@ _jit_function_get_bytecode(jit_function_t func, void *pc, int exact) jit_varint_decoder_t decoder; jit_uint off, noff; -#ifdef JIT_PROLOG_SIZE - start = func->code_start; -#else - start = func->entry_point; -#endif - + start = _jit_memory_get_function_start(func->context, func); native_offset = pc - start; _jit_varint_init_decoder(&decoder, func->bytecode_offset); diff --git a/jit/jit-dump.c b/jit/jit-dump.c index c3a87f1..36704bf 100644 --- a/jit/jit-dump.c +++ b/jit/jit-dump.c @@ -887,6 +887,7 @@ void jit_dump_function(FILE *stream, jit_function_t func, const char *name) } else if(func->is_compiled) { + void *end = _jit_memory_get_function_end(func->context, func); #if defined(JIT_BACKEND_INTERP) /* Dump the interpreter's bytecode representation */ jit_function_interp_t interp; @@ -895,9 +896,9 @@ void jit_dump_function(FILE *stream, jit_function_t func, const char *name) (long)(jit_nint)interp, (long)(jit_nint)func, (int)(interp->args_size), (int)(interp->frame_size), (int)(interp->working_area)); - dump_interp_code(stream, (void **)(interp + 1), (void **)func->code_end); + dump_interp_code(stream, (void **)(interp + 1), (void **)end); #else - dump_object_code(stream, func->entry_point, func->code_end); + dump_object_code(stream, func->entry_point, end); #endif } diff --git a/jit/jit-internal.h b/jit/jit-internal.h index bf32490..6e42e40 100644 --- a/jit/jit-internal.h +++ b/jit/jit-internal.h @@ -490,11 +490,6 @@ struct _jit_function /* Flag set once the function is compiled */ int volatile is_compiled; - /* Start of the cache region */ - unsigned char *code_start; - /* End of the cache region */ - unsigned char *code_end; - /* The entry point for the function's compiled code */ void * volatile entry_point; @@ -605,6 +600,8 @@ int _jit_memory_ensure(jit_context_t context); void _jit_memory_destroy(jit_context_t context); jit_function_t _jit_memory_find_function(jit_context_t context, void *pc); +void *_jit_memory_get_function_start(jit_context_t context, jit_function_t func); +void *_jit_memory_get_function_end(jit_context_t context, jit_function_t func); jit_function_t _jit_memory_alloc_function(jit_context_t context); void _jit_memory_free_function(jit_context_t context, jit_function_t func); diff --git a/jit/jit-memory.c b/jit/jit-memory.c index b743361..8e8a25e 100644 --- a/jit/jit-memory.c +++ b/jit/jit-memory.c @@ -63,6 +63,20 @@ _jit_memory_find_function(jit_context_t context, void *pc) return context->memory_manager->find_function(context->memory_context, pc); } +void * +_jit_memory_get_function_start(jit_context_t context, jit_function_t func) +{ + /* TODO: read lock? */ + return context->memory_manager->get_function_start(context->memory_context, func); +} + +void * +_jit_memory_get_function_end(jit_context_t context, jit_function_t func) +{ + /* TODO: read lock? */ + return context->memory_manager->get_function_end(context->memory_context, func); +} + jit_function_t _jit_memory_alloc_function(jit_context_t context) { diff --git a/jit/jit-rules.c b/jit/jit-rules.c index 874f1cb..62337a6 100644 --- a/jit/jit-rules.c +++ b/jit/jit-rules.c @@ -740,11 +740,10 @@ int _jit_create_call_setup_insns void _jit_gen_check_space(jit_gencode_t gen, int space) { - if((gen->ptr + space) >= gen->limit) + if((gen->ptr + space) >= gen->mem_limit) { /* No space left on the current cache page. */ - gen->ptr = gen->limit; - jit_exception_builtin(JIT_RESULT_CACHE_FULL); + jit_exception_builtin(JIT_RESULT_MEMORY_FULL); } } @@ -756,9 +755,9 @@ _jit_gen_alloc(jit_gencode_t gen, unsigned long size) ptr = _jit_memory_alloc_data(gen->context, size, JIT_BEST_ALIGNMENT); if(!ptr) { - jit_exception_builtin(JIT_RESULT_CACHE_FULL); + jit_exception_builtin(JIT_RESULT_MEMORY_FULL); } - gen->limit = _jit_memory_get_limit(gen->context); + gen->mem_limit = _jit_memory_get_limit(gen->context); return ptr; } diff --git a/jit/jit-rules.h b/jit/jit-rules.h index bc023b8..ac1f6de 100644 --- a/jit/jit-rules.h +++ b/jit/jit-rules.h @@ -160,7 +160,10 @@ struct jit_gencode { jit_context_t context; /* Context this position is attached to */ unsigned char *ptr; /* Current code pointer */ - unsigned char *limit; /* Current code space limit */ + unsigned char *mem_start; /* Available space start */ + unsigned char *mem_limit; /* Available space limit */ + unsigned char *code_start; /* Real code start */ + unsigned char *code_end; /* Real code end */ jit_regused_t permanent; /* Permanently allocated global regs */ jit_regused_t touched; /* All registers that were touched */ jit_regused_t inhibit; /* Temporarily inhibited registers */