From adb07727736e4c061f2bf4e2072af00f9a45acf2 Mon Sep 17 00:00:00 2001 From: Aleksey Demakov Date: Tue, 16 Oct 2012 12:30:27 +0400 Subject: [PATCH] Add plugable memory manager interface. --- ChangeLog | 13 +++ include/jit/Makefile.am | 1 + include/jit/jit-context.h | 8 ++ include/jit/jit-memory.h | 79 +++++++++++++++++ jit/Makefile.am | 2 +- jit/jit-apply.c | 24 +++--- jit/jit-cache.c | 43 ++++++++-- jit/jit-cache.h | 173 -------------------------------------- jit/jit-compile.c | 50 ++++++----- jit/jit-context.c | 119 +++++++++++++++----------- jit/jit-elf-read.c | 16 ++-- jit/jit-except.c | 24 ++---- jit/jit-function.c | 72 ++++++++-------- jit/jit-internal.h | 57 ++++++++----- jit/jit-memory.c | 142 +++++++++++++++++++++++++++++++ jit/jit-rules.c | 6 +- jit/jit-rules.h | 3 +- jit/jit-unwind.c | 4 +- 18 files changed, 477 insertions(+), 359 deletions(-) create mode 100644 include/jit/jit-memory.h delete mode 100644 jit/jit-cache.h create mode 100644 jit/jit-memory.c diff --git a/ChangeLog b/ChangeLog index 8f3514c..d6d1876 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2012-10-16 Aleksey Demakov + + * include/jit/jit-memory.h: add file that defines pluggable memory + manager interface. + * jit-internal.h, jit/jit-memory.c: add a number of _jit_memory_* + pluggable memory wrapper functions. Replace with these wrappers + all _jit_cache_* calls. + * jit/jit-cache.c (jit_default_memory_manager): add function that + gets memory mamnager plugin interface. + * jit/jit-cache.h: remove file. + * include/jit/jit-context.h: + * jit/jit-context.c (jit_context_set_memory_manager): add function. + 2012-10-12 Aleksey Demakov * include/jit/jit-util.h, jit/jit-alloc.c (jit_malloc_exec) diff --git a/include/jit/Makefile.am b/include/jit/Makefile.am index 3e84067..f56e402 100644 --- a/include/jit/Makefile.am +++ b/include/jit/Makefile.am @@ -19,6 +19,7 @@ dist_libjitinclude_HEADERS = \ jit-init.h \ jit-insn.h \ jit-intrinsic.h \ + jit-memory.h \ jit-meta.h \ jit-objmodel.h \ jit-objmodel-private.h \ diff --git a/include/jit/jit-context.h b/include/jit/jit-context.h index cce58a6..cfa1ec0 100644 --- a/include/jit/jit-context.h +++ b/include/jit/jit-context.h @@ -22,6 +22,7 @@ #define _JIT_CONTEXT_H #include +#include #ifdef __cplusplus extern "C" { @@ -29,11 +30,18 @@ extern "C" { jit_context_t jit_context_create(void) JIT_NOTHROW; void jit_context_destroy(jit_context_t context) JIT_NOTHROW; + void jit_context_build_start(jit_context_t context) JIT_NOTHROW; void jit_context_build_end(jit_context_t context) JIT_NOTHROW; + void jit_context_set_on_demand_driver( jit_context_t context, jit_on_demand_driver_func driver) JIT_NOTHROW; + +void jit_context_set_memory_manager( + jit_context_t context, + jit_memory_manager_t manager) JIT_NOTHROW; + int jit_context_set_meta (jit_context_t context, int type, void *data, jit_meta_free_func free_data) JIT_NOTHROW; diff --git a/include/jit/jit-memory.h b/include/jit/jit-memory.h new file mode 100644 index 0000000..1d8e68f --- /dev/null +++ b/include/jit/jit-memory.h @@ -0,0 +1,79 @@ +/* + * jit-memory.h - Memory management. + * + * Copyright (C) 2012 Southern Storm Software, Pty Ltd. + * + * The libjit library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 2.1 of + * the License, or (at your option) any later version. + * + * The libjit library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the libjit library. If not, see + * . + */ + +#ifndef _JIT_MEMORY_H +#define _JIT_MEMORY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Result values for "_jit_cache_start_function" and "_jit_cache_end_function". + */ +#define JIT_MEMORY_OK 0 /* Function is OK */ +#define JIT_MEMORY_RESTART 1 /* Restart is required */ +#define JIT_MEMORY_TOO_BIG 2 /* Function is too big for the cache */ +#define JIT_MEMORY_ERROR 3 /* Other error */ + + +/* TODO: the proper place for this is jit-def.h and it's going to depend on the platform. */ +typedef unsigned int jit_size_t; + +typedef void *jit_memory_context_t; + +typedef struct jit_memory_manager const* jit_memory_manager_t; + +struct jit_memory_manager +{ + jit_memory_context_t (*create)(jit_context_t context); + void (*destroy)(jit_memory_context_t memctx); + + jit_function_t (*find_function)(jit_memory_context_t memctx, void *pc); + + jit_function_t (*alloc_function)(jit_memory_context_t memctx); + void (*free_function)(jit_memory_context_t memctx, jit_function_t func); + + int (*start_function)(jit_memory_context_t memctx, jit_function_t func); + int (*end_function)(jit_memory_context_t memctx, int result); + int (*extend_limit)(jit_memory_context_t memctx, int count); + + void * (*get_limit)(jit_memory_context_t memctx); + void * (*get_break)(jit_memory_context_t memctx); + void (*set_break)(jit_memory_context_t memctx, void *brk); + + void * (*alloc_trampoline)(jit_memory_context_t memctx); + void (*free_trampoline)(jit_memory_context_t memctx, void *ptr); + + void * (*alloc_closure)(jit_memory_context_t memctx); + void (*free_closure)(jit_memory_context_t memctx, void *ptr); + + void * (*alloc_data)(jit_memory_context_t memctx, jit_size_t size, jit_size_t align); +}; + +jit_memory_manager_t jit_default_memory_manager(void) JIT_NOTHROW; + +#ifdef __cplusplus +} +#endif + +#endif /* _JIT_MEMORY_H */ diff --git a/jit/Makefile.am b/jit/Makefile.am index eda454c..f61bda7 100644 --- a/jit/Makefile.am +++ b/jit/Makefile.am @@ -17,7 +17,6 @@ libjit_la_SOURCES = \ jit-bitset.h \ jit-bitset.c \ jit-block.c \ - jit-cache.h \ jit-cache.c \ jit-compile.c \ jit-config.h \ @@ -45,6 +44,7 @@ libjit_la_SOURCES = \ jit-interp-opcode.c \ jit-intrinsic.c \ jit-live.c \ + jit-memory.c \ jit-meta.c \ jit-opcode-apply.c \ jit-objmodel.c \ diff --git a/jit/jit-apply.c b/jit/jit-apply.c index 0b4ecef..393658d 100644 --- a/jit/jit-apply.c +++ b/jit/jit-apply.c @@ -23,7 +23,6 @@ #include "jit-internal.h" #include "jit-apply-rules.h" #include "jit-apply-func.h" -#include "jit-cache.h" #if HAVE_STDLIB_H #include #endif @@ -872,7 +871,6 @@ void * jit_closure_create(jit_context_t context, jit_type_t signature, jit_closure_func func, void *user_data) { #ifdef jit_closure_size - jit_cache_t cache; jit_closure_t closure; /* Validate the parameters */ @@ -881,21 +879,19 @@ jit_closure_create(jit_context_t context, jit_type_t signature, jit_closure_func return 0; } - /* Acquire the cache lock while we do this */ - jit_mutex_lock(&context->cache_lock); - - /* Allocate space for the closure within the context's function cache */ - cache = _jit_context_get_cache(context); - if(!cache) + /* Acquire the memory context */ + _jit_memory_lock(context); + if(!_jit_memory_ensure(context)) { - jit_mutex_unlock(&context->cache_lock); + _jit_memory_unlock(context); return 0; } - closure = (jit_closure_t)_jit_cache_alloc_closure(cache); + /* Allocate memory space for the closure */ + closure = (jit_closure_t) _jit_memory_alloc_closure(context); if(!closure) { - jit_mutex_unlock(&context->cache_lock); + _jit_memory_unlock(context); return 0; } @@ -905,12 +901,12 @@ jit_closure_create(jit_context_t context, jit_type_t signature, jit_closure_func closure->func = func; closure->user_data = user_data; + /* Release the memory context, as we are finished with it */ + _jit_memory_unlock(context); + /* Perform a cache flush on the closure's code */ _jit_flush_exec(closure->buf, sizeof(closure->buf)); - /* Unlock the cache, as we are finished with it */ - jit_mutex_unlock(&context->cache_lock); - /* Return the completed closure to the caller */ return closure; diff --git a/jit/jit-cache.c b/jit/jit-cache.c index 62536ce..58ec608 100644 --- a/jit/jit-cache.c +++ b/jit/jit-cache.c @@ -25,7 +25,6 @@ See the bottom of this file for documentation on the cache system. */ #include "jit-internal.h" -#include "jit-cache.h" #include "jit-apply-func.h" #include /* for offsetof */ @@ -76,7 +75,7 @@ struct jit_cache_page /* * Structure of the method cache. */ -#define JIT_CACHE_DEBUG_SIZE 64 +typedef struct jit_cache *jit_cache_t; struct jit_cache { struct jit_cache_page *pages; /* List of pages currently in the cache */ @@ -117,6 +116,8 @@ struct jit_cache #define SetBlack(node) \ ((node)->left = (jit_cache_method_t)(((jit_nuint)(node)->left) & ~((jit_nuint)1))) +void _jit_cache_destroy(jit_cache_t cache); + /* * Allocate a cache page and add it to the cache. */ @@ -517,13 +518,13 @@ _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; + return JIT_MEMORY_ERROR; } /* Bail out if the cache is already full */ if(!cache->free_start) { - return JIT_CACHE_TOO_BIG; + return JIT_MEMORY_TOO_BIG; } /* Save the cache position */ @@ -540,7 +541,7 @@ _jit_cache_start_function(jit_cache_t cache, jit_function_t func) cache->method->left = 0; cache->method->right = 0; - return JIT_CACHE_OK; + return JIT_MEMORY_OK; } int @@ -549,17 +550,17 @@ _jit_cache_end_function(jit_cache_t cache, int result) /* Bail out if there is no started function */ if(!cache->method) { - return JIT_CACHE_ERROR; + return JIT_MEMORY_ERROR; } /* Determine if we ran out of space while writing the function */ - if(result != JIT_CACHE_OK || cache->free_start >= cache->free_end) + if(result != JIT_MEMORY_OK || cache->free_start >= cache->free_end) { /* Restore the saved cache position */ cache->free_start = cache->prev_start; cache->free_end = cache->prev_end; cache->method = 0; - return JIT_CACHE_RESTART; + return JIT_MEMORY_RESTART; } /* Update the method region block and then add it to the lookup tree */ @@ -568,7 +569,7 @@ _jit_cache_end_function(jit_cache_t cache, int result) cache->method = 0; /* The method is ready to go */ - return JIT_CACHE_OK; + return JIT_MEMORY_OK; } void * @@ -797,6 +798,30 @@ _jit_cache_get_function(jit_cache_t cache, void *pc) return 0; } +jit_memory_manager_t +jit_default_memory_manager(void) +{ + static const struct jit_memory_manager mm = { + &_jit_cache_create, + &_jit_cache_destroy, + &_jit_cache_get_function, + &_jit_cache_alloc_function, + &_jit_cache_free_function, + &_jit_cache_start_function, + &_jit_cache_end_function, + &_jit_cache_extend, + &_jit_cache_get_code_limit, + &_jit_cache_get_code_break, + &_jit_cache_set_code_break, + &_jit_cache_alloc_trampoline, + &_jit_cache_free_trampoline, + &_jit_cache_alloc_closure, + &_jit_cache_free_closure, + &_jit_cache_alloc_data + }; + return &mm; +} + /* Using the cache diff --git a/jit/jit-cache.h b/jit/jit-cache.h deleted file mode 100644 index 5f23d02..0000000 --- a/jit/jit-cache.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * jit-cache.h - Translated function cache implementation. - * - * Copyright (C) 2002, 2004, 2008 Southern Storm Software, Pty Ltd. - * - * This file is part of the libjit library. - * - * The libjit library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 2.1 of - * the License, or (at your option) any later version. - * - * The libjit library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the libjit library. If not, see - * . - */ - -#ifndef _JIT_CACHE_H -#define _JIT_CACHE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Result values for "_jit_cache_start_function" and "_jit_cache_end_function". - */ -#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 code cache. Returns NULL if out of memory. - * If "limit" is non-zero, then it specifies the maximum - * size of the cache in bytes. If "cache_page_size" is - * non-zero, then it indicates the dafault/minimum cache - * page size. If "max_page_factor" is not zero, then it - * indicates the maximum cache page size as multiple of - * "max_page_factor" and "cache_page_size". - */ -jit_cache_t _jit_cache_create(jit_context_t context); - -/* - * Destroy a code cache. - */ -void _jit_cache_destroy(jit_cache_t cache); - -/* - * Request to allocate more code cache space. - * - * The "count" value should normally be zero except if just after the last - * call a function is being recompiled again because it is still too big - * to fit into the available cache space. In this case the "count" value - * should gradually increase. - */ -void _jit_cache_extend(jit_cache_t cache, int count); - -/* - * Allocate a function information structure. - */ -jit_function_t _jit_cache_alloc_function(jit_cache_t cache); - -/* - * Release a function information structure. - */ -void _jit_cache_free_function(jit_cache_t cache, jit_function_t func); - -/* - * Start output of a function. - */ -int _jit_cache_start_function(jit_cache_t cache, jit_function_t func); - -/* - * End output of a function. - */ -int _jit_cache_end_function(jit_cache_t cache, int result); - -/* - * Get the start address of memory available for function code generation. - * - * This function is only called betweed _jit_cache_start_function() and - * corresponding _jit_cache_end_function() calls. - * - * Initially it should return the start address of the allocated memory. - * Then the address may be moved forward with _jit_cache_set_code_break() - * calls. - */ -void *_jit_cache_get_code_break(jit_cache_t cache); - -/* - * Set the address of memory yet available for function code generation. - * - * This function is only called betweed _jit_cache_start_function() and - * corresponding _jit_cache_end_function() calls. - * - * The given address must be greater than or equal to its last value as - * returned by the _jit_cache_get_code_break() call and also less than or - * equal to the memory the address returned by _jit_cache_get_code_limit() - * call. - * - * This function is to be used in two cases. First, on the end of code - * generation just before the _jit_cache_end_function() call. Second, - * before allocating data with _jit_cache_alloc_data() calls. This lets - * the cache know how much space was actually used and how much is still - * free. - */ -void _jit_cache_set_code_break(jit_cache_t cache, void *ptr); - -/* - * Get the end address of memory available for function code generation. - * - * This function is only called betweed _jit_cache_start_function() and - * corresponding _jit_cache_end_function() calls. - * - * The available memory may change if during code generation there were - * _jit_cache_alloc_data() calls. So after such calls available memory - * should be rechecked. - */ -void *_jit_cache_get_code_limit(jit_cache_t cache); - -/* - * Allocate "size" bytes of memory in the data area. Returns NULL if - * there is insufficient space to satisfy the request. - */ -void *_jit_cache_alloc_data(jit_cache_t cache, - unsigned long size, - unsigned long align); - -/* - * Allocate memory for a trampoline. - * - * The required size and alignment can be determined with these functions: - * jit_get_trampoline_size(), jit_get_trampoline_alignment(). - */ -void *_jit_cache_alloc_trampoline(jit_cache_t cache); - -/* - * Free memory used by a trampoline. - */ -void _jit_cache_free_trampoline(jit_cache_t cache, void *trampoline); - -/* - * Allocate memory for a closure. - * - * The required size and alignment can be determined with these functions: - * jit_get_closure_size(), jit_get_closure_alignment(). - */ -void *_jit_cache_alloc_closure(jit_cache_t cache); - -/* - * Free memory used by a closure. - */ -void _jit_cache_free_closure(jit_cache_t cache, void *closure); - -/* - * Find the method that is associated with a particular - * program counter. Returns NULL if the PC is not associated - * with a method within the cache. - */ -jit_function_t _jit_cache_get_function(jit_cache_t cache, void *pc); - - -#ifdef __cplusplus -}; -#endif - -#endif /* _JIT_CACHE_H */ diff --git a/jit/jit-compile.c b/jit/jit-compile.c index 151e381..88b8946 100644 --- a/jit/jit-compile.c +++ b/jit/jit-compile.c @@ -385,15 +385,16 @@ cleanup_on_restart(jit_gencode_t gen, jit_function_t func) static void cache_acquire(_jit_compile_t *state) { - /* Acquire the cache lock */ - jit_mutex_lock(&state->func->context->cache_lock); + /* Store the function's context as codegen context */ + state->gen.context = state->func->context; + + /* Acquire the memory context lock */ + _jit_memory_lock(state->gen.context); /* Remember that the lock is acquired */ state->cache_locked = 1; - /* Get the method cache */ - state->gen.cache = _jit_context_get_cache(state->func->context); - if(!state->gen.cache) + if(!_jit_memory_ensure(state->gen.context)) { jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); } @@ -408,7 +409,7 @@ cache_release(_jit_compile_t *state) /* Release the lock if it was previously acquired */ if(state->cache_locked) { - jit_mutex_unlock(&state->func->context->cache_lock); + _jit_memory_unlock(state->gen.context); state->cache_locked = 0; } } @@ -462,20 +463,20 @@ cache_alloc(_jit_compile_t *state) int result; /* First try with the current cache page */ - result = _jit_cache_start_function(state->gen.cache, state->func); - if(result == JIT_CACHE_RESTART) + result = _jit_memory_start_function(state->gen.context, state->func); + if(result == JIT_MEMORY_RESTART) { /* No space left on the current cache page. Allocate a new one. */ - _jit_cache_extend(state->gen.cache, state->page_factor++); - result = _jit_cache_start_function(state->gen.cache, state->func); + _jit_memory_extend_limit(state->gen.context, state->page_factor++); + result = _jit_memory_start_function(state->gen.context, state->func); } - if(result != JIT_CACHE_OK) + if(result != JIT_MEMORY_OK) { /* Failed to allocate any cache space */ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); } - state->gen.ptr = _jit_cache_get_code_break(state->gen.cache); - state->gen.limit = _jit_cache_get_code_limit(state->gen.cache); + state->gen.ptr = _jit_memory_get_break(state->gen.context); + state->gen.limit = _jit_memory_get_limit(state->gen.context); /* Align the function code. */ cache_align(state, JIT_FUNCTION_ALIGNMENT, JIT_FUNCTION_ALIGNMENT, 0); @@ -500,13 +501,13 @@ cache_flush(_jit_compile_t *state) state->cache_started = 0; /* Let the cache know where we are */ - _jit_cache_set_code_break(state->gen.cache, state->gen.ptr); + _jit_memory_set_break(state->gen.context, state->gen.ptr); /* End the function's output process */ - result = _jit_cache_end_function(state->gen.cache, JIT_CACHE_OK); - if(result != JIT_CACHE_OK) + result = _jit_memory_end_function(state->gen.context, JIT_MEMORY_OK); + if(result != JIT_MEMORY_OK) { - if(result == JIT_CACHE_RESTART) + if(result == JIT_MEMORY_RESTART) { /* Throw an internal exception that causes a larger code space to be allocated and @@ -547,7 +548,7 @@ cache_abort(_jit_compile_t *state) state->cache_started = 0; /* Release the cache space */ - _jit_cache_end_function(state->gen.cache, JIT_CACHE_RESTART); + _jit_memory_end_function(state->gen.context, JIT_MEMORY_RESTART); /* Free encoded bytecode offset data */ _jit_varint_free_data(_jit_varint_get_data(&state->gen.offset_encoder)); @@ -567,15 +568,15 @@ cache_realloc(_jit_compile_t *state) /* Allocate a new cache page with the size that grows by factor of 2 on each reallocation */ - _jit_cache_extend(state->gen.cache, state->page_factor++); - result = _jit_cache_start_function(state->gen.cache, state->func); - if(result != JIT_CACHE_OK) + _jit_memory_extend_limit(state->gen.context, state->page_factor++); + result = _jit_memory_start_function(state->gen.context, state->func); + if(result != JIT_MEMORY_OK) { /* Failed to allocate enough cache space */ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); } - state->gen.ptr = _jit_cache_get_code_break(state->gen.cache); - state->gen.limit = _jit_cache_get_code_limit(state->gen.cache); + state->gen.ptr = _jit_memory_get_break(state->gen.context); + state->gen.limit = _jit_memory_get_limit(state->gen.context); /* Align the function code. */ cache_align(state, JIT_FUNCTION_ALIGNMENT, JIT_FUNCTION_ALIGNMENT, 0); @@ -1015,14 +1016,11 @@ 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 diff --git a/jit/jit-context.c b/jit/jit-context.c index db66fc4..a38d93f 100644 --- a/jit/jit-context.c +++ b/jit/jit-context.c @@ -21,7 +21,6 @@ */ #include "jit-internal.h" -#include "jit-cache.h" /*@ @@ -71,7 +70,8 @@ ultimately destroy JIT contexts: * if out of memory. * @end deftypefun @*/ -jit_context_t jit_context_create(void) +jit_context_t +jit_context_create(void) { jit_context_t context; @@ -86,11 +86,12 @@ jit_context_t jit_context_create(void) } /* Initialize the context and return it */ - jit_mutex_create(&(context->builder_lock)); - jit_mutex_create(&(context->cache_lock)); + jit_mutex_create(&context->memory_lock); + jit_mutex_create(&context->builder_lock); context->functions = 0; context->last_function = 0; context->on_demand_driver = _jit_function_compile_on_demand; + context->memory_manager = jit_default_memory_manager(); return context; } @@ -101,28 +102,33 @@ jit_context_t jit_context_create(void) * running compiled code when this function is called. * @end deftypefun @*/ -void jit_context_destroy(jit_context_t context) +void +jit_context_destroy(jit_context_t context) { int sym; - if(context) + + if(!context) + { + return; + } + + for(sym = 0; sym < context->num_registered_symbols; ++sym) + { + jit_free(context->registered_symbols[sym]); + } + jit_free(context->registered_symbols); + + while(context->functions != 0) { - while(context->functions != 0) - { - _jit_function_destroy(context->functions); - } - if(context->cache) - { - _jit_cache_destroy(context->cache); - } - for(sym = 0; sym < context->num_registered_symbols; ++sym) - { - jit_free(context->registered_symbols[sym]); - } - jit_free(context->registered_symbols); - jit_mutex_destroy(&(context->cache_lock)); - jit_mutex_destroy(&(context->builder_lock)); - jit_free(context); + _jit_function_destroy(context->functions); } + + _jit_memory_destroy(context); + + jit_mutex_destroy(&context->memory_lock); + jit_mutex_destroy(&context->builder_lock); + + jit_free(context); } /*@ @@ -133,9 +139,10 @@ void jit_context_destroy(jit_context_t context) * can be performing build operations at any one time. * @end deftypefun @*/ -void jit_context_build_start(jit_context_t context) +void +jit_context_build_start(jit_context_t context) { - jit_mutex_lock(&(context->builder_lock)); + jit_mutex_lock(&context->builder_lock); } /*@ @@ -146,9 +153,10 @@ void jit_context_build_start(jit_context_t context) * that are waiting on the builder to proceed. * @end deftypefun @*/ -void jit_context_build_end(jit_context_t context) +void +jit_context_build_end(jit_context_t context) { - jit_mutex_unlock(&(context->builder_lock)); + jit_mutex_unlock(&context->builder_lock); } /*@ @@ -185,8 +193,7 @@ void jit_context_build_end(jit_context_t context) * or @code{JIT_RESULT_OUT_OF_MEMORY} will be thrown. * * @item - * The entry point of the compiled function is returned from the - * driver. + * The entry point of the compiled function is returned from the driver. * @end enumerate * * You may need to provide your own driver if some additional actions @@ -194,7 +201,8 @@ void jit_context_build_end(jit_context_t context) * * @end deftypefun @*/ -void jit_context_set_on_demand_driver(jit_context_t context, jit_on_demand_driver_func driver) +void +jit_context_set_on_demand_driver(jit_context_t context, jit_on_demand_driver_func driver) { if (driver) { @@ -206,6 +214,31 @@ void jit_context_set_on_demand_driver(jit_context_t context, jit_on_demand_drive } } +/*@ + * @deftypefun void jit_context_set_memory_manager (jit_context_t @var{context}, jit_memory_manager_t @var{manager}) + * Specify the memory manager plug-in. + * @end deftypefun +@*/ +void +jit_context_set_memory_manager(jit_context_t context, jit_memory_manager_t manager) +{ + /* Bail out if there is already an established memory context */ + if (context->memory_context) + { + return; + } + + /* Set the context memory manager */ + if (manager) + { + context->memory_manager = manager; + } + else + { + context->memory_manager = jit_default_memory_manager(); + } +} + /*@ * @deftypefun int jit_context_set_meta (jit_context_t @var{context}, int @var{type}, void *@var{data}, jit_meta_free_func @var{free_data}) * Tag a context with some metadata. Returns zero if out of memory. @@ -220,9 +253,8 @@ void jit_context_set_on_demand_driver(jit_context_t context, jit_on_demand_drive * the previous value will be freed. * @end deftypefun @*/ -int jit_context_set_meta - (jit_context_t context, int type, void *data, - jit_meta_free_func free_data) +int +jit_context_set_meta(jit_context_t context, int type, void *data, jit_meta_free_func free_data) { return jit_meta_set(&(context->meta), type, data, free_data, 0); } @@ -272,8 +304,8 @@ int jit_context_set_meta * Metadata type values of 10000 or greater are reserved for internal use. * @end deftypefun @*/ -int jit_context_set_meta_numeric - (jit_context_t context, int type, jit_nuint data) +int +jit_context_set_meta_numeric(jit_context_t context, int type, jit_nuint data) { return jit_meta_set(&(context->meta), type, (void *)data, 0, 0); } @@ -284,7 +316,8 @@ int jit_context_set_meta_numeric * if @var{type} does not have any metadata associated with it. * @end deftypefun @*/ -void *jit_context_get_meta(jit_context_t context, int type) +void * +jit_context_get_meta(jit_context_t context, int type) { return jit_meta_get(context->meta, type); } @@ -296,7 +329,8 @@ void *jit_context_get_meta(jit_context_t context, int type) * This version is more convenient for the pre-defined numeric option values. * @end deftypefun @*/ -jit_nuint jit_context_get_meta_numeric(jit_context_t context, int type) +jit_nuint +jit_context_get_meta_numeric(jit_context_t context, int type) { return (jit_nuint)jit_meta_get(context->meta, type); } @@ -307,17 +341,8 @@ jit_nuint jit_context_get_meta_numeric(jit_context_t context, int type) * the @var{type} does not have any metadata associated with it. * @end deftypefun @*/ -void jit_context_free_meta(jit_context_t context, int type) +void +jit_context_free_meta(jit_context_t context, int type) { jit_meta_free(&(context->meta), type); } - -struct jit_cache * -_jit_context_get_cache(jit_context_t context) -{ - if(!context->cache) - { - context->cache = _jit_cache_create(context); - } - return context->cache; -} diff --git a/jit/jit-elf-read.c b/jit/jit-elf-read.c index 7d23e46..bb1d670 100644 --- a/jit/jit-elf-read.c +++ b/jit/jit-elf-read.c @@ -1422,10 +1422,13 @@ void jit_readelf_add_to_context(jit_readelf_t readelf, jit_context_t context) { return; } - jit_mutex_lock(&(context->cache_lock)); + + _jit_memory_lock(context); + readelf->next = context->elf_binaries; context->elf_binaries = readelf; - jit_mutex_unlock(&(context->cache_lock)); + + _jit_memory_unlock(context); } /* @@ -1773,13 +1776,15 @@ static int perform_relocations @*/ int jit_readelf_resolve_all(jit_context_t context, int print_failures) { - jit_readelf_t readelf; int ok = 1; + jit_readelf_t readelf; if(!context) { return 0; } - jit_mutex_lock(&(context->cache_lock)); + + _jit_memory_lock(context); + readelf = context->elf_binaries; while(readelf != 0) { @@ -1793,7 +1798,8 @@ int jit_readelf_resolve_all(jit_context_t context, int print_failures) } readelf = readelf->next; } - jit_mutex_unlock(&(context->cache_lock)); + + _jit_memory_unlock(context); return ok; } diff --git a/jit/jit-except.c b/jit/jit-except.c index 91054e7..a24389e 100644 --- a/jit/jit-except.c +++ b/jit/jit-except.c @@ -392,16 +392,12 @@ unsigned int jit_stack_trace_get_size(jit_stack_trace_t trace) * @var{posn} within the stack trace. * @end deftypefun @*/ -jit_function_t jit_stack_trace_get_function - (jit_context_t context, jit_stack_trace_t trace, unsigned int posn) +jit_function_t +jit_stack_trace_get_function(jit_context_t context, jit_stack_trace_t trace, unsigned int posn) { if(trace && posn < trace->size) { - jit_cache_t cache = _jit_context_get_cache(context); - if(cache) - { - return _jit_cache_get_function(cache, trace->items[posn]); - } + return _jit_memory_find_function(context, trace->items[posn]); } return 0; } @@ -433,19 +429,15 @@ void *jit_stack_trace_get_pc * is no bytecode offset associated with @var{posn}. * @end deftypefun @*/ -unsigned int jit_stack_trace_get_offset - (jit_context_t context, jit_stack_trace_t trace, unsigned int posn) +unsigned int +jit_stack_trace_get_offset(jit_context_t context, jit_stack_trace_t trace, unsigned int posn) { if(trace && posn < trace->size) { - jit_cache_t cache = _jit_context_get_cache(context); - if(cache) + jit_function_t func = _jit_memory_find_function(context, trace->items[posn]); + if (func) { - jit_function_t func = _jit_cache_get_function(cache, trace->items[posn]); - if (func) - { - return _jit_function_get_bytecode(func, trace->items[posn], 0); - } + return _jit_function_get_bytecode(func, trace->items[posn], 0); } } return JIT_NO_OFFSET; diff --git a/jit/jit-function.c b/jit/jit-function.c index b8c5768..edad6d7 100644 --- a/jit/jit-function.c +++ b/jit/jit-function.c @@ -22,7 +22,6 @@ #include "jit-internal.h" #include "jit-apply-func.h" -#include "jit-cache.h" #include "jit-rules.h" #include "jit-setjmp.h" @@ -48,36 +47,32 @@ jit_function_t jit_function_create(jit_context_t context, jit_type_t signature) { jit_function_t func; - jit_cache_t cache; #if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size)) unsigned char *trampoline; #endif - /* We need the cache lock. */ - jit_mutex_lock(&context->cache_lock); - - /* Get the method cache */ - cache = _jit_context_get_cache(context); - if(!cache) + /* Acquire the memory context */ + _jit_memory_lock(context); + if(!_jit_memory_ensure(context)) { - jit_mutex_unlock(&context->cache_lock); + _jit_memory_unlock(context); return 0; } /* Allocate memory for the function and clear it */ - func = _jit_cache_alloc_function(cache); + func = _jit_memory_alloc_function(context); if(!func) { - jit_mutex_unlock(&context->cache_lock); + _jit_memory_unlock(context); return 0; } #if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size)) - trampoline = (unsigned char *) _jit_cache_alloc_trampoline(cache); + trampoline = (unsigned char *) _jit_memory_alloc_trampoline(context); if(!trampoline) { - _jit_cache_free_function(cache, func); - jit_mutex_unlock(&context->cache_lock); + _jit_memory_free_function(context, func); + _jit_memory_unlock(context); return 0; } # if defined(jit_redirector_size) @@ -89,7 +84,8 @@ jit_function_create(jit_context_t context, jit_type_t signature) # endif #endif /* !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size)) */ - jit_mutex_unlock(&context->cache_lock); + /* Release the memory context */ + _jit_memory_unlock(context); /* Initialize the function block */ func->context = context; @@ -261,16 +257,18 @@ _jit_function_destroy(jit_function_t func) jit_meta_destroy(&func->meta); jit_type_free(func->signature); - jit_mutex_lock(&context->cache_lock); + _jit_memory_lock(context); + #if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size)) # if defined(jit_redirector_size) - _jit_cache_free_trampoline(context->cache, func->redirector); + _jit_memory_free_trampoline(context, func->redirector); # else - _jit_cache_free_trampoline(context->cache, func->indirector); + _jit_memory_free_trampoline(context, func->indirector); # endif #endif - _jit_cache_free_function(context->cache, func); - jit_mutex_unlock(&context->cache_lock); + _jit_memory_free_function(context, func); + + _jit_memory_unlock(context); } /*@ @@ -647,13 +645,14 @@ void *jit_function_to_closure(jit_function_t func) * closure does not correspond to a function in the specified context. * @end deftypefun @*/ -jit_function_t jit_function_from_closure(jit_context_t context, void *closure) +jit_function_t +jit_function_from_closure(jit_context_t context, void *closure) { - if(!context || !(context->cache)) + if(!context) { return 0; } - return _jit_cache_get_function(context->cache, closure); + return _jit_memory_find_function(context, closure); } /*@ @@ -664,40 +663,37 @@ jit_function_t jit_function_from_closure(jit_context_t context, void *closure) * under the control of @var{context}. * @end deftypefun @*/ -jit_function_t jit_function_from_pc - (jit_context_t context, void *pc, void **handler) +jit_function_t +jit_function_from_pc(jit_context_t context, void *pc, void **handler) { jit_function_t func; - void *cookie; - /* Bail out if we don't have a function cache yet */ - if(!context || !(context->cache)) + if(!context) { return 0; } /* Get the function and the exception handler cookie */ - func = _jit_cache_get_function(context->cache, pc); + func = _jit_memory_find_function(context, pc); if(!func) { return 0; } - cookie = func->cookie; /* Convert the cookie into a handler address */ if(handler) { #if 0 - if(cookie) + if(func->cookie) { - *handler = ((jit_cache_eh_t)cookie)->handler; + *handler = ((jit_cache_eh_t) func->cookie)->handler; } else { *handler = 0; } #else - *handler = cookie; + *handler = func->cookie; #endif } return func; @@ -716,7 +712,8 @@ jit_function_t jit_function_from_pc * guaranteed. Closures can be used with @code{jit_insn_call_indirect}. * @end deftypefun @*/ -void *jit_function_to_vtable_pointer(jit_function_t func) +void * +jit_function_to_vtable_pointer(jit_function_t func) { #ifdef JIT_BACKEND_INTERP /* In the interpreted version, the function pointer is used in vtables */ @@ -741,7 +738,8 @@ void *jit_function_to_vtable_pointer(jit_function_t func) * vtable_pointer does not correspond to a function in the specified context. * @end deftypefun @*/ -jit_function_t jit_function_from_vtable_pointer(jit_context_t context, void *vtable_pointer) +jit_function_t +jit_function_from_vtable_pointer(jit_context_t context, void *vtable_pointer) { #ifdef JIT_BACKEND_INTERP /* In the interpreted version, the function pointer is used in vtables */ @@ -753,11 +751,11 @@ jit_function_t jit_function_from_vtable_pointer(jit_context_t context, void *vta } return 0; #else - if(!context || !(context->cache)) + if(!context) { return 0; } - return _jit_cache_get_function(context->cache, vtable_pointer); + return _jit_memory_find_function(context, vtable_pointer); #endif } diff --git a/jit/jit-internal.h b/jit/jit-internal.h index fe68aef..bf32490 100644 --- a/jit/jit-internal.h +++ b/jit/jit-internal.h @@ -62,10 +62,6 @@ # define jit_memchr(s, c, len) (memchr((s), (c), (len))) #endif -#ifdef __cplusplus -extern "C" { -#endif - /* * We need the apply rules for "jit_redirector_size". */ @@ -81,9 +77,9 @@ extern "C" { */ #include "jit-varint.h" -void *_jit_malloc_exec(unsigned int size); -void _jit_free_exec(void *ptr, unsigned int size); -void _jit_flush_exec(void *ptr, unsigned int size); +#ifdef __cplusplus +extern "C" { +#endif /* * The following is some macro magic that attempts to detect @@ -148,11 +144,6 @@ _JIT_ALIGN_CHECK_TYPE(jit_nfloat, nfloat); #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. */ @@ -573,12 +564,14 @@ struct jit_regsym */ struct _jit_context { + /* The context's memory control */ + jit_memory_manager_t memory_manager; + jit_memory_context_t memory_context; + jit_mutex_t memory_lock; + /* Lock that controls access to the building process */ jit_mutex_t builder_lock; - /* Lock that controls access to the function code cache */ - jit_mutex_t cache_lock; - /* List of functions that are currently registered with the context */ jit_function_t functions; jit_function_t last_function; @@ -586,9 +579,6 @@ struct _jit_context /* Metadata that is associated with the context */ jit_meta_t meta; - /* The context's function code cache */ - struct jit_cache *cache; - /* ELF binaries that have been loaded into this context */ jit_readelf_t elf_binaries; @@ -604,6 +594,32 @@ struct _jit_context jit_on_demand_driver_func on_demand_driver; }; +void *_jit_malloc_exec(unsigned int size); +void _jit_free_exec(void *ptr, unsigned int size); +void _jit_flush_exec(void *ptr, unsigned int size); + +void _jit_memory_lock(jit_context_t context); +void _jit_memory_unlock(jit_context_t context); + +int _jit_memory_ensure(jit_context_t context); +void _jit_memory_destroy(jit_context_t context); + +jit_function_t _jit_memory_find_function(jit_context_t context, void *pc); + +jit_function_t _jit_memory_alloc_function(jit_context_t context); +void _jit_memory_free_function(jit_context_t context, jit_function_t func); +int _jit_memory_start_function(jit_context_t context, jit_function_t func); +int _jit_memory_end_function(jit_context_t context, int result); +int _jit_memory_extend_limit(jit_context_t context, int count); +void *_jit_memory_get_limit(jit_context_t context); +void *_jit_memory_get_break(jit_context_t context); +void _jit_memory_set_break(jit_context_t context, void *brk); +void *_jit_memory_alloc_trampoline(jit_context_t context); +void _jit_memory_free_trampoline(jit_context_t context, void *ptr); +void *_jit_memory_alloc_closure(jit_context_t context); +void _jit_memory_free_closure(jit_context_t context, void *ptr); +void *_jit_memory_alloc_data(jit_context_t context, jit_size_t size, jit_size_t align); + /* * Backtrace control structure, for managing stack traces. * These structures must be allocated on the stack. @@ -644,11 +660,6 @@ struct jit_thread_control struct jit_jmp_buf *setjmp_head; }; -/* - * Get the function code cache for a context, creating it if necessary. - */ -struct jit_cache *_jit_context_get_cache(jit_context_t context); - /* * Initialize the block list for a function. */ diff --git a/jit/jit-memory.c b/jit/jit-memory.c new file mode 100644 index 0000000..b743361 --- /dev/null +++ b/jit/jit-memory.c @@ -0,0 +1,142 @@ +/* + * jit-memory.c - Memory management. + * + * Copyright (C) 2012 Southern Storm Software, Pty Ltd. + * + * The libjit library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 2.1 of + * the License, or (at your option) any later version. + * + * The libjit library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the libjit library. If not, see + * . + */ + +#include "jit-internal.h" + +void +_jit_memory_lock(jit_context_t context) +{ + jit_mutex_lock(&context->memory_lock); +} + +void +_jit_memory_unlock(jit_context_t context) +{ + jit_mutex_unlock(&context->memory_lock); +} + +int +_jit_memory_ensure(jit_context_t context) +{ + if(!context->memory_context) + { + context->memory_context = context->memory_manager->create(context); + } + return (context->memory_context != 0); +} + +void +_jit_memory_destroy(jit_context_t context) +{ + if(!context->memory_context) + { + return; + } + context->memory_manager->destroy(context->memory_context); +} + +jit_function_t +_jit_memory_find_function(jit_context_t context, void *pc) +{ + if(!context->memory_context) + { + return 0; + } + /* TODO: read lock? */ + return context->memory_manager->find_function(context->memory_context, pc); +} + +jit_function_t +_jit_memory_alloc_function(jit_context_t context) +{ + return context->memory_manager->alloc_function(context->memory_context); +} + +void +_jit_memory_free_function(jit_context_t context, jit_function_t func) +{ + context->memory_manager->free_function(context->memory_context, func); +} + +int +_jit_memory_start_function(jit_context_t context, jit_function_t func) +{ + return context->memory_manager->start_function(context->memory_context, func); +} + +int +_jit_memory_end_function(jit_context_t context, int result) +{ + return context->memory_manager->end_function(context->memory_context, result); +} + +int +_jit_memory_extend_limit(jit_context_t context, int count) +{ + return context->memory_manager->extend_limit(context->memory_context, count); +} + +void * +_jit_memory_get_limit(jit_context_t context) +{ + return context->memory_manager->get_limit(context->memory_context); +} + +void * +_jit_memory_get_break(jit_context_t context) +{ + return context->memory_manager->get_break(context->memory_context); +} + +void +_jit_memory_set_break(jit_context_t context, void *brk) +{ + context->memory_manager->set_break(context->memory_context, brk); +} + +void * +_jit_memory_alloc_trampoline(jit_context_t context) +{ + return context->memory_manager->alloc_trampoline(context->memory_context); +} + +void +_jit_memory_free_trampoline(jit_context_t context, void *ptr) +{ + context->memory_manager->free_trampoline(context->memory_context, ptr); +} + +void * +_jit_memory_alloc_closure(jit_context_t context) +{ + return context->memory_manager->alloc_closure(context->memory_context); +} + +void +_jit_memory_free_closure(jit_context_t context, void *ptr) +{ + context->memory_manager->free_closure(context->memory_context, ptr); +} + +void * +_jit_memory_alloc_data(jit_context_t context, jit_size_t size, jit_size_t align) +{ + return context->memory_manager->alloc_data(context->memory_context, size, align); +} diff --git a/jit/jit-rules.c b/jit/jit-rules.c index 32f5a10..874f1cb 100644 --- a/jit/jit-rules.c +++ b/jit/jit-rules.c @@ -752,13 +752,13 @@ 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); + _jit_memory_set_break(gen->context, gen->ptr); + ptr = _jit_memory_alloc_data(gen->context, size, JIT_BEST_ALIGNMENT); if(!ptr) { jit_exception_builtin(JIT_RESULT_CACHE_FULL); } - gen->limit = _jit_cache_get_code_limit(gen->cache); + gen->limit = _jit_memory_get_limit(gen->context); return ptr; } diff --git a/jit/jit-rules.h b/jit/jit-rules.h index 6af7e87..bc023b8 100644 --- a/jit/jit-rules.h +++ b/jit/jit-rules.h @@ -24,7 +24,6 @@ #define _JIT_RULES_H #include "jit-config.h" -#include "jit-cache.h" #ifdef __cplusplus extern "C" { @@ -159,7 +158,7 @@ struct jit_regcontents typedef struct jit_gencode *jit_gencode_t; struct jit_gencode { - jit_cache_t cache; /* Cache this position is attached to */ + jit_context_t context; /* Context 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 */ diff --git a/jit/jit-unwind.c b/jit/jit-unwind.c index 8e91fdf..5276a2b 100644 --- a/jit/jit-unwind.c +++ b/jit/jit-unwind.c @@ -21,7 +21,6 @@ */ #include "jit-internal.h" -#include "jit-cache.h" #include "jit-rules.h" #include "jit-apply-rules.h" #include @@ -167,9 +166,8 @@ jit_unwind_get_function(jit_unwind_context_t *unwind) if(!unwind->cache) { - jit_cache_t cache = _jit_context_get_cache(unwind->context); void *pc = jit_unwind_get_pc(unwind); - unwind->cache = _jit_cache_get_function(cache, pc); + unwind->cache = _jit_memory_find_function(unwind->context, pc); } return (jit_function_t) unwind->cache; -- 2.47.3