From: Aleksey Demakov Date: Wed, 3 Oct 2012 23:19:12 +0000 (+0400) Subject: tweak code cache API X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=e7547a603440183b9ae66e7c14065ee5138c172c;p=francis%2Flibjit.git tweak code cache API --- diff --git a/ChangeLog b/ChangeLog index 5f3b432..036b35d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2012-10-04 Aleksey Demakov + + * jit/jit-cache.h, jit/jit-cache.c (_jit_cache_start_function): + remove the restart_count argument. + * jit/jit-cache.h, jit/jit-cache.c (_jit_cache_extend): add + function to allocate more cache space. + * jit/jit-cache.c (_jit_cache_alloc_data): let be called outside + function generation context. + 2012-07-29 Aleksey Demakov * jit/jit-cache.h, jit/jit-cache.c (_jit_cache_start_function) diff --git a/jit/jit-cache.c b/jit/jit-cache.c index deaedd8..5ab3cab 100644 --- a/jit/jit-cache.c +++ b/jit/jit-cache.c @@ -118,7 +118,8 @@ struct jit_cache /* * Allocate a cache page and add it to the cache. */ -static void AllocCachePage(jit_cache_t cache, int factor) +static void +AllocCachePage(jit_cache_t cache, int factor) { long num; unsigned char *ptr; @@ -230,8 +231,8 @@ CacheCompare(jit_cache_t cache, unsigned char *key, jit_cache_method_t node) /* * Rotate a sub-tree around a specific node. */ -static jit_cache_method_t CacheRotate(jit_cache_t cache, unsigned char *key, - jit_cache_method_t around) +static jit_cache_method_t +CacheRotate(jit_cache_t cache, unsigned char *key, jit_cache_method_t around) { jit_cache_method_t child, grandChild; int setOnLeft; @@ -293,7 +294,8 @@ static jit_cache_method_t CacheRotate(jit_cache_t cache, unsigned char *key, * Add a method region block to the red-black lookup tree * that is associated with a method cache. */ -static void AddToLookupTree(jit_cache_t cache, jit_cache_method_t method) +static void +AddToLookupTree(jit_cache_t cache, jit_cache_method_t method) { unsigned char *key = method->func->code_start; jit_cache_method_t temp; @@ -354,27 +356,6 @@ static void AddToLookupTree(jit_cache_t cache, jit_cache_method_t method) SetBlack(cache->head.right); } -static unsigned char * -cache_alloc_data(jit_cache_t cache, unsigned long size, unsigned long align) -{ - unsigned char *ptr; - - /* Allocate memory from the top of the free region, so that it - does not overlap with the method code being written at the - bottom of the free region */ - ptr = cache->free_end - size; - ptr = (unsigned char *) (((jit_nuint) ptr) & ~((jit_nuint) align - 1)); - if(ptr < cache->free_start) - { - /* When we aligned the block, it caused an overflow */ - return 0; - } - - /* Allocate the block and return it */ - cache->free_end = ptr; - return ptr; -} - jit_cache_t _jit_cache_create(long limit, long cache_page_size, int max_page_factor) { @@ -468,45 +449,51 @@ _jit_cache_destroy(jit_cache_t cache) jit_free(cache); } -int -_jit_cache_start_function(jit_cache_t cache, jit_function_t func, int restart_count) +void +_jit_cache_extend(jit_cache_t cache, int count) { - /* Bail out if there is a started function already */ + /* Compute the page size factor */ + int factor = 1 << count; + + /* Bail out if there is a started function */ if(cache->method) { - return JIT_CACHE_ERROR; + return; } - /* Do we need to allocate a new cache page? */ - if(restart_count > 0) + /* If we had a newly allocated page then it has to be freed + to let allocate another new page of appropriate size. */ + struct jit_cache_page *p = &cache->pages[cache->numPages - 1]; + if((cache->free_start == ((unsigned char *)p->page)) + && (cache->free_end == (cache->free_start + cache->pageSize * p->factor))) { - /* Compute the page size factor */ - int factor = 1 << (restart_count - 1); + jit_free_exec(p->page, cache->pageSize * p->factor); - /* If we had a newly allocated page then it has to be freed - to let allocate another new page of appropriate size. */ - struct jit_cache_page *p = &cache->pages[cache->numPages - 1]; - if((cache->free_start == ((unsigned char *)p->page)) - && (cache->free_end == (cache->free_start + cache->pageSize * p->factor))) + --(cache->numPages); + if(cache->pagesLeft >= 0) { - jit_free_exec(p->page, cache->pageSize * p->factor); - - --(cache->numPages); - if(cache->pagesLeft >= 0) - { - cache->pagesLeft += p->factor; - } - cache->free_start = 0; - cache->free_end = 0; + cache->pagesLeft += p->factor; + } + cache->free_start = 0; + cache->free_end = 0; - if(factor <= p->factor) - { - factor = p->factor << 1; - } + if(factor <= p->factor) + { + factor = p->factor << 1; } + } - /* Allocate a new page now */ - AllocCachePage(cache, factor); + /* Allocate a new page now */ + AllocCachePage(cache, factor); +} + +int +_jit_cache_start_function(jit_cache_t cache, jit_function_t func) +{ + /* Bail out if there is a started function already */ + if(cache->method) + { + return JIT_CACHE_ERROR; } /* Bail out if the cache is already full */ @@ -519,15 +506,18 @@ _jit_cache_start_function(jit_cache_t cache, jit_function_t func, int restart_co cache->prev_start = cache->free_start; cache->prev_end = cache->free_end; - /* Allocate memory for the method information block */ - cache->method = (jit_cache_method_t) cache_alloc_data(cache, - sizeof(struct jit_cache_method), - JIT_BEST_ALIGNMENT); + /* Allocate memory for the function information block */ + cache->method = (jit_cache_method_t) + _jit_cache_alloc_data(cache, + sizeof(struct jit_cache_method), + JIT_BEST_ALIGNMENT); if(!cache->method) { /* There is insufficient space in this page */ return JIT_CACHE_RESTART; } + + /* Initialize the function information */ cache->method->func = func; cache->method->func->code_start = cache->free_start; cache->method->func->code_end = cache->free_start; @@ -591,7 +581,8 @@ _jit_cache_set_code_break(jit_cache_t cache, void *ptr) { return; } - if ((unsigned char *) ptr > cache->free_end) { + if ((unsigned char *) ptr > cache->free_end) + { return; } @@ -615,14 +606,22 @@ _jit_cache_get_code_limit(jit_cache_t cache) void * _jit_cache_alloc_data(jit_cache_t cache, unsigned long size, unsigned long align) { - /* Bail out if there is no started function */ - if(!cache->method) + unsigned char *ptr; + + /* Get memory from the top of the free region, so that it does not + overlap with the function code possibly being written at the bottom + of the free region */ + ptr = cache->free_end - size; + ptr = (unsigned char *) (((jit_nuint) ptr) & ~(align - 1)); + if(ptr < cache->free_start) { + /* When we aligned the block, it caused an overflow */ return 0; } /* Allocate the block and return it */ - return cache_alloc_data(cache, size, align); + cache->free_end = ptr; + return ptr; } void * diff --git a/jit/jit-cache.h b/jit/jit-cache.h index 13dfd38..016f004 100644 --- a/jit/jit-cache.h +++ b/jit/jit-cache.h @@ -1,5 +1,5 @@ /* - * jit-cache.h - Translated method cache implementation. + * jit-cache.h - Translated function cache implementation. * * Copyright (C) 2002, 2004, 2008 Southern Storm Software, Pty Ltd. * @@ -36,7 +36,7 @@ extern "C" { #define JIT_CACHE_ERROR 3 /* Other error */ /* - * Create a method cache. Returns NULL if out of memory. + * Create a code cache. Returns NULL if out of memory. * If "limit" is non-zero, then it specifies the maximum * size of the cache in bytes. If "cache_page_size" is * non-zero, then it indicates the dafault/minimum cache @@ -49,46 +49,76 @@ jit_cache_t _jit_cache_create(long limit, int max_page_factor); /* - * Destroy a method cache. + * Destroy a code cache. */ void _jit_cache_destroy(jit_cache_t cache); /* - * Start output of a function. The "restart_count" value should be - * equal to zero unless the method is being recompiled because it did - * not fit last time into the memory. In the later case the value - * should gradually increase until either the methods fits or the - * maximum restart_count value is exceeded. + * Request to allocate more code cache space. + * + * The "count" value should normally be zero except if just after the last + * call a function is being recompiled again because it is still too big + * to fit into the available cache space. In this case the "count" value + * should gradually increase. + */ +void _jit_cache_extend(jit_cache_t cache, int count); + +/* + * Start output of a function. */ -int _jit_cache_start_function(jit_cache_t cache, - jit_function_t func, - int restart_count); +int _jit_cache_start_function(jit_cache_t cache, jit_function_t func); /* - * End output of a function. Returns zero if a restart is needed. + * End output of a function. */ int _jit_cache_end_function(jit_cache_t cache, int result); /* - * Get the boundary between used and free code space. + * Get the start address of memory available for function code generation. + * + * This function is only called betweed _jit_cache_start_function() and + * corresponding _jit_cache_end_function() calls. + * + * Initially it should return the start address of the allocated memory. + * Then the address may be moved forward with _jit_cache_set_code_break() + * calls. */ void *_jit_cache_get_code_break(jit_cache_t cache); /* - * Set the boundary between used and free code space. + * Set the address of memory yet available for function code generation. + * + * This function is only called betweed _jit_cache_start_function() and + * corresponding _jit_cache_end_function() calls. + * + * The given address must be greater than or equal to its last value as + * returned by the _jit_cache_get_code_break() call and also less than or + * equal to the memory the address returned by _jit_cache_get_code_limit() + * call. + * + * This function is to be used in two cases. First, on the end of code + * generation just before the _jit_cache_end_function() call. Second, + * before allocating data with _jit_cache_alloc_data() calls. This lets + * the cache know how much space was actually used and how much is still + * free. */ void _jit_cache_set_code_break(jit_cache_t cache, void *ptr); /* - * Get the end address of the free code space. + * Get the end address of memory available for function code generation. + * + * This function is only called betweed _jit_cache_start_function() and + * corresponding _jit_cache_end_function() calls. + * + * The available memory may change if during code generation there were + * _jit_cache_alloc_data() calls. So after such calls available memory + * should be rechecked. */ void *_jit_cache_get_code_limit(jit_cache_t cache); /* - * Allocate "size" bytes of storage in the function cache's - * auxiliary data area. Returns NULL if insufficient space - * to satisfy the request. It may be possible to satisfy - * the request after a restart. + * Allocate "size" bytes of memory in the data area. Returns NULL if + * there is insufficient space to satisfy the request. */ void *_jit_cache_alloc_data(jit_cache_t cache, unsigned long size, @@ -98,8 +128,7 @@ void *_jit_cache_alloc_data(jit_cache_t cache, * Allocate "size" bytes of storage when we aren't currently * translating a method. */ -void *_jit_cache_alloc_no_method - (jit_cache_t cache, unsigned long size, unsigned long align); +void *_jit_cache_alloc_no_method(jit_cache_t cache, unsigned long size, unsigned long align); /* * Find the method that is associated with a particular diff --git a/jit/jit-compile.c b/jit/jit-compile.c index 6eb610d..3c648c9 100644 --- a/jit/jit-compile.c +++ b/jit/jit-compile.c @@ -463,15 +463,12 @@ cache_alloc(_jit_compile_t *state) int result; /* First try with the current cache page */ - result = _jit_cache_start_function(state->gen.cache, - state->func, - state->page_factor++); + result = _jit_cache_start_function(state->gen.cache, state->func); if(result == JIT_CACHE_RESTART) { /* No space left on the current cache page. Allocate a new one. */ - result = _jit_cache_start_function(state->gen.cache, - state->func, - state->page_factor++); + _jit_cache_extend(state->gen.cache, state->page_factor++); + result = _jit_cache_start_function(state->gen.cache, state->func); } if(result != JIT_CACHE_OK) { @@ -571,9 +568,8 @@ cache_realloc(_jit_compile_t *state) /* Allocate a new cache page with the size that grows by factor of 2 on each reallocation */ - result = _jit_cache_start_function(state->gen.cache, - state->func, - state->page_factor++); + _jit_cache_extend(state->gen.cache, state->page_factor++); + result = _jit_cache_start_function(state->gen.cache, state->func); if(result != JIT_CACHE_OK) { /* Failed to allocate enough cache space */