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.
1620 lines
44 KiB
1620 lines
44 KiB
/*
|
|
* jit-type.c - Functions for manipulating type descriptors.
|
|
*
|
|
* Copyright (C) 2004 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/>.
|
|
*/
|
|
|
|
#include "jit-internal.h"
|
|
#include "jit-apply-rules.h"
|
|
#include "jit-rules.h"
|
|
|
|
/*@
|
|
|
|
@cindex jit-type.h
|
|
@tindex jit_type_t
|
|
|
|
The functions that are defined in @code{<jit/jit-type.h>} allow
|
|
the library user to create and manipulate objects that represent
|
|
native system types. For example, @code{jit_type_int} represents
|
|
the signed 32-bit integer type.
|
|
|
|
Each @code{jit_type_t} object represents a basic system type,
|
|
be it a primitive, a struct, a union, a pointer, or a function signature.
|
|
The library uses this information to lay out values in memory.
|
|
|
|
The following pre-defined types are available:
|
|
|
|
@table @code
|
|
@vindex jit_type_void
|
|
@item jit_type_void
|
|
Represents the @code{void} type.
|
|
|
|
@vindex jit_type_sbyte
|
|
@item jit_type_sbyte
|
|
Represents a signed 8-bit integer type.
|
|
|
|
@vindex jit_type_ubyte
|
|
@item jit_type_ubyte
|
|
Represents an unsigned 8-bit integer type.
|
|
|
|
@vindex jit_type_short
|
|
@item jit_type_short
|
|
Represents a signed 16-bit integer type.
|
|
|
|
@vindex jit_type_ushort
|
|
@item jit_type_ushort
|
|
Represents an unsigned 16-bit integer type.
|
|
|
|
@vindex jit_type_int
|
|
@item jit_type_int
|
|
Represents a signed 32-bit integer type.
|
|
|
|
@vindex jit_type_uint
|
|
@item jit_type_uint
|
|
Represents an unsigned 32-bit integer type.
|
|
|
|
@vindex jit_type_nint
|
|
@item jit_type_nint
|
|
Represents a signed integer type that has the same size and
|
|
alignment as a native pointer.
|
|
|
|
@vindex jit_type_nuint
|
|
@item jit_type_nuint
|
|
Represents an unsigned integer type that has the same size and
|
|
alignment as a native pointer.
|
|
|
|
@vindex jit_type_long
|
|
@item jit_type_long
|
|
Represents a signed 64-bit integer type.
|
|
|
|
@vindex jit_type_ulong
|
|
@item jit_type_ulong
|
|
Represents an unsigned 64-bit integer type.
|
|
|
|
@vindex jit_type_float32
|
|
@item jit_type_float32
|
|
Represents a 32-bit floating point type.
|
|
|
|
@vindex jit_type_float64
|
|
@item jit_type_float64
|
|
Represents a 64-bit floating point type.
|
|
|
|
@vindex jit_type_nfloat
|
|
@item jit_type_nfloat
|
|
Represents a floating point type that represents the greatest
|
|
precision supported on the native platform.
|
|
|
|
@vindex jit_type_void_ptr
|
|
@item jit_type_void_ptr
|
|
Represents the system's @code{void *} type. This can be used wherever
|
|
a native pointer type is required.
|
|
@end table
|
|
|
|
Type descriptors are reference counted. You can make a copy of a type
|
|
descriptor using the @code{jit_type_copy} function, and free the copy with
|
|
@code{jit_type_free}.
|
|
|
|
Some languages have special versions of the primitive numeric types
|
|
(e.g. boolean types, 16-bit Unicode character types, enumerations, etc).
|
|
If it is important to distinguish these special versions from the
|
|
numeric types, then you should use the @code{jit_type_create_tagged}
|
|
function below.
|
|
|
|
The following types correspond to the system types on the local
|
|
platform. i.e. @code{jit_type_sys_int} will be the same size as
|
|
@code{long} on the local platform, whereas @code{jit_type_long} is
|
|
always 64 bits in size. These types should not be used to compile
|
|
code that is intended to work identically on all platforms:
|
|
|
|
@table @code
|
|
@vindex jit_type_sys_bool
|
|
@item jit_type_sys_bool
|
|
Corresponds to the system @code{bool} type.
|
|
|
|
@vindex jit_type_sys_char
|
|
@item jit_type_sys_char
|
|
Corresponds to the system @code{char} type. This may be either signed
|
|
or unsigned, depending upon the underlying system.
|
|
|
|
@vindex jit_type_sys_schar
|
|
@item jit_type_sys_schar
|
|
Corresponds to the system @code{signed char} type.
|
|
|
|
@vindex jit_type_sys_uchar
|
|
@item jit_type_sys_uchar
|
|
Corresponds to the system @code{unsigned char} type.
|
|
|
|
@vindex jit_type_sys_short
|
|
@item jit_type_sys_short
|
|
Corresponds to the system @code{short} type.
|
|
|
|
@vindex jit_type_sys_ushort
|
|
@item jit_type_sys_ushort
|
|
Corresponds to the system @code{unsigned short} type.
|
|
|
|
@vindex jit_type_sys_int
|
|
@item jit_type_sys_int
|
|
Corresponds to the system @code{int} type.
|
|
|
|
@vindex jit_type_sys_uint
|
|
@item jit_type_sys_uint
|
|
Corresponds to the system @code{unsigned int} type.
|
|
|
|
@vindex jit_type_sys_long
|
|
@item jit_type_sys_long
|
|
Corresponds to the system @code{long} type.
|
|
|
|
@vindex jit_type_sys_ulong
|
|
@item jit_type_sys_ulong
|
|
Corresponds to the system @code{unsigned long} type.
|
|
|
|
@vindex jit_type_sys_longlong
|
|
@item jit_type_sys_longlong
|
|
Corresponds to the system @code{long long} type (@code{__int64} under Win32).
|
|
|
|
@vindex jit_type_sys_ulonglong
|
|
@item jit_type_sys_ulonglong
|
|
Corresponds to the system @code{unsigned long long} type
|
|
(@code{unsigned __int64} under Win32).
|
|
|
|
@vindex jit_type_sys_float
|
|
@item jit_type_sys_float
|
|
Corresponds to the system @code{float} type.
|
|
|
|
@vindex jit_type_sys_double
|
|
@item jit_type_sys_double
|
|
Corresponds to the system @code{double} type.
|
|
|
|
@vindex jit_type_sys_long_double
|
|
@item jit_type_sys_long_double
|
|
Corresponds to the system @code{long double} type.
|
|
@end table
|
|
|
|
@*/
|
|
|
|
/*
|
|
* Pre-defined type descriptors.
|
|
*/
|
|
struct _jit_type const _jit_type_void_def =
|
|
{1, JIT_TYPE_VOID, 0, 1, 0, 1, 1};
|
|
jit_type_t const jit_type_void = (jit_type_t)&_jit_type_void_def;
|
|
struct _jit_type const _jit_type_sbyte_def =
|
|
{1, JIT_TYPE_SBYTE, 0, 1, 0, sizeof(jit_sbyte), JIT_ALIGN_SBYTE};
|
|
jit_type_t const jit_type_sbyte = (jit_type_t)&_jit_type_sbyte_def;
|
|
struct _jit_type const _jit_type_ubyte_def =
|
|
{1, JIT_TYPE_UBYTE, 0, 1, 0, sizeof(jit_ubyte), JIT_ALIGN_UBYTE};
|
|
jit_type_t const jit_type_ubyte = (jit_type_t)&_jit_type_ubyte_def;
|
|
struct _jit_type const _jit_type_short_def =
|
|
{1, JIT_TYPE_SHORT, 0, 1, 0, sizeof(jit_short), JIT_ALIGN_SHORT};
|
|
jit_type_t const jit_type_short = (jit_type_t)&_jit_type_short_def;
|
|
struct _jit_type const _jit_type_ushort_def =
|
|
{1, JIT_TYPE_USHORT, 0, 1, 0, sizeof(jit_ushort), JIT_ALIGN_USHORT};
|
|
jit_type_t const jit_type_ushort = (jit_type_t)&_jit_type_ushort_def;
|
|
struct _jit_type const _jit_type_int_def =
|
|
{1, JIT_TYPE_INT, 0, 1, 0, sizeof(jit_int), JIT_ALIGN_INT};
|
|
jit_type_t const jit_type_int = (jit_type_t)&_jit_type_int_def;
|
|
struct _jit_type const _jit_type_uint_def =
|
|
{1, JIT_TYPE_UINT, 0, 1, 0, sizeof(jit_uint), JIT_ALIGN_UINT};
|
|
jit_type_t const jit_type_uint = (jit_type_t)&_jit_type_uint_def;
|
|
struct _jit_type const _jit_type_nint_def =
|
|
{1, JIT_TYPE_NINT, 0, 1, 0, sizeof(jit_nint), JIT_ALIGN_NINT};
|
|
jit_type_t const jit_type_nint = (jit_type_t)&_jit_type_nint_def;
|
|
struct _jit_type const _jit_type_nuint_def =
|
|
{1, JIT_TYPE_NUINT, 0, 1, 0, sizeof(jit_nuint), JIT_ALIGN_NUINT};
|
|
jit_type_t const jit_type_nuint = (jit_type_t)&_jit_type_nuint_def;
|
|
struct _jit_type const _jit_type_long_def =
|
|
{1, JIT_TYPE_LONG, 0, 1, 0, sizeof(jit_long), JIT_ALIGN_LONG};
|
|
jit_type_t const jit_type_long = (jit_type_t)&_jit_type_long_def;
|
|
struct _jit_type const _jit_type_ulong_def =
|
|
{1, JIT_TYPE_ULONG, 0, 1, 0, sizeof(jit_ulong), JIT_ALIGN_ULONG};
|
|
jit_type_t const jit_type_ulong = (jit_type_t)&_jit_type_ulong_def;
|
|
struct _jit_type const _jit_type_float32_def =
|
|
{1, JIT_TYPE_FLOAT32, 0, 1, 0, sizeof(jit_float32), JIT_ALIGN_FLOAT32};
|
|
jit_type_t const jit_type_float32 = (jit_type_t)&_jit_type_float32_def;
|
|
struct _jit_type const _jit_type_float64_def =
|
|
{1, JIT_TYPE_FLOAT64, 0, 1, 0, sizeof(jit_float64), JIT_ALIGN_FLOAT64};
|
|
jit_type_t const jit_type_float64 = (jit_type_t)&_jit_type_float64_def;
|
|
struct _jit_type const _jit_type_nfloat_def =
|
|
{1, JIT_TYPE_NFLOAT, 0, 1, 0, sizeof(jit_nfloat), JIT_ALIGN_NFLOAT};
|
|
jit_type_t const jit_type_nfloat = (jit_type_t)&_jit_type_nfloat_def;
|
|
struct _jit_type const _jit_type_void_ptr_def =
|
|
{1, JIT_TYPE_PTR, 0, 1, 0, sizeof(void *), JIT_ALIGN_PTR,
|
|
(jit_type_t)&_jit_type_void_def};
|
|
jit_type_t const jit_type_void_ptr = (jit_type_t)&_jit_type_void_ptr_def;
|
|
|
|
/*
|
|
* Type descriptors for the system "char", "int", "long", etc types.
|
|
* These are defined to one of the above values, tagged with a value
|
|
* that indicates which system type it is referring to.
|
|
*/
|
|
#define DECLARE_TAGGED(name,real,tag) \
|
|
static struct jit_tagged_type const name##_tagged = \
|
|
{{1, JIT_TYPE_FIRST_TAGGED + (tag), 0, 1, 0, 0, 0, \
|
|
(jit_type_t)&_jit_type_##real}, 0, 0}; \
|
|
jit_type_t const jit_type_##name = (jit_type_t)&name##_tagged
|
|
DECLARE_TAGGED(sys_bool, ubyte_def, JIT_TYPETAG_SYS_BOOL);
|
|
#ifdef __CHAR_UNSIGNED__
|
|
DECLARE_TAGGED(sys_char, ubyte_def, JIT_TYPETAG_SYS_CHAR);
|
|
#else
|
|
DECLARE_TAGGED(sys_char, sbyte_def, JIT_TYPETAG_SYS_CHAR);
|
|
#endif
|
|
DECLARE_TAGGED(sys_schar, sbyte_def, JIT_TYPETAG_SYS_SCHAR);
|
|
DECLARE_TAGGED(sys_uchar, ubyte_def, JIT_TYPETAG_SYS_UCHAR);
|
|
#if SIZEOF_SHORT == 4
|
|
DECLARE_TAGGED(sys_short, int_def, JIT_TYPETAG_SYS_SHORT);
|
|
DECLARE_TAGGED(sys_ushort, uint_def, JIT_TYPETAG_SYS_USHORT);
|
|
#elif SIZEOF_SHORT == 8
|
|
DECLARE_TAGGED(sys_short, long_def, JIT_TYPETAG_SYS_SHORT);
|
|
DECLARE_TAGGED(sys_ushort, ulong_def, JIT_TYPETAG_SYS_USHORT);
|
|
#else
|
|
DECLARE_TAGGED(sys_short, short_def, JIT_TYPETAG_SYS_SHORT);
|
|
DECLARE_TAGGED(sys_ushort, ushort_def, JIT_TYPETAG_SYS_USHORT);
|
|
#endif
|
|
#if SIZEOF_INT == 8
|
|
DECLARE_TAGGED(sys_int, long_def, JIT_TYPETAG_SYS_INT);
|
|
DECLARE_TAGGED(sys_uint, ulong_def, JIT_TYPETAG_SYS_UINT);
|
|
#elif SIZEOF_INT == 2
|
|
DECLARE_TAGGED(sys_int, short_def, JIT_TYPETAG_SYS_INT);
|
|
DECLARE_TAGGED(sys_uint, ushort_def, JIT_TYPETAG_SYS_UINT);
|
|
#else
|
|
DECLARE_TAGGED(sys_int, int_def, JIT_TYPETAG_SYS_INT);
|
|
DECLARE_TAGGED(sys_uint, uint_def, JIT_TYPETAG_SYS_UINT);
|
|
#endif
|
|
#if SIZEOF_LONG == 8
|
|
DECLARE_TAGGED(sys_long, long_def, JIT_TYPETAG_SYS_LONG);
|
|
DECLARE_TAGGED(sys_ulong, ulong_def, JIT_TYPETAG_SYS_ULONG);
|
|
#elif SIZEOF_LONG == 2
|
|
DECLARE_TAGGED(sys_long, short_def, JIT_TYPETAG_SYS_LONG);
|
|
DECLARE_TAGGED(sys_ulong, ushort_def, JIT_TYPETAG_SYS_ULONG);
|
|
#else
|
|
DECLARE_TAGGED(sys_long, int_def, JIT_TYPETAG_SYS_LONG);
|
|
DECLARE_TAGGED(sys_ulong, uint_def, JIT_TYPETAG_SYS_ULONG);
|
|
#endif
|
|
#if SIZEOF_LONG_LONG == 8 || SIZEOF___INT64 == 8
|
|
DECLARE_TAGGED(sys_longlong, long_def, JIT_TYPETAG_SYS_LONGLONG);
|
|
DECLARE_TAGGED(sys_ulonglong, ulong_def, JIT_TYPETAG_SYS_ULONGLONG);
|
|
#elif SIZEOF_LONG_LONG == 4
|
|
DECLARE_TAGGED(sys_longlong, int_def, JIT_TYPETAG_SYS_LONGLONG);
|
|
DECLARE_TAGGED(sys_ulonglong, uint_def, JIT_TYPETAG_SYS_ULONGLONG);
|
|
#elif SIZEOF_LONG_LONG == 2
|
|
DECLARE_TAGGED(sys_longlong, short_def, JIT_TYPETAG_SYS_LONGLONG);
|
|
DECLARE_TAGGED(sys_ulonglong, ushort_def, JIT_TYPETAG_SYS_ULONGLONG);
|
|
#else
|
|
DECLARE_TAGGED(sys_longlong, long_def, JIT_TYPETAG_SYS_LONGLONG);
|
|
DECLARE_TAGGED(sys_ulonglong, ulong_def, JIT_TYPETAG_SYS_ULONGLONG);
|
|
#endif
|
|
DECLARE_TAGGED(sys_float, float32_def, JIT_TYPETAG_SYS_FLOAT);
|
|
DECLARE_TAGGED(sys_double, float64_def, JIT_TYPETAG_SYS_DOUBLE);
|
|
DECLARE_TAGGED(sys_long_double, nfloat_def, JIT_TYPETAG_SYS_LONGDOUBLE);
|
|
|
|
/*
|
|
* Special offset flags.
|
|
*/
|
|
#define JIT_OFFSET_IS_INTERNAL (((jit_nuint)1) << (sizeof(jit_nint) * 8 - 1))
|
|
#define JIT_OFFSET_NOT_SET (~((jit_nuint)0))
|
|
|
|
/*
|
|
* Layout flags.
|
|
*/
|
|
#define JIT_LAYOUT_NEEDED 1
|
|
#define JIT_LAYOUT_EXPLICIT_SIZE 2
|
|
#define JIT_LAYOUT_EXPLICIT_ALIGN 4
|
|
|
|
/*
|
|
* Perform layout on a structure or union type.
|
|
*/
|
|
static void perform_layout(jit_type_t type)
|
|
{
|
|
jit_nuint size = 0;
|
|
jit_nuint maxSize = 0;
|
|
jit_nuint maxAlign = 1;
|
|
jit_nuint alignLimit;
|
|
jit_nuint fieldSize;
|
|
jit_nuint fieldAlign;
|
|
unsigned int index;
|
|
|
|
/* Determine the alignment limit, if there is an override */
|
|
#ifdef JIT_ALIGN_OVERRIDES
|
|
if((type->layout_flags & JIT_LAYOUT_EXPLICIT_ALIGN) != 0)
|
|
{
|
|
alignLimit = type->alignment;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
alignLimit = 0;
|
|
}
|
|
|
|
/* Lay out all of the fields in this structure */
|
|
for(index = 0; index < type->num_components; ++index)
|
|
{
|
|
/* Get the size and alignment of the field */
|
|
fieldSize = jit_type_get_size(type->components[index].type);
|
|
fieldAlign = jit_type_get_alignment(type->components[index].type);
|
|
|
|
/* Clamp the alignment if we have a limit */
|
|
if(alignLimit != 0 && fieldAlign > alignLimit)
|
|
{
|
|
fieldAlign = alignLimit;
|
|
}
|
|
|
|
/* Update the size and alignment values */
|
|
if(type->kind == JIT_TYPE_STRUCT)
|
|
{
|
|
/* Perform layout for a struct type */
|
|
if((type->components[index].offset & JIT_OFFSET_IS_INTERNAL) != 0)
|
|
{
|
|
/* Calculate the offset for the field automatically */
|
|
if((size % fieldAlign) != 0)
|
|
{
|
|
size += fieldAlign - (size % fieldAlign);
|
|
}
|
|
type->components[index].offset = JIT_OFFSET_IS_INTERNAL | size;
|
|
size += fieldSize;
|
|
}
|
|
else
|
|
{
|
|
/* Use the explicitly-supplied offset for the field */
|
|
size = type->components[index].offset + fieldSize;
|
|
}
|
|
if(size > maxSize)
|
|
{
|
|
maxSize = size;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Perform layout for a union type (offset is always zero) */
|
|
type->components[index].offset = JIT_OFFSET_IS_INTERNAL | 0;
|
|
if((fieldSize % fieldAlign) != 0)
|
|
{
|
|
fieldSize += fieldAlign - (fieldSize % fieldAlign);
|
|
}
|
|
if(fieldSize > maxSize)
|
|
{
|
|
maxSize = fieldSize;
|
|
}
|
|
}
|
|
if(fieldAlign > maxAlign)
|
|
{
|
|
maxAlign = fieldAlign;
|
|
}
|
|
}
|
|
|
|
/* Align the full structure */
|
|
if((maxSize % maxAlign) != 0)
|
|
{
|
|
maxSize += maxAlign - (maxSize % maxAlign);
|
|
}
|
|
|
|
/* Record the final size and alignment values */
|
|
if((type->layout_flags & JIT_LAYOUT_EXPLICIT_SIZE) != 0)
|
|
{
|
|
if(maxSize > type->size)
|
|
{
|
|
type->size = maxSize;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
type->size = maxSize;
|
|
}
|
|
if(maxAlign > type->alignment)
|
|
{
|
|
type->alignment = maxAlign;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_copy (jit_type_t @var{type})
|
|
* Make a copy of the type descriptor @var{type} by increasing
|
|
* its reference count.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_copy(jit_type_t type)
|
|
{
|
|
if(!type || type->is_fixed)
|
|
{
|
|
return type;
|
|
}
|
|
++(type->ref_count);
|
|
return type;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun void jit_type_free (jit_type_t @var{type})
|
|
* Free a type descriptor by decreasing its reference count.
|
|
* This function is safe to use on pre-defined types, which are
|
|
* never actually freed.
|
|
* @end deftypefun
|
|
@*/
|
|
void jit_type_free(jit_type_t type)
|
|
{
|
|
unsigned int index;
|
|
if(!type || type->is_fixed)
|
|
{
|
|
return;
|
|
}
|
|
if(--(type->ref_count) != 0)
|
|
{
|
|
return;
|
|
}
|
|
jit_type_free(type->sub_type);
|
|
for(index = 0; index < type->num_components; ++index)
|
|
{
|
|
jit_type_free(type->components[index].type);
|
|
if(type->components[index].name)
|
|
{
|
|
jit_free(type->components[index].name);
|
|
}
|
|
}
|
|
if(type->kind >= JIT_TYPE_FIRST_TAGGED)
|
|
{
|
|
struct jit_tagged_type *tagged = (struct jit_tagged_type *)type;
|
|
if(tagged->free_func)
|
|
{
|
|
(*(tagged->free_func))(tagged->data);
|
|
}
|
|
}
|
|
jit_free(type);
|
|
}
|
|
|
|
static jit_type_t create_complex(int kind, jit_type_t *types,
|
|
unsigned int num, int incref)
|
|
{
|
|
jit_type_t type;
|
|
unsigned int index;
|
|
if(num <= 1)
|
|
{
|
|
type = jit_cnew(struct _jit_type);
|
|
}
|
|
else
|
|
{
|
|
type = (jit_type_t)jit_calloc
|
|
(1, sizeof(struct _jit_type) +
|
|
(num - 1) * sizeof(struct jit_component));
|
|
}
|
|
if(!type)
|
|
{
|
|
return 0;
|
|
}
|
|
type->ref_count = 1;
|
|
type->kind = kind;
|
|
type->layout_flags = JIT_LAYOUT_NEEDED;
|
|
type->num_components = num;
|
|
for(index = 0; index < num; ++index)
|
|
{
|
|
if(incref)
|
|
{
|
|
type->components[index].type = jit_type_copy(types[index]);
|
|
}
|
|
else
|
|
{
|
|
type->components[index].type = types[index];
|
|
}
|
|
type->components[index].offset = JIT_OFFSET_NOT_SET;
|
|
type->components[index].name = 0;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_create_struct (jit_type_t *@var{fields}, unsigned int @var{num_fields}, int @var{incref})
|
|
* Create a type descriptor for a structure. Returns NULL if out of memory.
|
|
* If there are no fields, then the size of the structure will be zero.
|
|
* It is necessary to add a padding field if the language does not allow
|
|
* zero-sized structures. The reference counts on the field types are
|
|
* incremented if @var{incref} is non-zero.
|
|
*
|
|
* The @code{libjit} library does not provide any special support for
|
|
* implementing structure inheritance, where one structure extends the
|
|
* definition of another. The effect of inheritance can be achieved
|
|
* by always allocating the first field of a structure to be an instance
|
|
* of the inherited structure. Multiple inheritance can be supported
|
|
* by allocating several special fields at the front of an inheriting
|
|
* structure.
|
|
*
|
|
* Similarly, no special support is provided for vtables. The program
|
|
* is responsible for allocating an appropriate slot in a structure to
|
|
* contain the vtable pointer, and dereferencing it wherever necessary.
|
|
* The vtable will itself be a structure, containing signature types
|
|
* for each of the method slots.
|
|
*
|
|
* The choice not to provide special support for inheritance and vtables
|
|
* in @code{libjit} was deliberate. The layout of objects and vtables
|
|
* is highly specific to the language and virtual machine being emulated,
|
|
* and no single scheme can hope to capture all possibilities.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_create_struct(jit_type_t *fields, unsigned int num_fields,
|
|
int incref)
|
|
{
|
|
return create_complex(JIT_TYPE_STRUCT, fields, num_fields, incref);
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_create_union (jit_type_t *@var{fields}, unsigned int @var{num_fields}, int @var{incref})
|
|
* Create a type descriptor for a union. Returns NULL if out of memory.
|
|
* If there are no fields, then the size of the union will be zero.
|
|
* It is necessary to add a padding field if the language does not allow
|
|
* zero-sized unions. The reference counts on the field types are
|
|
* incremented if @var{incref} is non-zero.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_create_union(jit_type_t *fields, unsigned int num_fields,
|
|
int incref)
|
|
{
|
|
return create_complex(JIT_TYPE_UNION, fields, num_fields, incref);
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_create_signature (jit_abi_t @var{abi}, jit_type_t @var{return_type}, jit_type_t *@var{params}, unsigned int @var{num_params}, int @var{incref})
|
|
* Create a type descriptor for a function signature. Returns NULL if out
|
|
* of memory. The reference counts on the component types are incremented
|
|
* if @var{incref} is non-zero.
|
|
*
|
|
* When used as a structure or union field, function signatures are laid
|
|
* out like pointers. That is, they represent a pointer to a function
|
|
* that has the specified parameters and return type.
|
|
*
|
|
* @tindex jit_abi_t
|
|
* The @var{abi} parameter specifies the Application Binary Interface (ABI)
|
|
* that the function uses. It may be one of the following values:
|
|
*
|
|
* @table @code
|
|
* @vindex jit_abi_cdecl
|
|
* @item jit_abi_cdecl
|
|
* Use the native C ABI definitions of the underlying platform.
|
|
*
|
|
* @vindex jit_abi_vararg
|
|
* @item jit_abi_vararg
|
|
* Use the native C ABI definitions of the underlying platform,
|
|
* and allow for an optional list of variable argument parameters.
|
|
*
|
|
* @vindex jit_abi_stdcall
|
|
* @item jit_abi_stdcall
|
|
* Use the Win32 STDCALL ABI definitions, whereby the callee pops
|
|
* its arguments rather than the caller. If the platform does
|
|
* not support this type of ABI, then @code{jit_abi_stdcall} will be
|
|
* identical to @code{jit_abi_cdecl}.
|
|
*
|
|
* @vindex jit_abi_fastcall
|
|
* @item jit_abi_fastcall
|
|
* Use the Win32 FASTCALL ABI definitions, whereby the callee pops
|
|
* its arguments rather than the caller, and the first two word
|
|
* arguments are passed in ECX and EDX. If the platform does
|
|
* not support this type of ABI, then @code{jit_abi_fastcall} will be
|
|
* identical to @code{jit_abi_cdecl}.
|
|
* @end table
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_create_signature(jit_abi_t abi, jit_type_t return_type,
|
|
jit_type_t *params,
|
|
unsigned int num_params, int incref)
|
|
{
|
|
jit_type_t type;
|
|
type = create_complex(JIT_TYPE_SIGNATURE, params, num_params, incref);
|
|
if(type)
|
|
{
|
|
type->abi = (int)abi;
|
|
type->layout_flags = 0;
|
|
type->size = 0;
|
|
type->alignment = JIT_ALIGN_PTR;
|
|
if(incref)
|
|
{
|
|
type->sub_type = jit_type_copy(return_type);
|
|
}
|
|
else
|
|
{
|
|
type->sub_type = return_type;
|
|
}
|
|
}
|
|
return type;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_create_pointer (jit_type_t @var{type}, int @var{incref})
|
|
* Create a type descriptor for a pointer to another type. Returns NULL
|
|
* if out of memory. The reference count on @var{type} is incremented if
|
|
* @var{incref} is non-zero.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_create_pointer(jit_type_t type, int incref)
|
|
{
|
|
jit_type_t ntype;
|
|
if(type == jit_type_void)
|
|
{
|
|
return jit_type_void_ptr;
|
|
}
|
|
if((ntype = jit_cnew(struct _jit_type)) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
ntype->ref_count = 1;
|
|
ntype->kind = JIT_TYPE_PTR;
|
|
ntype->size = sizeof(void *);
|
|
ntype->alignment = JIT_ALIGN_PTR;
|
|
if(incref)
|
|
{
|
|
ntype->sub_type = jit_type_copy(type);
|
|
}
|
|
else
|
|
{
|
|
ntype->sub_type = type;
|
|
}
|
|
return ntype;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_create_tagged (jit_type_t @var{type}, int @var{kind}, void *@var{data}, jit_meta_free_func @var{free_func}, int @var{incref})
|
|
* Tag a type with some additional user data. Tagging is typically used by
|
|
* higher-level programs to embed extra information about a type that
|
|
* @code{libjit} itself does not support.
|
|
*
|
|
* As an example, a language might have a 16-bit Unicode character type
|
|
* and a 16-bit unsigned integer type that are distinct types, even though
|
|
* they share the same fundamental representation (@code{jit_ushort}).
|
|
* Tagging allows the program to distinguish these two types, when
|
|
* it is necessary to do so, without affecting @code{libjit}'s ability
|
|
* to compile the code efficiently.
|
|
*
|
|
* The @var{kind} is a small positive integer value that the program
|
|
* can use to distinguish multiple tag types. The @var{data} pointer is
|
|
* the actual data that you wish to store. And @var{free_func} is a
|
|
* function that is used to free @var{data} when the type is freed
|
|
* with @code{jit_type_free}.
|
|
*
|
|
* If you need to store more than one piece of information, you can
|
|
* tag a type multiple times. The order in which multiple tags are
|
|
* applied is irrelevant to @code{libjit}, although it may be relevant
|
|
* to the higher-level program.
|
|
*
|
|
* Tag kinds of 10000 or greater are reserved for @code{libjit} itself.
|
|
* The following special tag kinds are currently provided in the
|
|
* base implementation:
|
|
*
|
|
* @table @code
|
|
* @vindex JIT_TYPETAG_NAME
|
|
* @item JIT_TYPETAG_NAME
|
|
* The @var{data} pointer is a @code{char *} string indicating a friendly
|
|
* name to display for the type.
|
|
*
|
|
* @vindex JIT_TYPETAG_STRUCT_NAME
|
|
* @vindex JIT_TYPETAG_UNION_NAME
|
|
* @vindex JIT_TYPETAG_ENUM_NAME
|
|
* @item JIT_TYPETAG_STRUCT_NAME
|
|
* @itemx JIT_TYPETAG_UNION_NAME
|
|
* @itemx JIT_TYPETAG_ENUM_NAME
|
|
* The @var{data} pointer is a @code{char *} string indicating a friendly
|
|
* name to display for a @code{struct}, @code{union}, or @code{enum} type.
|
|
* This is for languages like C that have separate naming scopes for
|
|
* typedef's and structures.
|
|
*
|
|
* @vindex JIT_TYPETAG_CONST
|
|
* @item JIT_TYPETAG_CONST
|
|
* The underlying value is assumed to have @code{const} semantics.
|
|
* The @code{libjit} library doesn't enforce such semantics: it is
|
|
* up to the front-end to only use constant values in appopriate contexts.
|
|
*
|
|
* @vindex JIT_TYPETAG_VOLATILE
|
|
* @item JIT_TYPETAG_VOLATILE
|
|
* The underlying value is assumed to be volatile. The @code{libjit}
|
|
* library will automatically call @code{jit_value_set_volatile} when a
|
|
* value is constructed using this type.
|
|
*
|
|
* @vindex JIT_TYPETAG_REFERENCE
|
|
* @item JIT_TYPETAG_REFERENCE
|
|
* The underlying value is a pointer, but it is assumed to refer to a
|
|
* pass-by-reference parameter.
|
|
*
|
|
* @vindex JIT_TYPETAG_OUTPUT
|
|
* @item JIT_TYPETAG_OUTPUT
|
|
* This is similar to @code{JIT_TYPETAG_REFERENCE}, except that the
|
|
* underlying parameter is assumed to be output-only.
|
|
*
|
|
* @vindex JIT_TYPETAG_RESTRICT
|
|
* @item JIT_TYPETAG_RESTRICT
|
|
* The underlying type is marked as @code{restrict}. Normally ignored.
|
|
*
|
|
* @vindex JIT_TYPETAG_SYS_BOOL
|
|
* @vindex JIT_TYPETAG_SYS_CHAR
|
|
* @vindex JIT_TYPETAG_SYS_SCHAR
|
|
* @vindex JIT_TYPETAG_SYS_UCHAR
|
|
* @vindex JIT_TYPETAG_SYS_SHORT
|
|
* @vindex JIT_TYPETAG_SYS_USHORT
|
|
* @vindex JIT_TYPETAG_SYS_INT
|
|
* @vindex JIT_TYPETAG_SYS_UINT
|
|
* @vindex JIT_TYPETAG_SYS_LONG
|
|
* @vindex JIT_TYPETAG_SYS_ULONG
|
|
* @vindex JIT_TYPETAG_SYS_LONGLONG
|
|
* @vindex JIT_TYPETAG_SYS_ULONGLONG
|
|
* @vindex JIT_TYPETAG_SYS_FLOAT
|
|
* @vindex JIT_TYPETAG_SYS_DOUBLE
|
|
* @vindex JIT_TYPETAG_SYS_LONGDOUBLE
|
|
* @item JIT_TYPETAG_SYS_BOOL
|
|
* @itemx JIT_TYPETAG_SYS_CHAR
|
|
* @itemx JIT_TYPETAG_SYS_SCHAR
|
|
* @itemx JIT_TYPETAG_SYS_UCHAR
|
|
* @itemx JIT_TYPETAG_SYS_SHORT
|
|
* @itemx JIT_TYPETAG_SYS_USHORT
|
|
* @itemx JIT_TYPETAG_SYS_INT
|
|
* @itemx JIT_TYPETAG_SYS_UINT
|
|
* @itemx JIT_TYPETAG_SYS_LONG
|
|
* @itemx JIT_TYPETAG_SYS_ULONG
|
|
* @itemx JIT_TYPETAG_SYS_LONGLONG
|
|
* @itemx JIT_TYPETAG_SYS_ULONGLONG
|
|
* @itemx JIT_TYPETAG_SYS_FLOAT
|
|
* @itemx JIT_TYPETAG_SYS_DOUBLE
|
|
* @itemx JIT_TYPETAG_SYS_LONGDOUBLE
|
|
* Used to mark types that we know for a fact correspond to the system
|
|
* C types of the corresponding names. This is primarily used to distinguish
|
|
* system types like @code{int} and @code{long} types on 32-bit platforms
|
|
* when it is necessary to do so. The @code{jit_type_sys_xxx} values are
|
|
* all tagged in this manner.
|
|
* @end table
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_create_tagged(jit_type_t type, int kind, void *data,
|
|
jit_meta_free_func free_func, int incref)
|
|
{
|
|
struct jit_tagged_type *ntype;
|
|
if((ntype = jit_cnew(struct jit_tagged_type)) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
ntype->type.ref_count = 1;
|
|
ntype->type.kind = JIT_TYPE_FIRST_TAGGED + kind;
|
|
ntype->type.size = 0;
|
|
ntype->type.alignment = 1;
|
|
if(incref)
|
|
{
|
|
ntype->type.sub_type = jit_type_copy(type);
|
|
}
|
|
else
|
|
{
|
|
ntype->type.sub_type = type;
|
|
}
|
|
ntype->data = data;
|
|
ntype->free_func = free_func;
|
|
return &(ntype->type);
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_type_set_names (jit_type_t @var{type}, char **@var{names}, unsigned int @var{num_names})
|
|
* Set the field or parameter names for @var{type}. Returns zero
|
|
* if there is insufficient memory to set the names.
|
|
*
|
|
* Normally fields are accessed via their index. Field names are a
|
|
* convenience for front ends that prefer to use names to indices.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_type_set_names(jit_type_t type, char **names, unsigned int num_names)
|
|
{
|
|
char *temp;
|
|
if(!type || type->is_fixed || !names)
|
|
{
|
|
return 1;
|
|
}
|
|
if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION ||
|
|
type->kind == JIT_TYPE_SIGNATURE)
|
|
{
|
|
if(num_names > type->num_components)
|
|
{
|
|
num_names = type->num_components;
|
|
}
|
|
while(num_names > 0)
|
|
{
|
|
--num_names;
|
|
if(type->components[num_names].name)
|
|
{
|
|
jit_free(type->components[num_names].name);
|
|
type->components[num_names].name = 0;
|
|
}
|
|
if(names[num_names])
|
|
{
|
|
temp = jit_strdup(names[num_names]);
|
|
if(!temp)
|
|
{
|
|
return 0;
|
|
}
|
|
type->components[num_names].name = temp;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun void jit_type_set_size_and_alignment (jit_type_t @var{type}, jit_nint @var{size}, jit_nint @var{alignment})
|
|
* Set the size and alignment information for a structure or union
|
|
* type. Use this for performing explicit type layout. Normally
|
|
* the size is computed automatically. Ignored if not a
|
|
* structure or union type. Setting either value to -1 will cause
|
|
* that value to be computed automatically.
|
|
* @end deftypefun
|
|
@*/
|
|
void jit_type_set_size_and_alignment(jit_type_t type, jit_nint size,
|
|
jit_nint alignment)
|
|
{
|
|
if(!type)
|
|
{
|
|
return;
|
|
}
|
|
if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
|
|
{
|
|
type->size = (jit_nuint)size;
|
|
type->alignment = (jit_nuint)alignment;
|
|
if(size != -1)
|
|
{
|
|
type->layout_flags |= JIT_LAYOUT_EXPLICIT_SIZE;
|
|
}
|
|
if(alignment != -1)
|
|
{
|
|
type->layout_flags |= JIT_LAYOUT_EXPLICIT_ALIGN;
|
|
}
|
|
type->layout_flags |= JIT_LAYOUT_NEEDED;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun void jit_type_set_offset (jit_type_t @var{type}, unsigned int @var{field_index}, jit_nuint @var{offset})
|
|
* Set the offset of a specific structure field. Use this for
|
|
* performing explicit type layout. Normally the offset is
|
|
* computed automatically. Ignored if not a structure type,
|
|
* or the field index is out of range.
|
|
* @end deftypefun
|
|
@*/
|
|
void jit_type_set_offset(jit_type_t type, unsigned int field_index,
|
|
jit_nuint offset)
|
|
{
|
|
if(!type || field_index >= type->num_components)
|
|
{
|
|
return;
|
|
}
|
|
if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
|
|
{
|
|
type->components[field_index].offset = offset;
|
|
type->layout_flags |= JIT_LAYOUT_NEEDED;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_type_get_kind (jit_type_t @var{type})
|
|
* Get a value that indicates the kind of @var{type}. This allows
|
|
* callers to quickly classify a type to determine how it should be
|
|
* handled further.
|
|
*
|
|
* @table @code
|
|
* @vindex JIT_TYPE_INVALID
|
|
* @item JIT_TYPE_INVALID
|
|
* The value of the @var{type} parameter is NULL.
|
|
*
|
|
* @vindex JIT_TYPE_VOID
|
|
* @item JIT_TYPE_VOID
|
|
* The type is @code{jit_type_void}.
|
|
*
|
|
* @vindex JIT_TYPE_SBYTE
|
|
* @item JIT_TYPE_SBYTE
|
|
* The type is @code{jit_type_sbyte}.
|
|
*
|
|
* @vindex JIT_TYPE_UBYTE
|
|
* @item JIT_TYPE_UBYTE
|
|
* The type is @code{jit_type_ubyte}.
|
|
*
|
|
* @vindex JIT_TYPE_SHORT
|
|
* @item JIT_TYPE_SHORT
|
|
* The type is @code{jit_type_short}.
|
|
*
|
|
* @vindex JIT_TYPE_USHORT
|
|
* @item JIT_TYPE_USHORT
|
|
* The type is @code{jit_type_ushort}.
|
|
*
|
|
* @vindex JIT_TYPE_INT
|
|
* @item JIT_TYPE_INT
|
|
* The type is @code{jit_type_int}.
|
|
*
|
|
* @vindex JIT_TYPE_UINT
|
|
* @item JIT_TYPE_UINT
|
|
* The type is @code{jit_type_uint}.
|
|
*
|
|
* @vindex JIT_TYPE_NINT
|
|
* @item JIT_TYPE_NINT
|
|
* The type is @code{jit_type_nint}.
|
|
*
|
|
* @vindex JIT_TYPE_NUINT
|
|
* @item JIT_TYPE_NUINT
|
|
* The type is @code{jit_type_nuint}.
|
|
*
|
|
* @vindex JIT_TYPE_LONG
|
|
* @item JIT_TYPE_LONG
|
|
* The type is @code{jit_type_long}.
|
|
*
|
|
* @vindex JIT_TYPE_ULONG
|
|
* @item JIT_TYPE_ULONG
|
|
* The type is @code{jit_type_ulong}.
|
|
*
|
|
* @vindex JIT_TYPE_FLOAT32
|
|
* @item JIT_TYPE_FLOAT32
|
|
* The type is @code{jit_type_float32}.
|
|
*
|
|
* @vindex JIT_TYPE_FLOAT64
|
|
* @item JIT_TYPE_FLOAT64
|
|
* The type is @code{jit_type_float64}.
|
|
*
|
|
* @vindex JIT_TYPE_NFLOAT
|
|
* @item JIT_TYPE_NFLOAT
|
|
* The type is @code{jit_type_nfloat}.
|
|
*
|
|
* @vindex JIT_TYPE_STRUCT
|
|
* @item JIT_TYPE_STRUCT
|
|
* The type is the result of calling @code{jit_type_create_struct}.
|
|
*
|
|
* @vindex JIT_TYPE_UNION
|
|
* @item JIT_TYPE_UNION
|
|
* The type is the result of calling @code{jit_type_create_union}.
|
|
*
|
|
* @vindex JIT_TYPE_SIGNATURE
|
|
* @item JIT_TYPE_SIGNATURE
|
|
* The type is the result of calling @code{jit_type_create_signature}.
|
|
*
|
|
* @vindex JIT_TYPE_PTR
|
|
* @item JIT_TYPE_PTR
|
|
* The type is the result of calling @code{jit_type_create_pointer}.
|
|
* @end table
|
|
*
|
|
* @vindex JIT_TYPE_FIRST_TAGGED
|
|
* If this function returns @code{JIT_TYPE_FIRST_TAGGED} or higher,
|
|
* then the type is tagged and its tag kind is the return value minus
|
|
* @code{JIT_TYPE_FIRST_TAGGED}. That is, the following two expressions
|
|
* will be identical if @var{type} is tagged:
|
|
*
|
|
* @example
|
|
* jit_type_get_tagged_kind(type)
|
|
* jit_type_get_kind(type) - JIT_TYPE_FIRST_TAGGED
|
|
* @end example
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_type_get_kind(jit_type_t type)
|
|
{
|
|
if(!type)
|
|
{
|
|
return JIT_TYPE_INVALID;
|
|
}
|
|
else
|
|
{
|
|
return type->kind;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_nuint jit_type_get_size (jit_type_t @var{type})
|
|
* Get the size of a type in bytes.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_nuint jit_type_get_size(jit_type_t type)
|
|
{
|
|
if(!type)
|
|
{
|
|
return 0;
|
|
}
|
|
if(type->kind == JIT_TYPE_SIGNATURE)
|
|
{
|
|
/* The "size" field is used for argument size, not type size,
|
|
so we ignore it and return the real size here */
|
|
return sizeof(void *);
|
|
}
|
|
else if(type->kind >= JIT_TYPE_FIRST_TAGGED)
|
|
{
|
|
return jit_type_get_size(type->sub_type);
|
|
}
|
|
if((type->layout_flags & JIT_LAYOUT_NEEDED) != 0)
|
|
{
|
|
perform_layout(type);
|
|
}
|
|
return type->size;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_nuint jit_type_get_alignment (jit_type_t @var{type})
|
|
* Get the alignment of a type. An alignment value of 2 indicates
|
|
* that the type should be aligned on a two-byte boundary, for example.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_nuint jit_type_get_alignment(jit_type_t type)
|
|
{
|
|
if(!type)
|
|
{
|
|
return 0;
|
|
}
|
|
if(type->kind >= JIT_TYPE_FIRST_TAGGED)
|
|
{
|
|
return jit_type_get_alignment(type->sub_type);
|
|
}
|
|
if((type->layout_flags & JIT_LAYOUT_NEEDED) != 0)
|
|
{
|
|
perform_layout(type);
|
|
}
|
|
return type->alignment;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun {unsigned int} jit_type_num_fields (jit_type_t @var{type})
|
|
* Get the number of fields in a structure or union type.
|
|
* @end deftypefun
|
|
@*/
|
|
unsigned int jit_type_num_fields(jit_type_t type)
|
|
{
|
|
if(!type ||
|
|
(type->kind != JIT_TYPE_STRUCT && type->kind != JIT_TYPE_UNION))
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return type->num_components;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_get_field (jit_type_t @var{type}, unsigned int @var{field_index})
|
|
* Get the type of a specific field within a structure or union.
|
|
* Returns NULL if not a structure or union, or the index is out of range.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_get_field(jit_type_t type, unsigned int field_index)
|
|
{
|
|
if(!type || field_index >= type->num_components)
|
|
{
|
|
return 0;
|
|
}
|
|
if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
|
|
{
|
|
return type->components[field_index].type;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_nuint jit_type_get_offset (jit_type_t @var{type}, unsigned int @var{field_index})
|
|
* Get the offset of a specific field within a structure.
|
|
* Returns zero if not a structure, or the index is out of range,
|
|
* so this is safe to use on non-structure types.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_nuint jit_type_get_offset(jit_type_t type, unsigned int field_index)
|
|
{
|
|
if(!type || field_index >= type->num_components)
|
|
{
|
|
return 0;
|
|
}
|
|
if(type->kind != JIT_TYPE_STRUCT && type->kind != JIT_TYPE_UNION)
|
|
{
|
|
return 0;
|
|
}
|
|
if((type->layout_flags & JIT_LAYOUT_NEEDED) != 0)
|
|
{
|
|
perform_layout(type);
|
|
}
|
|
return type->components[field_index].offset & ~JIT_OFFSET_IS_INTERNAL;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun {const char *} jit_type_get_name (jit_type_t @var{type}, unsigned int @var{index})
|
|
* Get the name of a structure, union, or signature field/parameter.
|
|
* Returns NULL if not a structure, union, or signature, the index
|
|
* is out of range, or there is no name associated with the component.
|
|
* @end deftypefun
|
|
@*/
|
|
const char *jit_type_get_name(jit_type_t type, unsigned int index)
|
|
{
|
|
if(!type || index >= type->num_components)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return type->components[index].name;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun {unsigned int} jit_type_find_name (jit_type_t @var{type}, const char *@var{name})
|
|
* Find the field/parameter index for a particular name. Returns
|
|
* @code{JIT_INVALID_NAME} if the name was not present.
|
|
* @end deftypefun
|
|
@*/
|
|
unsigned int jit_type_find_name(jit_type_t type, const char *name)
|
|
{
|
|
unsigned int index;
|
|
if(!type || !name)
|
|
{
|
|
return JIT_INVALID_NAME;
|
|
}
|
|
if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION ||
|
|
type->kind == JIT_TYPE_SIGNATURE)
|
|
{
|
|
for(index = 0; index < type->num_components; ++index)
|
|
{
|
|
if(type->components[index].name &&
|
|
!jit_strcmp(type->components[index].name, name))
|
|
{
|
|
return index;
|
|
}
|
|
}
|
|
}
|
|
return JIT_INVALID_NAME;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun {unsigned int} jit_type_num_params (jit_type_t @var{type})
|
|
* Get the number of parameters in a signature type.
|
|
* @end deftypefun
|
|
@*/
|
|
unsigned int jit_type_num_params(jit_type_t type)
|
|
{
|
|
if(!type || type->kind != JIT_TYPE_SIGNATURE)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return type->num_components;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_get_return (jit_type_t @var{type})
|
|
* Get the return type from a signature type. Returns NULL if
|
|
* not a signature type.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_get_return(jit_type_t type)
|
|
{
|
|
if(type)
|
|
{
|
|
if(type->kind == JIT_TYPE_SIGNATURE)
|
|
{
|
|
return type->sub_type;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_get_param (jit_type_t @var{type}, unsigned int @var{param_index})
|
|
* Get a specific parameter from a signature type. Returns NULL
|
|
* if not a signature type or the index is out of range.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_get_param(jit_type_t type, unsigned int param_index)
|
|
{
|
|
if(!type || param_index >= type->num_components)
|
|
{
|
|
return 0;
|
|
}
|
|
if(type->kind == JIT_TYPE_SIGNATURE)
|
|
{
|
|
return type->components[param_index].type;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_abi_t jit_type_get_abi (jit_type_t @var{type})
|
|
* Get the ABI code from a signature type. Returns @code{jit_abi_cdecl}
|
|
* if not a signature type.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_abi_t jit_type_get_abi(jit_type_t type)
|
|
{
|
|
if(type)
|
|
{
|
|
return (jit_abi_t)(type->abi);
|
|
}
|
|
else
|
|
{
|
|
return jit_abi_cdecl;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_get_ref (jit_type_t @var{type})
|
|
* Get the type that is referred to by a pointer type. Returns NULL
|
|
* if not a pointer type.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_get_ref(jit_type_t type)
|
|
{
|
|
if(type)
|
|
{
|
|
if(type->kind == JIT_TYPE_PTR)
|
|
{
|
|
return type->sub_type;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_get_tagged_type (jit_type_t @var{type})
|
|
* Get the type that underlies a tagged type. Returns NULL
|
|
* if not a tagged type.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_get_tagged_type(jit_type_t type)
|
|
{
|
|
if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
|
|
{
|
|
return type->sub_type;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun void jit_type_set_tagged_type (jit_type_t @var{type}, jit_type_t @var{underlying}, int @var{incref})
|
|
* Set the type that underlies a tagged type. Ignored if @var{type}
|
|
* is not a tagged type. If @var{type} already has an underlying
|
|
* type, then the original is freed. The reference count on @var{underlying}
|
|
* is incremented if @var{incref} is non-zero.
|
|
*
|
|
* This function is typically used to flesh out the body of a
|
|
* forward-declared type. The tag is used as a placeholder
|
|
* until the definition can be located.
|
|
* @end deftypefun
|
|
@*/
|
|
void jit_type_set_tagged_type(jit_type_t type, jit_type_t underlying,
|
|
int incref)
|
|
{
|
|
if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
|
|
{
|
|
if(type->sub_type != underlying)
|
|
{
|
|
jit_type_free(type->sub_type);
|
|
if(incref)
|
|
{
|
|
type->sub_type = jit_type_copy(underlying);
|
|
}
|
|
else
|
|
{
|
|
type->sub_type = underlying;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_type_get_tagged_kind (jit_type_t @var{type})
|
|
* Get the kind of tag that is applied to a tagged type. Returns -1
|
|
* if not a tagged type.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_type_get_tagged_kind(jit_type_t type)
|
|
{
|
|
if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
|
|
{
|
|
return type->kind - JIT_TYPE_FIRST_TAGGED;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun {void *} jit_type_get_tagged_data (jit_type_t @var{type})
|
|
* Get the user data is associated with a tagged type. Returns NULL
|
|
* if not a tagged type.
|
|
* @end deftypefun
|
|
@*/
|
|
void *jit_type_get_tagged_data(jit_type_t type)
|
|
{
|
|
if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
|
|
{
|
|
return ((struct jit_tagged_type *)type)->data;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun void jit_type_set_tagged_data (jit_type_t @var{type}, void *@var{data}, jit_meta_free_func @var{free_func})
|
|
* Set the user data is associated with a tagged type. The original data,
|
|
* if any, is freed.
|
|
* @end deftypefun
|
|
@*/
|
|
void jit_type_set_tagged_data(jit_type_t type, void *data,
|
|
jit_meta_free_func free_func)
|
|
{
|
|
if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
|
|
{
|
|
struct jit_tagged_type *tagged = (struct jit_tagged_type *)type;
|
|
if(tagged->data != data)
|
|
{
|
|
if(tagged->free_func)
|
|
{
|
|
(*(tagged->free_func))(tagged->data);
|
|
}
|
|
tagged->data = data;
|
|
tagged->free_func = free_func;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_type_is_primitive (jit_type_t @var{type})
|
|
* Determine if a type is primitive.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_type_is_primitive(jit_type_t type)
|
|
{
|
|
if(type)
|
|
{
|
|
return (type->kind <= JIT_TYPE_MAX_PRIMITIVE);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_type_is_struct (jit_type_t @var{type})
|
|
* Determine if a type is a structure.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_type_is_struct(jit_type_t type)
|
|
{
|
|
if(type)
|
|
{
|
|
return (type->kind == JIT_TYPE_STRUCT);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_type_is_union (jit_type_t @var{type})
|
|
* Determine if a type is a union.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_type_is_union(jit_type_t type)
|
|
{
|
|
if(type)
|
|
{
|
|
return (type->kind == JIT_TYPE_UNION);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_type_is_signature (jit_type_t @var{type})
|
|
* Determine if a type is a function signature.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_type_is_signature(jit_type_t type)
|
|
{
|
|
if(type)
|
|
{
|
|
return (type->kind == JIT_TYPE_SIGNATURE);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_type_is_pointer (jit_type_t @var{type})
|
|
* Determine if a type is a pointer.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_type_is_pointer(jit_type_t type)
|
|
{
|
|
if(type)
|
|
{
|
|
return (type->kind == JIT_TYPE_PTR);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_type_is_tagged (jit_type_t @var{type})
|
|
* Determine if a type is a tagged type.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_type_is_tagged(jit_type_t type)
|
|
{
|
|
if(type)
|
|
{
|
|
return (type->kind >= JIT_TYPE_FIRST_TAGGED);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_nuint jit_type_best_alignment (void)
|
|
* Get the best alignment value for this platform.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_nuint jit_type_best_alignment(void)
|
|
{
|
|
return JIT_BEST_ALIGNMENT;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_normalize (jit_type_t @var{type})
|
|
* Normalize a type to its basic numeric form. e.g. "jit_type_nint" is
|
|
* turned into "jit_type_int" or "jit_type_long", depending upon
|
|
* the underlying platform. Pointers are normalized like "jit_type_nint".
|
|
* If the type does not have a normalized form, it is left unchanged.
|
|
*
|
|
* Normalization is typically used prior to applying a binary numeric
|
|
* instruction, to make it easier to determine the common type.
|
|
* It will also remove tags from the specified type.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_normalize(jit_type_t type)
|
|
{
|
|
while(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
|
|
{
|
|
/* Remove any tags that are attached to the type */
|
|
type = type->sub_type;
|
|
}
|
|
if(!type)
|
|
{
|
|
return type;
|
|
}
|
|
if(type == jit_type_nint || type->kind == JIT_TYPE_PTR ||
|
|
type->kind == JIT_TYPE_SIGNATURE)
|
|
{
|
|
#ifdef JIT_NATIVE_INT32
|
|
return jit_type_int;
|
|
#else
|
|
return jit_type_long;
|
|
#endif
|
|
}
|
|
else if(type == jit_type_nuint)
|
|
{
|
|
#ifdef JIT_NATIVE_INT32
|
|
return jit_type_uint;
|
|
#else
|
|
return jit_type_ulong;
|
|
#endif
|
|
}
|
|
else if(type == jit_type_nfloat)
|
|
{
|
|
if(sizeof(jit_nfloat) == sizeof(jit_float64))
|
|
{
|
|
return jit_type_float64;
|
|
}
|
|
else if(sizeof(jit_nfloat) == sizeof(jit_float32))
|
|
{
|
|
return jit_type_float32;
|
|
}
|
|
}
|
|
return type;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_remove_tags (jit_type_t @var{type})
|
|
* Remove tags from a type, and return the underlying type.
|
|
* This is different from normalization, which will also collapses
|
|
* native types to their basic numeric counterparts.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_remove_tags(jit_type_t type)
|
|
{
|
|
while(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
|
|
{
|
|
type = type->sub_type;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun jit_type_t jit_type_promote_int (jit_type_t @var{type})
|
|
* If @var{type} is @code{jit_type_sbyte} or @code{jit_type_short},
|
|
* then return @code{jit_type_int}. If @var{type} is
|
|
* @code{jit_type_ubyte} or @code{jit_type_ushort}, then return
|
|
* @code{jit_type_uint}. Otherwise return @var{type} as-is.
|
|
* @end deftypefun
|
|
@*/
|
|
jit_type_t jit_type_promote_int(jit_type_t type)
|
|
{
|
|
if(type == jit_type_sbyte || type == jit_type_short)
|
|
{
|
|
return jit_type_int;
|
|
}
|
|
else if(type == jit_type_ubyte || type == jit_type_ushort)
|
|
{
|
|
return jit_type_uint;
|
|
}
|
|
else
|
|
{
|
|
return type;
|
|
}
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_type_return_via_pointer (jit_type_t @var{type})
|
|
* Determine if a type should be returned via a pointer if it appears
|
|
* as the return type in a signature.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_type_return_via_pointer(jit_type_t type)
|
|
{
|
|
extern unsigned char const _jit_apply_return_in_reg[];
|
|
unsigned int size;
|
|
|
|
/* Normalize the type first, just in case the structure is tagged */
|
|
type = jit_type_normalize(type);
|
|
|
|
/* Only structure and union types require special handling */
|
|
if(!jit_type_is_struct(type) && !jit_type_is_union(type))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* Determine if the structure can be returned in a register */
|
|
size = jit_type_get_size(type);
|
|
if(size >= 1 && size <= 64)
|
|
{
|
|
if((_jit_apply_return_in_reg[(size - 1) / 8] &
|
|
(1 << ((size - 1) % 8))) != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*@
|
|
* @deftypefun int jit_type_has_tag (jit_type_t @var{type}, int @var{kind})
|
|
* Determine if @var{type} has a specific kind of tag. This will
|
|
* resolve multiple levels of tagging.
|
|
* @end deftypefun
|
|
@*/
|
|
int jit_type_has_tag(jit_type_t type, int kind)
|
|
{
|
|
while(type != 0 && type->kind >= JIT_TYPE_FIRST_TAGGED)
|
|
{
|
|
if(type->kind == (JIT_TYPE_FIRST_TAGGED + kind))
|
|
{
|
|
return 1;
|
|
}
|
|
type = type->sub_type;
|
|
}
|
|
return 0;
|
|
}
|
|
|