+2012-10-16 Aleksey Demakov <ademakov@gmail.com>
+
+ * 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 <ademakov@gmail.com>
* include/jit/jit-util.h, jit/jit-alloc.c (jit_malloc_exec)
jit-init.h \
jit-insn.h \
jit-intrinsic.h \
+ jit-memory.h \
jit-meta.h \
jit-objmodel.h \
jit-objmodel-private.h \
#define _JIT_CONTEXT_H
#include <jit/jit-common.h>
+#include <jit/jit-memory.h>
#ifdef __cplusplus
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;
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _JIT_MEMORY_H
+#define _JIT_MEMORY_H
+
+#include <jit/jit-defs.h>
+
+#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 */
jit-bitset.h \
jit-bitset.c \
jit-block.c \
- jit-cache.h \
jit-cache.c \
jit-compile.c \
jit-config.h \
jit-interp-opcode.c \
jit-intrinsic.c \
jit-live.c \
+ jit-memory.c \
jit-meta.c \
jit-opcode-apply.c \
jit-objmodel.c \
#include "jit-internal.h"
#include "jit-apply-rules.h"
#include "jit-apply-func.h"
-#include "jit-cache.h"
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
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 */
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;
}
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;
*/
#include "jit-internal.h"
-#include "jit-cache.h"
#include "jit-apply-func.h"
#include <stddef.h> /* for offsetof */
/*
* 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 */
#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.
*/
/* 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 */
cache->method->left = 0;
cache->method->right = 0;
- return JIT_CACHE_OK;
+ return JIT_MEMORY_OK;
}
int
/* 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 */
cache->method = 0;
/* The method is ready to go */
- return JIT_CACHE_OK;
+ return JIT_MEMORY_OK;
}
void *
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
+++ /dev/null
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- */
-
-#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 */
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);
}
/* 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;
}
}
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);
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
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));
/* 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);
_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
*/
#include "jit-internal.h"
-#include "jit-cache.h"
/*@
* if out of memory.
* @end deftypefun
@*/
-jit_context_t jit_context_create(void)
+jit_context_t
+jit_context_create(void)
{
jit_context_t context;
}
/* 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;
}
* 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);
}
/*@
* 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);
}
/*@
* 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);
}
/*@
* 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
*
* @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)
{
}
}
+/*@
+ * @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.
* 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);
}
* 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);
}
* 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);
}
* 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);
}
* 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;
-}
{
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);
}
/*
@*/
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)
{
}
readelf = readelf->next;
}
- jit_mutex_unlock(&(context->cache_lock));
+
+ _jit_memory_unlock(context);
return ok;
}
* @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;
}
* 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;
#include "jit-internal.h"
#include "jit-apply-func.h"
-#include "jit-cache.h"
#include "jit-rules.h"
#include "jit-setjmp.h"
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)
# 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;
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);
}
/*@
* 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);
}
/*@
* 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;
* 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 */
* 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 */
}
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
}
# 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".
*/
*/
#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
#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.
*/
*/
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;
/* 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;
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.
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.
*/
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#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);
+}
_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;
}
#define _JIT_RULES_H
#include "jit-config.h"
-#include "jit-cache.h"
#ifdef __cplusplus
extern "C" {
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 */
*/
#include "jit-internal.h"
-#include "jit-cache.h"
#include "jit-rules.h"
#include "jit-apply-rules.h"
#include <jit/jit-unwind.h>
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;