++2012-07-29 Aleksey Demakov <ademakov@gmail.com>
++
++ * jit/jit-cache.h, jit/jit-cache.c (_jit_cache_start_function)
++ (_jit_cache_end_function, _jit_cache_get_code_break)
++ (_jit_cache_set_code_break, _jit_cache_get_code_limit)
++ (_jit_cache_alloc_data): new API for function allocation.
++ * jit/jit-cache.h, jit/jit-cache.c (_jit_cache_is_full)
++ (_jit_cache_start_method, _jit_cache_end_method)
++ (_jit_cache_alloc, _jit_cache_check_space): remove.
++ * jit/jit-cache.h, jit/jit-rules.h: remove jit_cache_posn struct.
++ Store the cache position data in jit_gencode struct.
++ * jit/jit-rules.h, jit/jit-rules.c: (_jit_gen_check_space)
++ (_jit_gen_alloc): add.
++
+2012-02-11 Aleksey Demakov <ademakov@gmail.com>
+
+ * jit/jit-cache.h, jit/jit-cache.c (_jit_cache_end_method): add
+ result argument that indicates if the code genration will need
+ to be restarted.
+ * jit/jit-cache.h, jit/jit-cache.c (jit_cache_mark_full): remove
+ macro and replace it with direct jit_cache_posn access where
+ appropriate.
+ * jit/jit-cache.h, jit/jit-cache.c (jit_cache_get_posn): likewise.
+ * jit/jit-cache.h, jit/jit-rules-interp.c (jit_cache_native): move
+ macro to where it only used.
+ * jit/jit-cache.h, jit/jit-cache.c: remove other unused stuff.
+
+ 2012-01-22 Klaus Treichel <ktreichel@web.de>
+
+ * config/jit-opcodes.ops: Move declaration of obsolete opcodes to
+ the separate include file jit-opcode-compat.h and include this new
+ file instead.
+
+ * include/jit/jit-opcode-compat.h: add new include file for
+ obsolete opcodes.
+
+ * include/jit/Makefile.am: add jit-opcode-compat.h to the include
+ sources.
+
+2012-01-21 Aleksey Demakov <ademakov@gmail.com>
+
+ * jit/jit-rules.h (struct jit_gencode): add offset_encoder field
+ to encode bytecode offsets with jit_varints.
+
+ * jit/jit-internal.h (struct _jit_function): move fields cookie,
+ start, end here from jit_cache_method; add bytecode_offset field
+ to encode bytecode offsets with jit_varints.
+
+ * jit/jit-compile.c (mark_offset, _jit_function_get_bytecode): add
+ functions that use jit_varints for bytecode offset compression.
+
+ * jit/jit-cache.h, jit/jit-cache.c (_jit_cache_get_method):
+ remove cookie argument.
+
+ * jit/jit-cache.h, jit/jit-cache.c (_jit_cache_mark_bytecode)
+ (_jit_cache_set_cookie, _jit_cache_get_start_method)
+ (_jit_cache_get_end_method, _jit_cache_get_native)
+ (_jit_cache_get_bytecode, _jit_cache_get_size): remove functions,
+ get rid of bytecode offset compression and method region machinary.
+
+ * jit/jit-dump.c, jit/jit-function.c, jit/jit-rules-interp.c
+ * jit/jit-except.c, jit/jit-unwind.c: adjust where appropriate for
+ cache API change.
+
2011-12-18 Aleksey Demakov <ademakov@gmail.com>
* jit/Makefile.am:
unsigned long maxNumPages; /* Maximum number of pages that could be in the list */
unsigned long pageSize; /* Default size of a page for allocation */
unsigned int maxPageFactor; /* Maximum page size factor */
-- unsigned char *freeStart; /* Start of the current free region */
-- unsigned char *freeEnd; /* End of the current free region */
long pagesLeft; /* Number of pages left to allocate */
++ unsigned char *free_start; /* Current start of the free region */
++ unsigned char *free_end; /* Current end of the free region */
++ unsigned char *prev_start; /* Previous start of the free region */
++ unsigned char *prev_end; /* Previous end of the free region */
jit_cache_method_t method; /* Information for the current method */
struct jit_cache_method head; /* Head of the lookup tree */
struct jit_cache_method nil; /* Nil pointer for the lookup tree */
-- unsigned char *start; /* Start of the current method */
- unsigned char debugData[JIT_CACHE_DEBUG_SIZE];
- int debugLen; /* Length of temporary debug data */
- jit_cache_debug_t firstDebug; /* First debug block for method */
- jit_cache_debug_t lastDebug; /* Last debug block for method */
-
};
- * Compress a "long" value so that it takes up less bytes.
- * This is used to store offsets within functions and
- * debug line numbers, which are usually small integers.
- */
-static int CompressInt(unsigned char *buf, long data)
-{
- if(data >= 0)
- {
- if(data < (long)0x40)
- {
- buf[0] = (unsigned char)(data << 1);
- return 1;
- }
- else if(data < (long)(1 << 13))
- {
- buf[0] = (unsigned char)(((data >> 7) & 0x3F) | 0x80);
- buf[1] = (unsigned char)(data << 1);
- return 2;
- }
- else if(data < (long)(1L << 28))
- {
- buf[0] = (unsigned char)((data >> 23) | 0xC0);
- buf[1] = (unsigned char)(data >> 15);
- buf[2] = (unsigned char)(data >> 7);
- buf[3] = (unsigned char)(data << 1);
- return 4;
- }
- else
- {
- buf[0] = (unsigned char)0xE0;
- buf[1] = (unsigned char)(data >> 23);
- buf[2] = (unsigned char)(data >> 15);
- buf[3] = (unsigned char)(data >> 7);
- buf[4] = (unsigned char)(data << 1);
- return 5;
- }
- }
- else
- {
- if(data >= ((long)-0x40))
- {
- buf[0] = ((((unsigned char)(data << 1)) & 0x7E) | 0x01);
- return 1;
- }
- else if(data >= ((long)-(1 << 13)))
- {
- buf[0] = (unsigned char)(((data >> 7) & 0x3F) | 0x80);
- buf[1] = (unsigned char)((data << 1) | 0x01);
- return 2;
- }
- else if(data >= ((long)-(1L << 29)))
- {
- buf[0] = (unsigned char)(((data >> 23) & 0x1F) | 0xC0);
- buf[1] = (unsigned char)(data >> 15);
- buf[2] = (unsigned char)(data >> 7);
- buf[3] = (unsigned char)((data << 1) | 0x01);
- return 4;
- }
- else
- {
- buf[0] = (unsigned char)0xE1;
- buf[1] = (unsigned char)(data >> 23);
- buf[2] = (unsigned char)(data >> 15);
- buf[3] = (unsigned char)(data >> 7);
- buf[4] = (unsigned char)((data << 1) | 0x01);
- return 5;
- }
- }
-}
-
-/*
- * Control data structure that is used by "UncompressInt".
+ /*
-typedef struct
-{
- const unsigned char *data; /* Current data position */
- unsigned long len; /* Length remaining to read */
- int error; /* Set to non-zero if error encountered */
-
-} UncompressReader;
++ * Get or set the sub-trees of a node.
+ */
- * Uncompress a value that was compressed by "CompressInt".
++#define GetLeft(node) \
++ ((jit_cache_method_t)(((jit_nuint)(node)->left) & ~((jit_nuint)1)))
++#define GetRight(node) \
++ ((node)->right)
++#define SetLeft(node,value) \
++ ((node)->left = (jit_cache_method_t)(((jit_nuint)value) | \
++ (((jit_nuint)(node)->left) & ((jit_nuint)1))))
++#define SetRight(node,value) \
++ ((node)->right = (value))
+
+ /*
-static long UncompressInt(UncompressReader *meta)
-{
- unsigned char ch;
- unsigned char ch2;
- unsigned char ch3;
- unsigned char ch4;
- unsigned long value;
-
- if(meta->len > 0)
- {
- ch = *((meta->data)++);
- --(meta->len);
- if((ch & 0x80) == 0x00)
- {
- /* One-byte form of the item */
- if((ch & 0x01) == 0x00)
- return (long)(ch >> 1);
- else
- return (long)(signed char)((ch >> 1) | 0xC0);
- }
- else if((ch & 0xC0) == 0x80)
- {
- /* Two-byte form of the item */
- if(meta->len > 0)
- {
- --(meta->len);
- value = (((unsigned long)(ch & 0x3F)) << 8) |
- ((unsigned long)(*((meta->data)++)));
- if((value & 0x01) == 0x00)
- return (long)(value >> 1);
- else
- return (long)(jit_int)((value >> 1) | 0xFFFFE000);
- }
- else
- {
- meta->error = 1;
- return 0;
- }
- }
- else if((ch & 0xE0) == 0xC0)
- {
- /* Four-byte form of the item */
- if(meta->len >= 3)
- {
- ch2 = meta->data[0];
- ch3 = meta->data[1];
- ch4 = meta->data[2];
- meta->len -= 3;
- meta->data += 3;
- value = (((unsigned long)(ch & 0x1F)) << 24) |
- (((unsigned long)ch2) << 16) |
- (((unsigned long)ch3) << 8) |
- ((unsigned long)ch4);
- if((value & 0x01) == 0x00)
- return (long)(value >> 1);
- else
- return (long)(jit_int)((value >> 1) | 0xF0000000);
- }
- else
- {
- meta->len = 0;
- meta->error = 1;
- return 0;
- }
- }
- else
- {
- /* Five-byte form of the item */
- if(meta->len >= 4)
- {
- ch = meta->data[0];
- ch2 = meta->data[1];
- ch3 = meta->data[2];
- ch4 = meta->data[3];
- meta->len -= 4;
- meta->data += 4;
- value = (((unsigned long)ch) << 24) |
- (((unsigned long)ch2) << 16) |
- (((unsigned long)ch3) << 8) |
- ((unsigned long)ch4);
- return (long)(jit_int)value;
- }
- else
- {
- meta->len = 0;
- meta->error = 1;
- return 0;
- }
- }
- }
- else
- {
- meta->error = 1;
- return 0;
- }
-}
++ * Get or set the red/black state of a node.
+ */
++#define GetRed(node) \
++ ((((jit_nuint)((node)->left)) & ((jit_nuint)1)) != 0)
++#define SetRed(node) \
++ ((node)->left = (jit_cache_method_t)(((jit_nuint)(node)->left) | ((jit_nuint)1)))
++#define SetBlack(node) \
++ ((node)->left = (jit_cache_method_t)(((jit_nuint)(node)->left) & ~((jit_nuint)1)))
+
/*
* Allocate a cache page and add it to the cache.
*/
{
jit_free_exec(ptr, cache->pageSize * factor);
failAlloc:
-- cache->freeStart = 0;
-- cache->freeEnd = 0;
++ cache->free_start = 0;
++ cache->free_end = 0;
return;
}
}
/* Set up the working region within the new page */
-- cache->freeStart = ptr;
-- cache->freeEnd = ptr + (int) cache->pageSize * factor;
++ cache->free_start = ptr;
++ cache->free_end = ptr + (int) cache->pageSize * factor;
}
--/*
-- * Get or set the sub-trees of a node.
-- */
--#define GetLeft(node) \
-- ((jit_cache_method_t)(((jit_nuint)((node)->left)) & ~((jit_nuint)1)))
--#define GetRight(node) ((node)->right)
--#define SetLeft(node,value) \
-- ((node)->left = (jit_cache_method_t)(((jit_nuint)(value)) | \
-- (((jit_nuint)((node)->left)) & ((jit_nuint)1))))
--#define SetRight(node,value) \
-- ((node)->right = (value))
--
--/*
-- * Get or set the red/black state of a node.
-- */
--#define GetRed(node) \
-- ((((jit_nuint)((node)->left)) & ((jit_nuint)1)) != 0)
--#define SetRed(node) \
-- ((node)->left = (jit_cache_method_t)(((jit_nuint)((node)->left)) | \
-- ((jit_nuint)1)))
--#define SetBlack(node) \
-- ((node)->left = (jit_cache_method_t)(((jit_nuint)((node)->left)) & \
-- ~((jit_nuint)1)))
--
/*
* Compare a key against a node, being careful of sentinel nodes.
*/
--static int CacheCompare(jit_cache_t cache, unsigned char *key,
-- jit_cache_method_t node)
++static int
++CacheCompare(jit_cache_t cache, unsigned char *key, jit_cache_method_t node)
{
if(node == &(cache->nil) || node == &(cache->head))
{
else
{
/* Compare a regular node */
- if(key < node->func->start)
- if(key < node->start)
++ if(key < node->func->code_start)
{
return -1;
}
- else if(key > node->func->start)
- else if(key > node->start)
++ else if(key > node->func->code_start)
{
return 1;
}
*/
static void AddToLookupTree(jit_cache_t cache, jit_cache_method_t method)
{
- unsigned char *key = method->func->start;
- unsigned char *key = method->start;
++ unsigned char *key = method->func->code_start;
jit_cache_method_t temp;
jit_cache_method_t greatGrandParent;
jit_cache_method_t grandParent;
SetBlack(cache->head.right);
}
- jit_cache_t _jit_cache_create(long limit, long cache_page_size, int max_page_factor)
-/*
- * Flush the current debug buffer.
- */
-static void FlushCacheDebug(jit_cache_posn *posn)
++static unsigned char *
++cache_alloc_data(jit_cache_t cache, unsigned long size, unsigned long align)
+ {
- jit_cache_t cache = posn->cache;
- jit_cache_debug_t debug;
-
- /* Allocate a new jit_cache_debug structure to hold the data */
- debug = _jit_cache_alloc(posn,
- (unsigned long)(sizeof(struct jit_cache_debug) + cache->debugLen));
- if(!debug)
- {
- cache->debugLen = 0;
- return;
- }
-
- /* Copy the temporary debug data into the new structure */
- jit_memcpy(debug + 1, cache->debugData, cache->debugLen);
-
- /* Link the structure into the debug list */
- debug->next = 0;
- if(cache->lastDebug)
- {
- cache->lastDebug->next = debug;
- }
- else
- {
- cache->firstDebug = debug;
- }
- cache->lastDebug = debug;
-
- /* Reset the temporary debug buffer */
- cache->debugLen = 0;
-}
++ unsigned char *ptr;
+
-/*
- * Write a debug pair to the cache. The pair (-1, -1)
- * terminates the debug information for a method.
- */
-static void WriteCacheDebug(jit_cache_posn *posn, long offset, long nativeOffset)
-{
- jit_cache_t cache = posn->cache;
-
- /* Write the two values to the temporary debug buffer */
- cache->debugLen += CompressInt
- (cache->debugData + cache->debugLen, offset);
- cache->debugLen += CompressInt
- (cache->debugData + cache->debugLen, nativeOffset);
- if((cache->debugLen + 5 * 2 + 1) > (int)(sizeof(cache->debugData)))
++ /* 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)
+ {
- /* Overflow occurred: write -2 to mark the end of this buffer */
- cache->debugLen += CompressInt
- (cache->debugData + cache->debugLen, -2);
-
- /* Flush the debug data that we have collected so far */
- FlushCacheDebug(posn);
++ /* 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)
++jit_cache_t
++_jit_cache_create(long limit, long cache_page_size, int max_page_factor)
{
jit_cache_t cache;
unsigned long exec_page_size;
cache->maxNumPages = 0;
cache->pageSize = cache_page_size;
cache->maxPageFactor = max_page_factor;
-- cache->freeStart = 0;
-- cache->freeEnd = 0;
++ cache->free_start = 0;
++ cache->free_end = 0;
if(limit > 0)
{
cache->pagesLeft = limit / cache_page_size;
cache->pagesLeft = -1;
}
cache->method = 0;
- cache->nil.method = 0;
- cache->nil.cookie = 0;
- cache->nil.start = 0;
- cache->nil.end = 0;
- cache->nil.debug = 0;
+ cache->nil.func = 0;
cache->nil.left = &(cache->nil);
cache->nil.right = &(cache->nil);
- cache->head.method = 0;
- cache->head.cookie = 0;
- cache->head.start = 0;
- cache->head.end = 0;
- cache->head.debug = 0;
+ cache->head.func = 0;
cache->head.left = 0;
cache->head.right = &(cache->nil);
-- cache->start = 0;
- cache->debugLen = 0;
- cache->firstDebug = 0;
- cache->lastDebug = 0;
/* Allocate the initial cache page */
AllocCachePage(cache, 0);
-- if(!cache->freeStart)
++ if(!cache->free_start)
{
_jit_cache_destroy(cache);
return 0;
return cache;
}
--void _jit_cache_destroy(jit_cache_t cache)
++void
++_jit_cache_destroy(jit_cache_t cache)
{
unsigned long page;
jit_free(cache);
}
--int _jit_cache_is_full(jit_cache_t cache, jit_cache_posn *posn)
- {
- return (!cache->freeStart || (posn && posn->ptr >= posn->limit));
- }
-
- void
- _jit_cache_check_space(jit_cache_posn *posn, int space)
++int
++_jit_cache_start_function(jit_cache_t cache, jit_function_t func, int restart_count)
{
- if((posn->ptr + space) >= posn->limit)
- return (!cache->freeStart || (posn && posn->ptr >= posn->limit));
-}
-
-void
-_jit_cache_check_space(jit_cache_posn *posn, int space)
-{
- if(!jit_cache_check_for_n(posn, space))
++ /* Bail out if there is a started function already */
++ if(cache->method)
{
-- /* No space left on the current cache page. */
- posn->ptr = posn->limit;
- jit_cache_mark_full(posn);
-- jit_exception_builtin(JIT_RESULT_CACHE_FULL);
++ return JIT_CACHE_ERROR;
}
--}
--
--int _jit_cache_start_method(jit_cache_t cache,
-- jit_cache_posn *posn,
-- int page_factor,
-- int align,
- jit_function_t func)
- void *method)
--{
-- unsigned char *ptr;
/* Do we need to allocate a new cache page? */
-- if(page_factor > 0)
++ if(restart_count > 0)
{
-- AllocCachePage(cache, page_factor);
++ /* Compute the page size factor */
++ int factor = 1 << (restart_count - 1);
++
++ /* 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)))
++ {
++ 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;
++
++ if(factor <= p->factor)
++ {
++ factor = p->factor << 1;
++ }
++ }
++
++ /* Allocate a new page now */
++ AllocCachePage(cache, factor);
}
/* Bail out if the cache is already full */
-- if(!cache->freeStart)
++ if(!cache->free_start)
{
return JIT_CACHE_TOO_BIG;
}
-- /* Set up the initial cache position */
-- posn->cache = cache;
-- posn->ptr = cache->freeStart;
-- posn->limit = cache->freeEnd;
--
-- /* Align the method start */
-- ptr = posn->ptr;
-- if(align > 1)
-- {
-- ptr = (unsigned char *)(((jit_nuint) (ptr + align - 1)) & ~((jit_nuint) (align - 1)));
-- }
-- if(ptr >= posn->limit)
-- {
-- /* There is insufficient space in this page */
-- posn->ptr = posn->limit;
-- return JIT_CACHE_RESTART;
-- }
--#ifdef jit_should_pad
-- if(ptr > posn->ptr)
-- {
-- _jit_pad_buffer(posn->ptr, ptr - posn->ptr);
-- }
--#endif
-- posn->ptr = ptr;
++ /* Save the cache position */
++ 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) _jit_cache_alloc(posn, sizeof(struct jit_cache_method));
++ cache->method = (jit_cache_method_t) 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;
}
- cache->method->method = method;
- cache->method->cookie = 0;
- cache->method->start = posn->ptr;
- cache->method->end = posn->ptr;
- cache->method->debug = 0;
+ cache->method->func = func;
- cache->method->func->start = posn->ptr;
- cache->method->func->end = posn->ptr;
++ cache->method->func->code_start = cache->free_start;
++ cache->method->func->code_end = cache->free_start;
cache->method->left = 0;
cache->method->right = 0;
-- /* Store the method start address */
-- cache->start = posn->ptr;
-
- /* Clear the debug data */
- cache->debugLen = 0;
- cache->firstDebug = 0;
- cache->lastDebug = 0;
--
return JIT_CACHE_OK;
}
-int _jit_cache_end_method(jit_cache_posn *posn)
+int
- _jit_cache_end_method(jit_cache_posn *posn, int result)
++_jit_cache_end_function(jit_cache_t cache, int result)
{
-- jit_cache_t cache = posn->cache;
-- jit_cache_method_t method;
-- jit_cache_method_t next;
--
- if (result != JIT_CACHE_OK)
- /* Determine if we ran out of space while writing the method */
- if(posn->ptr >= posn->limit)
- {
- /* If we had a newly allocated page then it has to be freed
- to let allocate another new page of appropriate size. */
- if((cache->freeStart == ((unsigned char *)(cache->pages[cache->numPages - 1].page)))
- && (cache->freeEnd
- == (cache->freeStart + (cache->pageSize * cache->pages[cache->numPages - 1].factor))))
- {
- --(cache->numPages);
- jit_free_exec(cache->pages[cache->numPages].page,
- cache->pageSize * cache->pages[cache->numPages].factor);
- if (cache->pagesLeft >= 0)
- {
- cache->pagesLeft += cache->pages[cache->numPages].factor;
- }
- cache->freeStart = 0;
- cache->freeEnd = 0;
- }
- return JIT_CACHE_RESTART;
- }
-
- /* Terminate the debug information and flush it */
- if(cache->firstDebug || cache->debugLen)
++ /* Bail out if there is no started function */
++ if(!cache->method)
{
- /* mark cache page full */
- posn->ptr = posn->limit;
- WriteCacheDebug(posn, -1, -1);
- if(cache->debugLen)
- {
- FlushCacheDebug(posn);
- }
++ return JIT_CACHE_ERROR;
}
- /* Determine if we ran out of space while writing the method */
- if(posn->ptr >= posn->limit)
- /* Flush the position information back to the cache */
- cache->freeStart = posn->ptr;
- cache->freeEnd = posn->limit;
-
- /* Update the last method region block and then
- add all method regions to the lookup tree */
- method = cache->method;
- if(method)
++ /* Determine if we ran out of space while writing the function */
++ if(result != JIT_CACHE_OK || cache->free_start >= cache->free_end)
{
- /* If we had a newly allocated page then it has to be freed
- to let allocate another new page of appropriate size. */
- if((cache->freeStart == ((unsigned char *)(cache->pages[cache->numPages - 1].page)))
- && (cache->freeEnd
- == (cache->freeStart + (cache->pageSize * cache->pages[cache->numPages - 1].factor))))
- method->end = posn->ptr;
- do
-- {
- --(cache->numPages);
- jit_free_exec(cache->pages[cache->numPages].page,
- cache->pageSize * cache->pages[cache->numPages].factor);
- if (cache->pagesLeft >= 0)
- {
- cache->pagesLeft += cache->pages[cache->numPages].factor;
- }
- cache->freeStart = 0;
- cache->freeEnd = 0;
- method->debug = cache->firstDebug;
- next = method->right;
- AddToLookupTree(cache, method);
- method = next;
-- }
- while(method != 0);
++ /* Restore the saved cache position */
++ cache->free_start = cache->prev_start;
++ cache->free_end = cache->prev_end;
+ cache->method = 0;
+ return JIT_CACHE_RESTART;
}
- /* Flush the position information back to the cache */
- cache->freeStart = posn->ptr;
- cache->freeEnd = posn->limit;
++ /* Update the method region block and then add it to the lookup tree */
++ cache->method->func->code_end = cache->free_start;
++ AddToLookupTree(cache, cache->method);
++ cache->method = 0;
++
+ /* The method is ready to go */
+ return JIT_CACHE_OK;
+ }
- /* Update the last method region block and then
- add all method regions to the lookup tree */
- method = cache->method;
- if(method)
-void *_jit_cache_alloc(jit_cache_posn *posn, unsigned long size)
-{
- unsigned char *ptr;
-
- /* Bail out if the request is too big to ever be satisfiable */
- if(size > (unsigned long)(posn->limit - posn->ptr))
- {
- posn->ptr = posn->limit;
- return 0;
- }
-
- /* 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 = (unsigned char *)(((jit_nuint)(posn->limit - size)) &
- ~(((jit_nuint)JIT_BEST_ALIGNMENT) - 1));
- if(ptr < posn->ptr)
- {
- /* When we aligned the block, it caused an overflow */
- posn->ptr = posn->limit;
- return 0;
- }
-
- /* Allocate the block and return it */
- posn->limit = ptr;
- return (void *)ptr;
-}
-
-void *_jit_cache_alloc_no_method
- (jit_cache_t cache, unsigned long size, unsigned long align)
++void *
++_jit_cache_get_code_break(jit_cache_t cache)
+ {
- unsigned char *ptr;
-
- /* Bail out if the request is too big to ever be satisfiable */
- if(size > (unsigned long)(cache->freeEnd - cache->freeStart))
- {
- AllocCachePage(cache, 0);
- if(size > (unsigned long)(cache->freeEnd - cache->freeStart))
- {
- return 0;
- }
- }
-
- /* 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 = (unsigned char *)(((jit_nuint)(cache->freeEnd - size)) &
- ~(((jit_nuint)align) - 1));
- if(ptr < cache->freeStart)
++ /* Bail out if there is no started function */
++ if(!cache->method)
{
- method->func->end = posn->ptr;
- do
- {
- next = method->right;
- AddToLookupTree(cache, method);
- method = next;
- }
- while(method != 0);
- cache->method = 0;
- /* When we aligned the block, it caused an overflow */
+ return 0;
}
- /* The method is ready to go */
- return JIT_CACHE_OK;
- /* Allocate the block and return it */
- cache->freeEnd = ptr;
- return (void *)ptr;
++ /* Return the address of the available code area */
++ return cache->free_start;
}
- void *_jit_cache_alloc(jit_cache_posn *posn, unsigned long size)
-void _jit_cache_align(jit_cache_posn *posn, int align, int diff, int nop)
++void
++_jit_cache_set_code_break(jit_cache_t cache, void *ptr)
{
- unsigned char *ptr;
- jit_nuint current;
- jit_nuint next;
-
- /* Determine the location of the next alignment boundary */
- if(align <= 1)
- {
- align = 1;
- }
- current = (jit_nuint)(posn->ptr);
- next = (current + ((jit_nuint)align) - 1) &
- ~(((jit_nuint)align) - 1);
- if(current == next || (next - current) >= (jit_nuint)diff)
++ /* Bail out if there is no started function */
++ if(!cache->method)
+ {
+ return;
+ }
-
- /* Detect overflow of the free memory region */
- if(next > ((jit_nuint)(posn->limit)))
++ /* Sanity checks */
++ if ((unsigned char *) ptr < cache->free_start)
+ {
- posn->ptr = posn->limit;
+ return;
+ }
-
-#ifndef jit_should_pad
- /* Fill from "current" to "next" with nop bytes */
- while(current < next)
- {
- *((posn->ptr)++) = (unsigned char)nop;
- ++current;
++ if ((unsigned char *) ptr > cache->free_end) {
++ return;
+ }
-#else
- /* Use CPU-specific padding, because it may be more efficient */
- _jit_pad_buffer((unsigned char *)current, (int)(next - current));
-#endif
-}
- /* Bail out if the request is too big to ever be satisfiable */
- if(size > (unsigned long)(posn->limit - posn->ptr))
-void _jit_cache_mark_bytecode(jit_cache_posn *posn, unsigned long offset)
-{
- WriteCacheDebug(posn, (long)offset,
- (long)(posn->ptr - posn->cache->start));
++ /* Update the address of the available code area */
++ cache->free_start = ptr;
+ }
+
-void _jit_cache_set_cookie(jit_cache_posn *posn, void *cookie)
++void *
++_jit_cache_get_code_limit(jit_cache_t cache)
+ {
- if(posn->cache->method)
++ /* Bail out if there is no started function */
++ if(!cache->method)
{
- posn->ptr = posn->limit;
- posn->cache->method->cookie = cookie;
+ return 0;
}
-}
- /* 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 = (unsigned char *)(((jit_nuint)(posn->limit - size)) &
- ~(((jit_nuint)JIT_BEST_ALIGNMENT) - 1));
- if(ptr < posn->ptr)
-void *_jit_cache_get_method(jit_cache_t cache, void *pc, void **cookie)
-{
- jit_cache_method_t node = cache->head.right;
- while(node != &(cache->nil))
- {
- if(((unsigned char *)pc) < node->start)
- {
- node = GetLeft(node);
- }
- else if(((unsigned char *)pc) >= node->end)
- {
- node = GetRight(node);
- }
- else
- {
- if(cookie)
- {
- *cookie = node->cookie;
- }
- return node->method;
- }
- }
- return 0;
++ /* Return the end address of the available code area */
++ return cache->free_end;
+ }
+
-/*
- * Add a parent pointer to a list. Returns null if out of memory.
- */
-static int add_parent(jit_cache_method_t *parent_buf,
- jit_cache_method_t **parents,
- int *num_parents, int *max_parents,
- jit_cache_method_t node)
++void *
++_jit_cache_alloc_data(jit_cache_t cache, unsigned long size, unsigned long align)
+ {
- jit_cache_method_t *new_list;
- if(*num_parents >= *max_parents)
++ /* Bail out if there is no started function */
++ if(!cache->method)
{
- /* When we aligned the block, it caused an overflow */
- posn->ptr = posn->limit;
- if(*parents == parent_buf)
- {
- new_list = (jit_cache_method_t *)jit_malloc
- ((*max_parents * 2) * sizeof(jit_cache_method_t));
- if(new_list)
- {
- jit_memcpy(new_list, *parents,
- (*num_parents) * sizeof(jit_cache_method_t));
- }
- }
- else
- {
- new_list = (jit_cache_method_t *)jit_realloc
- (*parents, (*max_parents * 2) * sizeof(jit_cache_method_t));
- }
- if(!new_list)
- {
- return 0;
- }
- *parents = new_list;
- *max_parents *= 2;
+ return 0;
}
- (*parents)[*num_parents] = node;
- ++(*num_parents);
- return 1;
+
+ /* Allocate the block and return it */
- posn->limit = ptr;
- return (void *)ptr;
++ return cache_alloc_data(cache, size, align);
}
- void *_jit_cache_alloc_no_method
- (jit_cache_t cache, unsigned long size, unsigned long align)
-void *_jit_cache_get_start_method(jit_cache_t cache, void *pc)
++void *
++_jit_cache_alloc_no_method(jit_cache_t cache, unsigned long size, unsigned long align)
{
- /* TODO: This function is not currently aware of multiple regions. */
- jit_cache_method_t node = cache->head.right;
- while(node != &(cache->nil))
+ unsigned char *ptr;
+
++ /* Bail out if there is a started function */
++ if(cache->method)
+ {
- if(((unsigned char *)pc) < node->start)
- {
- node = GetLeft(node);
- }
- else if(((unsigned char *)pc) >= node->end)
- {
- node = GetRight(node);
- }
- else
- {
- return node->start;
- }
++ return 0;
+ }
- return 0;
-}
-
-void *_jit_cache_get_end_method(jit_cache_t cache, void *pc)
-{
- jit_cache_method_t parent_buf[16];
- jit_cache_method_t *parents = parent_buf;
- int num_parents = 0;
- int max_parents = 16;
- jit_cache_method_t node = cache->head.right;
- jit_cache_method_t last;
- jit_cache_method_t parent;
- void *method;
- while(node != &(cache->nil))
++ /* Bail out if there is no cache available */
++ if(!cache->free_start)
+ {
- if(((unsigned char *)pc) < node->start)
- {
- if(!add_parent(parent_buf, &parents, &num_parents,
- &max_parents, node))
- {
- break;
- }
- node = GetLeft(node);
- }
- else if(((unsigned char *)pc) >= node->end)
- {
- if(!add_parent(parent_buf, &parents, &num_parents,
- &max_parents, node))
- {
- break;
- }
- node = GetRight(node);
- }
- else
- {
- /* This is the node that contains the starting position.
- We now need to do an inorder traversal from this point
- to find the last node that mentions this method */
- method = node->method;
- last = node;
- do
- {
- if(GetRight(node) != &(cache->nil))
- {
- /* Move down the left-most sub-tree of the right */
- if(!add_parent(parent_buf, &parents, &num_parents,
- &max_parents, node))
- {
- goto failed;
- }
- node = GetRight(node);
- while(GetLeft(node) != &(cache->nil))
- {
- if(!add_parent(parent_buf, &parents, &num_parents,
- &max_parents, node))
- {
- goto failed;
- }
- node = GetLeft(node);
- }
- }
- else
- {
- /* Find a parent or other ancestor that contains this
- node within its left sub-tree */
- for(;;)
- {
- if(num_parents == 0)
- {
- node = 0;
- break;
- }
- parent = parents[--num_parents];
- if(GetLeft(parent) == node)
- {
- /* We are on our parent's left, so next is parent */
- node = parent;
- break;
- }
- node = parent;
- }
- if(!node)
- {
- /* We reached the root of the tree */
- break;
- }
- }
- if(node->method == method)
- {
- last = node;
- }
- }
- while(node->method == method);
- if(parents != parent_buf)
- {
- jit_free(parents);
- }
- return last->end;
- }
++ return 0;
+ }
-failed:
- if(parents != parent_buf)
+ /* Bail out if the request is too big to ever be satisfiable */
- if(size > (unsigned long)(cache->freeEnd - cache->freeStart))
++ if ((size + align - 1) > (cache->pageSize * cache->maxPageFactor))
{
- AllocCachePage(cache, 0);
- if(size > (unsigned long)(cache->freeEnd - cache->freeStart))
- jit_free(parents);
++ return 0;
+ }
- return 0;
-}
-
-/*
- * Temporary structure for iterating over a method's debug list.
- */
-typedef struct
-{
- jit_cache_debug_t list;
- UncompressReader reader;
+
-} jit_cache_debug_iter;
++ /* Allocate memory from the top of the current 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));
+
-/*
- * Initialize a debug information list iterator for a method.
- */
-static void InitDebugIter(jit_cache_debug_iter *iter,
- jit_cache_t cache, void *start)
-{
- jit_cache_method_t node = cache->head.right;
- while(node != &(cache->nil))
++ /* Do we need to allocate a new cache page? */
++ if(ptr < cache->free_start)
+ {
- if(((unsigned char *)start) < node->start)
- {
- node = GetLeft(node);
++ /* Find the appropriate page size */
++ int factor = 1;
++ while((size + align - 1) > (factor * cache->pageSize)) {
++ factor <<= 1;
+ }
- else if(((unsigned char *)start) >= node->end)
- {
- node = GetRight(node);
- }
- else
- {
- iter->list = node->debug;
- if(iter->list)
- {
- iter->reader.data = (unsigned char *)(iter->list + 1);
- iter->reader.len = JIT_CACHE_DEBUG_SIZE;
- iter->reader.error = 0;
- }
- return;
- }
- }
- iter->list = 0;
-}
+
-/*
- * Get the next debug offset pair from a debug information list.
- * Returns non-zero if OK, or zero at the end of the list.
- */
-static int GetNextDebug(jit_cache_debug_iter *iter, unsigned long *offset,
- unsigned long *nativeOffset)
-{
- long value;
- while(iter->list)
- {
- value = UncompressInt(&(iter->reader));
- if(value == -1)
++ /* Try to allocate it */
++ AllocCachePage(cache, factor);
++
++ /* Bail out if the cache is full */
++ if(!cache->free_start)
{
return 0;
}
- }
- else if(value != -2)
- {
- *offset = (unsigned long)value;
- *nativeOffset = (unsigned long)(UncompressInt(&(iter->reader)));
- return 1;
- }
- iter->list = iter->list->next;
- if(iter->list)
- {
- iter->reader.data = (unsigned char *)(iter->list + 1);
- iter->reader.len = JIT_CACHE_DEBUG_SIZE;
- iter->reader.error = 0;
- }
+
- /* 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 = (unsigned char *)(((jit_nuint)(cache->freeEnd - size)) &
- ~(((jit_nuint)align) - 1));
- if(ptr < cache->freeStart)
- {
- /* When we aligned the block, it caused an overflow */
- return 0;
++ /* Allocate memory from the new page */
++ ptr = cache->free_end - size;
++ ptr = (unsigned char *) (((jit_nuint) ptr) & ~((jit_nuint) align - 1));
}
-
- return 0;
++
+ /* Allocate the block and return it */
- cache->freeEnd = ptr;
++ cache->free_end = ptr;
+ return (void *)ptr;
}
-unsigned long _jit_cache_get_native(jit_cache_t cache, void *start,
- unsigned long offset, int exact)
+jit_function_t
+_jit_cache_get_method(jit_cache_t cache, void *pc)
{
- jit_cache_debug_iter iter;
- unsigned long ofs, nativeOfs;
- unsigned long prevNativeOfs = JIT_CACHE_NO_OFFSET;
-
- /* Search for the bytecode offset */
- InitDebugIter(&iter, cache, start);
- while(GetNextDebug(&iter, &ofs, &nativeOfs))
+ jit_cache_method_t node = cache->head.right;
+ while(node != &(cache->nil))
{
- if(((unsigned char *)pc) < node->func->start)
- if(exact)
++ if(((unsigned char *)pc) < node->func->code_start)
{
- if(ofs == offset)
- {
- return nativeOfs;
- }
+ node = GetLeft(node);
}
- else if(((unsigned char *)pc) >= node->func->end)
- else if(ofs > offset)
++ else if(((unsigned char *)pc) >= node->func->code_end)
{
- return prevNativeOfs;
- }
- prevNativeOfs = nativeOfs;
- }
-
- return exact ? JIT_CACHE_NO_OFFSET : prevNativeOfs;
-}
-
-unsigned long _jit_cache_get_bytecode(jit_cache_t cache, void *start,
- unsigned long offset, int exact)
-{
- jit_cache_debug_iter iter;
- unsigned long ofs, nativeOfs;
- unsigned long prevOfs = JIT_CACHE_NO_OFFSET;
-
- /* Search for the native offset */
- InitDebugIter(&iter, cache, start);
- while(GetNextDebug(&iter, &ofs, &nativeOfs))
- {
- if(exact)
- {
- if(nativeOfs == offset)
- {
- return ofs;
- }
+ node = GetRight(node);
}
- else if(nativeOfs > offset)
+ else
{
- return prevOfs;
+ return node->func;
}
- prevOfs = ofs;
}
-
- return exact ? JIT_CACHE_NO_OFFSET : prevOfs;
-}
-
-unsigned long _jit_cache_get_size(jit_cache_t cache)
-{
- return (cache->numPages * cache->pageSize) -
- (cache->freeEnd - cache->freeStart);
+ return 0;
}
/*
#endif
/*
-- * Opaque method cache type.
++ * Result values for "_jit_cache_start_function" and "_jit_cache_end_function".
*/
--typedef struct jit_cache *jit_cache_t;
--
--/*
-- * Writing position within a cache.
-- */
--typedef struct
--{
-- jit_cache_t cache; /* Cache this position is attached to */
-- unsigned char *ptr; /* Current code pointer */
-- unsigned char *limit; /* Limit of the current page */
--
--} jit_cache_posn;
++#define JIT_CACHE_OK 0 /* Function is OK */
++#define JIT_CACHE_RESTART 1 /* Restart is required */
++#define JIT_CACHE_TOO_BIG 2 /* Function is too big for the cache */
++#define JIT_CACHE_ERROR 3 /* Other error */
/*
* Create a method cache. Returns NULL if out of memory.
void _jit_cache_destroy(jit_cache_t cache);
/*
-- * Determine if the cache is full. The "posn" value should
-- * be supplied while translating a method, or be NULL otherwise.
++ * 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.
*/
--int _jit_cache_is_full(jit_cache_t cache, jit_cache_posn *posn);
++int _jit_cache_start_function(jit_cache_t cache,
++ jit_function_t func,
++ int restart_count);
/*
-- * Determine if there is sufficient space in the code cache.
-- * If not throws JIT_RESULT_CACHE_FULL exception.
++ * End output of a function. Returns zero if a restart is needed.
*/
--void _jit_cache_check_space(jit_cache_posn *posn, int space);
++int _jit_cache_end_function(jit_cache_t cache, int result);
/*
-- * Return values for "_jit_cache_start_method" and "_jit_cache_end_method".
++ * Get the boundary between used and free code space.
*/
--#define JIT_CACHE_OK 0 /* Function is OK */
--#define JIT_CACHE_RESTART 1 /* Restart is required */
--#define JIT_CACHE_TOO_BIG 2 /* Function is too big for the cache */
++void *_jit_cache_get_code_break(jit_cache_t cache);
/*
-- * Start output of a method, returning a cache position.
-- * The "page_factor" value should be equal to zero unless
-- * the method is being recompiled because it did not fit
-- * into the current page. In the later case the value
-- * should gradually increase until either the methods fits
-- * or the maximum page factor value is exceeded.
-- * The "align" value indicates the default alignment for
-- * the start of the method. The "cookie" value is a
-- * cookie for referring to the method. Returns the
-- * method entry point, or NULL if the cache is full.
++ * Set the boundary between used and free code space.
*/
--int _jit_cache_start_method(jit_cache_t cache,
-- jit_cache_posn *posn,
-- int page_factor,
-- int align,
- jit_function_t func);
- void *cookie);
++void _jit_cache_set_code_break(jit_cache_t cache, void *ptr);
/*
-- * End output of a method. Returns zero if a restart.
++ * Get the end address of the free code space.
*/
- int _jit_cache_end_method(jit_cache_posn *posn, int result);
-int _jit_cache_end_method(jit_cache_posn *posn);
++void *_jit_cache_get_code_limit(jit_cache_t cache);
/*
-- * Allocate "size" bytes of storage in the method cache's
-- * auxillary data area. Returns NULL if insufficient space
++ * 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.
*/
--void *_jit_cache_alloc(jit_cache_posn *posn, unsigned long size);
++void *_jit_cache_alloc_data(jit_cache_t cache,
++ unsigned long size,
++ unsigned long align);
/*
* Allocate "size" bytes of storage when we aren't currently
{
jit_function_t func;
-- jit_cache_t cache;
int cache_locked;
int cache_started;
return JIT_RESULT_OK;
}
- unsigned long native_offset = gen->posn.ptr - func->start;
+/*
+ * Mark the current position with a bytecode offset value.
+ */
+void
+mark_offset(jit_gencode_t gen, jit_function_t func, unsigned long offset)
+{
++ unsigned long native_offset = gen->ptr - func->code_start;
+ if(!_jit_varint_encode_uint(&gen->offset_encoder, (jit_uint) offset))
+ {
+ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
+ }
+ if(!_jit_varint_encode_uint(&gen->offset_encoder, (jit_uint) native_offset))
+ {
+ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
+ }
+}
+
/*
* Compile a single basic block within a function.
*/
{
#ifdef _JIT_COMPILE_DEBUG
unsigned char *p1, *p2;
-- p1 = gen->posn.ptr;
++ p1 = gen->ptr;
printf("Insn #%d: ", func->builder->insn_count++);
jit_dump_insn(stdout, func, insn);
printf("\nStart of binary code: 0x%08x\n", p1);
}
#ifdef _JIT_COMPILE_DEBUG
-- p2 = gen->posn.ptr;
++ p2 = gen->ptr;
printf("Length of binary code: %d\n\n", p2 - p1);
fflush(stdout);
#endif
state->cache_locked = 1;
/* Get the method cache */
-- state->cache = _jit_context_get_cache(state->func->context);
-- if(!state->cache)
++ state->gen.cache = _jit_context_get_cache(state->func->context);
++ if(!state->gen.cache)
{
jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
}
}
}
- * Allocate some space in the code cache.
+/*
- cache_alloc(_jit_compile_t *state)
++ * Align the method code on a particular boundary if the
++ * difference between the current position and the aligned
++ * boundary is less than "diff". The "nop" value is used
++ * to pad unused bytes.
+ */
+static void
- int result;
++cache_align(_jit_compile_t *state, int align, int diff, int nop)
+{
- /* First try with the current cache page */
- result = _jit_cache_start_method(state->cache,
- &state->gen.posn,
- state->page_factor++,
- JIT_FUNCTION_ALIGNMENT,
- state->func);
- if(result == JIT_CACHE_RESTART)
++ jit_nuint p, n;
+
- /* No space left on the current cache page. Allocate a new one. */
- result = _jit_cache_start_method(state->cache,
- &state->gen.posn,
- state->page_factor++,
- JIT_FUNCTION_ALIGNMENT,
- state->func);
++ /* Adjust the required alignment */
++ if(align < 1)
+ {
- if(result != JIT_CACHE_OK)
++ align = 1;
+ }
- /* Failed to allocate any cache space */
- jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
++
++ /* Determine the location of the next alignment boundary */
++ p = (jit_nuint) state->gen.ptr;
++ n = (p + (jit_nuint) align - 1) & ~((jit_nuint) align - 1);
++ if(p == n || (p - n) >= (jit_nuint) diff)
+ {
- /* Prepare the bytecode offset encoder */
- _jit_varint_init_encoder(&state->gen.offset_encoder);
++ return;
+ }
+
- /* On success remember the cache state */
- state->cache_started = 1;
++ /* Determine the actual alignment */
++ align = (int) (n - p);
+
- #if NOT_USED
++ /* Detect overflow of the free memory region */
++ _jit_gen_check_space(&state->gen, align);
++
++#ifdef jit_should_pad
++ /* Use CPU-specific padding, because it may be more efficient */
++ _jit_pad_buffer(state->gen.ptr, align);
++#else
++ jit_memset(state->gen.ptr, nop, align);
++ state->gen.ptr += align;
++#endif
+}
+
/*
- * Align the method code on a particular boundary if the
- * difference between the current position and the aligned
- * boundary is less than "diff". The "nop" value is used
- * to pad unused bytes.
+ * Allocate some space in the code cache.
*/
static void
- cache_align(jit_cache_posn *posn, int align, int diff, int nop)
+ cache_alloc(_jit_compile_t *state)
{
- jit_nuint current;
- jit_nuint next;
+ int result;
- /* Determine the location of the next alignment boundary */
- if(align <= 1)
+ /* First try with the current cache page */
- result = _jit_cache_start_method(state->cache,
- &state->gen.posn,
- state->page_factor++,
- JIT_FUNCTION_ALIGNMENT,
- state->func);
++ result = _jit_cache_start_function(state->gen.cache,
++ state->func,
++ state->page_factor++);
+ if(result == JIT_CACHE_RESTART)
{
- align = 1;
+ /* No space left on the current cache page. Allocate a new one. */
- result = _jit_cache_start_method(state->cache,
- &state->gen.posn,
- state->page_factor++,
- JIT_FUNCTION_ALIGNMENT,
- state->func);
++ result = _jit_cache_start_function(state->gen.cache,
++ state->func,
++ state->page_factor++);
}
- current = (jit_nuint)(posn->ptr);
- next = (current + ((jit_nuint)align) - 1) &
- ~(((jit_nuint)align) - 1);
- if(current == next || (next - current) >= (jit_nuint)diff)
+ if(result != JIT_CACHE_OK)
{
- return;
+ /* Failed to allocate any cache space */
+ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
}
- /* Detect overflow of the free memory region */
- if(next > ((jit_nuint)(posn->limit)))
- {
- posn->ptr = posn->limit;
- return;
- }
++ state->gen.ptr = _jit_cache_get_code_break(state->gen.cache);
++ state->gen.limit = _jit_cache_get_code_limit(state->gen.cache);
+
- #ifndef jit_should_pad
- /* Fill from "current" to "next" with nop bytes */
- while(current < next)
- {
- *((posn->ptr)++) = (unsigned char)nop;
- ++current;
- }
- #else
- /* Use CPU-specific padding, because it may be more efficient */
- _jit_pad_buffer((unsigned char *)current, (int)(next - current));
- #endif
- }
- #endif
++ /* 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;
+ }
/*
* End function output to the cache.
{
state->cache_started = 0;
++ /* Let the cache know where we are */
++ _jit_cache_set_code_break(state->gen.cache, state->gen.ptr);
++
/* End the function's output process */
- result = _jit_cache_end_method(&state->gen.posn, JIT_CACHE_OK);
- result = _jit_cache_end_method(&state->gen.posn);
++ result = _jit_cache_end_function(state->gen.cache, JIT_CACHE_OK);
if(result != JIT_CACHE_OK)
{
if(result == JIT_CACHE_RESTART)
{
state->cache_started = 0;
- /* Make sure that the _jit_cache_end_method() call below will
- release the currently held cache space rather than make it
- allocated permanently */
- jit_cache_mark_full(&state->gen.posn);
+ /* Release the cache space */
- _jit_cache_end_method(&state->gen.posn, JIT_CACHE_RESTART);
++ _jit_cache_end_function(state->gen.cache, JIT_CACHE_RESTART);
- /* Actually release the cache space */
- _jit_cache_end_method(&state->gen.posn);
+ /* Free encoded bytecode offset data */
+ _jit_varint_free_data(_jit_varint_get_data(&state->gen.offset_encoder));
}
}
/* Allocate a new cache page with the size that grows
by factor of 2 on each reallocation */
-- result = _jit_cache_start_method(state->cache,
-- &state->gen.posn,
-- state->page_factor,
-- JIT_FUNCTION_ALIGNMENT,
-- state->func);
++ result = _jit_cache_start_function(state->gen.cache,
++ state->func,
++ state->page_factor++);
if(result != JIT_CACHE_OK)
{
/* Failed to allocate enough cache space */
jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
}
- state->page_factor *= 2;
++ state->gen.ptr = _jit_cache_get_code_break(state->gen.cache);
++ state->gen.limit = _jit_cache_get_code_limit(state->gen.cache);
+
++ /* Align the function code. */
++ cache_align(state, JIT_FUNCTION_ALIGNMENT, JIT_FUNCTION_ALIGNMENT, 0);
- state->page_factor *= 2;
+ /* Prepare the bytecode offset encoder */
+ _jit_varint_init_encoder(&state->gen.offset_encoder);
/* On success remember the cache state */
state->cache_started = 1;
struct jit_gencode *gen = &state->gen;
jit_block_t block;
-- state->code_start = gen->posn.ptr;
++ state->code_start = gen->ptr;
#ifdef JIT_PROLOG_SIZE
/* Output space for the function prolog */
-- _jit_cache_check_space(&gen->posn, JIT_PROLOG_SIZE);
-- gen->posn.ptr += JIT_PROLOG_SIZE;
++ _jit_gen_check_space(gen, JIT_PROLOG_SIZE);
++ gen->ptr += JIT_PROLOG_SIZE;
#endif
/* Generate code for the blocks in the function */
/* Notify the back end that the block is finished */
_jit_gen_end_block(gen, block);
--
-- /* Stop code generation if the cache page is full */
-- if(_jit_cache_is_full(state->cache, &gen->posn))
-- {
-- /* No space left on the current cache page. Restart. */
-- jit_exception_builtin(JIT_RESULT_CACHE_FULL);
-- }
}
/* Output the function epilog. All return paths will jump to here */
_jit_gen_epilog(gen, func);
-- state->code_end = gen->posn.ptr;
++ state->code_end = gen->ptr;
#ifdef JIT_PROLOG_SIZE
/* Back-patch the function prolog and get the real entry point */
return func->entry_point;
}
- start = func->start;
+
+#define JIT_CACHE_NO_OFFSET (~((unsigned long)0))
+
+unsigned long
+_jit_function_get_bytecode(jit_function_t func, void *pc, int exact)
+{
+ unsigned long offset = JIT_CACHE_NO_OFFSET;
+ jit_cache_t cache;
+ void *start;
+ unsigned long native_offset;
+ jit_varint_decoder_t decoder;
+ jit_uint off, noff;
+
+ cache = _jit_context_get_cache(func->context);
+
+#ifdef JIT_PROLOG_SIZE
++ start = func->code_start;
+#else
+ start = func->entry_point;
+#endif
+
+ native_offset = pc - start;
+
+ _jit_varint_init_decoder(&decoder, func->bytecode_offset);
+ for(;;)
+ {
+ off = _jit_varint_decode_uint(&decoder);
+ noff = _jit_varint_decode_uint(&decoder);
+ if(_jit_varint_decode_end(&decoder))
+ {
+ if(exact)
+ {
+ offset = JIT_CACHE_NO_OFFSET;
+ }
+ break;
+ }
+ if(noff >= native_offset)
+ {
+ if(noff == native_offset)
+ {
+ offset = off;
+ }
+ else if (exact)
+ {
+ offset = JIT_CACHE_NO_OFFSET;
+ }
+ break;
+ }
+ offset = off;
+ }
+
+ return offset;
+}
(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->end);
- dump_interp_code(stream, (void **)(interp + 1), (void **)end);
++ dump_interp_code(stream, (void **)(interp + 1), (void **)func->code_end);
#else
- dump_object_code(stream, func->entry_point, func->end);
- dump_object_code(stream, func->entry_point, end);
++ dump_object_code(stream, func->entry_point, func->code_end);
#endif
}
#define JIT_ALIGN_NFLOAT _JIT_ALIGN_FOR_TYPE(nfloat)
#define JIT_ALIGN_PTR _JIT_ALIGN_FOR_TYPE(ptr)
++/*
++ * Opaque function cache type.
++ */
++typedef struct jit_cache *jit_cache_t;
++
/*
* Structure of a memory pool.
*/
/* Flag set once the function is compiled */
int volatile is_compiled;
- unsigned char *start;
+ /* Start of the cache region */
- unsigned char *end;
++ 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;
{
_jit_regs_assign(gen, regs);
_jit_regs_gen(gen, regs);
-- _jit_cache_check_space(&gen->posn, space);
++ _jit_gen_check_space(gen, space);
}
* Setup or teardown the alpha code output process.
*/
#define jit_cache_setup_output(needed) \
-- alpha_inst inst = (alpha_inst) gen->posn.ptr; \
-- _jit_cache_check_space(&gen->posn, (needed))
++ alpha_inst inst = (alpha_inst) gen->ptr; \
++ _jit_gen_check_space(gen, (needed))
#define jit_cache_end_output() \
-- gen->posn.ptr = (unsigned char*) inst
++ gen->ptr = (unsigned char*) inst
/*
* Load the instruction pointer from the generation context.
*/
#define jit_gen_load_inst_ptr(gen,inst) \
-- inst = (alpha_inst) (gen)->posn.ptr;
++ inst = (alpha_inst) (gen)->ptr;
/*
* Save the instruction pointer back to the generation context.
*/
#define jit_gen_save_inst_ptr(gen,inst) \
-- (gen)->posn.ptr = (unsigned char *) inst;
++ (gen)->ptr = (unsigned char *) inst;
static _jit_regclass_t *alpha_reg;
static _jit_regclass_t *alpha_freg;
void **fixup, **next;
/* Set the address of this block */
-- block->address = (void *)(gen->posn.ptr);
++ block->address = (void *)(gen->ptr);
/* If this block has pending fixups, then apply them now */
fixup = (void **)(block->fixup_list);
alpha_inst code = (alpha_inst) fixup;
next = (void **)(fixup[0]);
-- _alpha_li64(code,ALPHA_AT,(long int)(gen->posn.ptr));
++ _alpha_li64(code,ALPHA_AT,(long int)(gen->ptr));
alpha_jmp(code,ALPHA_ZERO,ALPHA_AT,1);
fixup = next;
*/
void *_jit_gen_redirector(jit_gencode_t gen, jit_function_t func) {
void *ptr, *entry;
-- alpha_inst inst = (alpha_inst) gen->posn.ptr;
++ alpha_inst inst = (alpha_inst) gen->ptr;
-- _jit_cache_check_space(&gen->posn, 8*6);
++ _jit_gen_check_space(gen, 8*6);
ptr = (void *)&(func->entry_point);
-- entry = gen->posn.ptr;
++ entry = gen->ptr;
alpha_call(inst, ptr);
_jit_pad_buffer((unsigned char*)inst,6); /* to be overwritten later with jmp */
-- (gen)->posn.ptr = (unsigned char*) inst;
++ (gen)->ptr = (unsigned char*) inst;
}
#endif /* JIT_BACKEND_ALPHA */
*/
#define jit_gen_load_inst_ptr(gen,inst) \
do { \
-- arm_inst_buf_init((inst), (gen)->posn.ptr, (gen)->posn.limit); \
++ arm_inst_buf_init((inst), (gen)->ptr, (gen)->limit); \
} while (0)
/*
*/
#define jit_gen_save_inst_ptr(gen,inst) \
do { \
-- (gen)->posn.ptr = (unsigned char *)arm_inst_get_posn(inst); \
++ (gen)->ptr = (unsigned char *)arm_inst_get_posn(inst); \
} while (0)
/*
static int flush_if_too_far(jit_gencode_t gen)
{
if(gen->first_constant_use &&
-- (((arm_inst_word *)(gen->posn.ptr)) -
++ (((arm_inst_word *)(gen->ptr)) -
((arm_inst_word *)(gen->first_constant_use))) >= 100)
{
flush_constants(gen, 0);
{
arm_inst_word *prev;
int value;
-- if(((unsigned char *)fixup) >= gen->posn.limit)
++ if(((unsigned char *)fixup) >= gen->limit)
{
/* The instruction buffer is full, so don't record this fixup */
return;
arm_inst_buf inst;
jit_gen_load_inst_ptr(gen, inst);
ptr = (void *)&(func->entry_point);
-- entry = gen->posn.ptr;
++ entry = gen->ptr;
arm_load_membase(inst, ARM_WORK, ARM_PC, 0);
arm_load_membase(inst, ARM_PC, ARM_WORK, 0);
arm_inst_add(inst, (unsigned int)ptr);
arm_inst_buf inst;
/* Set the address of this block */
-- block->address = (void *)(gen->posn.ptr);
++ block->address = (void *)(gen->ptr);
/* If this block has pending fixups, then apply them now */
fixup = (void **)(block->fixup_list);
_jit_regs_spill_all(gen);
_jit_gen_fix_value(insn->value1);
jit_gen_load_inst_ptr(gen, inst);
-- _jit_cache_check_space(&gen->posn, 128);
++ _jit_gen_check_space(gen, 128);
reg = _jit_reg_info[reg].cpu_reg;
inst = memory_copy(gen, inst, reg, (int)(insn->value2->address),
ARM_FP, insn->value1->frame_offset,
@*/
- #define jit_cache_native(posn,value) \
+/*
+ * Output a native word to the current method.
+ */
- _jit_cache_check_space((posn), sizeof(jit_nuint)); \
- *((jit_nuint *)((posn)->ptr)) = (jit_nuint)(value); \
- (posn)->ptr += sizeof(jit_nuint); \
++#define jit_cache_native(gen,value) \
+ do { \
++ _jit_gen_check_space((gen), sizeof(jit_nuint)); \
++ *((jit_nuint *)((gen)->ptr)) = (jit_nuint)(value); \
++ (gen)->ptr += sizeof(jit_nuint); \
+ } while (0)
+
/*
* Write an interpreter opcode to the cache.
*/
--#define jit_cache_opcode(posn,opcode) \
-- jit_cache_native((posn), (jit_nint)(opcode))
++#define jit_cache_opcode(gen,opcode) \
++ jit_cache_native((gen), (jit_nint)(opcode))
/*
* Write "n" bytes to the cache, rounded up to a multiple of "void *".
*/
--#define jit_cache_add_n(posn,buf,size) \
++#define jit_cache_add_n(gen,buf,size) \
do { \
unsigned int __size = \
((size) + sizeof(void *) - 1) & ~(sizeof(void *) - 1); \
-- _jit_cache_check_space((posn), __size); \
-- jit_memcpy((posn)->ptr, (buf), (size)); \
-- (posn)->ptr += __size; \
++ _jit_gen_check_space((gen), __size); \
++ jit_memcpy((gen)->ptr, (buf), (size)); \
++ (gen)->ptr += __size; \
} while (0)
/*
case JIT_TYPE_USHORT:
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDC_0_INT + index);
-- jit_cache_native(&(gen->posn), (jit_nint)(value->address));
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDC_0_INT + index);
++ jit_cache_native(gen, (jit_nint)(value->address));
break;
case JIT_TYPE_LONG:
{
jit_long long_value;
long_value = jit_value_get_long_constant(value);
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDC_0_LONG + index);
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDC_0_LONG + index);
#ifdef JIT_NATIVE_INT64
-- jit_cache_native(&(gen->posn), long_value);
++ jit_cache_native(gen, long_value);
#else
-- jit_cache_add_n(&(gen->posn), &long_value, sizeof(long_value));
++ jit_cache_add_n(gen, &long_value, sizeof(long_value));
#endif
break;
}
{
jit_float32 float32_value;
float32_value = jit_value_get_float32_constant(value);
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDC_0_FLOAT32 + index);
-- jit_cache_add_n(&(gen->posn), &float32_value, sizeof(float32_value));
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDC_0_FLOAT32 + index);
++ jit_cache_add_n(gen, &float32_value, sizeof(float32_value));
break;
}
{
jit_float64 float64_value;
float64_value = jit_value_get_float64_constant(value);
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDC_0_FLOAT64 + index);
-- jit_cache_add_n (&(gen->posn), &float64_value, sizeof(float64_value));
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDC_0_FLOAT64 + index);
++ jit_cache_add_n (gen, &float64_value, sizeof(float64_value));
break;
}
{
jit_nfloat nfloat_value;
nfloat_value = jit_value_get_nfloat_constant(value);
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDC_0_NFLOAT + index);
-- jit_cache_add_n (&(gen->posn), &nfloat_value, sizeof(nfloat_value));
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDC_0_NFLOAT + index);
++ jit_cache_add_n (gen, &nfloat_value, sizeof(nfloat_value));
break;
}
}
offset = -(value->frame_offset + 1);
}
-- jit_cache_opcode(&(gen->posn), opcode);
-- jit_cache_native(&(gen->posn), offset);
++ jit_cache_opcode(gen, opcode);
++ jit_cache_native(gen, offset);
}
}
opcode = _jit_store_opcode(JIT_INTERP_OP_STA_0_BYTE, 0, value->type);
offset = -(offset + 1);
}
-- jit_cache_opcode(&(gen->posn), opcode);
-- jit_cache_native(&(gen->posn), offset);
++ jit_cache_opcode(gen, opcode);
++ jit_cache_native(gen, offset);
}
/*@
/* Unconditional branch */
branch:
label = (jit_label_t)(insn->dest);
-- pc = (void **)(gen->posn.ptr);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ pc = (void **)(gen->ptr);
++ jit_cache_opcode(gen, insn->opcode);
block = jit_block_from_label(func, label);
if(!block)
{
if(block->address)
{
/* We already know the address of the block */
-- jit_cache_native(&(gen->posn), ((void **)(block->address)) - pc);
++ jit_cache_native(gen, ((void **)(block->address)) - pc);
}
else
{
/* Record this position on the block's fixup list */
-- jit_cache_native(&(gen->posn), block->fixup_list);
++ jit_cache_native(gen, block->fixup_list);
block->fixup_list = (void *)pc;
}
break;
labels = (jit_label_t *) insn->value1->address;
num_labels = insn->value2->address;
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), num_labels);
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, num_labels);
for(index = 0; index < num_labels; index++)
{
block = jit_block_from_label(func, labels[index]);
if(block->address)
{
/* We already know the address of the block */
-- jit_cache_native(&(gen->posn), block->address);
++ jit_cache_native(gen, block->address);
}
else
{
/* Record this position on the block's fixup list */
-- pc = (void **)(gen->posn.ptr);
-- jit_cache_native(&(gen->posn), block->fixup_absolute_list);
++ pc = (void **)(gen->ptr);
++ jit_cache_native(gen, block->fixup_absolute_list);
block->fixup_absolute_list = pc;
}
}
{
break;
}
-- pc = (void **)(gen->posn.ptr);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ pc = (void **)(gen->ptr);
++ jit_cache_opcode(gen, insn->opcode);
if(block->address)
{
/* We already know the address of the block */
-- jit_cache_native(&(gen->posn), ((void **)(block->address)) - pc);
++ jit_cache_native(gen, ((void **)(block->address)) - pc);
}
else
{
/* Record this position on the block's fixup list */
-- jit_cache_native(&(gen->posn), block->fixup_list);
++ jit_cache_native(gen, block->fixup_list);
block->fixup_list = (void *)pc;
}
store_value(gen, insn->dest);
case JIT_OP_CALL:
case JIT_OP_CALL_TAIL:
/* Call a function, whose pointer is supplied explicitly */
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), (jit_nint)(insn->dest));
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, (jit_nint)(insn->dest));
break;
case JIT_OP_CALL_INDIRECT:
case JIT_OP_CALL_INDIRECT_TAIL:
/* Call a function, whose pointer is supplied in the register */
load_value(gen, insn->value1, 1);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), (jit_nint)(insn->value2));
-- jit_cache_native(&(gen->posn), (jit_nint)
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, (jit_nint)(insn->value2));
++ jit_cache_native(gen, (jit_nint)
(jit_type_num_params((jit_type_t)(insn->value2))));
break;
case JIT_OP_CALL_VTABLE_PTR_TAIL:
/* Call a function, whose vtable pointer is supplied in the register */
load_value(gen, insn->value1, 1);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ jit_cache_opcode(gen, insn->opcode);
break;
case JIT_OP_CALL_EXTERNAL:
case JIT_OP_CALL_EXTERNAL_TAIL:
/* Call a native function, whose pointer is supplied explicitly */
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), (jit_nint)(insn->value2));
-- jit_cache_native(&(gen->posn), (jit_nint)(insn->dest));
-- jit_cache_native(&(gen->posn), (jit_nint)
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, (jit_nint)(insn->value2));
++ jit_cache_native(gen, (jit_nint)(insn->dest));
++ jit_cache_native(gen, (jit_nint)
(jit_type_num_params((jit_type_t)(insn->value2))));
break;
case JIT_OP_RETURN:
/* Return from the current function with no result */
-- jit_cache_opcode(&(gen->posn), JIT_OP_RETURN);
++ jit_cache_opcode(gen, JIT_OP_RETURN);
break;
case JIT_OP_RETURN_INT:
case JIT_OP_RETURN_NFLOAT:
/* Return from the current function with a specific result */
load_value(gen, insn->value1, 1);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ jit_cache_opcode(gen, insn->opcode);
break;
case JIT_OP_RETURN_SMALL_STRUCT:
/* Return from current function with a small structure result */
load_value(gen, insn->value1, 1);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), jit_value_get_nint_constant(insn->value2));
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, jit_value_get_nint_constant(insn->value2));
break;
case JIT_OP_SETUP_FOR_NESTED:
/* TODO!!! */
/* Set up to call a nested child */
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ jit_cache_opcode(gen, insn->opcode);
adjust_working(gen, 2);
break;
case JIT_OP_SETUP_FOR_SIBLING:
/* TODO!!! */
/* Set up to call a nested sibling */
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn),
-- jit_value_get_nint_constant(insn->value1));
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, jit_value_get_nint_constant(insn->value1));
adjust_working(gen, 2);
break;
_jit_gen_fix_value(insn->value1);
if(insn->value1->frame_offset >= 0)
{
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_IMPORT_LOCAL);
-- jit_cache_native(&(gen->posn), insn->value1->frame_offset);
-- jit_cache_native(&(gen->posn), jit_value_get_nint_constant(insn->value2));
++ jit_cache_opcode(gen, JIT_INTERP_OP_IMPORT_LOCAL);
++ jit_cache_native(gen, insn->value1->frame_offset);
++ jit_cache_native(gen, jit_value_get_nint_constant(insn->value2));
}
else
{
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_IMPORT_ARG);
-- jit_cache_native(&(gen->posn), -(insn->value1->frame_offset + 1));
-- jit_cache_native(&(gen->posn), jit_value_get_nint_constant(insn->value2));
++ jit_cache_opcode(gen, JIT_INTERP_OP_IMPORT_ARG);
++ jit_cache_native(gen, -(insn->value1->frame_offset + 1));
++ jit_cache_native(gen, jit_value_get_nint_constant(insn->value2));
}
store_value(gen, insn->dest);
break;
case JIT_OP_THROW:
/* Throw an exception */
load_value(gen, insn->value1, 1);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ jit_cache_opcode(gen, insn->opcode);
break;
case JIT_OP_LOAD_PC:
case JIT_OP_LOAD_EXCEPTION_PC:
/* Load the current program counter onto the stack */
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ jit_cache_opcode(gen, insn->opcode);
store_value(gen, insn->dest);
break;
case JIT_OP_LEAVE_FINALLY:
/* Leave a finally clause */
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ jit_cache_opcode(gen, insn->opcode);
break;
case JIT_OP_ENTER_FILTER:
case JIT_OP_LEAVE_FILTER:
/* Leave a filter clause, returning a particular value */
load_value(gen, insn->value1, 0);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ jit_cache_opcode(gen, insn->opcode);
break;
case JIT_OP_INCOMING_REG:
case JIT_TYPE_USHORT:
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDR_0_INT);
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDR_0_INT);
store_value(gen, insn->value1);
break;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDR_0_LONG);
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDR_0_LONG);
store_value(gen, insn->value1);
break;
case JIT_TYPE_FLOAT32:
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDR_0_FLOAT32);
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDR_0_FLOAT32);
store_value(gen, insn->value1);
break;
case JIT_TYPE_FLOAT64:
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDR_0_FLOAT64);
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDR_0_FLOAT64);
store_value(gen, insn->value1);
break;
case JIT_TYPE_NFLOAT:
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDR_0_NFLOAT);
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDR_0_NFLOAT);
store_value(gen, insn->value1);
break;
}
load_value(gen, insn->dest, 0);
load_value(gen, insn->value1, 1);
size = (jit_nint)jit_type_get_size(jit_value_get_type(insn->dest));
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), size);
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, size);
break;
case JIT_OP_ADDRESS_OF:
_jit_gen_fix_value(insn->value1);
if(insn->value1->frame_offset >= 0)
{
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDLA_0);
-- jit_cache_native(&(gen->posn), insn->value1->frame_offset);
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDLA_0);
++ jit_cache_native(gen, insn->value1->frame_offset);
}
else
{
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_LDAA_0);
-- jit_cache_native(&(gen->posn), -(insn->value1->frame_offset + 1));
++ jit_cache_opcode(gen, JIT_INTERP_OP_LDAA_0);
++ jit_cache_native(gen, -(insn->value1->frame_offset + 1));
}
store_value(gen, insn->dest);
break;
case JIT_OP_PUSH_NFLOAT:
/* Push an item onto the stack, ready for a function call */
load_value(gen, insn->value1, 1);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ jit_cache_opcode(gen, insn->opcode);
adjust_working(gen, 1);
break;
load_value(gen, insn->value1, 1);
/* Push the structure at the designated pointer */
size = jit_value_get_nint_constant(insn->value2);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), size);
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, size);
adjust_working(gen, JIT_NUM_ITEMS_IN_STRUCT(size));
break;
case JIT_OP_PUSH_RETURN_AREA_PTR:
/* Push the address of the interpreter's return area */
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ jit_cache_opcode(gen, insn->opcode);
adjust_working(gen, 1);
break;
size = jit_value_get_nint_constant(insn->value1);
if(size == 1)
{
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_POP);
++ jit_cache_opcode(gen, JIT_INTERP_OP_POP);
}
else if(size == 2)
{
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_POP_2);
++ jit_cache_opcode(gen, JIT_INTERP_OP_POP_2);
}
else if(size == 3)
{
-- jit_cache_opcode(&(gen->posn), JIT_INTERP_OP_POP_3);
++ jit_cache_opcode(gen, JIT_INTERP_OP_POP_3);
}
else if(size != 0)
{
-- jit_cache_opcode(&(gen->posn), JIT_OP_POP_STACK);
-- jit_cache_native(&(gen->posn), size);
++ jit_cache_opcode(gen, JIT_OP_POP_STACK);
++ jit_cache_native(gen, size);
}
break;
/* Flush a small structure return value back into the frame */
load_value(gen, insn->value1, 0);
size = (jit_nint)jit_type_get_size(jit_value_get_type(insn->value1));
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), size);
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, size);
break;
case JIT_OP_LOAD_RELATIVE_SBYTE:
/* Load a value from a relative pointer */
load_value(gen, insn->value1, 1);
offset = jit_value_get_nint_constant(insn->value2);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), offset);
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, offset);
store_value(gen, insn->dest);
break;
load_value(gen, insn->value1, 1);
offset = jit_value_get_nint_constant(insn->value2);
size = (jit_nint)jit_type_get_size(jit_value_get_type(insn->dest));
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), offset);
-- jit_cache_native(&(gen->posn), size);
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, offset);
++ jit_cache_native(gen, size);
break;
case JIT_OP_STORE_RELATIVE_BYTE:
load_value(gen, insn->dest, 0);
load_value(gen, insn->value1, 1);
offset = jit_value_get_nint_constant(insn->value2);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), offset);
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, offset);
break;
case JIT_OP_STORE_RELATIVE_STRUCT:
load_value(gen, insn->value1, 1);
offset = jit_value_get_nint_constant(insn->value2);
size = (jit_nint)jit_type_get_size(jit_value_get_type(insn->value1));
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), offset);
-- jit_cache_native(&(gen->posn), size);
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, offset);
++ jit_cache_native(gen, size);
break;
case JIT_OP_ADD_RELATIVE:
if(offset != 0)
{
load_value(gen, insn->value1, 1);
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), offset);
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, offset);
store_value(gen, insn->dest);
}
else
case JIT_OP_MARK_BREAKPOINT:
/* Mark the current location as a potential breakpoint */
-- jit_cache_opcode(&(gen->posn), insn->opcode);
-- jit_cache_native(&(gen->posn), insn->value1->address);
-- jit_cache_native(&(gen->posn), insn->value2->address);
++ jit_cache_opcode(gen, insn->opcode);
++ jit_cache_native(gen, insn->value1->address);
++ jit_cache_native(gen, insn->value2->address);
break;
default:
{
load_value(gen, insn->value2, 2);
}
-- jit_cache_opcode(&(gen->posn), insn->opcode);
++ jit_cache_opcode(gen, insn->opcode);
if(insn->dest && (insn->flags & JIT_INSN_DEST_IS_VALUE) == 0)
{
store_value(gen, insn->dest);
void **next;
/* Set the address of this block */
-- block->address = (void *)(gen->posn.ptr);
++ block->address = (void *)(gen->ptr);
/* If this block has pending fixups, then apply them now */
fixup = (void **)(block->fixup_list);
/*
* Setup or teardown the x86 code output process.
*/
--#define jit_cache_setup_output(needed) \
-- unsigned char *inst = gen->posn.ptr; \
-- _jit_cache_check_space(&gen->posn, (needed))
++#define jit_cache_setup_output(needed) \
++ unsigned char *inst = gen->ptr; \
++ _jit_gen_check_space(gen, (needed))
#define jit_cache_end_output() \
-- gen->posn.ptr = inst
++ gen->ptr = inst
/*
* Set this to 1 for debugging fixups
unsigned char *inst;
inst = *inst_ptr;
-- ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float32));
++ ptr = _jit_gen_alloc(gen, sizeof(jit_float32));
if(!ptr)
{
return 0;
unsigned char *inst;
inst = *inst_ptr;
-- ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float64));
++ ptr = _jit_gen_alloc(gen, sizeof(jit_float64));
if(!ptr)
{
return 0;
unsigned char *inst;
inst = *inst_ptr;
-- ptr = _jit_cache_alloc(&(gen->posn), 16);
++ ptr = _jit_gen_alloc(gen, 16);
if(!ptr)
{
return 0;
unsigned char *inst;
inst = *inst_ptr;
-- ptr = _jit_cache_alloc(&(gen->posn), 16);
++ ptr = _jit_gen_alloc(gen, 16);
if(!ptr)
{
return 0;
floating-point register whose value hasn't been used yet */
if(!value_used && IS_FPU_REG(reg))
{
-- _jit_cache_check_space(&gen->posn, 2);
-- x86_fstp(gen->posn.ptr, reg - X86_64_REG_ST0);
++ _jit_gen_check_space(gen, 2);
++ x86_fstp(gen->ptr, reg - X86_64_REG_ST0);
}
}
if(is_double)
{
-- ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float64));
++ ptr = _jit_gen_alloc(gen, sizeof(jit_float64));
if(!ptr)
{
return 0;
}
else
{
-- ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float32));
++ ptr = _jit_gen_alloc(gen, sizeof(jit_float32));
if(!ptr)
{
return 0;
{
jit_nint offset;
-- ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float32));
++ ptr = _jit_gen_alloc(gen, sizeof(jit_float32));
jit_memcpy(ptr, &float32_value, sizeof(float32_value));
offset = (jit_nint)ptr - ((jit_nint)inst + 6);
{
jit_nint offset;
-- ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float64));
++ ptr = _jit_gen_alloc(gen, sizeof(jit_float64));
jit_memcpy(ptr, &float64_value, sizeof(float64_value));
offset = (jit_nint)ptr - ((jit_nint)inst + 6);
jit_nint offset;
int xmm_reg = _jit_reg_info[reg].cpu_reg;
-- ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_nfloat));
++ ptr = _jit_gen_alloc(gen, sizeof(jit_nfloat));
jit_memcpy(ptr, &nfloat_value, sizeof(nfloat_value));
offset = (jit_nint)ptr -
((jit_nint)inst + (xmm_reg > 7 ? 9 : 8));
{
jit_nint offset;
-- ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_nfloat));
++ ptr = _jit_gen_alloc(gen, sizeof(jit_nfloat));
jit_memcpy(ptr, &nfloat_value, sizeof(nfloat_value));
offset = (jit_nint)ptr - ((jit_nint)inst + 6);
jit_int *next;
/* Bail out if there is insufficient space for the epilog */
-- _jit_cache_check_space(&gen->posn, 48);
++ _jit_gen_check_space(gen, 48);
-- inst = gen->posn.ptr;
++ inst = gen->ptr;
/* Perform fixups on any blocks that jump to the epilog */
fixup = (jit_int *)(gen->epilog_fixup);
/* and return */
x86_64_ret(inst);
-- gen->posn.ptr = inst;
++ gen->ptr = inst;
}
/*
void **absolute_next;
/* Set the address of this block */
-- block->address = (void *)(gen->posn.ptr);
++ block->address = (void *)(gen->ptr);
/* If this block has pending fixups, then apply them now */
fixup = (jit_int *)(block->fixup_list);
labels = (jit_label_t *) $2;
num_labels = $3;
-- patch_jump_table = (unsigned char *)_jit_cache_alloc(&(gen->posn),
-- sizeof(void *) * $3);
++ patch_jump_table = (unsigned char *)_jit_gen_alloc(gen, sizeof(void *) * $3);
if(!patch_jump_table)
{
/* The cache is full */
void **next;
/* Check if there is sufficient space for the epilog */
-- _jit_cache_check_space(&gen->posn, 48);
++ _jit_gen_check_space(gen, 48);
#if JIT_APPLY_X86_FASTCALL == 1
/* Determine the number of parameter bytes to pop when we return */
#endif
/* Perform fixups on any blocks that jump to the epilog */
-- inst = gen->posn.ptr;
++ inst = gen->ptr;
fixup = (void **)(gen->epilog_fixup);
while(fixup != 0)
{
{
x86_ret(inst);
}
-- gen->posn.ptr = inst;
++ gen->ptr = inst;
}
#if 0
void *_jit_gen_redirector(jit_gencode_t gen, jit_function_t func)
{
void *ptr, *entry;
-- _jit_cache_check_space(&gen->posn, 8);
++ _jit_gen_check_space(gen, 8);
ptr = (void *)&(func->entry_point);
-- entry = gen->posn.ptr;
-- x86_jump_mem(gen->posn.ptr, ptr);
++ entry = gen->ptr;
++ x86_jump_mem(gen->ptr, ptr);
return entry;
}
#endif
* Setup or teardown the x86 code output process.
*/
#define jit_cache_setup_output(needed) \
-- unsigned char *inst = gen->posn.ptr; \
-- _jit_cache_check_space(&gen->posn, (needed))
++ unsigned char *inst = gen->ptr; \
++ _jit_gen_check_space(gen, (needed))
#define jit_cache_end_output() \
-- gen->posn.ptr = inst
++ gen->ptr = inst
/*
* Get a temporary register that isn't one of the specified registers.
floating-point register whose value hasn't been used yet */
if(!value_used && IS_FLOAT_REG(reg))
{
-- _jit_cache_check_space(&gen->posn, 2);
-- x86_fstp(gen->posn.ptr, reg - X86_REG_ST0);
++ _jit_gen_check_space(gen, 2);
++ x86_fstp(gen->ptr, reg - X86_REG_ST0);
}
}
}
else
{
-- ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float32));
++ ptr = _jit_gen_alloc(gen, sizeof(jit_float32));
jit_memcpy(ptr, &float32_value, sizeof(float32_value));
x86_fld(inst, ptr, 0);
}
}
else
{
-- ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float64));
++ ptr = _jit_gen_alloc(gen, sizeof(jit_float64));
jit_memcpy(ptr, &float64_value, sizeof(float64_value));
x86_fld(inst, ptr, 1);
}
}
else
{
-- ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_nfloat));
++ ptr = _jit_gen_alloc(gen, sizeof(jit_nfloat));
jit_memcpy(ptr, &nfloat_value, sizeof(nfloat_value));
if(sizeof(jit_nfloat) == sizeof(jit_float64))
{
void **next;
/* Set the address of this block */
-- block->address = (void *)(gen->posn.ptr);
++ block->address = (void *)(gen->ptr);
/* If this block has pending fixups, then apply them now */
fixup = (void **)(block->fixup_list);
}
while(level > 0)
{
-- gen->posn.ptr = inst;
-- _jit_cache_check_space(&gen->posn, 16);
++ gen->ptr = inst;
++ _jit_gen_check_space(gen, 16);
x86_mov_reg_membase(inst, cpu_reg, cpu_reg, 0, sizeof(void *));
--level;
}
_jit_gen_fix_value(insn->value1);
reg = _jit_regs_load_value
(gen, func->builder->parent_frame, 1, 0);
-- inst = gen->posn.ptr;
-- _jit_cache_check_space(&gen->posn, 32 + level * 8);
++ inst = gen->ptr;
++ _jit_gen_check_space(gen, 32 + level * 8);
reg = _jit_reg_info[reg].cpu_reg;
while(level > 0)
{
{
x86_alu_reg_imm(inst, X86_ADD, reg, insn->value1->frame_offset);
}
-- gen->posn.ptr = inst;
++ gen->ptr = inst;
}
/*
JIT_INSN_DEST_LIVE)));
_jit_regs_spill_all(gen);
_jit_gen_fix_value(insn->value1);
-- inst = gen->posn.ptr;
-- _jit_cache_check_space(&gen->posn, 128);
++ inst = gen->ptr;
++ _jit_gen_check_space(gen, 128);
reg = _jit_reg_info[reg].cpu_reg;
inst = memory_copy(gen, inst, reg, (int)(insn->value2->address),
X86_EBP, insn->value1->frame_offset,
jit_type_get_size(jit_value_get_type(insn->value1)));
-- gen->posn.ptr = inst;
++ gen->ptr = inst;
}
JIT_OP_ADD_RELATIVE:
#endif /* JIT_CDECL_WORD_REG_PARAMS */
++void
++_jit_gen_check_space(jit_gencode_t gen, int space)
++{
++ if((gen->ptr + space) >= gen->limit)
++ {
++ /* No space left on the current cache page. */
++ gen->ptr = gen->limit;
++ jit_exception_builtin(JIT_RESULT_CACHE_FULL);
++ }
++}
++
++void *
++_jit_gen_alloc(jit_gencode_t gen, unsigned long size)
++{
++ void *ptr;
++ _jit_cache_set_code_break(gen->cache, gen->ptr);
++ ptr = _jit_cache_alloc_data(gen->cache, size, JIT_BEST_ALIGNMENT);
++ if(!ptr)
++ {
++ jit_exception_builtin(JIT_RESULT_CACHE_FULL);
++ }
++ gen->limit = _jit_cache_get_code_limit(gen->cache);
++ return ptr;
++}
++
int _jit_int_lowest_byte(void)
{
union
typedef struct jit_gencode *jit_gencode_t;
struct jit_gencode
{
++ jit_cache_t cache; /* Cache this position is attached to */
++ unsigned char *ptr; /* Current code pointer */
++ unsigned char *limit; /* Current code space limit */
jit_regused_t permanent; /* Permanently allocated global regs */
jit_regused_t touched; /* All registers that were touched */
jit_regused_t inhibit; /* Temporarily inhibited registers */
-- jit_cache_posn posn; /* Current cache output position */
jit_regcontents_t contents[JIT_NUM_REGS]; /* Contents of each register */
int current_age; /* Current age value for registers */
#ifdef JIT_REG_STACK
* External function defintions.
*/
++/*
++ * Determine if there is sufficient space in the code cache.
++ * If not throws JIT_RESULT_CACHE_FULL exception.
++ */
++void _jit_gen_check_space(jit_gencode_t gen, int space);
++
++/*
++ * Allocate a memory chunk for data.
++ */
++void *_jit_gen_alloc(jit_gencode_t gen, unsigned long size);
++
void _jit_init_backend(void);
void _jit_gen_get_elf_info(jit_elf_info_t *info);
int _jit_create_entry_insns(jit_function_t func);
}
else
{
-- printf("\t\t_jit_cache_check_space(&gen->posn, ");
++ printf("\t\t_jit_gen_check_space(gen, ");
}
if(space && space->values && space->values->value)
{
printf(");\n");
}
-- printf("\t\tinst = (%s)(gen->posn.ptr);\n", gensel_inst_type);
++ printf("\t\tinst = (%s)(gen->ptr);\n", gensel_inst_type);
regs = 0;
imms = 0;
}
else
{
-- printf("\t\tgen->posn.ptr = (unsigned char *)inst;\n");
++ printf("\t\tgen->ptr = (unsigned char *)inst;\n");
}
if(contains_registers)
{