Browse Source

tweak code cache API

cache-refactoring
Aleksey Demakov 12 years ago
parent
commit
e7547a6034
  1. 9
      ChangeLog
  2. 121
      jit/jit-cache.c
  3. 71
      jit/jit-cache.h
  4. 14
      jit/jit-compile.c

9
ChangeLog

@ -1,3 +1,12 @@
2012-10-04 Aleksey Demakov <ademakov@gmail.com>
* 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 <ademakov@gmail.com> 2012-07-29 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-cache.h, jit/jit-cache.c (_jit_cache_start_function) * jit/jit-cache.h, jit/jit-cache.c (_jit_cache_start_function)

121
jit/jit-cache.c

@ -118,7 +118,8 @@ struct jit_cache
/* /*
* Allocate a cache page and add it to the 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; long num;
unsigned char *ptr; 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. * Rotate a sub-tree around a specific node.
*/ */
static jit_cache_method_t CacheRotate(jit_cache_t cache, unsigned char *key, static jit_cache_method_t
jit_cache_method_t around) CacheRotate(jit_cache_t cache, unsigned char *key, jit_cache_method_t around)
{ {
jit_cache_method_t child, grandChild; jit_cache_method_t child, grandChild;
int setOnLeft; 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 * Add a method region block to the red-black lookup tree
* that is associated with a method cache. * 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; unsigned char *key = method->func->code_start;
jit_cache_method_t temp; 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); 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_t
_jit_cache_create(long limit, long cache_page_size, int max_page_factor) _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); jit_free(cache);
} }
int void
_jit_cache_start_function(jit_cache_t cache, jit_function_t func, int restart_count) _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) if(cache->method)
{ {
return JIT_CACHE_ERROR; return;
} }
/* Do we need to allocate a new cache page? */ /* If we had a newly allocated page then it has to be freed
if(restart_count > 0) 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 */ jit_free_exec(p->page, cache->pageSize * p->factor);
int factor = 1 << (restart_count - 1);
/* If we had a newly allocated page then it has to be freed --(cache->numPages);
to let allocate another new page of appropriate size. */ if(cache->pagesLeft >= 0)
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)))
{ {
jit_free_exec(p->page, cache->pageSize * p->factor); cache->pagesLeft += p->factor;
}
--(cache->numPages); cache->free_start = 0;
if(cache->pagesLeft >= 0) cache->free_end = 0;
{
cache->pagesLeft += p->factor;
}
cache->free_start = 0;
cache->free_end = 0;
if(factor <= p->factor) if(factor <= p->factor)
{ {
factor = p->factor << 1; factor = p->factor << 1;
}
} }
}
/* Allocate a new page now */ /* Allocate a new page now */
AllocCachePage(cache, factor); 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 */ /* 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_start = cache->free_start;
cache->prev_end = cache->free_end; cache->prev_end = cache->free_end;
/* Allocate memory for the method information block */ /* Allocate memory for the function information block */
cache->method = (jit_cache_method_t) cache_alloc_data(cache, cache->method = (jit_cache_method_t)
sizeof(struct jit_cache_method), _jit_cache_alloc_data(cache,
JIT_BEST_ALIGNMENT); sizeof(struct jit_cache_method),
JIT_BEST_ALIGNMENT);
if(!cache->method) if(!cache->method)
{ {
/* There is insufficient space in this page */ /* There is insufficient space in this page */
return JIT_CACHE_RESTART; return JIT_CACHE_RESTART;
} }
/* Initialize the function information */
cache->method->func = func; cache->method->func = func;
cache->method->func->code_start = cache->free_start; cache->method->func->code_start = cache->free_start;
cache->method->func->code_end = 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; return;
} }
if ((unsigned char *) ptr > cache->free_end) { if ((unsigned char *) ptr > cache->free_end)
{
return; return;
} }
@ -615,14 +606,22 @@ _jit_cache_get_code_limit(jit_cache_t cache)
void * void *
_jit_cache_alloc_data(jit_cache_t cache, unsigned long size, unsigned long align) _jit_cache_alloc_data(jit_cache_t cache, unsigned long size, unsigned long align)
{ {
/* Bail out if there is no started function */ unsigned char *ptr;
if(!cache->method)
/* 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; return 0;
} }
/* Allocate the block and return it */ /* Allocate the block and return it */
return cache_alloc_data(cache, size, align); cache->free_end = ptr;
return ptr;
} }
void * void *

71
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. * Copyright (C) 2002, 2004, 2008 Southern Storm Software, Pty Ltd.
* *
@ -36,7 +36,7 @@ extern "C" {
#define JIT_CACHE_ERROR 3 /* Other error */ #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 * If "limit" is non-zero, then it specifies the maximum
* size of the cache in bytes. If "cache_page_size" is * size of the cache in bytes. If "cache_page_size" is
* non-zero, then it indicates the dafault/minimum cache * 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); int max_page_factor);
/* /*
* Destroy a method cache. * Destroy a code cache.
*/ */
void _jit_cache_destroy(jit_cache_t cache); void _jit_cache_destroy(jit_cache_t cache);
/* /*
* Start output of a function. The "restart_count" value should be * Request to allocate more code cache space.
* 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 * The "count" value should normally be zero except if just after the last
* should gradually increase until either the methods fits or the * call a function is being recompiled again because it is still too big
* maximum restart_count value is exceeded. * 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, int _jit_cache_start_function(jit_cache_t cache, jit_function_t func);
jit_function_t func,
int restart_count);
/* /*
* 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); 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); 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); 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); void *_jit_cache_get_code_limit(jit_cache_t cache);
/* /*
* Allocate "size" bytes of storage in the function cache's * Allocate "size" bytes of memory in the data area. Returns NULL if
* auxiliary data area. Returns NULL if insufficient space * there is insufficient space to satisfy the request.
* to satisfy the request. It may be possible to satisfy
* the request after a restart.
*/ */
void *_jit_cache_alloc_data(jit_cache_t cache, void *_jit_cache_alloc_data(jit_cache_t cache,
unsigned long size, 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 * Allocate "size" bytes of storage when we aren't currently
* translating a method. * translating a method.
*/ */
void *_jit_cache_alloc_no_method void *_jit_cache_alloc_no_method(jit_cache_t cache, unsigned long size, unsigned long align);
(jit_cache_t cache, unsigned long size, unsigned long align);
/* /*
* Find the method that is associated with a particular * Find the method that is associated with a particular

14
jit/jit-compile.c

@ -463,15 +463,12 @@ cache_alloc(_jit_compile_t *state)
int result; int result;
/* First try with the current cache page */ /* First try with the current cache page */
result = _jit_cache_start_function(state->gen.cache, result = _jit_cache_start_function(state->gen.cache, state->func);
state->func,
state->page_factor++);
if(result == JIT_CACHE_RESTART) if(result == JIT_CACHE_RESTART)
{ {
/* No space left on the current cache page. Allocate a new one. */ /* No space left on the current cache page. Allocate a new one. */
result = _jit_cache_start_function(state->gen.cache, _jit_cache_extend(state->gen.cache, state->page_factor++);
state->func, result = _jit_cache_start_function(state->gen.cache, state->func);
state->page_factor++);
} }
if(result != JIT_CACHE_OK) 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 /* Allocate a new cache page with the size that grows
by factor of 2 on each reallocation */ by factor of 2 on each reallocation */
result = _jit_cache_start_function(state->gen.cache, _jit_cache_extend(state->gen.cache, state->page_factor++);
state->func, result = _jit_cache_start_function(state->gen.cache, state->func);
state->page_factor++);
if(result != JIT_CACHE_OK) if(result != JIT_CACHE_OK)
{ {
/* Failed to allocate enough cache space */ /* Failed to allocate enough cache space */

Loading…
Cancel
Save