[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6 Manipulating system types

The functions that are defined in <jit/jit-type.h> allow the library user to create and manipulate objects that represent native system types. For example, jit_type_int represents the signed 32-bit integer type.

Each 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:

jit_type_void

Represents the void type.

jit_type_sbyte

Represents a signed 8-bit integer type.

jit_type_ubyte

Represents an unsigned 8-bit integer type.

jit_type_short

Represents a signed 16-bit integer type.

jit_type_ushort

Represents an unsigned 16-bit integer type.

jit_type_int

Represents a signed 32-bit integer type.

jit_type_uint

Represents an unsigned 32-bit integer type.

jit_type_nint

Represents a signed integer type that has the same size and alignment as a native pointer.

jit_type_nuint

Represents an unsigned integer type that has the same size and alignment as a native pointer.

jit_type_long

Represents a signed 64-bit integer type.

jit_type_ulong

Represents an unsigned 64-bit integer type.

jit_type_float32

Represents a 32-bit floating point type.

jit_type_float64

Represents a 64-bit floating point type.

jit_type_nfloat

Represents a floating point type that represents the greatest precision supported on the native platform.

jit_type_void_ptr

Represents the system’s void * type. This can be used wherever a native pointer type is required.

Type descriptors are reference counted. You can make a copy of a type descriptor using the jit_type_copy function, and free the copy with 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 jit_type_create_tagged function below.

The following types correspond to the system types on the local platform. i.e. jit_type_sys_int will be the same size as long on the local platform, whereas 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:

jit_type_sys_bool

Corresponds to the system bool type.

jit_type_sys_char

Corresponds to the system char type. This may be either signed or unsigned, depending upon the underlying system.

jit_type_sys_schar

Corresponds to the system signed char type.

jit_type_sys_uchar

Corresponds to the system unsigned char type.

jit_type_sys_short

Corresponds to the system short type.

jit_type_sys_ushort

Corresponds to the system unsigned short type.

jit_type_sys_int

Corresponds to the system int type.

jit_type_sys_uint

Corresponds to the system unsigned int type.

jit_type_sys_long

Corresponds to the system long type.

jit_type_sys_ulong

Corresponds to the system unsigned long type.

jit_type_sys_longlong

Corresponds to the system long long type (__int64 under Win32).

jit_type_sys_ulonglong

Corresponds to the system unsigned long long type (unsigned __int64 under Win32).

jit_type_sys_float

Corresponds to the system float type.

jit_type_sys_double

Corresponds to the system double type.

jit_type_sys_long_double

Corresponds to the system long double type.

Function: jit_type_t jit_type_copy (jit_type_t type)

Make a copy of the type descriptor type by increasing its reference count.

Function: void jit_type_free (jit_type_t 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.

Function: jit_type_t jit_type_create_struct (jit_type_t *fields, unsigned int num_fields, int 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 incref is non-zero.

The 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 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.

Function: jit_type_t jit_type_create_union (jit_type_t *fields, unsigned int num_fields, int 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 incref is non-zero.

Function: 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)

Create a type descriptor for a function signature. Returns NULL if out of memory. The reference counts on the component types are incremented if 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.

The abi parameter specifies the Application Binary Interface (ABI) that the function uses. It may be one of the following values:

jit_abi_cdecl

Use the native C ABI definitions of the underlying platform.

jit_abi_vararg

Use the native C ABI definitions of the underlying platform, and allow for an optional list of variable argument parameters.

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 jit_abi_stdcall will be identical to jit_abi_cdecl.

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 jit_abi_fastcall will be identical to jit_abi_cdecl.

Function: jit_type_t jit_type_create_pointer (jit_type_t type, int incref)

Create a type descriptor for a pointer to another type. Returns NULL if out of memory. The reference count on type is incremented if incref is non-zero.

Function: jit_type_t jit_type_create_tagged (jit_type_t type, int kind, void *data, jit_meta_free_func free_func, int 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 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 (jit_ushort). Tagging allows the program to distinguish these two types, when it is necessary to do so, without affecting libjit’s ability to compile the code efficiently.

The kind is a small positive integer value that the program can use to distinguish multiple tag types. The data pointer is the actual data that you wish to store. And free_func is a function that is used to free data when the type is freed with 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 libjit, although it may be relevant to the higher-level program.

Tag kinds of 10000 or greater are reserved for libjit itself. The following special tag kinds are currently provided in the base implementation:

JIT_TYPETAG_NAME

The data pointer is a char * string indicating a friendly name to display for the type.

JIT_TYPETAG_STRUCT_NAME
JIT_TYPETAG_UNION_NAME
JIT_TYPETAG_ENUM_NAME

The data pointer is a char * string indicating a friendly name to display for a struct, union, or enum type. This is for languages like C that have separate naming scopes for typedef’s and structures.

JIT_TYPETAG_CONST

The underlying value is assumed to have const semantics. The libjit library doesn’t enforce such semantics: it is up to the front-end to only use constant values in appopriate contexts.

JIT_TYPETAG_VOLATILE

The underlying value is assumed to be volatile. The libjit library will automatically call jit_value_set_volatile when a value is constructed using this type.

JIT_TYPETAG_REFERENCE

The underlying value is a pointer, but it is assumed to refer to a pass-by-reference parameter.

JIT_TYPETAG_OUTPUT

This is similar to JIT_TYPETAG_REFERENCE, except that the underlying parameter is assumed to be output-only.

JIT_TYPETAG_RESTRICT

The underlying type is marked as restrict. Normally ignored.

JIT_TYPETAG_SYS_BOOL
JIT_TYPETAG_SYS_CHAR
JIT_TYPETAG_SYS_SCHAR
JIT_TYPETAG_SYS_UCHAR
JIT_TYPETAG_SYS_SHORT
JIT_TYPETAG_SYS_USHORT
JIT_TYPETAG_SYS_INT
JIT_TYPETAG_SYS_UINT
JIT_TYPETAG_SYS_LONG
JIT_TYPETAG_SYS_ULONG
JIT_TYPETAG_SYS_LONGLONG
JIT_TYPETAG_SYS_ULONGLONG
JIT_TYPETAG_SYS_FLOAT
JIT_TYPETAG_SYS_DOUBLE
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 int and long types on 32-bit platforms when it is necessary to do so. The jit_type_sys_xxx values are all tagged in this manner.

Function: int jit_type_set_names (jit_type_t type, char **names, unsigned int num_names)

Set the field or parameter names for 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.

Function: void jit_type_set_size_and_alignment (jit_type_t type, jit_nint size, jit_nint 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.

Function: void jit_type_set_offset (jit_type_t type, unsigned int field_index, jit_nuint 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.

Function: int jit_type_get_kind (jit_type_t type)

Get a value that indicates the kind of type. This allows callers to quickly classify a type to determine how it should be handled further.

JIT_TYPE_INVALID

The value of the type parameter is NULL.

JIT_TYPE_VOID

The type is jit_type_void.

JIT_TYPE_SBYTE

The type is jit_type_sbyte.

JIT_TYPE_UBYTE

The type is jit_type_ubyte.

JIT_TYPE_SHORT

The type is jit_type_short.

JIT_TYPE_USHORT

The type is jit_type_ushort.

JIT_TYPE_INT

The type is jit_type_int.

JIT_TYPE_UINT

The type is jit_type_uint.

JIT_TYPE_NINT

The type is jit_type_nint.

JIT_TYPE_NUINT

The type is jit_type_nuint.

JIT_TYPE_LONG

The type is jit_type_long.

JIT_TYPE_ULONG

The type is jit_type_ulong.

JIT_TYPE_FLOAT32

The type is jit_type_float32.

JIT_TYPE_FLOAT64

The type is jit_type_float64.

JIT_TYPE_NFLOAT

The type is jit_type_nfloat.

JIT_TYPE_STRUCT

The type is the result of calling jit_type_create_struct.

JIT_TYPE_UNION

The type is the result of calling jit_type_create_union.

JIT_TYPE_SIGNATURE

The type is the result of calling jit_type_create_signature.

JIT_TYPE_PTR

The type is the result of calling jit_type_create_pointer.

If this function returns JIT_TYPE_FIRST_TAGGED or higher, then the type is tagged and its tag kind is the return value minus JIT_TYPE_FIRST_TAGGED. That is, the following two expressions will be identical if type is tagged:

jit_type_get_tagged_kind(type)
jit_type_get_kind(type) - JIT_TYPE_FIRST_TAGGED
Function: jit_nuint jit_type_get_size (jit_type_t type)

Get the size of a type in bytes.

Function: jit_nuint jit_type_get_alignment (jit_type_t 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.

Function: unsigned int jit_type_num_fields (jit_type_t type)

Get the number of fields in a structure or union type.

Function: jit_type_t jit_type_get_field (jit_type_t type, unsigned int 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.

Function: jit_nuint jit_type_get_offset (jit_type_t type, unsigned int 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.

Function: const char * jit_type_get_name (jit_type_t type, unsigned int 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.

Function: unsigned int jit_type_find_name (jit_type_t type, const char *name)

Find the field/parameter index for a particular name. Returns JIT_INVALID_NAME if the name was not present.

Function: unsigned int jit_type_num_params (jit_type_t type)

Get the number of parameters in a signature type.

Function: jit_type_t jit_type_get_return (jit_type_t type)

Get the return type from a signature type. Returns NULL if not a signature type.

Function: jit_type_t jit_type_get_param (jit_type_t type, unsigned int param_index)

Get a specific parameter from a signature type. Returns NULL if not a signature type or the index is out of range.

Function: jit_abi_t jit_type_get_abi (jit_type_t type)

Get the ABI code from a signature type. Returns jit_abi_cdecl if not a signature type.

Function: jit_type_t jit_type_get_ref (jit_type_t type)

Get the type that is referred to by a pointer type. Returns NULL if not a pointer type.

Function: jit_type_t jit_type_get_tagged_type (jit_type_t type)

Get the type that underlies a tagged type. Returns NULL if not a tagged type.

Function: void jit_type_set_tagged_type (jit_type_t type, jit_type_t underlying, int incref)

Set the type that underlies a tagged type. Ignored if type is not a tagged type. If type already has an underlying type, then the original is freed. The reference count on underlying is incremented if 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.

Function: int jit_type_get_tagged_kind (jit_type_t type)

Get the kind of tag that is applied to a tagged type. Returns -1 if not a tagged type.

Function: void * jit_type_get_tagged_data (jit_type_t type)

Get the user data is associated with a tagged type. Returns NULL if not a tagged type.

Function: void jit_type_set_tagged_data (jit_type_t type, void *data, jit_meta_free_func free_func)

Set the user data is associated with a tagged type. The original data, if any, is freed.

Function: int jit_type_is_primitive (jit_type_t type)

Determine if a type is primitive.

Function: int jit_type_is_struct (jit_type_t type)

Determine if a type is a structure.

Function: int jit_type_is_union (jit_type_t type)

Determine if a type is a union.

Function: int jit_type_is_signature (jit_type_t type)

Determine if a type is a function signature.

Function: int jit_type_is_pointer (jit_type_t type)

Determine if a type is a pointer.

Function: int jit_type_is_tagged (jit_type_t type)

Determine if a type is a tagged type.

Function: jit_nuint jit_type_best_alignment (void)

Get the best alignment value for this platform.

Function: jit_type_t jit_type_normalize (jit_type_t 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.

Function: jit_type_t jit_type_remove_tags (jit_type_t 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.

Function: jit_type_t jit_type_promote_int (jit_type_t type)

If type is jit_type_sbyte or jit_type_short, then return jit_type_int. If type is jit_type_ubyte or jit_type_ushort, then return jit_type_uint. Otherwise return type as-is.

Function: int jit_type_return_via_pointer (jit_type_t type)

Determine if a type should be returned via a pointer if it appears as the return type in a signature.

Function: int jit_type_has_tag (jit_type_t type, int kind)

Determine if type has a specific kind of tag. This will resolve multiple levels of tagging.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated on September 17, 2016 using texi2html 5.0.