mirror of https://github.com/ademakov/libjit
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
980 lines
22 KiB
980 lines
22 KiB
/*
|
|
* jit-apply.c - Dynamic invocation and closure support functions.
|
|
*
|
|
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "jit-internal.h"
|
|
#include "jit-memory.h"
|
|
#include "jit-apply-rules.h"
|
|
#include "jit-apply-func.h"
|
|
#include "jit-cache.h"
|
|
#if HAVE_ALLOCA_H
|
|
#include <alloca.h>
|
|
#endif
|
|
#ifdef JIT_WIN32_PLATFORM
|
|
#include <malloc.h>
|
|
#ifndef alloca
|
|
#define alloca _alloca
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
|
|
If you need to tweak the way that this code behaves for a specific
|
|
platform, then you would normally do it in "tools/gen-apply.c" or
|
|
the CPU-specific "jit-apply-XXX.h" file, not here.
|
|
|
|
*/
|
|
|
|
/*@
|
|
|
|
@section Function application and closures
|
|
@cindex Function application
|
|
@cindex Closures
|
|
@cindex jit-apply.h
|
|
|
|
Sometimes all you have for a function is a pointer to it and a dynamic
|
|
description of its arguments. Calling such a function can be extremely
|
|
difficult in standard C. The routines in this section, particularly
|
|
@code{jit_apply}, provide a convenient interface for doing this.
|
|
|
|
At other times, you may wish to wrap up one of your own dynamic functions
|
|
in such a way that it appears to be a regular C function. This is
|
|
performed with @code{jit_closure_create}.
|
|
|
|
@*/
|
|
|
|
/*
|
|
* Flags that indicate which structure sizes are returned in registers.
|
|
*/
|
|
unsigned char const _jit_apply_return_in_reg[] =
|
|
JIT_APPLY_STRUCT_RETURN_IN_REG_INIT;
|
|
|
|
/*
|
|
* Get the maximum argument stack size of a signature type.
|
|
*/
|
|
static unsigned int jit_type_get_max_arg_size(jit_type_t signature)
|
|
{
|
|
unsigned int size;
|
|
unsigned int typeSize;
|
|
unsigned int param;
|
|
jit_type_t type;
|
|
if(signature->size)
|
|
{
|
|
/* We have a cached argument size from last time */
|
|
return signature->size;
|
|
}
|
|
size = 0;
|
|
param = jit_type_num_params(signature);
|
|
while(param > 0)
|
|
{
|
|
--param;
|
|
type = jit_type_normalize(jit_type_get_param(signature, param));
|
|
switch(type->kind)
|
|
{
|
|
case JIT_TYPE_SBYTE:
|
|
case JIT_TYPE_UBYTE:
|
|
case JIT_TYPE_SHORT:
|
|
case JIT_TYPE_USHORT:
|
|
case JIT_TYPE_INT:
|
|
case JIT_TYPE_UINT:
|
|
case JIT_TYPE_NINT:
|
|
case JIT_TYPE_NUINT:
|
|
case JIT_TYPE_PTR:
|
|
case JIT_TYPE_SIGNATURE:
|
|
{
|
|
size += sizeof(jit_nint);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
case JIT_TYPE_ULONG:
|
|
{
|
|
#ifdef JIT_NATIVE_INT32
|
|
/* Add one extra word for possible alignment padding */
|
|
size += sizeof(jit_long) + sizeof(jit_nint);
|
|
#else
|
|
size += sizeof(jit_nint);
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
case JIT_TYPE_FLOAT64:
|
|
case JIT_TYPE_NFLOAT:
|
|
{
|
|
/* Allocate space for an "nfloat" and an alignment word */
|
|
size += (sizeof(jit_nfloat) + sizeof(jit_nint) * 2 - 1) &
|
|
~(sizeof(jit_nint) - 1);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_STRUCT:
|
|
case JIT_TYPE_UNION:
|
|
{
|
|
/* Allocate space for the structure and an alignment word */
|
|
typeSize = jit_type_get_size(type);
|
|
size += (typeSize + sizeof(jit_nint) * 2 - 1) &
|
|
~(sizeof(jit_nint) - 1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
type = jit_type_get_return(signature);
|
|
if(jit_type_is_struct(type) || jit_type_is_union(type))
|
|
{
|
|
/* Add one extra word for the possibility of a structure pointer */
|
|
size += sizeof(jit_nint);
|
|
}
|
|
signature->size = size;
|
|
return size;
|
|
}
|
|
|
|
/*
|
|
* Copy apply arguments into position.
|
|
*/
|
|
static void jit_apply_builder_add_arguments
|
|
(jit_apply_builder *builder, jit_type_t signature,
|
|
void **args, unsigned int index, unsigned int num_args)
|
|
{
|
|
unsigned int param;
|
|
jit_type_t type;
|
|
for(param = 0; param < num_args; ++param)
|
|
{
|
|
type = jit_type_normalize
|
|
(jit_type_get_param(signature, index + param));
|
|
switch(type->kind)
|
|
{
|
|
case JIT_TYPE_SBYTE:
|
|
{
|
|
jit_apply_builder_add_sbyte
|
|
(builder, *((jit_sbyte *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UBYTE:
|
|
{
|
|
jit_apply_builder_add_ubyte
|
|
(builder, *((jit_ubyte *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_SHORT:
|
|
{
|
|
jit_apply_builder_add_short
|
|
(builder, *((jit_short *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_USHORT:
|
|
{
|
|
jit_apply_builder_add_ushort
|
|
(builder, *((jit_ushort *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_INT:
|
|
{
|
|
jit_apply_builder_add_int
|
|
(builder, *((jit_int *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
{
|
|
jit_apply_builder_add_uint
|
|
(builder, *((jit_uint *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NINT:
|
|
case JIT_TYPE_PTR:
|
|
case JIT_TYPE_SIGNATURE:
|
|
{
|
|
jit_apply_builder_add_nint
|
|
(builder, *((jit_nint *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NUINT:
|
|
{
|
|
jit_apply_builder_add_nuint
|
|
(builder, *((jit_nuint *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
{
|
|
jit_apply_builder_add_long
|
|
(builder, *((jit_long *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
{
|
|
jit_apply_builder_add_ulong
|
|
(builder, *((jit_ulong *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
{
|
|
jit_apply_builder_add_float32
|
|
(builder, *((jit_float32 *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
{
|
|
jit_apply_builder_add_float64
|
|
(builder, *((jit_float64 *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
{
|
|
jit_apply_builder_add_nfloat
|
|
(builder, *((jit_nfloat *)(args[param])));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_STRUCT:
|
|
case JIT_TYPE_UNION:
|
|
{
|
|
jit_apply_builder_add_struct
|
|
(builder, args[param], jit_type_get_size(type),
|
|
jit_type_get_alignment(type));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get the return value after calling a function using "__builtin_apply".
|
|
*/
|
|
static void jit_apply_builder_get_return
|
|
(jit_apply_builder *builder, void *return_value,
|
|
jit_type_t type, jit_apply_return *result)
|
|
{
|
|
switch(type->kind)
|
|
{
|
|
case JIT_TYPE_SBYTE:
|
|
{
|
|
*((jit_sbyte *)return_value) =
|
|
jit_apply_return_get_sbyte(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UBYTE:
|
|
{
|
|
*((jit_ubyte *)return_value) =
|
|
jit_apply_return_get_ubyte(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_SHORT:
|
|
{
|
|
*((jit_short *)return_value) =
|
|
jit_apply_return_get_short(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_USHORT:
|
|
{
|
|
*((jit_ushort *)return_value) =
|
|
jit_apply_return_get_ushort(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_INT:
|
|
{
|
|
*((jit_int *)return_value) =
|
|
jit_apply_return_get_int(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
{
|
|
*((jit_uint *)return_value) =
|
|
jit_apply_return_get_uint(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NINT:
|
|
case JIT_TYPE_PTR:
|
|
case JIT_TYPE_SIGNATURE:
|
|
{
|
|
*((jit_nint *)return_value) =
|
|
jit_apply_return_get_nint(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NUINT:
|
|
{
|
|
*((jit_nuint *)return_value) =
|
|
jit_apply_return_get_nuint(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
{
|
|
*((jit_long *)return_value) =
|
|
jit_apply_return_get_long(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
{
|
|
*((jit_ulong *)return_value) =
|
|
jit_apply_return_get_ulong(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
{
|
|
*((jit_float32 *)return_value) =
|
|
jit_apply_return_get_float32(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
{
|
|
*((jit_float64 *)return_value) =
|
|
jit_apply_return_get_float64(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
{
|
|
*((jit_nfloat *)return_value) =
|
|
jit_apply_return_get_nfloat(result);
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_STRUCT:
|
|
case JIT_TYPE_UNION:
|
|
{
|
|
unsigned int size = jit_type_get_size(type);
|
|
jit_apply_builder_get_struct_return
|
|
(builder, size, return_value, result);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun void jit_apply (jit_type_t signature, {void *} func, {void **} args, {unsigned int} num_fixed_args, {void *} return_value)
|
|
* Call a function that has a particular function signature.
|
|
* If the signature has more than @code{num_fixed_args} arguments,
|
|
* then it is assumed to be a vararg call, with the additional
|
|
* arguments passed in the vararg argument area on the stack.
|
|
* The @code{signature} must specify the type of all arguments,
|
|
* including those in the vararg argument area.
|
|
* @end deftypefun
|
|
@*/
|
|
void jit_apply(jit_type_t signature, void *func,
|
|
void **args, unsigned int num_fixed_args,
|
|
void *return_value)
|
|
{
|
|
jit_apply_builder builder;
|
|
unsigned int size;
|
|
jit_apply_return *apply_return;
|
|
jit_type_t type;
|
|
|
|
/* Initialize the argument builder */
|
|
jit_apply_builder_init(&builder, signature);
|
|
|
|
/* Handle the structure return argument */
|
|
type = jit_type_normalize(jit_type_get_return(signature));
|
|
if(jit_type_is_struct(type) || jit_type_is_union(type))
|
|
{
|
|
size = jit_type_get_size(type);
|
|
jit_apply_builder_add_struct_return(&builder, size, return_value);
|
|
}
|
|
|
|
/* Copy the arguments into position */
|
|
jit_apply_builder_add_arguments
|
|
(&builder, signature, args, 0, num_fixed_args);
|
|
jit_apply_builder_start_varargs(&builder);
|
|
jit_apply_builder_add_arguments
|
|
(&builder, signature, args + num_fixed_args, num_fixed_args,
|
|
jit_type_num_params(signature) - num_fixed_args);
|
|
|
|
/* Call the function using "__builtin_apply" or something similar */
|
|
if(type->kind < JIT_TYPE_FLOAT32 || type->kind > JIT_TYPE_NFLOAT)
|
|
{
|
|
jit_builtin_apply(func, builder.apply_args,
|
|
builder.stack_used, 0, apply_return);
|
|
}
|
|
else
|
|
{
|
|
jit_builtin_apply(func, builder.apply_args,
|
|
builder.stack_used, 1, apply_return);
|
|
}
|
|
|
|
/* Copy the return value into position */
|
|
if(return_value != 0 && type != jit_type_void)
|
|
{
|
|
jit_apply_builder_get_return
|
|
(&builder, return_value, type, apply_return);
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun void jit_apply_raw (jit_type_t signature, {void *} func, {void *} args, {void *} return_value)
|
|
* Call a function, passing a set of raw arguments. This can only
|
|
* be used if @code{jit_raw_supported} returns non-zero for the signature.
|
|
* The @code{args} value is assumed to be an array of @code{jit_nint} values
|
|
* that correspond to each of the arguments. Raw function calls
|
|
* are slightly faster than their non-raw counterparts, but can
|
|
* only be used in certain circumstances.
|
|
* @end deftypefun
|
|
@*/
|
|
void jit_apply_raw(jit_type_t signature, void *func,
|
|
void *args, void *return_value)
|
|
{
|
|
jit_apply_return *apply_return;
|
|
unsigned int size;
|
|
jit_type_t type;
|
|
|
|
/* Call the function using "__builtin_apply" or something similar */
|
|
type = jit_type_normalize(jit_type_get_return(signature));
|
|
size = jit_type_num_params(signature) * sizeof(jit_nint);
|
|
if(type->kind < JIT_TYPE_FLOAT32 || type->kind > JIT_TYPE_NFLOAT)
|
|
{
|
|
jit_builtin_apply(func, args, size, 0, apply_return);
|
|
}
|
|
else
|
|
{
|
|
jit_builtin_apply(func, args, size, 1, apply_return);
|
|
}
|
|
|
|
/* Copy the return value into position */
|
|
if(return_value != 0 && type != jit_type_void)
|
|
{
|
|
jit_apply_builder_get_return
|
|
(0, return_value, type, apply_return);
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_raw_supported (jit_type_t signature)
|
|
* Determine if @code{jit_apply_raw} can be used to call functions
|
|
* with a particular signature. Returns zero if not.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_raw_supported(jit_type_t signature)
|
|
{
|
|
#if JIT_APPLY_NUM_WORD_REGS == 0 && JIT_APPLY_NUM_FLOAT_REGS == 0 && \
|
|
JIT_APPLY_STRUCT_RETURN_SPECIAL_REG == 0
|
|
|
|
unsigned int param;
|
|
jit_type_t type;
|
|
|
|
#if JIT_APPLY_X86_FASTCALL != 0
|
|
/* Cannot use raw calls with fastcall functions */
|
|
if(jit_type_get_abi(signature) == jit_abi_fastcall)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* Check that all of the arguments are word-sized */
|
|
param = jit_type_num_params(signature);
|
|
while(param > 0)
|
|
{
|
|
--param;
|
|
type = jit_type_normalize(jit_type_get_param(signature, param));
|
|
if(type->kind < JIT_TYPE_SBYTE || type->kind > JIT_TYPE_NUINT)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Check that the return value does not involve structures */
|
|
type = jit_type_get_return(signature);
|
|
if(jit_type_is_struct(type) || jit_type_is_union(type))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* The signature is suitable for use with "jit_apply_raw" */
|
|
return 1;
|
|
|
|
#else
|
|
/* We cannot use raw calls if we need to use registers in applys */
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Define the structure of a vararg list for closures.
|
|
*/
|
|
struct jit_closure_va_list
|
|
{
|
|
jit_apply_builder builder;
|
|
};
|
|
|
|
#ifdef jit_closure_size
|
|
|
|
/*
|
|
* Define the closure structure.
|
|
*/
|
|
typedef struct jit_closure *jit_closure_t;
|
|
struct jit_closure
|
|
{
|
|
unsigned char buf[jit_closure_size];
|
|
jit_type_t signature;
|
|
jit_closure_func func;
|
|
void *user_data;
|
|
};
|
|
|
|
/*
|
|
* Handler that is called when a closure is invoked.
|
|
*/
|
|
static void closure_handler(jit_closure_t closure, void *apply_args)
|
|
{
|
|
jit_type_t signature = closure->signature;
|
|
jit_type_t type;
|
|
jit_apply_builder parser;
|
|
void *return_buffer;
|
|
void **args;
|
|
void *temp_arg;
|
|
unsigned int num_params;
|
|
unsigned int param;
|
|
jit_apply_return apply_return;
|
|
int is_float_return;
|
|
|
|
/* Initialize the argument parser */
|
|
jit_apply_parser_init(&parser, closure->signature, apply_args);
|
|
|
|
/* Allocate space for the return value */
|
|
type = jit_type_normalize(jit_type_get_return(signature));
|
|
if(!type || type == jit_type_void)
|
|
{
|
|
return_buffer = 0;
|
|
}
|
|
else if(jit_type_return_via_pointer(type))
|
|
{
|
|
jit_apply_parser_get_struct_return(&parser, return_buffer);
|
|
}
|
|
else
|
|
{
|
|
return_buffer = alloca(jit_type_get_size(type));
|
|
}
|
|
|
|
/* Allocate space for the argument buffer. We allow for one
|
|
extra argument to hold the "va" list */
|
|
num_params = jit_type_num_params(signature);
|
|
args = (void **)alloca((num_params + 1) * sizeof(void *));
|
|
|
|
/* Extract the fixed arguments */
|
|
for(param = 0; param < num_params; ++param)
|
|
{
|
|
type = jit_type_normalize(jit_type_get_param(signature, param));
|
|
if(!type)
|
|
{
|
|
args[param] = 0;
|
|
continue;
|
|
}
|
|
temp_arg = alloca(jit_type_get_size(type));
|
|
args[param] = temp_arg;
|
|
switch(type->kind)
|
|
{
|
|
case JIT_TYPE_SBYTE:
|
|
{
|
|
jit_apply_parser_get_sbyte
|
|
(&parser, *((jit_sbyte *)temp_arg));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UBYTE:
|
|
{
|
|
jit_apply_parser_get_ubyte
|
|
(&parser, *((jit_ubyte *)temp_arg));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_SHORT:
|
|
{
|
|
jit_apply_parser_get_short
|
|
(&parser, *((jit_short *)temp_arg));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_USHORT:
|
|
{
|
|
jit_apply_parser_get_ushort
|
|
(&parser, *((jit_ushort *)temp_arg));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_INT:
|
|
{
|
|
jit_apply_parser_get_int
|
|
(&parser, *((jit_int *)temp_arg));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
{
|
|
jit_apply_parser_get_uint
|
|
(&parser, *((jit_uint *)temp_arg));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
{
|
|
jit_apply_parser_get_long
|
|
(&parser, *((jit_long *)temp_arg));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
{
|
|
jit_apply_parser_get_ulong
|
|
(&parser, *((jit_ulong *)temp_arg));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
{
|
|
jit_apply_parser_get_float32
|
|
(&parser, *((jit_float32 *)temp_arg));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
{
|
|
jit_apply_parser_get_float64
|
|
(&parser, *((jit_float64 *)temp_arg));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
{
|
|
jit_apply_parser_get_nfloat
|
|
(&parser, *((jit_nfloat *)temp_arg));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_STRUCT:
|
|
case JIT_TYPE_UNION:
|
|
{
|
|
jit_apply_parser_get_struct
|
|
(&parser, jit_type_get_size(type),
|
|
jit_type_get_alignment(type), temp_arg);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Adjust the argument parser for the start of the va arguments */
|
|
jit_apply_parser_start_varargs(&parser);
|
|
|
|
/* Record the address of the va handler in the last argument slot.
|
|
Not all functions will need this, but it doesn't hurt to include it */
|
|
args[num_params] = &parser;
|
|
|
|
/* Call the user's closure handling function */
|
|
(*(closure->func))(signature, return_buffer, args, closure->user_data);
|
|
|
|
/* Set up the "apply return" buffer */
|
|
jit_memzero(&apply_return, sizeof(apply_return));
|
|
type = jit_type_normalize(jit_type_get_return(signature));
|
|
is_float_return = 0;
|
|
if(type)
|
|
{
|
|
switch(type->kind)
|
|
{
|
|
case JIT_TYPE_SBYTE:
|
|
{
|
|
jit_apply_return_set_sbyte
|
|
(&apply_return, *((jit_sbyte *)return_buffer));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UBYTE:
|
|
{
|
|
jit_apply_return_set_ubyte
|
|
(&apply_return, *((jit_ubyte *)return_buffer));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_SHORT:
|
|
{
|
|
jit_apply_return_set_short
|
|
(&apply_return, *((jit_short *)return_buffer));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_USHORT:
|
|
{
|
|
jit_apply_return_set_ushort
|
|
(&apply_return, *((jit_ushort *)return_buffer));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_INT:
|
|
{
|
|
jit_apply_return_set_int
|
|
(&apply_return, *((jit_int *)return_buffer));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_UINT:
|
|
{
|
|
jit_apply_return_set_uint
|
|
(&apply_return, *((jit_uint *)return_buffer));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_LONG:
|
|
{
|
|
jit_apply_return_set_long
|
|
(&apply_return, *((jit_long *)return_buffer));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_ULONG:
|
|
{
|
|
jit_apply_return_set_ulong
|
|
(&apply_return, *((jit_ulong *)return_buffer));
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT32:
|
|
{
|
|
jit_apply_return_set_float32
|
|
(&apply_return, *((jit_float32 *)return_buffer));
|
|
is_float_return = 1;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_FLOAT64:
|
|
{
|
|
jit_apply_return_set_float64
|
|
(&apply_return, *((jit_float64 *)return_buffer));
|
|
is_float_return = 1;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_NFLOAT:
|
|
{
|
|
jit_apply_return_set_nfloat
|
|
(&apply_return, *((jit_nfloat *)return_buffer));
|
|
is_float_return = 1;
|
|
}
|
|
break;
|
|
|
|
case JIT_TYPE_STRUCT:
|
|
case JIT_TYPE_UNION:
|
|
{
|
|
if(!jit_type_return_via_pointer(type))
|
|
{
|
|
jit_memcpy(&apply_return, return_buffer,
|
|
jit_type_get_size(type));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Return the result to the caller */
|
|
if(!is_float_return)
|
|
{
|
|
jit_builtin_return_int(&apply_return);
|
|
}
|
|
else
|
|
{
|
|
jit_builtin_return_float(&apply_return);
|
|
}
|
|
}
|
|
|
|
#endif /* jit_closure_size */
|
|
|
|
/*@
|
|
* @deftypefun {void *} jit_closure_create (jit_context_t context, jit_type_t signature, {jit_closure_func} func, {void *} user_data)
|
|
* Create a closure from a function signature, a closure handling function,
|
|
* and a user data value. Returns NULL if out of memory, or if closures are
|
|
* not supported. The @code{func} argument should have the following
|
|
* prototype:
|
|
*
|
|
* @example
|
|
* void func (jit_type_t signature, void *result,
|
|
* void **args, void *user_data);
|
|
* @end example
|
|
*
|
|
* If the closure signature includes variable arguments, then @code{args}
|
|
* will contain pointers to the fixed arguments, followed by a
|
|
* @code{jit_closure_va_list_t} value for accessing the remainder of
|
|
* the arguments.
|
|
*
|
|
* The memory for the closure will be reclaimed when the @code{context}
|
|
* is destroyed.
|
|
* @end deftypefun
|
|
@*/
|
|
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 */
|
|
if(!context || !signature || !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)
|
|
{
|
|
jit_mutex_unlock(&(context->cache_lock));
|
|
return 0;
|
|
}
|
|
closure = (jit_closure_t)_jit_cache_alloc_no_method
|
|
(cache, sizeof(struct jit_closure), jit_closure_align);
|
|
if(!closure)
|
|
{
|
|
jit_mutex_unlock(&(context->cache_lock));
|
|
return 0;
|
|
}
|
|
|
|
/* Fill in the closure fields */
|
|
_jit_create_closure
|
|
(closure->buf, (void *)closure_handler, closure, signature);
|
|
closure->signature = signature;
|
|
closure->func = func;
|
|
closure->user_data = user_data;
|
|
|
|
/* 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;
|
|
|
|
#else
|
|
/* Closures are not supported on this platform */
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_closures_supported (void)
|
|
* Determine if this platform has support for closures.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_closures_supported(void)
|
|
{
|
|
#ifdef jit_closure_size
|
|
return 1;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_nint jit_closure_va_get_nint (jit_closure_va_list_t va)
|
|
* @deftypefunx jit_nuint jit_closure_va_get_nuint (jit_closure_va_list_t va)
|
|
* @deftypefunx jit_long jit_closure_va_get_long (jit_closure_va_list_t va)
|
|
* @deftypefunx jit_ulong jit_closure_va_get_ulong (jit_closure_va_list_t va)
|
|
* @deftypefunx jit_float32 jit_closure_va_get_float32 (jit_closure_va_list_t va)
|
|
* @deftypefunx jit_float64 jit_closure_va_get_float64 (jit_closure_va_list_t va)
|
|
* @deftypefunx jit_nfloat jit_closure_va_get_nfloat (jit_closure_va_list_t va)
|
|
* @deftypefunx {void *} jit_closure_va_get_ptr (jit_closure_va_list_t va)
|
|
* Get the next value of a specific type from a closure's variable arguments.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_nint jit_closure_va_get_nint(jit_closure_va_list_t va)
|
|
{
|
|
jit_nint value;
|
|
jit_apply_parser_get_nint(&(va->builder), value);
|
|
return value;
|
|
}
|
|
|
|
jit_nuint jit_closure_va_get_nuint(jit_closure_va_list_t va)
|
|
{
|
|
jit_nuint value;
|
|
jit_apply_parser_get_nuint(&(va->builder), value);
|
|
return value;
|
|
}
|
|
|
|
jit_long jit_closure_va_get_long(jit_closure_va_list_t va)
|
|
{
|
|
jit_long value;
|
|
jit_apply_parser_get_long(&(va->builder), value);
|
|
return value;
|
|
}
|
|
|
|
jit_ulong jit_closure_va_get_ulong(jit_closure_va_list_t va)
|
|
{
|
|
jit_ulong value;
|
|
jit_apply_parser_get_ulong(&(va->builder), value);
|
|
return value;
|
|
}
|
|
|
|
jit_float32 jit_closure_va_get_float32(jit_closure_va_list_t va)
|
|
{
|
|
jit_float32 value;
|
|
jit_apply_parser_get_float32(&(va->builder), value);
|
|
return value;
|
|
}
|
|
|
|
jit_float64 jit_closure_va_get_float64(jit_closure_va_list_t va)
|
|
{
|
|
jit_float64 value;
|
|
jit_apply_parser_get_float64(&(va->builder), value);
|
|
return value;
|
|
}
|
|
|
|
jit_nfloat jit_closure_va_get_nfloat(jit_closure_va_list_t va)
|
|
{
|
|
jit_nfloat value;
|
|
jit_apply_parser_get_nfloat(&(va->builder), value);
|
|
return value;
|
|
}
|
|
|
|
void *jit_closure_va_get_ptr(jit_closure_va_list_t va)
|
|
{
|
|
jit_nint value;
|
|
jit_apply_parser_get_nint(&(va->builder), value);
|
|
return (void *)value;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun void jit_closure_va_get_struct (jit_closure_va_list_t va, void *buf, jit_type_t type)
|
|
* Get a structure or union value of a specific @code{type} from a closure's
|
|
* variable arguments, and copy it into @code{buf}.
|
|
* @end deftypefun
|
|
@*/
|
|
void jit_closure_va_get_struct
|
|
(jit_closure_va_list_t va, void *buf, jit_type_t type)
|
|
{
|
|
jit_apply_parser_get_struct
|
|
(&(va->builder), jit_type_get_size(type),
|
|
jit_type_get_alignment(type), buf);
|
|
}
|
|
|