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

14. Miscellaneous utility routines

The libjit library provides a number of utility routines that it itself uses internally, but which may also be useful to front ends.


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

14.1 Memory allocation

The libjit library provides an interface to the traditional system malloc routines. All heap allocation in libjit goes through these functions. If you need to perform some other kind of memory allocation, you can replace these functions with your own versions.

Function: void * jit_malloc (unsigned int size)

Allocate size bytes of memory from the heap.

Function: type * jit_new (type)

Allocate sizeof(type) bytes of memory from the heap and cast the return pointer to type *. This is a macro that wraps up the underlying jit_malloc function and is less error-prone when allocating structures.

Function: void * jit_calloc (unsigned int num, unsigned int size)

Allocate num * size bytes of memory from the heap and clear them to zero.

Function: type * jit_cnew (type)

Allocate sizeof(type) bytes of memory from the heap and cast the return pointer to type *. The memory is cleared to zero.

Function: void * jit_realloc (void *ptr, unsigned int size)

Re-allocate the memory at ptr to be size bytes in size. The memory block at ptr must have been allocated by a previous call to jit_malloc, jit_calloc, or jit_realloc.

Function: void jit_free (void *ptr)

Free the memory at ptr. It is safe to pass a NULL pointer.

Function: void * jit_malloc_exec (unsigned int size)

Allocate a block of memory that is read/write/executable. Such blocks are used to store JIT'ed code, function closures, and other trampolines. The size should be a multiple of jit_exec_page_size().

This will usually be identical to jit_malloc. However, some systems may need special handling to create executable code segments, so this function must be used instead.

You must never mix regular and executable segment allocation. That is, do not use jit_free to free the result of jit_malloc_exec.

Function: void jit_free_exec (void *ptr, unsigned int size)

Free a block of memory that was previously allocated by jit_malloc_exec. The size must be identical to the original allocated size, as some systems need to know this information to be able to free the block.

Function: void jit_flush_exec (void *ptr, unsigned int size)

Flush the contents of the block at ptr from the CPU's data and instruction caches. This must be used after the code is written to an executable code segment, but before the code is executed, to prepare it for execution.

Function: unsigned int jit_exec_page_size (void)

Get the page allocation size for the system. This is the preferred unit when making calls to jit_malloc_exec. It is not required that you supply a multiple of this size when allocating, but it can lead to better performance on some systems.


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

14.2 Memory set, copy, compare, etc

The following functions are provided to set, copy, compare, and search memory blocks.

Function: void * jit_memset (void *dest, int ch, unsigned int len)

Set the len bytes at dest to the value ch. Returns dest.

Function: void * jit_memcpy (void *dest, const void *src, unsigned int len)

Copy the len bytes at src to dest. Returns dest. The behavior is undefined if the blocks overlap (use jit_memmove instead for that case).

Function: void * jit_memmove (void *dest, const void *src, unsigned int len)

Copy the len bytes at src to dest and handle overlapping blocks correctly. Returns dest.

Function: int jit_memcmp (const void *s1, const void *s2, unsigned int len)

Compare len bytes at s1 and s2, returning a negative, zero, or positive result depending upon their relationship. It is system-specific as to whether this function uses signed or unsigned byte comparisons.

Function: void * jit_memchr (void *str, int ch, unsigned int len)

Search the len bytes at str for the first instance of the value ch. Returns the location of ch if it was found, or NULL if it was not found.


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

14.3 String operations

The following functions are provided to manipulate NULL-terminated strings. It is highly recommended that you use these functions in preference to system functions, because the corresponding system functions are extremely non-portable.

Function: unsigned int jit_strlen (const char *str)

Returns the length of str.

Function: char * jit_strcpy (char *dest, const char *src)

Copy the string at src to dest. Returns dest.

Function: char * jit_strcat (char *dest, const char *src)

Copy the string at src to the end of the string at dest. Returns dest.

Function: char * jit_strncpy (char *dest, const char *src, unsigned int len)

Copy at most len characters from the string at src to dest. Returns dest.

Function: char * jit_strdup (const char *str)

Allocate a block of memory using jit_malloc and copy str into it. Returns NULL if str is NULL or there is insufficient memory to perform the jit_malloc operation.

Function: char * jit_strndup (const char *str, unsigned int len)

Allocate a block of memory using jit_malloc and copy at most len characters of str into it. The copied string is then NULL-terminated. Returns NULL if str is NULL or there is insufficient memory to perform the jit_malloc operation.

Function: int jit_strcmp (const char *str1, const char *str2)

Compare the two strings str1 and str2, returning a negative, zero, or positive value depending upon their relationship.

Function: int jit_strncmp (const char *str1, const char *str2, unsigned int len)

Compare the two strings str1 and str2, returning a negative, zero, or positive value depending upon their relationship. At most len characters are compared.

Function: int jit_stricmp (const char *str1, const char *str2)

Compare the two strings str1 and str2, returning a negative, zero, or positive value depending upon their relationship. Instances of the English letters A to Z are converted into their lower case counterparts before comparison.

Note: this function is guaranteed to use English case comparison rules, no matter what the current locale is set to, making it suitable for comparing token tags and simple programming language identifiers.

Locale-sensitive string comparison is complicated and usually specific to the front end language or its supporting runtime library. We deliberately chose not to handle this in libjit.

Function: int jit_strnicmp (const char *str1, const char *str2, unsigned int len)

Compare the two strings str1 and str2, returning a negative, zero, or positive value depending upon their relationship. At most len characters are compared. Instances of the English letters A to Z are converted into their lower case counterparts before comparison.

Function: char * jit_strchr (const char *str, int ch)

Search str for the first occurrence of ch. Returns the address where ch was found, or NULL if not found.

Function: char * jit_strrchr (const char *str, int ch)

Search str for the first occurrence of ch, starting at the end of the string. Returns the address where ch was found, or NULL if not found.


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

14.4 Metadata handling

Many of the structures in the libjit library can have user-supplied metadata associated with them. Metadata may be used to store dependency graphs, branch prediction information, or any other information that is useful to optimizers or code generators.

Metadata can also be used by higher level user code to store information about the structures that is specific to the user's virtual machine or language.

The library structures have special-purpose metadata routines associated with them (e.g. jit_function_set_meta, jit_block_get_meta). However, sometimes you may wish to create your own metadata lists and attach them to your own structures. The functions below enable you to do this:

Function: int jit_meta_set (jit_meta_t *list, int type, void *data, jit_meta_free_func free_data, jit_function_t pool_owner)

Set a metadata value on a list. If the type is already present in the list, then its previous value will be freed. The free_func is called when the metadata value is freed with jit_meta_free or jit_meta_destroy. Returns zero if out of memory.

If pool_owner is not NULL, then the metadata value will persist until the specified function is finished building. Normally you would set this to NULL.

Metadata type values of 10000 or greater are reserved for internal use. They should never be used by external user code.

Function: void * jit_meta_get (jit_meta_t list, int type)

Get the value associated with type in the specified list. Returns NULL if type is not present.

Function: void jit_meta_free (jit_meta_t *list, int type)

Free the metadata value in the list that has the specified type. Does nothing if the type is not present.

Function: void jit_meta_destroy (jit_meta_t *list)

Destroy all of the metadata values in the specified list.


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

14.5 Function application and closures

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

Function: 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 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 signature must specify the type of all arguments, including those in the vararg argument area.

Function: 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 jit_raw_supported returns non-zero for the signature. The args value is assumed to be an array of 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.

Function: int jit_raw_supported (jit_type_t signature)

Determine if jit_apply_raw can be used to call functions with a particular signature. Returns zero if not.

Function: 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 func argument should have the following prototype:

 
void func (jit_type_t signature, void *result,
void **args, void *user_data);

If the closure signature includes variable arguments, then args will contain pointers to the fixed arguments, followed by a jit_closure_va_list_t value for accessing the remainder of the arguments.

The memory for the closure will be reclaimed when the context is destroyed.

Function: int jit_closures_supported (void)

Determine if this platform has support for closures.

Function: jit_nint jit_closure_va_get_nint (jit_closure_va_list_t va)
Function: jit_nuint jit_closure_va_get_nuint (jit_closure_va_list_t va)
Function: jit_long jit_closure_va_get_long (jit_closure_va_list_t va)
Function: jit_ulong jit_closure_va_get_ulong (jit_closure_va_list_t va)
Function: jit_float32 jit_closure_va_get_float32 (jit_closure_va_list_t va)
Function: jit_float64 jit_closure_va_get_float64 (jit_closure_va_list_t va)
Function: jit_nfloat jit_closure_va_get_nfloat (jit_closure_va_list_t va)
Function: 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.

Function: 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 type from a closure's variable arguments, and copy it into buf.


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

14.6 Stack walking

The functions in <jit/jit-walk.h> allow the caller to walk up the native execution stack, inspecting frames and return addresses.

Function: void * jit_get_frame_address (unsigned int n)

Get the frame address for the call frame n levels up the stack. Setting n to zero will retrieve the frame address for the current function. Returns NULL if it isn't possible to retrieve the address of the specified frame.

Function: void * jit_get_current_frame (void)

Get the frame address for the current function. This may be more efficient on some platforms than using jit_get_frame_address(0). Returns NULL if it isn't possible to retrieve the address of the current frame.

Function: void * jit_get_next_frame_address (void *frame)

Get the address of the next frame up the stack from frame. Returns NULL if it isn't possible to retrieve the address of the next frame up the stack.

Function: void * jit_get_return_address (void *frame)

Get the return address from a specified frame. The address represents the place where execution returns to when the specified frame exits. Returns NULL if it isn't possible to retrieve the return address of the specified frame.

Function: void * jit_get_current_return (void)

Get the return address for the current function. This may be more efficient on some platforms than using jit_get_return_address(0). Returns NULL if it isn't possible to retrieve the return address of the current frame.

Function: int jit_frame_contains_crawl_mark (void *frame, jit_crawl_mark_t *mark)

Determine if the stack frame that resides just above frame contains a local variable whose address is mark. The mark parameter should be the address of a local variable that is declared with jit_declare_crawl_mark(name).

Crawl marks are used internally by libjit to determine where control passes between JIT'ed and ordinary code during an exception throw. They can also be used to mark frames that have special security conditions associated with them.


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

14.7 Dynamic libraries

The following routines are supplied to help load and inspect dynamic libraries. They should be used in place of the traditional dlopen, dlclose, and dlsym functions, which are not portable across operating systems.

You must include <jit/jit-dynamic.h> to use these routines, and then link with -ljitdynamic -ljit.

Function: jit_dynlib_handle_t jit_dynlib_open (const char *name)

Opens the dynamic library called name, returning a handle for it.

Function: void jit_dynlib_close (jit_dynlib_handle_t handle)

Close a dynamic library.

Function: void * jit_dynlib_get_symbol (jit_dynlib_handle_t handle, const char *symbol)

Retrieve the symbol symbol from the specified dynamic library. Returns NULL if the symbol could not be found. This will try both non-prefixed and underscore-prefixed forms of symbol on platforms where it makes sense to do so, so there is no need for the caller to perform prefixing.

Function: void jit_dynlib_set_debug (int flag)

Enable or disable additional debug messages to stderr. Debugging is disabled by default. Normally the dynamic library routines will silently report errors via NULL return values, leaving reporting up to the caller. However, it can be useful to turn on additional diagnostics when tracking down problems with dynamic loading.

Function: const char * jit_dynlib_get_suffix (void)

Get the preferred dynamic library suffix for this platform. Usually something like so, dll, or dylib.

Sometimes you want to retrieve a C++ method from a dynamic library using jit_dynlib_get_symbol. Unfortunately, C++ name mangling rules differ from one system to another, making this process very error-prone.

The functions that follow try to help. They aren't necessarily fool-proof, but they should work in the most common cases. The only alternative is to wrap your C++ library with C functions, so that the names are predictable.

The basic idea is that you supply a description of the C++ method that you wish to access, and these functions return a number of candidate forms that you can try with jit_dynlib_get_symbol. If one form fails, you move on and try the next form, until either symbol lookup succeeds or until all forms have been exhausted.

The following code demonstrates how to resolve a global function:

 
jit_dynlib_handle_t handle;
jit_type_t signature;
int form = 0;
void *address = 0;
char *mangled;

while((mangled = jit_mangle_global_function
("foo", signature, form)) != 0)
{
address = jit_dynlib_get_symbol(handle, mangled);
if(address != 0)
{
break;
}
jit_free(mangled);
++form;
}

if(address)
{
printf("%s = 0x%lxn", mangled, (long)address);
}
else
{
printf("could not resolve foon");
}

This mechanism typically cannot be used to obtain the entry points for inline methods. You will need to make other arrangements to simulate the behaviour of inline methods, or recompile your dynamic C++ library in a mode that explicitly exports inlines.

C++ method names are very picky about types. On 32-bit systems, int and long are the same size, but they are mangled to different characters. To ensure that the correct function is picked, you should use jit_type_sys_int, jit_type_sys_long, etc instead of the platform independent types. If you do use a platform independent type like jit_type_int, this library will try to guess which system type you mean, but the guess will most likely be wrong.

Function: char * jit_mangle_global_function (const char *name, jit_type_t signature, int form)

Mangle the name of a global C++ function using the specified form. Returns NULL if out of memory, or if the form is not supported.

Function: char * jit_mangle_member_function (const char *class_name, const char *name, jit_type_t signature, int form, int flags)

Mangle the name of a C++ member function using the specified form. Returns NULL if out of memory, or if the form is not supported. The following flags may be specified to modify the mangling rules:

JIT_MANGLE_PUBLIC

The method has public access within its containing class.

JIT_MANGLE_PROTECTED

The method has protected access within its containing class.

JIT_MANGLE_PRIVATE

The method has private access within its containing class.

JIT_MANGLE_STATIC

The method is static.

JIT_MANGLE_VIRTUAL

The method is a virtual instance method. If neither JIT_MANGLE_STATIC nor JIT_MANGLE_VIRTUAL are supplied, then the method is assumed to be a non-virtual instance method.

JIT_MANGLE_CONST

The method is an instance method with the const qualifier.

JIT_MANGLE_EXPLICIT_THIS

The signature includes an extra pointer parameter at the start that indicates the type of the this pointer. This parameter won't be included in the final mangled name.

JIT_MANGLE_IS_CTOR

The method is a constructor. The name parameter will be ignored.

JIT_MANGLE_IS_DTOR

The method is a destructor. The name parameter will be ignored.

JIT_MANGLE_BASE

Fetch the "base" constructor or destructor entry point, rather than the "complete" entry point.

The class_name may include namespace and nested parent qualifiers by separating them with :: or .. Class names that involve template parameters are not supported yet.


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

This document was generated by Klaus Treichel on May, 11 2008 using texi2html 1.78.