This is libjit.info, produced by makeinfo version 4.8 from libjit.texi.

INFO-DIR-SECTION Libraries
START-INFO-DIR-ENTRY
* Libjit: (libjit).                Just-In-Time Compiler Library
END-INFO-DIR-ENTRY

   The libjit library assists with the process of building Just-In-Time
compilers for languages, virtual machines, and emulators.

   Copyright (C) 2004 Southern Storm Software, Pty Ltd


File: libjit.info,  Node: Top,  Next: Introduction,  Up: (dir)

* Menu:

* Introduction::            Introduction and rationale for libjit
* Features::                Features of libjit
* Tutorials::               Tutorials in using libjit
* Initialization::          Initializing the JIT
* Functions::               Building and compiling functions with the JIT
* Types::                   Manipulating system types
* Values::                  Working with temporary values in the JIT
* Instructions::            Working with instructions in the JIT
* Basic Blocks::            Working with basic blocks in the JIT
* Intrinsics::              Intrinsic functions available to libjit users
* Exceptions::              Handling exceptions
* Breakpoint Debugging::    Hooking a breakpoint debugger into libjit
* ELF Binaries::            Manipulating ELF binaries
* Utility Routines::        Miscellaneous utility routines
* Diagnostic Routines::     Diagnostic routines
* C++ Interface::           Using libjit from C++
* Porting::                 Porting libjit to new architectures
* Index::                   Index of concepts and facilities


File: libjit.info,  Node: Introduction,  Next: Features,  Prev: Top,  Up: Top

1 Introduction and rationale for libjit
***************************************

Just-In-Time compilers are becoming increasingly popular for executing
dynamic languages like Perl and Python and for semi-dynamic languages
like Java and C#.  Studies have shown that JIT techniques can get close
to, and sometimes exceed, the performance of statically-compiled native
code.

   However, there is a problem with current JIT approaches.  In almost
every case, the JIT is specific to the object model, runtime support
library, garbage collector, or bytecode peculiarities of a particular
system.  This inevitably leads to duplication of effort, where all of
the good JIT work that has gone into one virtual machine cannot be
reused in another.

   JIT's are not only useful for implementing languages.  They can also
be used in other programming fields.  Graphical applications can
achieve greater performance if they can compile a special-purpose
rendering routine on the fly, customized to the rendering task at hand,
rather than using static routines.  Needless to say, such applications
have no need for object models, garbage collectors, or huge runtime
class libraries.

   Most of the work on a JIT is concerned with arithmetic, numeric type
conversion, memory loads/stores, looping, performing data flow analysis,
assigning registers, and generating the executable machine code.  Only
a very small proportion of the work is concerned with language
specifics.

   The goal of the `libjit' project is to provide an extensive set of
routines that takes care of the bulk of the JIT process, without tying
the programmer down with language specifics.  Where we provide support
for common object models, we do so strictly in add-on libraries, not as
part of the core code.

   Unlike other systems such as the JVM, .NET, and Parrot, `libjit' is
not a virtual machine in its own right.  It is the foundation upon
which a number of different virtual machines, dynamic scripting
languages, or customized rendering routines can be built.

   The LLVM project (`http://www.llvm.org/') has some similar
characteristics to `libjit' in that its intermediate format is generic
across front-end languages.  It is written in C++ and provides a large
set of compiler development and optimization components; much larger
than `libjit' itself provides.  According to its author, Chris Lattner,
a subset of its capabilities can be used to build JIT's.

   Libjit should free developers to think about the design of their
front ends, and not get bogged down in the details of code execution.
Meanwhile, experts in the design and implementation of JIT's can
concentrate on solving code execution problems, instead of front end
support issues.

   This document describes how to use the library in application
programs.  We start with a list of features and some simple tutorials.
Finally, we provide a complete reference guide for all of the API
functions in `libjit', broken down by function category.

1.1 Obtaining libjit
====================

The latest version of `libjit' can be obtained from Southern Storm
Software, Pty Ltd's Web site:

     `http://www.southern-storm.com.au/libjit.html'

1.2 Further reading
===================

While it isn't strictly necessary to know about compiler internals to
use `libjit', you can make more effective use of the library if you do.
We recommend the "Dragon Book" as an excellent resource on compiler
internals, particularly the sections on code generation and
optimization:

     Alfred V. Aho, Ravi Sethi, and Jeffrey D. Ullman, "Compilers:
     Principles, Techniques, and Tools", Addison-Wesley, 1986.

   IBM, Intel, and others have done a lot of research into JIT
implementation techniques over the years.  If you are interested in
working on the internals of `libjit', then you may want to make
yourself familiar with the relevant literature (this is by no means a
complete list):

     IBM's Jikes RVM (Research Virtual Machine),
     `http://www-124.ibm.com/developerworks/oss/jikesrvm/'.

     Intel's ORP (Open Runtime Platform),
     `http://orp.sourceforge.net/'.


File: libjit.info,  Node: Features,  Next: Tutorials,  Prev: Introduction,  Up: Top

2 Features of libjit
********************

   * The primary interface is in C, for maximal reusability.  Class
     interfaces are available for programmers who prefer C++.

   * Designed for portability to all major 32-bit and 64-bit platforms.

   * Simple three-address API for library users, but opaque enough that
     other representations can be used inside the library in future
     without affecting existing users.

   * Up-front or on-demand compilation of any function.

   * In-built support to re-compile functions with greater optimization,
     automatically redirecting previous callers to the new version.

   * Fallback interpreter for running code on platforms that don't have
     a native code generator yet.  This reduces the need for
     programmers to write their own interpreters for such platforms.

   * Arithmetic, bitwise, conversion, and comparison operators for
     8-bit, 16-bit, 32-bit, or 64-bit integer types; and 32-bit,
     64-bit, or longer floating point types.  Includes overflow
     detecting arithmetic for integer types.

   * Large set of mathematical and trigonometric operations (sqrt, sin,
     cos, min, abs, etc) for inlining floating-point library functions.

   * Simplified type layout and exception handling mechanisms, upon
     which a variety of different object models can be built.

   * Support for nested functions, able to access their parent's local
     variables (for implementing Pascal-style languages).


File: libjit.info,  Node: Tutorials,  Next: Tutorial 1,  Prev: Features,  Up: Top

3 Tutorials in using libjit
***************************

In this chapter, we describe how to use `libjit' with a number of short
tutorial exercises.  Full source for these tutorials can be found in
the `tutorial' directory of the `libjit' source tree.

   For simplicity, we will ignore errors such as out of memory
conditions, but a real program would be expected to handle such errors.

* Menu:

* Tutorial 1::              Tutorial 1 - mul_add
* Tutorial 2::              Tutorial 2 - gcd
* Tutorial 3::              Tutorial 3 - compiling on-demand
* Tutorial 4::              Tutorial 4 - mul_add, C++ version
* Tutorial 5::              Tutorial 5 - gcd, with tail calls
* Dynamic Pascal::          Dynamic Pascal - A full JIT example


File: libjit.info,  Node: Tutorial 1,  Next: Tutorial 2,  Prev: Tutorials,  Up: Tutorials

3.1 Tutorial 1 - mul_add
========================

In the first tutorial, we will build and compile the following function
(the source code can be found in `tutorial/t1.c'):

     int mul_add(int x, int y, int z)
     {
         return x * y + z;
     }

To use the JIT, we first include the `<jit/jit.h>' file:

     #include <jit/jit.h>

   All of the header files are placed into the `jit' sub-directory, to
separate them out from regular system headers.  When `libjit' is
installed, you will typically find these headers in
`/usr/local/include/jit' or `/usr/include/jit', depending upon how your
system is configured.  You should also link with the `-ljit' option.

Every program that uses `libjit' needs to call `jit_context_create':

     jit_context_t context;
     ...
     context = jit_context_create();

   Almost everything that is done with `libjit' is done relative to a
context.  In particular, a context holds all of the functions that you
have built and compiled.

   You can have multiple contexts at any one time, but normally you will
only need one.  Multiple contexts may be useful if you wish to run
multiple virtual machines side by side in the same process, without
them interfering with each other.

   Whenever we are constructing a function, we need to lock down the
context to prevent multiple threads from using the builder at a time:

     jit_context_build_start(context);

   The next step is to construct the function object that will represent
our `mul_add' function:

     jit_function_t function;
     ...
     function = jit_function_create(context, signature);

   The `signature' is a `jit_type_t' object that describes the
function's parameters and return value.  This tells `libjit' how to
generate the proper calling conventions for the function:

     jit_type_t params[3];
     jit_type_t signature;
     ...
     params[0] = jit_type_int;
     params[1] = jit_type_int;
     params[2] = jit_type_int;
     signature = jit_type_create_signature
         (jit_abi_cdecl, jit_type_int, params, 3, 1);

   This declares a function that takes three parameters of type `int'
and returns a result of type `int'.  We've requested that the function
use the `cdecl' application binary interface (ABI), which indicates
normal C calling conventions.  *Note Types::, for more information on
signature types.

   Now that we have a function object, we need to construct the
instructions in its body.  First, we obtain references to each of the
function's parameter values:

     jit_value_t x, y, z;
     ...
     x = jit_value_get_param(function, 0);
     y = jit_value_get_param(function, 1);
     z = jit_value_get_param(function, 2);

   Values are one of the two cornerstones of the `libjit' process.
Values represent parameters, local variables, and intermediate
temporary results.  Once we have the parameters, we compute the result
of `x * y + z' as follows:

     jit_value_t temp1, temp2;
     ...
     temp1 = jit_insn_mul(function, x, y);
     temp2 = jit_insn_add(function, temp1, z);

   This demonstrates the other cornerstone of the `libjit' process:
instructions.  Each of these instructions takes two values as arguments
and returns a new temporary value with the result.

   Students of compiler design will notice that the above statements
look very suspiciously like the "three address statements" that are
described in compiler textbooks.  And that is indeed what they are
internally within `libjit'.

   If you don't know what three address statements are, then don't
worry.  The library hides most of the details from you.  All you need
to do is break your code up into simple operation steps (addition,
multiplication, negation, copy, etc).  Then perform the steps one at a
time, using the temporary values in subsequent steps.  *Note
Instructions::, for a complete list of all instructions that are
supported by `libjit'.

   Now that we have computed the desired result, we return it to the
caller using `jit_insn_return':

     jit_insn_return(function, temp2);

   We have completed the process of building the function body.  Now we
compile it into its executable form:

     jit_function_compile(function);
     jit_context_build_end(context);

   As a side-effect, this will discard all of the memory associated with
the values and instructions that we constructed while building the
function.  They are no longer required, because we now have the
executable form that we require.

   We also unlock the context, because it is now safe for other threads
to access the function building process.

   Up until this point, we haven't executed the `mul_add' function.
All we have done is build and compile it, ready for execution.  To
execute it, we call `jit_function_apply':

     jit_int arg1, arg2, arg3;
     void *args[3];
     jit_int result;
     ...
     arg1 = 3;
     arg2 = 5;
     arg3 = 2;
     args[0] = &arg1;
     args[1] = &arg2;
     args[2] = &arg3;
     jit_function_apply(function, args, &result);
     printf("mul_add(3, 5, 2) = %d\n", (int)result);

   We pass an array of pointers to `jit_function_apply', each one
pointing to the corresponding argument value.  This gives us a very
general purpose mechanism for calling any function that may be built
and compiled using `libjit'.  If all went well, the program should
print the following:

     mul_add(3, 5, 2) = 17

   You will notice that we used `jit_int' as the type of the arguments,
not `int'.  The `jit_int' type is guaranteed to be 32 bits in size on
all platforms, whereas `int' varies in size from platform to platform.
Since we wanted our function to work the same everywhere, we used a
type with a predictable size.

   If you really wanted the system `int' type, you would use
`jit_type_sys_int' instead of `jit_type_int' when you created the
function's signature.  The `jit_type_sys_int' type is guaranteed to
match the local system's `int' precision.

Finally, we clean up the context and all of the memory that was used:

     jit_context_destroy(context);


File: libjit.info,  Node: Tutorial 2,  Next: Tutorial 3,  Prev: Tutorial 1,  Up: Tutorials

3.2 Tutorial 2 - gcd
====================

In this second tutorial, we implement the subtracting Euclidean
Greatest Common Divisor (GCD) algorithm over positive integers.  This
tutorial demonstrates how to handle conditional branching and function
calls.  In C, the code for the `gcd' function is as follows:

     unsigned int gcd(unsigned int x, unsigned int y)
     {
         if(x == y)
         {
             return x;
         }
         else if(x < y)
         {
             return gcd(x, y - x);
         }
         else
         {
             return gcd(x - y, y);
         }
     }

   The source code for this tutorial can be found in `tutorial/t2.c'.
Many of the details are similar to the previous tutorial.  We omit
those details here and concentrate on how to build the function body.
*Note Tutorial 1::, for more information.

We start by checking the condition `x == y':

     jit_value_t x, y, temp1;
     ...
     x = jit_value_get_param(function, 0);
     y = jit_value_get_param(function, 1);
     temp1 = jit_insn_eq(function, x, y);

   This is very similar to our previous tutorial, except that we are
using the `eq' operator this time.  If the condition is not true, we
want to skip the `return' statement.  We achieve this with the
`jit_insn_branch_if_not' instruction:

     jit_label_t label1 = jit_label_undefined;
     ...
     jit_insn_branch_if_not(function, temp1, &label1);

   The label must be initialized to `jit_label_undefined'.  It will be
updated by `jit_insn_branch_if_not' to refer to a future position in
the code that we haven't seen yet.

   If the condition is true, then execution falls through to the next
instruction where we return `x' to the caller:

     jit_insn_return(function, x);

   If the condition was not true, then we branched to `label1' above.
We fix the location of the label using `jit_insn_label':

     jit_insn_label(function, &label1);

We use similar code to check the condition `x < y', and branch to
`label2' if it is not true:

     jit_value_t temp2;
     jit_label_t label2 = jit_label_undefined;
     ...
     temp2 = jit_insn_lt(function, x, y);
     jit_insn_branch_if_not(function, temp2, &label2);

   At this point, we need to call the `gcd' function with the arguments
`x' and `y - x'.  The code for this is fairly straight-forward.  The
`jit_insn_call' instruction calls the function listed in its third
argument.  In this case, we are calling ourselves recursively:

     jit_value_t temp_args[2];
     jit_value_t temp3;
     ...
     temp_args[0] = x;
     temp_args[1] = jit_insn_sub(function, y, x);
     temp3 = jit_insn_call
         (function, "gcd", function, 0, temp_args, 2, 0);
     jit_insn_return(function, temp3);

   The string `"gcd"' in the second argument is for diagnostic purposes
only.  It can be helpful when debugging, but the `libjit' library
otherwise makes no use of it.  You can set it to NULL if you wish.

   In general, `libjit' does not maintain mappings from names to
`jit_function_t' objects.  It is assumed that the front end will take
care of that, using whatever naming scheme is appropriate to its needs.

The final part of the `gcd' function is similar to the previous one:

     jit_value_t temp4;
     ...
     jit_insn_label(function, &label2);
     temp_args[0] = jit_insn_sub(function, x, y);
     temp_args[1] = y;
     temp4 = jit_insn_call
         (function, "gcd", function, 0, temp_args, 2, 0);
     jit_insn_return(function, temp4);

We can now compile the function and execute it in the usual manner.


File: libjit.info,  Node: Tutorial 3,  Next: Tutorial 4,  Prev: Tutorial 2,  Up: Tutorials

3.3 Tutorial 3 - compiling on-demand
====================================

In the previous tutorials, we compiled everything that we needed at
startup time, and then entered the execution phase.  The real power of
a JIT becomes apparent when you use it to compile functions only as
they are called.  You can thus avoid compiling functions that are never
called in a given program run, saving memory and startup time.

   We demonstrate how to do on-demand compilation by rewriting Tutorial
1.  The source code for the modified version is in `tutorial/t3.c'.

   When the `mul_add' function is created, we don't create its function
body or call `jit_function_compile'.  We instead provide a C function
called `compile_mul_add' that performs on-demand compilation:

     jit_function_t function;
     ...
     function = jit_function_create(context, signature);
     jit_function_set_on_demand_compiler(function, compile_mul_add);

   We can now call this function with `jit_function_apply', and the
system will automatically call `compile_mul_add' for us if the function
hasn't been built yet.  The contents of `compile_mul_add' are fairly
obvious:

     int compile_mul_add(jit_function_t function)
     {
         jit_value_t x, y, z;
         jit_value_t temp1, temp2;

         x = jit_value_get_param(function, 0);
         y = jit_value_get_param(function, 1);
         z = jit_value_get_param(function, 2);

         temp1 = jit_insn_mul(function, x, y);
         temp2 = jit_insn_add(function, temp1, z);

         jit_insn_return(function, temp2);
         return 1;
     }

   When the on-demand compiler returns, `libjit' will call
`jit_function_compile' and then jump to the newly compiled code.  Upon
the second and subsequent calls to the function, `libjit' will bypass
the on-demand compiler and call the compiled code directly.  Note that
in case of on-demand compilation `libjit' automatically locks and
unlocks the corresponding context with `jit_context_build_start' and
`jit_context_build_end' calls.

   Sometimes you may wish to force a commonly used function to be
recompiled, so that you can apply additional optimization.  To do this,
you must set the "recompilable" flag just after the function is first
created:

     jit_function_t function;
     ...
     function = jit_function_create(context, signature);
     jit_function_set_recompilable(function);
     jit_function_set_on_demand_compiler(function, compile_mul_add);

   Once the function is compiled (either on-demand or up-front) its
intermediate representation built by `libjit' is discarded.  To force
the function to be recompiled you need to build it again and call
`jit_function_compile' after that.  As always when the function is
built and compiled manually it is necessary to take care of context
locking:

     jit_context_build_start(context);
     jit_function_get_on_demand_compiler(function)(function);
     jit_function_compile(function);
     jit_context_build_end(context);

   After this, any existing references to the function will be
redirected to the new version.  However, if some thread is currently
executing the previous version, then it will keep doing so until the
previous version exits.  Only after that will subsequent calls go to
the new version.

   In this tutorial, we use the same on-demand compiler when we
recompile `mul_add'.  In a real program, you would probably call
`jit_function_set_on_demand_compiler' to set a new on-demand compiler
that performs greater levels of optimization.

   If you no longer intend to recompile the function, you should call
`jit_function_clear_recompilable' so that `libjit' can manage the
function more efficiently from then on.

   The exact conditions under which a function should be recompiled are
not specified by `libjit'.  It may be because the function has been
called several times and has reached some threshold.  Or it may be
because some other function that it calls has become a candidate for
inlining.  It is up to the front end to decide when recompilation is
warranted, usually based on language-specific heuristics.


File: libjit.info,  Node: Tutorial 4,  Next: Tutorial 5,  Prev: Tutorial 3,  Up: Tutorials

3.4 Tutorial 4 - mul_add, C++ version
=====================================

While `libjit' can be easily accessed from C++ programs using the C
API's, you may instead wish to use an API that better reflects the C++
programming paradigm.  We demonstrate how to do this by rewriting
Tutorial 3 using the `libjitplus' library.

To use the `libjitplus' library, we first include the
`<jit/jit-plus.h>' file:

     #include <jit/jit-plus.h>

   This file incorporates all of the definitions from `<jit/jit.h>', so
you have full access to the underlying C API if you need it.

   This time, instead of building the `mul_add' function with
`jit_function_create' and friends, we define a class to represent it:

     class mul_add_function : public jit_function
     {
     public:
         mul_add_function(jit_context& context) : jit_function(context)
         {
             create();
             set_recompilable();
         }

         virtual void build();

     protected:
         virtual jit_type_t create_signature();
     };

   Where we used `jit_function_t' and `jit_context_t' before, we now
use the C++ `jit_function' and `jit_context' classes.

   In our constructor, we attach ourselves to the context and then call
the `create()' method.  This is in turn will call our overridden
virtual method `create_signature()' to obtain the signature:

     jit_type_t mul_add_function::create_signature()
     {
         // Return type, followed by three parameters,
         // terminated with "end_params".
         return signature_helper
             (jit_type_int, jit_type_int, jit_type_int,
              jit_type_int, end_params);
     }

   The `signature_helper()' method is provided for your convenience, to
help with building function signatures.  You can create your own
signature manually using `jit_type_create_signature' if you wish.

   The final thing we do in the constructor is call `set_recompilable()'
to mark the `mul_add' function as recompilable, just as we did in
Tutorial 3.

   The C++ library will create the function as compilable on-demand for
us, so we don't have to do that explicitly.  But we do have to override
the virtual `build()' method to build the function's body on-demand:

     void mul_add_function::build()
     {
         jit_value x = get_param(0);
         jit_value y = get_param(1);
         jit_value z = get_param(2);

         insn_return(x * y + z);
     }

   This is similar to the first version that we wrote in Tutorial 1.
Instructions are created with `insn_*' methods that correspond to their
`jit_insn_*' counterparts in the C library.

   One of the nice things about the C++ API compared to the C API is
that we can use overloaded operators to manipulate `jit_value' objects.
This can simplify the function build process considerably when we have
lots of expressions to compile.  We could have used `insn_mul' and
`insn_add' instead in this example and the result would have been the
same.

   Now that we have our `mul_add_function' class, we can create an
instance of the function and apply it as follows:

     jit_context context;
     mul_add_function mul_add(context);

     jit_int arg1 = 3;
     jit_int arg2 = 5;
     jit_int arg3 = 2;
     jit_int args[3];
     args[0] = &arg1;
     args[1] = &arg2;
     args[2] = &arg3;

     mul_add.apply(args, &result);

*Note C++ Interface::, for more information on the `libjitplus' library.


File: libjit.info,  Node: Tutorial 5,  Next: Dynamic Pascal,  Prev: Tutorial 4,  Up: Tutorials

3.5 Tutorial 5 - gcd, with tail calls
=====================================

Astute readers would have noticed that Tutorial 2 included two instances
of "tail calls".  That is, calls to the same function that are
immediately followed by a `return' instruction.

   Libjit can optimize tail calls if you provide the `JIT_CALL_TAIL'
flag to `jit_insn_call'.  Previously, we used the following code to
call `gcd' recursively:

     temp3 = jit_insn_call
         (function, "gcd", function, 0, temp_args, 2, 0);
     jit_insn_return(function, temp3);

In Tutorial 5, this is modified to the following:

     jit_insn_call(function, "gcd", function, 0, temp_args, 2, JIT_CALL_TAIL);

   There is no need for the `jit_insn_return', because the call will
never return to that point in the code.  Behind the scenes, `libjit'
will convert the call into a jump back to the head of the function.

   Tail calls can only be used in certain circumstances.  The source
and destination of the call must have the same function signatures.
None of the parameters should point to local variables in the current
stack frame.  And tail calls cannot be used from any source function
that uses `try' or `alloca' statements.

   Because it can be difficult for `libjit' to determine when these
conditions have been met, it relies upon the caller to supply the
`JIT_CALL_TAIL' flag when it is appropriate to use a tail call.


File: libjit.info,  Node: Dynamic Pascal,  Next: Initialization,  Prev: Tutorial 5,  Up: Tutorials

3.6 Dynamic Pascal - A full JIT example
=======================================

This `libjit/dpas' directory contains an implementation of "Dynamic
Pascal", or "dpas" as we like to call it.  It is provided as an example
of using `libjit' in a real working environment.  We also use it to
write test programs that exercise the JIT's capabilities.

   Other Pascal implementations compile the source to executable form,
which is then run separately.  Dynamic Pascal loads the source code at
runtime, dynamically JIT'ing the program as it goes.  It thus has a lot
in common with scripting languages like Perl and Python.

   If you are writing a bytecode-based virtual machine, you would use a
similar approach to Dynamic Pascal.  The key difference is that you
would build the JIT data structures after loading the bytecode rather
than after parsing the source code.

   To run a Dynamic Pascal program, use `dpas name.pas'.  You may also
need to pass the `-I' option to specify the location of the system
library if you have used an `import' clause in your program.  e.g.
`dpas -I$HOME/libjit/dpas/library name.pas'.

This Pascal grammar is based on the EBNF description at the following
URL:

   `http://www.cs.qub.ac.uk/~S.Fitzpatrick/Teaching/Pascal/EBNF.html'

There are a few differences to "Standard Pascal":

  1. Identifiers are case-insensitive, but case-preserving.

  2. Program headings are normally `program Name (Input, Output);'.
     This can be abbreviated to `program Name;' as the program
     modifiers are ignored.

  3. Some GNU Pascal operators like `xor', `shl', `@', etc have been
     added.

  4. The integer type names (`Integer', `Cardinal', `LongInt', etc)
     follow those used in GNU Pascal also.  The `Integer' type is always
     32-bits in size, while `LongInt' is always 64-bits in size.

  5. The types `SysInt', `SysCard', `SysLong', `SysLongCard',
     `SysLongestInt', and `SysLongestCard' are guaranteed to be the
     same size as the underlying C system's `int', `unsigned int',
     `long', `unsigned long', `long long', and `unsigned long long'
     types.

  6. The type `Address' is logically equivalent to C's `void *'.  Any
     pointer or array can be implicitly cast to `Address'.  An explicit
     cast is required to cast back to a typed pointer (you cannot cast
     back to an array).

  7. The `String' type is declared as `^Char'.  Single-dimensional
     arrays of `Char' can be implicitly cast to any `String'
     destination.  Strings are not bounds-checked, so be careful.
     Arrays are bounds-checked.

  8. Pointers can be used as arrays.  e.g. `p[n]' will access the n'th
     item of an unbounded array located at `p'.  Use with care.

  9. We don't support `file of' types.  Data can be written to stdout
     using `Write' and `WriteLn', but that is the extent of the I/O
     facilities.

 10. The declaration `import Name1, Name2, ...;' can be used at the
     head of a program to declare additional files to include.  e.g.
     `import stdio' will import the contents of `stdio.pas'.  We don't
     support units.

 11. The idiom `; ..' can be used at the end of a formal parameter list
     to declare that the procedure or function takes a variable number
     of arguments.  The builtin function `va_arg(Type)' is used to
     extract the arguments.

 12. The directive `import("Library")' can be used to declare that a
     function or procedure was imported from an external C library.
     For example, the following imports the C `puts' and `printf'
     functions:

          function puts (str : String) : SysInt; import ("libc")
          function printf (format : String; ..) : SysInt; import ("libc")

     Functions that are imported in this manner have case-sensitive
     names.  i.e. using `Printf' above will fail.

 13. The `throw' keyword can be used to throw an exception.  The
     argument must be a pointer.  The `try', `catch', and `finally'
     keywords are used to manage such exceptions further up the stack.
     e.g.

          try
              ...
          catch Name : Type
              ...
          finally
              ...
          end

     The `catch' block will be invoked with the exception pointer that
     was supplied to `throw', after casting it to `Type' (which must be
     a pointer type).  Specifying `throw' on its own without an argument
     will rethrow the current exception pointer, and can only be used
     inside a `catch' block.

     Dynamic Pascal does not actually check the type of the thrown
     pointer.  If you have multiple kinds of exceptions, then you must
     store some kind of type indicator in the block that is thrown and
     then inspect `^Name' to see what the indicator says.

 14. The `exit' keyword can be used to break out of a loop.

 15. Function calls can be used as procedure calls.  The return value
     is ignored.

 16. Hexadecimal constants can be expressed as `XXH'.  The first digit
     must be between 0 and 9, but the remaining digits can be any hex
     digit.

 17. Ternary conditionals can be expressed as `(if e1 then e2 else e3)'.
     The brackets are required.  This is equivalent to C's `e1 ? e2 :
     e3'.

 18. Assigning to a function result will immediately return.  i.e. it is
     similar to `return value;' in C.  It isn't necessary to arrange for
     execution to flow through to the end of the function as in regular
     Pascal.

 19. The term `sizeof(Type)' can be used to get the size of a type.

 20. Procedure and function headings can appear in a record type to
     declare a field with a `pointer to procedure/function' type.


File: libjit.info,  Node: Initialization,  Next: Functions,  Prev: Dynamic Pascal,  Up: Top

4 Initializing the JIT
**********************

 -- Function: void jit_init (void)
     This is normally the first function that you call when using
     `libjit'.  It initializes the library and prepares for JIT
     operations.

     The `jit_context_create' function also calls this, so you can
     avoid using `jit_init' if `jit_context_create' is the first JIT
     function that you use.

     It is safe to initialize the JIT multiple times.  Subsequent
     initializations are quietly ignored.

 -- Function: int jit_uses_interpreter (void)
     Determine if the JIT uses a fall-back interpreter to execute code
     rather than generating and executing native code.  This can be
     called prior to `jit_init'.

   Everything that is done with `libjit' is done relative to a context.
It is possible to have more than one context at a time - each acts as an
independent environment for compiling and managing code.

   When you want to compile a function, you create it with
`jit_function_create', and then populate its body with calls to the
value and instruction functions.  See *Note Values::, and *Note
Instructions:: for more information on how to do this.

4.1 Using libjit in a multi-threaded environment
================================================

The library does not handle the creation, management, and destruction
of threads itself.  It is up to the front-end environment to take care
of that.  But the library is thread-aware, as long as you take some
very simple steps.

   In a multi-threaded environment, you must ensure that only one
thread can build functions at any one time.  Otherwise the JIT's
context may become corrupted.  To protect the system, you should call
`jit_context_build_start' before creating the function.  And then call
`jit_context_build_end' once the function has been fully compiled.

   You can compile multiple functions during the one build process if
you wish, which is the normal case when compiling a class.

   It is usually a good idea to suspend the finalization of
garbage-collected objects while function building is in progress.
Otherwise you may get a deadlock when the finalizer thread tries to
call the builder to compile a finalization routine.  Suspension of
finalization is the responsibility of the caller.

4.2 Context functions
=====================

The following functions are available to create, manage, and ultimately
destroy JIT contexts:

 -- Function: jit_context_t jit_context_create (void)
     Create a new context block for the JIT.  Returns NULL if out of
     memory.

 -- Function: void jit_context_destroy (jit_context_t CONTEXT)
     Destroy a JIT context block and everything that is associated with
     it.  It is very important that no threads within the program are
     currently running compiled code when this function is called.

 -- Function: int jit_context_supports_threads (jit_context_t CONTEXT)
     Determine if the JIT supports threads.

 -- Function: void jit_context_build_start (jit_context_t CONTEXT)
     This routine should be called before you start building a function
     to be JIT'ed.  It acquires a lock on the context to prevent other
     threads from accessing the build process, since only one thread
     can be performing build operations at any one time.

 -- Function: void jit_context_build_end (jit_context_t CONTEXT)
     This routine should be called once you have finished building and
     compiling a function and are ready to resume normal execution.
     This routine will release the build lock, allowing other threads
     that are waiting on the builder to proceed.

 -- Function: void jit_context_set_on_demand_driver (jit_context_t
          CONTEXT, jit_on_demand_driver_func DRIVER)
     Specify the C function to be called to drive on-demand compilation.

     When on-demand compilation is requested the default driver
     provided by `libjit' takes the following actions:

       1. The context is locked by calling `jit_context_build_start'.

       2. If the function has already been compiled, `libjit' unlocks
          the context and returns immediately.  This can happen because
          of race conditions between threads: some other thread may
          have beaten us to the on-demand compiler.

       3. The user's on-demand compiler is called.  It is responsible
          for building the instructions in the function's body.  It
          should return one of the result codes `JIT_RESULT_OK',
          `JIT_RESULT_COMPILE_ERROR', or `JIT_RESULT_OUT_OF_MEMORY'.

       4. If the user's on-demand function hasn't already done so,
          `libjit' will call `jit_function_compile' to compile the
          function.

       5. The context is unlocked by calling `jit_context_build_end' and
          `libjit' jumps to the newly-compiled entry point.  If an error
          occurs, a built-in exception of type
          `JIT_RESULT_COMPILE_ERROR' or `JIT_RESULT_OUT_OF_MEMORY' will
          be thrown.

       6. The entry point of the compiled function is returned from the
          driver.

     You may need to provide your own driver if some additional actions
     are required.


 -- Function: int jit_context_set_meta (jit_context_t CONTEXT, int
          TYPE, void *DATA, jit_meta_free_func FREE_DATA)
     Tag a context with some metadata.  Returns zero if out of memory.

     Metadata may be used to store dependency graphs, branch prediction
     information, or any other information that is useful to optimizers
     or code generators.  It can also be used by higher level user code
     to store information about the context that is specific to the
     virtual machine or language.

     If the TYPE already has some metadata associated with it, then the
     previous value will be freed.

 -- Function: int jit_context_set_meta_numeric (jit_context_t CONTEXT,
          int TYPE, jit_nuint DATA)
     Tag a context with numeric metadata.  Returns zero if out of
     memory.  This function is more convenient for accessing the
     context's special option values:

    `JIT_OPTION_CACHE_LIMIT'
          A numeric option that indicates the maximum size in bytes of
          the function cache.  If set to zero (the default), the
          function cache is unlimited in size.

    `JIT_OPTION_CACHE_PAGE_SIZE'
          A numeric option that indicates the size in bytes of a single
          page in the function cache.  Memory is allocated for the
          cache in chunks of this size.  If set to zero, the cache page
          size is set to an internally-determined default (usually
          128k).  The cache page size also determines the maximum size
          of a single compiled function.

    `JIT_OPTION_PRE_COMPILE'
          A numeric option that indicates that this context is being
          used for pre-compilation if it is set to a non-zero value.
          Code within pre-compiled contexts cannot be executed
          directly.  Instead, they can be written out to disk in ELF
          format to be reloaded at some future time.

    `JIT_OPTION_DONT_FOLD'
          A numeric option that disables constant folding when it is
          set to a non-zero value.  This is useful for debugging, as it
          forces `libjit' to always execute constant expressions at run
          time, instead of at compile time.

    `JIT_OPTION_POSITION_INDEPENDENT'
          A numeric option that forces generation of
          position-independent code (PIC) if it is set to a non-zero
          value. This may be mainly useful for pre-compiled contexts.

     Metadata type values of 10000 or greater are reserved for internal
     use.

 -- Function: void * jit_context_get_meta (jit_context_t CONTEXT, int
          TYPE)
     Get the metadata associated with a particular tag.  Returns NULL
     if TYPE does not have any metadata associated with it.

 -- Function: jit_nuint jit_context_get_meta_numeric (jit_context_t
          CONTEXT, int TYPE)
     Get the metadata associated with a particular tag.  Returns zero
     if TYPE does not have any metadata associated with it.  This
     version is more convenient for the pre-defined numeric option
     values.

 -- Function: void jit_context_free_meta (jit_context_t CONTEXT, int
          TYPE)
     Free metadata of a specific type on a context.  Does nothing if
     the TYPE does not have any metadata associated with it.


File: libjit.info,  Node: Functions,  Next: Types,  Prev: Initialization,  Up: Top

5 Building and compiling functions with the JIT
***********************************************

 -- Function: jit_function_t jit_function_create (jit_context_t
          CONTEXT, jit_type_t SIGNATURE)
     Create a new function block and associate it with a JIT context.
     Returns NULL if out of memory.

     A function persists for the lifetime of its containing context.
     It initially starts life in the "building" state, where the user
     constructs instructions that represents the function body.  Once
     the build process is complete, the user calls
     `jit_function_compile' to convert it into its executable form.

     It is recommended that you call `jit_context_build_start' before
     calling `jit_function_create', and then call
     `jit_context_build_end' after you have called
     `jit_function_compile'.  This will protect the JIT's internal data
     structures within a multi-threaded environment.

 -- Function: jit_function_t jit_function_create_nested (jit_context_t
          CONTEXT, jit_type_t SIGNATURE, jit_function_t PARENT)
     Create a new function block and associate it with a JIT context.
     In addition, this function is nested inside the specified PARENT
     function and is able to access its parent's (and grandparent's)
     local variables.

     The front end is responsible for ensuring that the nested function
     can never be called by anyone except its parent and sibling
     functions.  The front end is also responsible for ensuring that
     the nested function is compiled before its parent.

 -- Function: void jit_function_abandon (jit_function_t FUNC)
     Abandon this function during the build process.  This should be
     called when you detect a fatal error that prevents the function
     from being properly built.  The FUNC object is completely
     destroyed and detached from its owning context.  The function is
     left alone if it was already compiled.

 -- Function: jit_context_t jit_function_get_context (jit_function_t
          FUNC)
     Get the context associated with a function.

 -- Function: jit_type_t jit_function_get_signature (jit_function_t
          FUNC)
     Get the signature associated with a function.

 -- Function: int jit_function_set_meta (jit_function_t FUNC, int TYPE,
          void *DATA, jit_meta_free_func FREE_DATA, int BUILD_ONLY)
     Tag a function with some metadata.  Returns zero if out of memory.

     Metadata may be used to store dependency graphs, branch prediction
     information, or any other information that is useful to optimizers
     or code generators.  It can also be used by higher level user code
     to store information about the function that is specific to the
     virtual machine or language.

     If the TYPE already has some metadata associated with it, then the
     previous value will be freed.

     If BUILD_ONLY is non-zero, then the metadata will be freed when
     the function is compiled with `jit_function_compile'.  Otherwise
     the metadata will persist until the JIT context is destroyed, or
     `jit_function_free_meta' is called for the specified TYPE.

     Metadata type values of 10000 or greater are reserved for internal
     use.

 -- Function: void * jit_function_get_meta (jit_function_t FUNC, int
          TYPE)
     Get the metadata associated with a particular tag.  Returns NULL
     if TYPE does not have any metadata associated with it.

 -- Function: void jit_function_free_meta (jit_function_t FUNC, int
          TYPE)
     Free metadata of a specific type on a function.  Does nothing if
     the TYPE does not have any metadata associated with it.

 -- Function: jit_function_t jit_function_next (jit_context_t CONTEXT,
          jit_function_t PREV)
     Iterate over the defined functions in creation order.  The PREV
     argument should be NULL on the first call.  Returns NULL at the
     end.

 -- Function: jit_function_t jit_function_previous (jit_context_t
          CONTEXT, jit_function_t PREV)
     Iterate over the defined functions in reverse creation order.

 -- Function: jit_block_t jit_function_get_entry (jit_function_t FUNC)
     Get the entry block for a function.  This is always the first block
     created by `jit_function_create'.

 -- Function: jit_block_t jit_function_get_current (jit_function_t FUNC)
     Get the current block for a function.  New blocks are created by
     certain `jit_insn_xxx' calls.

 -- Function: jit_function_t jit_function_get_nested_parent
          (jit_function_t FUNC)
     Get the nested parent for a function, or NULL if FUNC does not
     have a nested parent.

 -- Function: int jit_function_compile (jit_function_t FUNC)
     Compile a function to its executable form.  If the function was
     already compiled, then do nothing.  Returns zero on error.

     If an error occurs, you can use `jit_function_abandon' to
     completely destroy the function.  Once the function has been
     compiled successfully, it can no longer be abandoned.

     Sometimes you may wish to recompile a function, to apply greater
     levels of optimization the second time around.  You must call
     `jit_function_set_recompilable' before you compile the function
     the first time.  On the second time around, build the function's
     instructions again, and call `jit_function_compile' a second time.

 -- Function: int jit_function_compile_entry (jit_function_t FUNC, void
          **ENTRY_POINT)
     Compile a function to its executable form but do not make it
     available for invocation yet. It may be made available later with
     `jit_function_setup_entry'.

 -- Function: int jit_function_setup_entry (jit_function_t FUNC, void
          *ENTRY_POINT)
     Make a function compiled with `jit_function_compile_entry'
     available for invocation and free the resources used for
     compilation. If ENTRY_POINT is null then it only frees the
     resources.

 -- Function: int jit_function_is_compiled (jit_function_t FUNC)
     Determine if a function has already been compiled.

 -- Function: int jit_function_set_recompilable (jit_function_t FUNC)
     Mark this function as a candidate for recompilation.  That is, it
     is possible that we may call `jit_function_compile' more than
     once, to re-optimize an existing function.

     It is very important that this be called before the first time that
     you call `jit_function_compile'.  Functions that are recompilable
     are invoked in a slightly different way to non-recompilable
     functions.  If you don't set this flag, then existing invocations
     of the function may continue to be sent to the original compiled
     version, not the new version.

 -- Function: void jit_function_clear_recompilable (jit_function_t FUNC)
     Clear the recompilable flag on this function.  Normally you would
     use this once you have decided that the function has been
     optimized enough, and that you no longer intend to call
     `jit_function_compile' again.

     Future uses of the function with `jit_insn_call' will output a
     direct call to the function, which is more efficient than calling
     its recompilable version.  Pre-existing calls to the function may
     still use redirection stubs, and will remain so until the
     pre-existing functions are themselves recompiled.

 -- Function: int jit_function_is_recompilable (jit_function_t FUNC)
     Determine if this function is recompilable.

 -- Function: void * jit_function_to_closure (jit_function_t FUNC)
     Convert a compiled function into a closure that can called directly
     from C.  Returns NULL if out of memory, or if closures are not
     supported on this platform.

     If the function has not been compiled yet, then this will return a
     pointer to a redirector that will arrange for the function to be
     compiled on-demand when it is called.

     Creating a closure for a nested function is not recommended as C
     does not have any way to call such closures directly.

 -- Function: jit_function_t jit_function_from_closure (jit_context_t
          CONTEXT, void *CLOSURE)
     Convert a closure back into a function.  Returns NULL if the
     closure does not correspond to a function in the specified context.

 -- Function: jit_function_t jit_function_from_pc (jit_context_t
          CONTEXT, void *PC, void **HANDLER)
     Get the function that contains the specified program counter
     location.  Also return the address of the `catch' handler for the
     same location.  Returns NULL if the program counter does not
     correspond to a function under the control of CONTEXT.

 -- Function: void * jit_function_to_vtable_pointer (jit_function_t
          FUNC)
     Return a pointer that is suitable for referring to this function
     from a vtable.  Such pointers should only be used with the
     `jit_insn_call_vtable' instruction.

     Using `jit_insn_call_vtable' is generally more efficient than
     `jit_insn_call_indirect' for calling virtual methods.

     The vtable pointer might be the same as the closure, but this isn't
     guaranteed.  Closures can be used with `jit_insn_call_indirect'.

 -- Function: jit_function_t jit_function_from_vtable_pointer
          (jit_context_t CONTEXT, void *VTABLE_POINTER)
     Convert a vtable_pointer back into a function.  Returns NULL if the
     vtable_pointer does not correspond to a function in the specified
     context.

 -- Function: void jit_function_set_on_demand_compiler (jit_function_t
          FUNC, jit_on_demand_func ON_DEMAND)
     Specify the C function to be called when FUNC needs to be compiled
     on-demand.  This should be set just after the function is created,
     before any build or compile processes begin.

     You won't need an on-demand compiler if you always build and
     compile your functions before you call them.  But if you can call
     a function before it is built, then you must supply an on-demand
     compiler.

     When on-demand compilation is requested, `libjit' takes the
     following actions:

       1. The context is locked by calling `jit_context_build_start'.

       2. If the function has already been compiled, `libjit' unlocks
          the context and returns immediately.  This can happen because
          of race conditions between threads: some other thread may
          have beaten us to the on-demand compiler.

       3. The user's on-demand compiler is called.  It is responsible
          for building the instructions in the function's body.  It
          should return one of the result codes `JIT_RESULT_OK',
          `JIT_RESULT_COMPILE_ERROR', or `JIT_RESULT_OUT_OF_MEMORY'.

       4. If the user's on-demand function hasn't already done so,
          `libjit' will call `jit_function_compile' to compile the
          function.

       5. The context is unlocked by calling `jit_context_build_end' and
          `libjit' jumps to the newly-compiled entry point.  If an error
          occurs, a built-in exception of type
          `JIT_RESULT_COMPILE_ERROR' or `JIT_RESULT_OUT_OF_MEMORY' will
          be thrown.

     Normally you will need some kind of context information to tell you
     which higher-level construct is being compiled.  You can use the
     metadata facility to add this context information to the function
     just after you create it with `jit_function_create'.

 -- Function: jit_on_demand_func jit_function_get_on_demand_compiler
          (jit_function_t FUNC)
     Returns function's on-demand compiler.

 -- Function: int jit_function_apply (jit_function_t FUNC, void **ARGS,
          void *RETURN_AREA)
     Call the function FUNC with the supplied arguments.  Each element
     in ARGS is a pointer to one of the arguments, and RETURN_AREA
     points to a buffer to receive the return value.  Returns zero if an
     exception occurred.

     This is the primary means for executing a function from ordinary C
     code without creating a closure first with
     `jit_function_to_closure'.  Closures may not be supported on all
     platforms, but function application is guaranteed to be supported
     everywhere.

     Function applications acts as an exception blocker.  If any
     exceptions occur during the execution of FUNC, they won't travel
     up the stack any further than this point.  This prevents ordinary
     C code from being accidentally presented with a situation that it
     cannot handle.  This blocking protection is not present when a
     function is invoked via its closure.

 -- Function: int jit_function_apply_vararg (jit_function_t FUNC,
          jit_type_t SIGNATURE, void **ARGS, void *RETURN_AREA)
     Call the function FUNC with the supplied arguments.  There may be
     more arguments than are specified in the function's original
     signature, in which case the additional values are passed as
     variable arguments.  This function is otherwise identical to
     `jit_function_apply'.

 -- Function: void jit_function_set_optimization_level (jit_function_t
          FUNC, unsigned int LEVEL)
     Set the optimization level for FUNC.  Increasing values indicate
     that the `libjit' dynamic compiler should expend more effort to
     generate better code for this function.  Usually you would increase
     this value just before forcing FUNC to recompile.

     When the optimization level reaches the value returned by
     `jit_function_get_max_optimization_level()', there is usually
     little point in continuing to recompile the function because
     `libjit' may not be able to do any better.

     The front end is usually responsible for choosing candidates for
     function inlining.  If it has identified more such candidates, then
     it may still want to recompile FUNC again even once it has reached
     the maximum optimization level.

 -- Function: unsigned int jit_function_get_optimization_level
          (jit_function_t FUNC)
     Get the current optimization level for FUNC.

 -- Function: unsigned int jit_function_get_max_optimization_level
          (void)
     Get the maximum optimization level that is supported by `libjit'.

 -- Function: jit_label_t jit_function_reserve_label (jit_function_t
          FUNC)
     Allocate a new label for later use within the function FUNC. Most
     instructions that require a label could perform label allocation
     themselves.  A separate label allocation could be useful to fill a
     jump table with identical entries.


File: libjit.info,  Node: Types,  Next: Values,  Prev: Functions,  Up: Top

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

     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_type (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.


File: libjit.info,  Node: Values,  Next: Instructions,  Prev: Types,  Up: Top

7 Working with temporary values in the JIT
******************************************

Values form the backbone of the storage system in `libjit'.  Every
value in the system, be it a constant, a local variable, or a temporary
result, is represented by an object of type `jit_value_t'.  The JIT
then allocates registers or memory locations to the values as
appropriate.

   We will demonstrate how to use values with a simple example of
adding two local variables together and putting the result into a third
local variable.  First, we allocate storage for the three local
variables:

     value1 = jit_value_create(func, jit_type_int);
     value2 = jit_value_create(func, jit_type_int);
     value3 = jit_value_create(func, jit_type_int);

   Here, `func' is the function that we are building.  To add `value1'
and `value2' and put the result into `value3', we use the following
code:

     temp = jit_insn_add(func, value1, value2);
     jit_insn_store(func, value3, temp);

   The `jit_insn_add' function allocates a temporary value (`temp') and
places the result of the addition into it.  The `jit_insn_store'
function then stores the temporary result into `value3'.

   You might be tempted to think that the above code is inefficient.
Why do we copy the result into a temporary variable first?  Why not put
the result directly to `value3'?

   Behind the scenes, the JIT will typically optimize `temp' away,
resulting in the final code that you expect (i.e. `value3 = value1 +
value2').  It is simply easier to use `libjit' if all results end up in
temporary variables first, so that's what we do.

   Using temporary values, it is very easy to convert stack machine
bytecodes into JIT instructions.  Consider the following Java Virtual
Machine bytecode (representing `value4 = value1 * value2 + value3'):

     iload 1
     iload 2
     imul
     iload 3
     iadd
     istore 4

   Let us demonstrate how this code would be translated, instruction by
instruction.  We assume that we have a `stack' available, which keeps
track of the temporary values in the system.  We also assume that
`jit_value_t' objects representing the local variables are already
stored in an array called `locals'.

First, we load local variable 1 onto the stack:

     stack[size++] = jit_insn_load(func, locals[1]);

We repeat this for local variable 2:

     stack[size++] = jit_insn_load(func, locals[2]);

Now we pop these two values and push their multiplication:

     stack[size - 2] = jit_insn_mul(func, stack[size - 2], stack[size - 1]);
     --size;

Next, we need to push the value of local variable 3 and add it to the
product that we just computed:

     stack[size++] = jit_insn_load(func, locals[3]);
     stack[size - 2] = jit_insn_add(func, stack[size - 2], stack[size - 1]);
     --size;

Finally, we store the result into local variable 4:

     jit_insn_store(func, locals[4], stack[--size]);

Collecting up all of the above code, we get the following:

     stack[size++] = jit_insn_load(func, locals[1]);
     stack[size++] = jit_insn_load(func, locals[2]);
     stack[size - 2] = jit_insn_mul(func, stack[size - 2], stack[size - 1]);
     --size;
     stack[size++] = jit_insn_load(func, locals[3]);
     stack[size - 2] = jit_insn_add(func, stack[size - 2], stack[size - 1]);
     --size;
     jit_insn_store(func, locals[4], stack[--size]);

   The JIT will optimize away most of these temporary results, leaving
the final machine code that you expect.

   If the virtual machine was register-based, then a slightly different
translation strategy would be used.  Consider the following code, which
computes `reg4 = reg1 * reg2 + reg3', with the intermediate result
stored temporarily in `reg5':

     mul reg5, reg1, reg2
     add reg4, reg5, reg3

   You would start by allocating value objects for all of the registers
in your system (with `jit_value_create'):

     reg[1] = jit_value_create(func, jit_type_int);
     reg[2] = jit_value_create(func, jit_type_int);
     reg[3] = jit_value_create(func, jit_type_int);
     reg[4] = jit_value_create(func, jit_type_int);
     reg[5] = jit_value_create(func, jit_type_int);

Then, the virtual register machine code is translated as follows:

     temp1 = jit_insn_mul(func, reg[1], reg[2]);
     jit_insn_store(reg[5], temp1);
     temp2 = jit_insn_add(func, reg[5], reg[3]);
     jit_insn_store(reg[4], temp2);

   Each virtual register machine instruction turns into two `libjit'
function calls.  The JIT will normally optimize away the temporary
results.  If the value in `reg5' is not used further down the code,
then the JIT may also be able to optimize `reg5' away.

   The rest of this section describes the functions that are available
to create and manipulate values.

 -- Function: jit_value_t jit_value_create (jit_function_t FUNC,
          jit_type_t TYPE)
     Create a new value in the context of a function's current block.
     The value initially starts off as a block-specific temporary.  It
     will be converted into a function-wide local variable if it is
     ever referenced from a different block.  Returns NULL if out of
     memory.

     Note: It isn't possible to refer to global variables directly using
     values.  If you need to access a global variable, then load its
     address into a temporary and use `jit_insn_load_relative' or
     `jit_insn_store_relative' to manipulate it.  It simplifies the JIT
     if it can assume that all values are local.

 -- Function: jit_value_t jit_value_create_nint_constant
          (jit_function_t FUNC, jit_type_t TYPE, jit_nint CONST_VALUE)
     Create a new native integer constant in the specified function.
     Returns NULL if out of memory.

     The TYPE parameter indicates the actual type of the constant, if
     it happens to be something other than `jit_type_nint'.  For
     example, the following will create an unsigned byte constant:

          value = jit_value_create_nint_constant(context, jit_type_ubyte, 128);

     This function can be used to create constants of type
     `jit_type_sbyte', `jit_type_ubyte', `jit_type_short',
     `jit_type_ushort', `jit_type_int', `jit_type_uint',
     `jit_type_nint', `jit_type_nuint', and all pointer types.

 -- Function: jit_value_t jit_value_create_long_constant
          (jit_function_t FUNC, jit_type_t TYPE, jit_long CONST_VALUE)
     Create a new 64-bit integer constant in the specified function.
     This can also be used to create constants of type
     `jit_type_ulong'.  Returns NULL if out of memory.

 -- Function: jit_value_t jit_value_create_float32_constant
          (jit_function_t FUNC, jit_type_t TYPE, jit_float32
          CONST_VALUE)
     Create a new 32-bit floating-point constant in the specified
     function.  Returns NULL if out of memory.

 -- Function: jit_value_t jit_value_create_float64_constant
          (jit_function_t FUNC, jit_type_t TYPE, jit_float64
          CONST_VALUE)
     Create a new 64-bit floating-point constant in the specified
     function.  Returns NULL if out of memory.

 -- Function: jit_value_t jit_value_create_nfloat_constant
          (jit_function_t FUNC, jit_type_t TYPE, jit_nfloat CONST_VALUE)
     Create a new native floating-point constant in the specified
     function.  Returns NULL if out of memory.

 -- Function: jit_value_t jit_value_create_constant (jit_function_t
          FUNC, const jit_constant *CONST_VALUE)
     Create a new constant from a generic constant structure in the
     specified function.  Returns NULL if out of memory or if the type
     in CONST_VALUE is not suitable for a constant.

 -- Function: jit_value_t jit_value_get_param (jit_function_t FUNC,
          unsigned int PARAM)
     Get the value that corresponds to a specified function parameter.
     Returns NULL if out of memory.

 -- Function: jit_value_t jit_value_get_struct_pointer (jit_function_t
          FUNC)
     Get the value that contains the structure return pointer for a
     function.  If the function does not have a structure return pointer
     (i.e. structures are returned in registers), then this returns
     NULL.

 -- Function: int jit_value_is_temporary (jit_value_t VALUE)
     Determine if a value is temporary.  i.e. its scope extends over a
     single block within its function.

 -- Function: int jit_value_is_local (jit_value_t VALUE)
     Determine if a value is local.  i.e. its scope extends over
     multiple blocks within its function.

 -- Function: int jit_value_is_constant (jit_value_t VALUE)
     Determine if a value is a constant.

 -- Function: int jit_value_is_parameter (jit_value_t VALUE)
     Determine if a value is a function parameter.

 -- Function: void jit_value_ref (jit_function_t FUNC, jit_value_t
          VALUE)
     Create a reference to the specified VALUE from the current block
     in FUNC.  This will convert a temporary value into a local value
     if VALUE is being referenced from a different block than its
     original.

     It is not necessary that FUNC be the same function as the one
     where the value was originally created.  It may be a nested
     function, referring to a local variable in its parent function.

 -- Function: void jit_value_set_volatile (jit_value_t VALUE)
     Set a flag on a value to indicate that it is volatile.  The
     contents of the value must always be reloaded from memory, never
     from a cached register copy.

 -- Function: int jit_value_is_volatile (jit_value_t VALUE)
     Determine if a value is volatile.

 -- Function: void jit_value_set_addressable (jit_value_t VALUE)
     Set a flag on a value to indicate that it is addressable.  This
     should be used when you want to take the address of a value (e.g.
     `&variable' in C).  The value is guaranteed to not be stored in a
     register across a function call.  If you refer to a value from a
     nested function (`jit_value_ref'), then the value will be
     automatically marked as addressable.

 -- Function: int jit_value_is_addressable (jit_value_t VALUE)
     Determine if a value is addressable.

 -- Function: jit_type_t jit_value_get_type (jit_value_t VALUE)
     Get the type that is associated with a value.

 -- Function: jit_function_t jit_value_get_function (jit_value_t VALUE)
     Get the function which owns a particular VALUE.

 -- Function: jit_block_t jit_value_get_block (jit_value_t VALUE)
     Get the block which owns a particular VALUE.

 -- Function: jit_context_t jit_value_get_context (jit_value_t VALUE)
     Get the context which owns a particular VALUE.

 -- Function: jit_constant_t jit_value_get_constant (jit_value_t VALUE)
     Get the constant value within a particular VALUE.  The returned
     structure's `type' field will be `jit_type_void' if `value' is not
     a constant.

 -- Function: jit_nint jit_value_get_nint_constant (jit_value_t VALUE)
     Get the constant value within a particular VALUE, assuming that
     its type is compatible with `jit_type_nint'.

 -- Function: jit_nint jit_value_get_long_constant (jit_value_t VALUE)
     Get the constant value within a particular VALUE, assuming that
     its type is compatible with `jit_type_long'.

 -- Function: jit_float32 jit_value_get_float32_constant (jit_value_t
          VALUE)
     Get the constant value within a particular VALUE, assuming that
     its type is compatible with `jit_type_float32'.

 -- Function: jit_float64 jit_value_get_float64_constant (jit_value_t
          VALUE)
     Get the constant value within a particular VALUE, assuming that
     its type is compatible with `jit_type_float64'.

 -- Function: jit_nfloat jit_value_get_nfloat_constant (jit_value_t
          VALUE)
     Get the constant value within a particular VALUE, assuming that
     its type is compatible with `jit_type_nfloat'.

 -- Function: int jit_value_is_true (jit_value_t VALUE)
     Determine if VALUE is constant and non-zero.

 -- Function: int jit_constant_convert (jit_constant_t *RESULT, const
          jit_constant_t *VALUE, jit_type_t TYPE, int OVERFLOW_CHECK)
     Convert a the constant VALUE into a new TYPE, and return its value
     in RESULT.  Returns zero if the conversion is not possible,
     usually due to overflow.


File: libjit.info,  Node: Instructions,  Next: Basic Blocks,  Prev: Values,  Up: Top

8 Working with instructions in the JIT
**************************************

 -- Function: int jit_insn_get_opcode (jit_insn_t INSN)
     Get the opcode that is associated with an instruction.

 -- Function: jit_value_t jit_insn_get_dest (jit_insn_t INSN)
     Get the destination value that is associated with an instruction.
     Returns NULL if the instruction does not have a destination.

 -- Function: jit_value_t jit_insn_get_value1 (jit_insn_t INSN)
     Get the first argument value that is associated with an
     instruction.  Returns NULL if the instruction does not have a
     first argument value.

 -- Function: jit_value_t jit_insn_get_value2 (jit_insn_t INSN)
     Get the second argument value that is associated with an
     instruction.  Returns NULL if the instruction does not have a
     second argument value.

 -- Function: jit_label_t jit_insn_get_label (jit_insn_t INSN)
     Get the label for a branch target from an instruction.  Returns
     NULL if the instruction does not have a branch target.

 -- Function: jit_function_t jit_insn_get_function (jit_insn_t INSN)
     Get the function for a call instruction.  Returns NULL if the
     instruction does not refer to a called function.

 -- Function: void * jit_insn_get_native (jit_insn_t INSN)
     Get the function pointer for a native call instruction.  Returns
     NULL if the instruction does not refer to a native function call.

 -- Function: const char * jit_insn_get_name (jit_insn_t INSN)
     Get the diagnostic name for a function call.  Returns NULL if the
     instruction does not have a diagnostic name.

 -- Function: jit_type_t jit_insn_get_signature (jit_insn_t INSN)
     Get the signature for a function call instruction.  Returns NULL
     if the instruction is not a function call.

 -- Function: int jit_insn_dest_is_value (jit_insn_t INSN)
     Returns a non-zero value if the destination for INSN is actually a
     source value.  This can happen with instructions such as
     `jit_insn_store_relative' where the instruction needs three source
     operands, and the real destination is a side-effect on one of the
     sources.

 -- Function: void jit_insn_label (jit_function_t FUNC, jit_label_t
          *LABEL)
     Start a new block within the function FUNC and give it the
     specified LABEL.  Returns zero if out of memory.

     If the contents of LABEL are `jit_label_undefined', then this
     function will allocate a new label for this block.  Otherwise it
     will reuse the specified label from a previous branch instruction.

 -- Function: int jit_insn_new_block (jit_function_t FUNC)
     Start a new basic block, without giving it an explicit label.

 -- Function: jit_value_t jit_insn_load (jit_function_t FUNC,
          jit_value_t VALUE)
     Load the contents of VALUE into a new temporary, essentially
     duplicating the value.  Constants are not duplicated.

 -- Function: jit_value_t jit_insn_dup (jit_function_t FUNC,
          jit_value_t VALUE)
     This is the same as `jit_insn_load', but the name may better
     reflect how it is used in some front ends.

 -- Function: jit_value_t jit_insn_load_small (jit_function_t FUNC,
          jit_value_t VALUE)
     If VALUE is of type `sbyte', `byte', `short', `ushort', a
     structure, or a union, then make a copy of it and return the
     temporary copy.  Otherwise return VALUE as-is.

     This is useful where you want to use VALUE directly without
     duplicating it first.  However, certain types usually cannot be
     operated on directly without first copying them elsewhere.  This
     function will do that whenever necessary.

 -- Function: void jit_insn_store (jit_function_t FUNC, jit_value_t
          DEST, jit_value_t VALUE)
     Store the contents of VALUE at the location referred to by DEST.
     The DEST should be a `jit_value_t' representing a local variable
     or temporary.  Use `jit_insn_store_relative' to store to a
     location referred to by a pointer.

 -- Function: jit_value_t jit_insn_load_relative (jit_function_t FUNC,
          jit_value_t VALUE, jit_nint OFFSET, jit_type_t TYPE)
     Load a value of the specified TYPE from the effective address
     `(VALUE + OFFSET)', where VALUE is a pointer.

 -- Function: int jit_insn_store_relative (jit_function_t FUNC,
          jit_value_t DEST, jit_nint OFFSET, jit_value_t VALUE)
     Store VALUE at the effective address `(DEST + OFFSET)', where DEST
     is a pointer.

 -- Function: jit_value_t jit_insn_add_relative (jit_function_t FUNC,
          jit_value_t VALUE, jit_nint OFFSET)
     Add the constant OFFSET to the specified pointer VALUE.  This is
     functionally identical to calling `jit_insn_add', but the JIT can
     optimize the code better if it knows that the addition is being
     used to perform a relative adjustment on a pointer.  In
     particular, multiple relative adjustments on the same pointer can
     be collapsed into a single adjustment.

 -- Function: jit_value_t jit_insn_load_elem (jit_function_t FUNC,
          jit_value_t BASE_ADDR, jit_value_t INDEX, jit_type_t
          ELEM_TYPE)
     Load an element of type ELEM_TYPE from position INDEX within the
     array starting at BASE_ADDR.  The effective address of the array
     element is `BASE_ADDR + INDEX * sizeof(ELEM_TYPE)'.

 -- Function: jit_value_t jit_insn_load_elem_address (jit_function_t
          FUNC, jit_value_t BASE_ADDR, jit_value_t INDEX, jit_type_t
          ELEM_TYPE)
     Load the effective address of an element of type ELEM_TYPE at
     position INDEX within the array starting at BASE_ADDR.
     Essentially, this computes the expression `BASE_ADDR + INDEX *
     sizeof(ELEM_TYPE)', but may be more efficient than performing the
     steps with `jit_insn_mul' and `jit_insn_add'.

 -- Function: int jit_insn_store_elem (jit_function_t FUNC, jit_value_t
          BASE_ADDR, jit_value_t INDEX, jit_value_t VALUE)
     Store VALUE at position INDEX of the array starting at BASE_ADDR.
     The effective address of the storage location is `BASE_ADDR +
     INDEX * sizeof(jit_value_get_type(VALUE))'.

 -- Function: int jit_insn_check_null (jit_function_t FUNC, jit_value_t
          VALUE)
     Check VALUE to see if it is NULL.  If it is, then throw the
     built-in `JIT_RESULT_NULL_REFERENCE' exception.

 -- Function: jit_value_t jit_insn_add (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Add two values together and return the result in a new temporary
     value.

 -- Function: jit_value_t jit_insn_add_ovf (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Add two values together and return the result in a new temporary
     value.  Throw an exception if overflow occurs.

 -- Function: jit_value_t jit_insn_sub (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Subtract two values and return the result in a new temporary value.

 -- Function: jit_value_t jit_insn_sub_ovf (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Subtract two values and return the result in a new temporary value.
     Throw an exception if overflow occurs.

 -- Function: jit_value_t jit_insn_mul (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Multiply two values and return the result in a new temporary value.

 -- Function: jit_value_t jit_insn_mul_ovf (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Multiply two values and return the result in a new temporary value.
     Throw an exception if overflow occurs.

 -- Function: jit_value_t jit_insn_div (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Divide two values and return the quotient in a new temporary value.
     Throws an exception on division by zero or arithmetic error (an
     arithmetic error is one where the minimum possible signed integer
     value is divided by -1).

 -- Function: jit_value_t jit_insn_rem (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Divide two values and return the remainder in a new temporary
     value.  Throws an exception on division by zero or arithmetic error
     (an arithmetic error is one where the minimum possible signed
     integer value is divided by -1).

 -- Function: jit_value_t jit_insn_rem_ieee (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Divide two values and return the remainder in a new temporary
     value.  Throws an exception on division by zero or arithmetic error
     (an arithmetic error is one where the minimum possible signed
     integer value is divided by -1).  This function is identical to
     `jit_insn_rem', except that it uses IEEE rules for computing the
     remainder of floating-point values.

 -- Function: jit_value_t jit_insn_neg (jit_function_t FUNC,
          jit_value_t VALUE1)
     Negate a value and return the result in a new temporary value.

 -- Function: jit_value_t jit_insn_and (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Bitwise AND two values and return the result in a new temporary
     value.

 -- Function: jit_value_t jit_insn_or (jit_function_t FUNC, jit_value_t
          VALUE1, jit_value_t VALUE2)
     Bitwise OR two values and return the result in a new temporary
     value.

 -- Function: jit_value_t jit_insn_xor (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Bitwise XOR two values and return the result in a new temporary
     value.

 -- Function: jit_value_t jit_insn_not (jit_function_t FUNC,
          jit_value_t VALUE1)
     Bitwise NOT a value and return the result in a new temporary value.

 -- Function: jit_value_t jit_insn_shl (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Perform a bitwise left shift on two values and return the result
     in a new temporary value.

 -- Function: jit_value_t jit_insn_shr (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Perform a bitwise right shift on two values and return the result
     in a new temporary value.  This performs a signed shift on signed
     operators, and an unsigned shift on unsigned operands.

 -- Function: jit_value_t jit_insn_ushr (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Perform a bitwise right shift on two values and return the result
     in a new temporary value.  This performs an unsigned shift on both
     signed and unsigned operands.

 -- Function: jit_value_t jit_insn_sshr (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Perform a bitwise right shift on two values and return the result
     in a new temporary value.  This performs an signed shift on both
     signed and unsigned operands.

 -- Function: jit_value_t jit_insn_eq (jit_function_t FUNC, jit_value_t
          VALUE1, jit_value_t VALUE2)
     Compare two values for equality and return the result in a new
     temporary value.

 -- Function: jit_value_t jit_insn_ne (jit_function_t FUNC, jit_value_t
          VALUE1, jit_value_t VALUE2)
     Compare two values for inequality and return the result in a new
     temporary value.

 -- Function: jit_value_t jit_insn_lt (jit_function_t FUNC, jit_value_t
          VALUE1, jit_value_t VALUE2)
     Compare two values for less than and return the result in a new
     temporary value.

 -- Function: jit_value_t jit_insn_le (jit_function_t FUNC, jit_value_t
          VALUE1, jit_value_t VALUE2)
     Compare two values for less than or equal and return the result in
     a new temporary value.

 -- Function: jit_value_t jit_insn_gt (jit_function_t FUNC, jit_value_t
          VALUE1, jit_value_t VALUE2)
     Compare two values for greater than and return the result in a new
     temporary value.

 -- Function: jit_value_t jit_insn_ge (jit_function_t FUNC, jit_value_t
          VALUE1, jit_value_t VALUE2)
     Compare two values for greater than or equal and return the result
     in a new temporary value.

 -- Function: jit_value_t jit_insn_cmpl (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Compare two values, and return a -1, 0, or 1 result.  If either
     value is "not a number", then -1 is returned.

 -- Function: jit_value_t jit_insn_cmpg (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
     Compare two values, and return a -1, 0, or 1 result.  If either
     value is "not a number", then 1 is returned.

 -- Function: jit_value_t jit_insn_to_bool (jit_function_t FUNC,
          jit_value_t VALUE1)
     Convert a value into a boolean 0 or 1 result of type
     `jit_type_int'.

 -- Function: jit_value_t jit_insn_to_not_bool (jit_function_t FUNC,
          jit_value_t VALUE1)
     Convert a value into a boolean 1 or 0 result of type `jit_type_int'
     (i.e. the inverse of `jit_insn_to_bool').

 -- Function: jit_value_t jit_insn_acos (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_asin (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_atan (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_atan2 (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
 -- Function: jit_value_t jit_insn_ceil (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_cos (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_cosh (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_exp (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_floor (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_log (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_log10 (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_pow (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
 -- Function: jit_value_t jit_insn_rint (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_round (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_sin (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_sinh (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_sqrt (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_tan (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_tanh (jit_function_t FUNC,
          jit_value_t VALUE1)
     Apply a mathematical function to floating-point arguments.

 -- Function: jit_value_t jit_insn_is_nan (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_is_finite (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_is_inf (jit_function_t FUNC,
          jit_value_t VALUE1)
     Test a floating point value for not a number, finite, or infinity.

 -- Function: jit_value_t jit_insn_abs (jit_function_t FUNC,
          jit_value_t VALUE1)
 -- Function: jit_value_t jit_insn_min (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
 -- Function: jit_value_t jit_insn_max (jit_function_t FUNC,
          jit_value_t VALUE1, jit_value_t VALUE2)
 -- Function: jit_value_t jit_insn_sign (jit_function_t FUNC,
          jit_value_t VALUE1)
     Calculate the absolute value, minimum, maximum, or sign of the
     specified values.

 -- Function: int jit_insn_branch (jit_function_t FUNC, jit_label_t
          *LABEL)
     Terminate the current block by branching unconditionally to a
     specific label.  Returns zero if out of memory.

 -- Function: int jit_insn_branch_if (jit_function_t FUNC, jit_value_t
          VALUE, jit_label_t *LABEL)
     Terminate the current block by branching to a specific label if
     the specified value is non-zero.  Returns zero if out of memory.

     If VALUE refers to a conditional expression that was created by
     `jit_insn_eq', `jit_insn_ne', etc, then the conditional expression
     will be replaced by an appropriate conditional branch instruction.

 -- Function: int jit_insn_branch_if_not (jit_function_t FUNC,
          jit_value_t VALUE, jit_label_t *LABEL)
     Terminate the current block by branching to a specific label if
     the specified value is zero.  Returns zero if out of memory.

     If VALUE refers to a conditional expression that was created by
     `jit_insn_eq', `jit_insn_ne', etc, then the conditional expression
     will be replaced by an appropriate conditional branch instruction.

 -- Function: int jit_insn_jump_table (jit_function_t FUNC, jit_value_t
          VALUE, jit_label_t *LABELS, unsigned int NUM_LABELS)
     Branch to a label from the LABELS table. The VALUE is the index of
     the label. It is allowed to have identical labels in the table.
     If an entry in the table has `jit_label_undefined' value then it is
     replaced with a newly allocated label.

 -- Function: jit_value_t jit_insn_address_of (jit_function_t FUNC,
          jit_value_t VALUE1)
     Get the address of a value into a new temporary.

 -- Function: jit_value_t jit_insn_address_of_label (jit_function_t
          FUNC, jit_label_t *LABEL)
     Get the address of LABEL into a new temporary.  This is typically
     used for exception handling, to track where in a function an
     exception was actually thrown.

 -- Function: jit_value_t jit_insn_convert (jit_function_t FUNC,
          jit_value_t VALUE, jit_type_t TYPE, int OVERFLOW_CHECK)
     Convert the contents of a value into a new type, with optional
     overflow checking.

 -- Function: jit_value_t jit_insn_call (jit_function_t FUNC, const
          char *NAME, jit_function_t JIT_FUNC, jit_type_t SIGNATURE,
          jit_value_t *ARGS, unsigned int NUM_ARGS, int FLAGS)
     Call the function JIT_FUNC, which may or may not be translated yet.
     The NAME is for diagnostic purposes only, and can be NULL.

     If SIGNATURE is NULL, then the actual signature of JIT_FUNC is
     used in its place.  This is the usual case.  However, if the
     function takes a variable number of arguments, then you may need
     to construct an explicit signature for the non-fixed argument
     values.

     The FLAGS parameter specifies additional information about the
     type of call to perform:

    `JIT_CALL_NOTHROW'
          The function never throws exceptions.

    `JIT_CALL_NORETURN'
          The function will never return directly to its caller.  It
          may however return to the caller indirectly by throwing an
          exception that the caller catches.

    `JIT_CALL_TAIL'
          Apply tail call optimizations, as the result of this function
          call will be immediately returned from the containing
          function.  Tail calls are only appropriate when the signature
          of the called function matches the callee, and none of the
          parameters point to local variables.

     If JIT_FUNC has already been compiled, then `jit_insn_call' may be
     able to intuit some of the above flags for itself.  Otherwise it
     is up to the caller to determine when the flags may be appropriate.

 -- Function: jit_value_t jit_insn_call_indirect (jit_function_t FUNC,
          jit_value_t VALUE, jit_type_t SIGNATURE, jit_value_t *ARGS,
          unsigned int NUM_ARGS, int FLAGS)
     Call a function via an indirect pointer.

 -- Function: jit_value_t jit_insn_call_indirect_vtable (jit_function_t
          FUNC, jit_value_t VALUE, jit_type_t SIGNATURE, jit_value_t
          *ARGS, unsigned int NUM_ARGS, int FLAGS)
     Call a function via an indirect pointer.  This version differs from
     `jit_insn_call_indirect' in that we assume that VALUE contains a
     pointer that resulted from calling
     `jit_function_to_vtable_pointer'.  Indirect vtable pointer calls
     may be more efficient on some platforms than regular indirect
     calls.

 -- Function: jit_value_t jit_insn_call_native (jit_function_t FUNC,
          const char *NAME, void *NATIVE_FUNC, jit_type_t SIGNATURE,
          jit_value_t *ARGS, unsigned int NUM_ARGS, int
          EXCEPTION_RETURN, int FLAGS)
     Output an instruction that calls an external native function.  The
     NAME is for diagnostic purposes only, and can be NULL.

 -- Function: jit_value_t jit_insn_call_intrinsic (jit_function_t FUNC,
          const char *NAME, void *INTRINSIC_FUNC, const
          jit_intrinsic_descr_t *DESCRIPTOR, jit_value_t ARG1,
          jit_value_t ARG2)
     Output an instruction that calls an intrinsic function.  The
     descriptor contains the following fields:

    `return_type'
          The type of value that is returned from the intrinsic.

    `ptr_result_type'
          This should be NULL for an ordinary intrinsic, or the result
          type if the intrinsic reports exceptions.

    `arg1_type'
          The type of the first argument.

    `arg2_type'
          The type of the second argument, or NULL for a unary
          intrinsic.

     If all of the arguments are constant, then
     `jit_insn_call_intrinsic' will call the intrinsic directly to
     calculate the constant result.  If the constant computation will
     result in an exception, then code is output to cause the exception
     at runtime.

     The NAME is for diagnostic purposes only, and can be NULL.

 -- Function: int jit_insn_incoming_reg (jit_function_t FUNC,
          jit_value_t VALUE, int REG)
     Output an instruction that notes that the contents of VALUE can be
     found in the register REG at this point in the code.

     You normally wouldn't call this yourself - it is used internally
     by the CPU back ends to set up the function's entry frame and the
     values of registers on return from a subroutine call.

 -- Function: int jit_insn_incoming_frame_posn (jit_function_t FUNC,
          jit_value_t VALUE, jit_nint FRAME_OFFSET)
     Output an instruction that notes that the contents of VALUE can be
     found in the stack frame at FRAME_OFFSET at this point in the code.

     You normally wouldn't call this yourself - it is used internally
     by the CPU back ends to set up the function's entry frame.

 -- Function: int jit_insn_outgoing_reg (jit_function_t FUNC,
          jit_value_t VALUE, int REG)
     Output an instruction that copies the contents of VALUE into the
     register REG at this point in the code.  This is typically used
     just before making an outgoing subroutine call.

     You normally wouldn't call this yourself - it is used internally
     by the CPU back ends to set up the registers for a subroutine call.

 -- Function: int jit_insn_outgoing_frame_posn (jit_function_t FUNC,
          jit_value_t VALUE, jit_nint FRAME_OFFSET)
     Output an instruction that notes that the contents of VALUE should
     be stored in the stack frame at FRAME_OFFSET at this point in the
     code.

     You normally wouldn't call this yourself - it is used internally
     by the CPU back ends to set up an outgoing frame for tail calls.

 -- Function: int jit_insn_return_reg (jit_function_t FUNC, jit_value_t
          VALUE, int REG)
     Output an instruction that notes that the contents of VALUE can be
     found in the register REG at this point in the code.  This is
     similar to `jit_insn_incoming_reg', except that it refers to
     return values, not parameter values.

     You normally wouldn't call this yourself - it is used internally
     by the CPU back ends to handle returns from subroutine calls.

 -- Function: int jit_insn_setup_for_nested (jit_function_t FUNC, int
          NESTED_LEVEL, int REG)
     Output an instruction to set up for a nested function call.  The
     NESTED_LEVEL value will be -1 to call a child, zero to call a
     sibling of FUNC, 1 to call a sibling of the parent, 2 to call a
     sibling of the grandparent, etc.  If REG is not -1, then it
     indicates the register to receive the parent frame information.
     If REG is -1, then the frame information will be pushed on the
     stack.

     You normally wouldn't call this yourself - it is used internally
     by the CPU back ends to set up the parameters for a nested
     subroutine call.

 -- Function: int jit_insn_flush_struct (jit_function_t FUNC,
          jit_value_t VALUE)
     Flush a small structure return value out of registers and back
     into the local variable frame.  You normally wouldn't call this
     yourself - it is used internally by the CPU back ends to handle
     structure returns from functions.

 -- Function: jit_value_t jit_insn_import (jit_function_t FUNC,
          jit_value_t VALUE)
     Import VALUE from an outer nested scope into FUNC.  Returns the
     effective address of the value for local access via a pointer.
     Returns NULL if out of memory or the value is not accessible via a
     parent, grandparent, or other ancestor of FUNC.

 -- Function: int jit_insn_push (jit_function_t FUNC, jit_value_t VALUE)
     Push a value onto the function call stack, in preparation for a
     call.  You normally wouldn't call this yourself - it is used
     internally by the CPU back ends to set up the stack for a
     subroutine call.

 -- Function: int jit_insn_push_ptr (jit_function_t FUNC, jit_value_t
          VALUE, jit_type_t TYPE)
     Push `*VALUE' onto the function call stack, in preparation for a
     call.  This is normally used for returning `struct' and `union'
     values where you have the effective address of the structure,
     rather than the structure's contents, in VALUE.

     You normally wouldn't call this yourself - it is used internally
     by the CPU back ends to set up the stack for a subroutine call.

 -- Function: int jit_insn_set_param (jit_function_t FUNC, jit_value_t
          VALUE, jit_nint OFFSET)
     Set the parameter slot at OFFSET in the outgoing parameter area to
     VALUE.  This may be used instead of `jit_insn_push' if it is more
     efficient to store directly to the stack than to push.  The
     outgoing parameter area is allocated within the frame when the
     function is first entered.

     You normally wouldn't call this yourself - it is used internally
     by the CPU back ends to set up the stack for a subroutine call.

 -- Function: int jit_insn_set_param_ptr (jit_function_t FUNC,
          jit_value_t VALUE, jit_type_t TYPE, jit_nint OFFSET)
     Same as `jit_insn_set_param_ptr', except that the parameter is at
     `*VALUE'.

 -- Function: int jit_insn_push_return_area_ptr (jit_function_t FUNC)
     Push the interpreter's return area pointer onto the stack.  You
     normally wouldn't call this yourself - it is used internally by
     the CPU back ends to set up the stack for a subroutine call.

 -- Function: int jit_insn_pop_stack (jit_function_t FUNC, jit_nint
          NUM_ITEMS)
     Pop NUM_ITEMS items from the function call stack.  You normally
     wouldn't call this yourself - it is used by CPU back ends to clean
     up the stack after calling a subroutine.  The size of an item is
     specific to the back end (it could be bytes, words, or some other
     measurement).

 -- Function: int jit_insn_defer_pop_stack (jit_function_t FUNC,
          jit_nint NUM_ITEMS)
     This is similar to `jit_insn_pop_stack', except that it tries to
     defer the pop as long as possible.  Multiple subroutine calls may
     result in parameters collecting up on the stack, and only being
     popped at the next branch or label instruction.  You normally
     wouldn't call this yourself - it is used by CPU back ends.

 -- Function: int jit_insn_flush_defer_pop (jit_function_t FUNC,
          jit_nint NUM_ITEMS)
     Flush any deferred items that were scheduled for popping by
     `jit_insn_defer_pop_stack' if there are NUM_ITEMS or more items
     scheduled.  You normally wouldn't call this yourself - it is used
     by CPU back ends to clean up the stack just prior to a subroutine
     call when too many items have collected up.  Calling
     `jit_insn_flush_defer_pop(func, 0)' will flush all deferred items.

 -- Function: int jit_insn_return (jit_function_t FUNC, jit_value_t
          VALUE)
     Output an instruction to return VALUE as the function's result.
     If VALUE is NULL, then the function is assumed to return `void'.
     If the function returns a structure, this will copy the value into
     the memory at the structure return address.

 -- Function: int jit_insn_return_ptr (jit_function_t FUNC, jit_value_t
          VALUE, jit_type_t TYPE)
     Output an instruction to return `*VALUE' as the function's result.
     This is normally used for returning `struct' and `union' values
     where you have the effective address of the structure, rather than
     the structure's contents, in VALUE.

 -- Function: int jit_insn_default_return (jit_function_t FUNC)
     Add an instruction to return a default value if control reaches
     this point.  This is typically used at the end of a function to
     ensure that all paths return to the caller.  Returns zero if out
     of memory, 1 if a default return was added, and 2 if a default
     return was not needed.

     Note: if this returns 1, but the function signature does not return
     `void', then it indicates that a higher-level language error has
     occurred and the function should be abandoned.

 -- Function: int jit_insn_throw (jit_function_t FUNC, jit_value_t
          VALUE)
     Throw a pointer VALUE as an exception object.  This can also be
     used to "rethrow" an object from a catch handler that is not
     interested in handling the exception.

 -- Function: jit_value_t jit_insn_get_call_stack (jit_function_t FUNC)
     Get an object that represents the current position in the code,
     and all of the functions that are currently on the call stack.
     This is equivalent to calling `jit_exception_get_stack_trace', and
     is normally used just prior to `jit_insn_throw' to record the
     location of the exception that is being thrown.

 -- Function: jit_value_t jit_insn_thrown_exception (jit_function_t
          FUNC)
     Get the value that holds the most recent thrown exception.  This is
     typically used in `catch' clauses.

 -- Function: int jit_insn_uses_catcher (jit_function_t FUNC)
     Notify the function building process that FUNC contains some form
     of `catch' clause for catching exceptions.  This must be called
     before any instruction that is covered by a `try', ideally at the
     start of the function output process.

 -- Function: jit_value_t jit_insn_start_catcher (jit_function_t FUNC)
     Start the catcher block for FUNC.  There should be exactly one
     catcher block for any function that involves a `try'.  All
     exceptions that are thrown within the function will cause control
     to jump to this point.  Returns a value that holds the exception
     that was thrown.

 -- Function: int jit_insn_branch_if_pc_not_in_range (jit_function_t
          FUNC, jit_label_t START_LABEL, jit_label_t END_LABEL,
          jit_label_t *LABEL)
     Branch to LABEL if the program counter where an exception occurred
     does not fall between START_LABEL and END_LABEL.

 -- Function: int jit_insn_rethrow_unhandled (jit_function_t FUNC)
     Rethrow the current exception because it cannot be handled by any
     of the `catch' blocks in the current function.

     Note: this is intended for use within catcher blocks.  It should
     not be used to rethrow exceptions in response to programmer
     requests (e.g. `throw;' in C#).  The `jit_insn_throw' function
     should be used for that purpose.

 -- Function: int jit_insn_start_finally (jit_function_t FUNC,
          jit_label_t *FINALLY_LABEL)
     Start a `finally' clause.

 -- Function: int jit_insn_return_from_finally (jit_function_t FUNC)
     Return from the `finally' clause to where it was called from.
     This is usually the last instruction in a `finally' clause.

 -- Function: int jit_insn_call_finally (jit_function_t FUNC,
          jit_label_t *FINALLY_LABEL)
     Call a `finally' clause.

 -- Function: jit_value_t jit_insn_start_filter (jit_function_t FUNC,
          jit_label_t *LABEL, jit_type_t TYPE)
     Define the start of a filter.  Filters are embedded subroutines
     within functions that are used to filter exceptions in `catch'
     blocks.

     A filter subroutine takes a single argument (usually a pointer) and
     returns a single result (usually a boolean).  The filter has
     complete access to the local variables of the function, and can
     use any of them in the filtering process.

     This function returns a temporary value of the specified TYPE,
     indicating the parameter that is supplied to the filter.

 -- Function: int jit_insn_return_from_filter (jit_function_t FUNC,
          jit_value_t VALUE)
     Return from a filter subroutine with the specified `value' as its
     result.

 -- Function: jit_value_t jit_insn_call_filter (jit_function_t FUNC,
          jit_label_t *LABEL, jit_value_t VALUE, jit_type_t TYPE)
     Call the filter subroutine at LABEL, passing it VALUE as its
     argument.  This function returns a value of the specified TYPE,
     indicating the filter's result.

 -- Function: int jit_insn_memcpy (jit_function_t FUNC, jit_value_t
          DEST, jit_value_t SRC, jit_value_t SIZE)
     Copy the SIZE bytes of memory at SRC to DEST.  It is assumed that
     the source and destination do not overlap.

 -- Function: int jit_insn_memmove (jit_function_t FUNC, jit_value_t
          DEST, jit_value_t SRC, jit_value_t SIZE)
     Copy the SIZE bytes of memory at SRC to DEST.  This is save to use
     if the source and destination overlap.

 -- Function: int jit_insn_memset (jit_function_t FUNC, jit_value_t
          DEST, jit_value_t VALUE, jit_value_t SIZE)
     Set the SIZE bytes at DEST to VALUE.

 -- Function: jit_value_t jit_insn_alloca (jit_function_t FUNC,
          jit_value_t SIZE)
     Allocate SIZE bytes of memory from the stack.

 -- Function: int jit_insn_move_blocks_to_end (jit_function_t FUNC,
          jit_label_t FROM_LABEL, jit_label_t TO_LABEL)
     Move all of the blocks between FROM_LABEL (inclusive) and TO_LABEL
     (exclusive) to the end of the current function.  This is typically
     used to move the expression in a `while' loop to the end of the
     body, where it can be executed more efficiently.

 -- Function: int jit_insn_move_blocks_to_start (jit_function_t FUNC,
          jit_label_t FROM_LABEL, jit_label_t TO_LABEL)
     Move all of the blocks between FROM_LABEL (inclusive) and TO_LABEL
     (exclusive) to the start of the current function.  This is
     typically used to move initialization code to the head of the
     function.

 -- Function: int jit_insn_mark_offset (jit_function_t FUNC, jit_int
          OFFSET)
     Mark the current position in FUNC as corresponding to the
     specified bytecode OFFSET.  This value will be returned by
     `jit_stack_trace_get_offset', and is useful for associating code
     positions with source line numbers.

 -- Function: void jit_insn_iter_init (jit_insn_iter_t *ITER,
          jit_block_t BLOCK)
     Initialize an iterator to point to the first instruction in BLOCK.

 -- Function: void jit_insn_iter_init_last (jit_insn_iter_t *ITER,
          jit_block_t BLOCK)
     Initialize an iterator to point to the last instruction in BLOCK.

 -- Function: jit_insn_t jit_insn_iter_next (jit_insn_iter_t *ITER)
     Get the next instruction in an iterator's block.  Returns NULL
     when there are no further instructions in the block.

 -- Function: jit_insn_t jit_insn_iter_previous (jit_insn_iter_t *ITER)
     Get the previous instruction in an iterator's block.  Returns NULL
     when there are no further instructions in the block.


File: libjit.info,  Node: Basic Blocks,  Next: Intrinsics,  Prev: Instructions,  Up: Top

9 Working with basic blocks in the JIT
**************************************

 -- Function: jit_function_t jit_block_get_function (jit_block_t BLOCK)
     Get the function that a particular BLOCK belongs to.

 -- Function: jit_context_t jit_block_get_context (jit_block_t BLOCK)
     Get the context that a particular BLOCK belongs to.

 -- Function: jit_label_t jit_block_get_label (jit_block_t BLOCK)
     Get the label associated with a block.

 -- Function: jit_block_t jit_block_next (jit_function_t FUNC,
          jit_block_t PREVIOUS)
     Iterate over the blocks in a function, in order of their creation.
     The PREVIOUS argument should be NULL on the first call.  This
     function will return NULL if there are no further blocks to
     iterate.

 -- Function: jit_block_t jit_block_previous (jit_function_t FUNC,
          jit_block_t PREVIOUS)
     Iterate over the blocks in a function, in reverse order of their
     creation.  The PREVIOUS argument should be NULL on the first call.
     This function will return NULL if there are no further blocks to
     iterate.

 -- Function: jit_block_t jit_block_from_label (jit_function_t FUNC,
          jit_label_t LABEL)
     Get the block that corresponds to a particular LABEL.  Returns
     NULL if there is no block associated with the label.

 -- Function: int jit_block_set_meta (jit_block_t BLOCK, int TYPE, void
          *DATA, jit_meta_free_func FREE_DATA)
     Tag a block with some metadata.  Returns zero if out of memory.
     If the TYPE already has some metadata associated with it, then the
     previous value will be freed.  Metadata may be used to store
     dependency graphs, branch prediction information, or any other
     information that is useful to optimizers or code generators.

     Metadata type values of 10000 or greater are reserved for internal
     use.

 -- Function: void * jit_block_get_meta (jit_block_t BLOCK, int TYPE)
     Get the metadata associated with a particular tag.  Returns NULL
     if TYPE does not have any metadata associated with it.

 -- Function: void jit_block_free_meta (jit_block_t BLOCK, int TYPE)
     Free metadata of a specific type on a block.  Does nothing if the
     TYPE does not have any metadata associated with it.

 -- Function: int jit_block_is_reachable (jit_block_t BLOCK)
     Determine if a block is reachable from some other point in its
     function.  Unreachable blocks can be discarded in their entirety.
     If the JIT is uncertain as to whether a block is reachable, or it
     does not wish to perform expensive flow analysis to find out, then
     it will err on the side of caution and assume that it is reachable.

 -- Function: int jit_block_ends_in_dead (jit_block_t BLOCK)
     Determine if a block ends in a "dead" marker.  That is, control
     will not fall out through the end of the block.

 -- Function: int jit_block_current_is_dead (jit_function_t FUNC)
     Determine if the current point in the function is dead.  That is,
     there are no existing branches or fall-throughs to this point.
     This differs slightly from `jit_block_ends_in_dead' in that this
     can skip past zero-length blocks that may not appear to be dead to
     find the dead block at the head of a chain of empty blocks.


File: libjit.info,  Node: Intrinsics,  Next: Exceptions,  Prev: Basic Blocks,  Up: Top

10 Intrinsic functions available to libjit users
************************************************

Intrinsics are functions that are provided to ease code generation on
platforms that may not be able to perform all operations natively.

   For example, on a CPU without a floating-point unit, the back end
code generator will output a call to an intrinsic function when a
floating-point operation is performed.  CPU's with a floating-point
unit would use a native instruction instead.

   Some platforms may already have appropriate intrinsics (e.g. the ARM
floating-point emulation routines).  The back end code generator may
choose to use either the system-supplied intrinsics or the ones
supplied by this library.  We supply all of them in our library just in
case a particular platform lacks an appropriate intrinsic.

   Some intrinsics have no equivalent in existing system libraries;
particularly those that deal with overflow checking.

   Functions that perform overflow checking or which divide integer
operands return a built-in exception code to indicate the type of
exception to be thrown (the caller is responsible for throwing the
actual exception).  *Note Exceptions::, for a list of built-in
exception codes.

   The following functions are defined in `<jit/jit-intrinsic.h>':

 -- Function: jit_int jit_int_add (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_sub (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_mul (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_neg (jit_int VALUE1)
 -- Function: jit_int jit_int_and (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_or (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_xor (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_not (jit_int VALUE1)
 -- Function: jit_int jit_int_not (jit_int VALUE1)
 -- Function: jit_int jit_int_shl (jit_int VALUE1, jit_uint VALUE2)
 -- Function: jit_int jit_int_shr (jit_int VALUE1, jit_uint VALUE2)
     Perform an arithmetic operation on signed 32-bit integers.

 -- Function: jit_int jit_int_add_ovf (jit_int *RESULT, jit_int VALUE1,
          jit_int VALUE2)
 -- Function: jit_int jit_int_sub_ovf (jit_int *RESULT, jit_int VALUE1,
          jit_int VALUE2)
 -- Function: jit_int jit_int_mul_ovf (jit_int *RESULT, jit_int VALUE1,
          jit_int VALUE2)
     Perform an arithmetic operation on two signed 32-bit integers,
     with overflow checking.  Returns `JIT_RESULT_OK' or
     `JIT_RESULT_OVERFLOW'.

 -- Function: jit_int jit_int_div_ovf (jit_int *RESULT, jit_int VALUE1,
          jit_int VALUE2)
 -- Function: jit_int jit_int_rem_ovf (jit_int *RESULT, jit_int VALUE1,
          jit_int VALUE2)
     Perform a division or remainder operation on two signed 32-bit
     integers.  Returns `JIT_RESULT_OK', `JIT_RESULT_DIVISION_BY_ZERO',
     or `JIT_RESULT_ARITHMETIC'.

 -- Function: jit_int jit_int_eq (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_ne (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_lt (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_le (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_gt (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_ge (jit_int VALUE1, jit_int VALUE2)
     Compare two signed 32-bit integers, returning 0 or 1 based on
     their relationship.

 -- Function: jit_int jit_int_cmp (jit_int VALUE1, jit_int VALUE2)
     Compare two signed 32-bit integers and return -1, 0, or 1 based on
     their relationship.

 -- Function: jit_int jit_int_abs (jit_int VALUE1)
 -- Function: jit_int jit_int_min (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_max (jit_int VALUE1, jit_int VALUE2)
 -- Function: jit_int jit_int_sign (jit_int VALUE1)
     Calculate the absolute value, minimum, maximum, or sign for signed
     32-bit integer values.

 -- Function: jit_uint jit_uint_add (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_uint jit_uint_sub (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_uint jit_uint_mul (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_uint jit_uint_neg (jit_uint VALUE1)
 -- Function: jit_uint jit_uint_and (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_uint jit_uint_or (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_uint jit_uint_xor (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_uint jit_uint_not (jit_uint VALUE1)
 -- Function: jit_uint jit_uint_not (jit_uint VALUE1)
 -- Function: jit_uint jit_uint_shl (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_uint jit_uint_shr (jit_uint VALUE1, jit_uint VALUE2)
     Perform an arithmetic operation on unsigned 32-bit integers.

 -- Function: jit_int jit_uint_add_ovf (jit_uint *RESULT, jit_uint
          VALUE1, jit_uint VALUE2)
 -- Function: jit_int jit_uint_sub_ovf (jit_uint *RESULT, jit_uint
          VALUE1, jit_uint VALUE2)
 -- Function: jit_int jit_uint_mul_ovf (jit_uint *RESULT, jit_uint
          VALUE1, jit_uint VALUE2)
     Perform an arithmetic operation on two unsigned 32-bit integers,
     with overflow checking.  Returns `JIT_RESULT_OK' or
     `JIT_RESULT_OVERFLOW'.

 -- Function: jit_int jit_uint_div_ovf (jit_uint *RESULT, jit_uint
          VALUE1, jit_uint VALUE2)
 -- Function: jit_int jit_uint_rem_ovf (jit_uint *RESULT, jit_uint
          VALUE1, jit_uint VALUE2)
     Perform a division or remainder operation on two unsigned 32-bit
     integers.  Returns `JIT_RESULT_OK' or `JIT_RESULT_DIVISION_BY_ZERO'
     (`JIT_RESULT_ARITHMETIC' is not possible with unsigned integers).

 -- Function: jit_int jit_uint_eq (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_int jit_uint_ne (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_int jit_uint_lt (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_int jit_uint_le (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_int jit_uint_gt (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_int jit_uint_ge (jit_uint VALUE1, jit_uint VALUE2)
     Compare two unsigned 32-bit integers, returning 0 or 1 based on
     their relationship.

 -- Function: jit_int jit_uint_cmp (jit_uint VALUE1, jit_uint VALUE2)
     Compare two unsigned 32-bit integers and return -1, 0, or 1 based
     on their relationship.

 -- Function: jit_uint jit_uint_min (jit_uint VALUE1, jit_uint VALUE2)
 -- Function: jit_uint jit_uint_max (jit_uint VALUE1, jit_uint VALUE2)
     Calculate the minimum or maximum for unsigned 32-bit integer
     values.

 -- Function: jit_long jit_long_add (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_long jit_long_sub (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_long jit_long_mul (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_long jit_long_neg (jit_long VALUE1)
 -- Function: jit_long jit_long_and (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_long jit_long_or (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_long jit_long_xor (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_long jit_long_not (jit_long VALUE1)
 -- Function: jit_long jit_long_not (jit_long VALUE1)
 -- Function: jit_long jit_long_shl (jit_long VALUE1, jit_uint VALUE2)
 -- Function: jit_long jit_long_shr (jit_long VALUE1, jit_uint VALUE2)
     Perform an arithmetic operation on signed 64-bit integers.

 -- Function: jit_int jit_long_add_ovf (jit_long *RESULT, jit_long
          VALUE1, jit_long VALUE2)
 -- Function: jit_int jit_long_sub_ovf (jit_long *RESULT, jit_long
          VALUE1, jit_long VALUE2)
 -- Function: jit_int jit_long_mul_ovf (jit_long *RESULT, jit_long
          VALUE1, jit_long VALUE2)
     Perform an arithmetic operation on two signed 64-bit integers,
     with overflow checking.  Returns `JIT_RESULT_OK' or
     `JIT_RESULT_OVERFLOW'.

 -- Function: jit_int jit_long_div_ovf (jit_long *RESULT, jit_long
          VALUE1, jit_long VALUE2)
 -- Function: jit_int jit_long_rem_ovf (jit_long *RESULT, jit_long
          VALUE1, jit_long VALUE2)
     Perform a division or remainder operation on two signed 64-bit
     integers.  Returns `JIT_RESULT_OK', `JIT_RESULT_DIVISION_BY_ZERO',
     or `JIT_RESULT_ARITHMETIC'.

 -- Function: jit_int jit_long_eq (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_int jit_long_ne (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_int jit_long_lt (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_int jit_long_le (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_int jit_long_gt (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_int jit_long_ge (jit_long VALUE1, jit_long VALUE2)
     Compare two signed 64-bit integers, returning 0 or 1 based on
     their relationship.

 -- Function: jit_int jit_long_cmp (jit_long VALUE1, jit_long VALUE2)
     Compare two signed 64-bit integers and return -1, 0, or 1 based on
     their relationship.

 -- Function: jit_long jit_long_abs (jit_long VALUE1)
 -- Function: jit_long jit_long_min (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_long jit_long_max (jit_long VALUE1, jit_long VALUE2)
 -- Function: jit_int jit_long_sign (jit_long VALUE1)
     Calculate the absolute value, minimum, maximum, or sign for signed
     64-bit integer values.

 -- Function: jit_ulong jit_ulong_add (jit_ulong VALUE1, jit_ulong
          VALUE2)
 -- Function: jit_ulong jit_ulong_sub (jit_ulong VALUE1, jit_ulong
          VALUE2)
 -- Function: jit_ulong jit_ulong_mul (jit_ulong VALUE1, jit_ulong
          VALUE2)
 -- Function: jit_ulong jit_ulong_neg (jit_ulong VALUE1)
 -- Function: jit_ulong jit_ulong_and (jit_ulong VALUE1, jit_ulong
          VALUE2)
 -- Function: jit_ulong jit_ulong_or (jit_ulong VALUE1, jit_ulong
          VALUE2)
 -- Function: jit_ulong jit_ulong_xor (jit_ulong VALUE1, jit_ulong
          VALUE2)
 -- Function: jit_ulong jit_ulong_not (jit_ulong VALUE1)
 -- Function: jit_ulong jit_ulong_not (jit_ulong VALUE1)
 -- Function: jit_ulong jit_ulong_shl (jit_ulong VALUE1, jit_uint
          VALUE2)
 -- Function: jit_ulong jit_ulong_shr (jit_ulong VALUE1, jit_uint
          VALUE2)
     Perform an arithmetic operation on unsigned 64-bit integers.

 -- Function: jit_int jit_ulong_add_ovf (jit_ulong *RESULT, jit_ulong
          VALUE1, jit_ulong VALUE2)
 -- Function: jit_int jit_ulong_sub_ovf (jit_ulong *RESULT, jit_ulong
          VALUE1, jit_ulong VALUE2)
 -- Function: jit_int jit_ulong_mul_ovf (jit_ulong *RESULT, jit_ulong
          VALUE1, jit_ulong VALUE2)
     Perform an arithmetic operation on two unsigned 64-bit integers,
     with overflow checking.  Returns `JIT_RESULT_OK' or
     `JIT_RESULT_OVERFLOW'.

 -- Function: jit_int jit_ulong_div_ovf (jit_ulong *RESULT, jit_ulong
          VALUE1, jit_ulong VALUE2)
 -- Function: jit_int jit_ulong_rem_ovf (jit_ulong *RESULT, jit_ulong
          VALUE1, jit_ulong VALUE2)
     Perform a division or remainder operation on two unsigned 64-bit
     integers.  Returns `JIT_RESULT_OK' or `JIT_RESULT_DIVISION_BY_ZERO'
     (`JIT_RESULT_ARITHMETIC' is not possible with unsigned integers).

 -- Function: jit_int jit_ulong_eq (jit_ulong VALUE1, jit_ulong VALUE2)
 -- Function: jit_int jit_ulong_ne (jit_ulong VALUE1, jit_ulong VALUE2)
 -- Function: jit_int jit_ulong_lt (jit_ulong VALUE1, jit_ulong VALUE2)
 -- Function: jit_int jit_ulong_le (jit_ulong VALUE1, jit_ulong VALUE2)
 -- Function: jit_int jit_ulong_gt (jit_ulong VALUE1, jit_ulong VALUE2)
 -- Function: jit_int jit_ulong_ge (jit_ulong VALUE1, jit_ulong VALUE2)
     Compare two unsigned 64-bit integers, returning 0 or 1 based on
     their relationship.

 -- Function: jit_int jit_ulong_cmp (jit_ulong VALUE1, jit_ulong VALUE2)
     Compare two unsigned 64-bit integers and return -1, 0, or 1 based
     on their relationship.

 -- Function: jit_ulong jit_ulong_min (jit_ulong VALUE1, jit_ulong
          VALUE2)
 -- Function: jit_ulong jit_ulong_max (jit_ulong VALUE1, jit_ulong
          VALUE2)
     Calculate the minimum or maximum for unsigned 64-bit integer
     values.

 -- Function: jit_float32 jit_float32_add (jit_float32 VALUE1,
          jit_float32 VALUE2)
 -- Function: jit_float32 jit_float32_sub (jit_float32 VALUE1,
          jit_float32 VALUE2)
 -- Function: jit_float32 jit_float32_mul (jit_float32 VALUE1,
          jit_float32 VALUE2)
 -- Function: jit_float32 jit_float32_div (jit_float32 VALUE1,
          jit_float32 VALUE2)
 -- Function: jit_float32 jit_float32_rem (jit_float32 VALUE1,
          jit_float32 VALUE2)
 -- Function: jit_float32 jit_float32_ieee_rem (jit_float32 VALUE1,
          jit_float32 VALUE2)
 -- Function: jit_float32 jit_float32_neg (jit_float32 VALUE1)
     Perform an arithmetic operation on 32-bit floating-point values.

 -- Function: jit_int jit_float32_eq (jit_float32 VALUE1, jit_float32
          VALUE2)
 -- Function: jit_int jit_float32_ne (jit_float32 VALUE1, jit_float32
          VALUE2)
 -- Function: jit_int jit_float32_lt (jit_float32 VALUE1, jit_float32
          VALUE2)
 -- Function: jit_int jit_float32_le (jit_float32 VALUE1, jit_float32
          VALUE2)
 -- Function: jit_int jit_float32_gt (jit_float32 VALUE1, jit_float32
          VALUE2)
 -- Function: jit_int jit_float32_ge (jit_float32 VALUE1, jit_float32
          VALUE2)
     Compare two 32-bit floating-point values, returning 0 or 1 based
     on their relationship.

 -- Function: jit_int jit_float32_cmpl (jit_float32 VALUE1, jit_float32
          VALUE2)
     Compare two 32-bit floating-point values and return -1, 0, or 1
     based on their relationship.  If either value is "not a number",
     then -1 is returned.

 -- Function: jit_int jit_float32_cmpg (jit_float32 VALUE1, jit_float32
          VALUE2)
     Compare two 32-bit floating-point values and return -1, 0, or 1
     based on their relationship.  If either value is "not a number",
     then 1 is returned.

 -- Function: jit_float32 jit_float32_abs (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_min (jit_float32 VALUE1,
          jit_float32 VALUE2)
 -- Function: jit_float32 jit_float32_max (jit_float32 VALUE1,
          jit_float32 VALUE2)
 -- Function: jit_int jit_float32_sign (jit_float32 VALUE1)
     Calculate the absolute value, minimum, maximum, or sign for 32-bit
     floating point values.

 -- Function: jit_float32 jit_float32_acos (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_asin (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_atan (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_atan2 (jit_float32 VALUE1,
          jit_float32 VALUE2)
 -- Function: jit_float32 jit_float32_ceil (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_cos (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_cosh (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_exp (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_floor (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_log (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_log10 (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_pow (jit_float32 VALUE1,
          jit_float32 VALUE2)
 -- Function: jit_float32 jit_float32_sin (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_sinh (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_sqrt (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_tan (jit_float32 VALUE1)
 -- Function: jit_float32 jit_float32_tanh (jit_float32 VALUE1)
     Apply a mathematical function to one or two 32-bit floating-point
     values.

 -- Function: jit_float32 jit_float32_rint (jit_float32 VALUE1)
     Round VALUE1 to the nearest integer.  Half-way cases are rounded
     to an even number.

 -- Function: jit_float32 jit_float32_round (jit_float32 VALUE1)
     Round VALUE1 to the nearest integer.  Half-way cases are rounded
     away from zero.

 -- Function: jit_int jit_float32_is_finite (jit_float32 VALUE)
     Determine if a 32-bit floating point value is finite, returning
     non-zero if it is, or zero if it is not.  If the value is "not a
     number", this function returns zero.

 -- Function: jit_int jit_float32_is_nan (jit_float32 VALUE)
     Determine if a 32-bit floating point value is "not a number",
     returning non-zero if it is, or zero if it is not.

 -- Function: jit_int jit_float32_is_inf (jit_float32 VALUE)
     Determine if a 32-bit floating point value is infinite or not.
     Returns -1 for negative infinity, 1 for positive infinity, and 0
     for everything else.

     Note: this function is preferable to the system `isinf' intrinsic
     because some systems have a broken `isinf' function that returns 1
     for both positive and negative infinity.

 -- Function: jit_float64 jit_float64_add (jit_float64 VALUE1,
          jit_float64 VALUE2)
 -- Function: jit_float64 jit_float64_sub (jit_float64 VALUE1,
          jit_float64 VALUE2)
 -- Function: jit_float64 jit_float64_mul (jit_float64 VALUE1,
          jit_float64 VALUE2)
 -- Function: jit_float64 jit_float64_div (jit_float64 VALUE1,
          jit_float64 VALUE2)
 -- Function: jit_float64 jit_float64_rem (jit_float64 VALUE1,
          jit_float64 VALUE2)
 -- Function: jit_float64 jit_float64_ieee_rem (jit_float64 VALUE1,
          jit_float64 VALUE2)
 -- Function: jit_float64 jit_float64_neg (jit_float64 VALUE1)
     Perform an arithmetic operation on 64-bit floating-point values.

 -- Function: jit_int jit_float64_eq (jit_float64 VALUE1, jit_float64
          VALUE2)
 -- Function: jit_int jit_float64_ne (jit_float64 VALUE1, jit_float64
          VALUE2)
 -- Function: jit_int jit_float64_lt (jit_float64 VALUE1, jit_float64
          VALUE2)
 -- Function: jit_int jit_float64_le (jit_float64 VALUE1, jit_float64
          VALUE2)
 -- Function: jit_int jit_float64_gt (jit_float64 VALUE1, jit_float64
          VALUE2)
 -- Function: jit_int jit_float64_ge (jit_float64 VALUE1, jit_float64
          VALUE2)
     Compare two 64-bit floating-point values, returning 0 or 1 based
     on their relationship.

 -- Function: jit_int jit_float64_cmpl (jit_float64 VALUE1, jit_float64
          VALUE2)
     Compare two 64-bit floating-point values and return -1, 0, or 1
     based on their relationship.  If either value is "not a number",
     then -1 is returned.

 -- Function: jit_int jit_float64_cmpg (jit_float64 VALUE1, jit_float64
          VALUE2)
     Compare two 64-bit floating-point values and return -1, 0, or 1
     based on their relationship.  If either value is "not a number",
     then 1 is returned.

 -- Function: jit_float64 jit_float64_abs (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_min (jit_float64 VALUE1,
          jit_float64 VALUE2)
 -- Function: jit_float64 jit_float64_max (jit_float64 VALUE1,
          jit_float64 VALUE2)
 -- Function: jit_int jit_float64_sign (jit_float64 VALUE1)
     Calculate the absolute value, minimum, maximum, or sign for 64-bit
     floating point values.

 -- Function: jit_float64 jit_float64_acos (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_asin (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_atan (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_atan2 (jit_float64 VALUE1,
          jit_float64 VALUE2)
 -- Function: jit_float64 jit_float64_ceil (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_cos (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_cosh (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_exp (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_floor (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_log (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_log10 (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_pow (jit_float64 VALUE1,
          jit_float64 VALUE2)
 -- Function: jit_float64 jit_float64_sin (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_sinh (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_sqrt (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_tan (jit_float64 VALUE1)
 -- Function: jit_float64 jit_float64_tanh (jit_float64 VALUE1)
     Apply a mathematical function to one or two 64-bit floating-point
     values.

 -- Function: jit_float64 jit_float64_rint (jit_float64 VALUE1)
     Round VALUE1 to the nearest integer.  Half-way cases are rounded
     to an even number.

 -- Function: jit_float64 jit_float64_round (jit_float64 VALUE1)
     Round VALUE1 to the nearest integer.  Half-way cases are rounded
     away from zero.

 -- Function: jit_int jit_float64_is_finite (jit_float64 VALUE)
     Determine if a 64-bit floating point value is finite, returning
     non-zero if it is, or zero if it is not.  If the value is "not a
     number", this function returns zero.

 -- Function: jit_int jit_float64_is_nan (jit_float64 VALUE)
     Determine if a 64-bit floating point value is "not a number",
     returning non-zero if it is, or zero if it is not.

 -- Function: jit_int jit_float64_is_inf (jit_float64 VALUE)
     Determine if a 64-bit floating point value is infinite or not.
     Returns -1 for negative infinity, 1 for positive infinity, and 0
     for everything else.

     Note: this function is preferable to the system `isinf' intrinsic
     because some systems have a broken `isinf' function that returns 1
     for both positive and negative infinity.

 -- Function: jit_nfloat jit_nfloat_add (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_nfloat jit_nfloat_sub (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_nfloat jit_nfloat_mul (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_nfloat jit_nfloat_div (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_nfloat jit_nfloat_rem (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_nfloat jit_nfloat_ieee_rem (jit_nfloat VALUE1,
          jit_nfloat VALUE2)
 -- Function: jit_nfloat jit_nfloat_neg (jit_nfloat VALUE1)
     Perform an arithmetic operation on native floating-point values.

 -- Function: jit_int jit_nfloat_eq (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_int jit_nfloat_ne (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_int jit_nfloat_lt (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_int jit_nfloat_le (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_int jit_nfloat_gt (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_int jit_nfloat_ge (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
     Compare two native floating-point values, returning 0 or 1 based
     on their relationship.

 -- Function: jit_int jit_nfloat_cmpl (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
     Compare two native floating-point values and return -1, 0, or 1
     based on their relationship.  If either value is "not a number",
     then -1 is returned.

 -- Function: jit_int jit_nfloat_cmpg (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
     Compare two native floating-point values and return -1, 0, or 1
     based on their relationship.  If either value is "not a number",
     then 1 is returned.

 -- Function: jit_nfloat jit_nfloat_abs (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_min (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_nfloat jit_nfloat_max (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_int jit_nfloat_sign (jit_nfloat VALUE1)
     Calculate the absolute value, minimum, maximum, or sign for native
     floating point values.

 -- Function: jit_nfloat jit_nfloat_acos (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_asin (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_atan (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_atan2 (jit_nfloat VALUE1,
          jit_nfloat VALUE2)
 -- Function: jit_nfloat jit_nfloat_ceil (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_cos (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_cosh (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_exp (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_floor (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_log (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_log10 (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_pow (jit_nfloat VALUE1, jit_nfloat
          VALUE2)
 -- Function: jit_nfloat jit_nfloat_sin (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_sinh (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_sqrt (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_tan (jit_nfloat VALUE1)
 -- Function: jit_nfloat jit_nfloat_tanh (jit_nfloat VALUE1)
     Apply a mathematical function to one or two native floating-point
     values.

 -- Function: jit_nfloat jit_nfloat_rint (jit_nfloat VALUE1)
     Round VALUE1 to the nearest integer.  Half-way cases are rounded
     to an even number.

 -- Function: jit_nfloat jit_nfloat_round (jit_nfloat VALUE1)
     Round VALUE1 to the nearest integer.  Half-way cases are rounded
     away from zero.

 -- Function: jit_int jit_nfloat_is_finite (jit_nfloat VALUE)
     Determine if a native floating point value is finite, returning
     non-zero if it is, or zero if it is not.  If the value is "not a
     number", this function returns zero.

 -- Function: jit_int jit_nfloat_is_nan (jit_nfloat VALUE)
     Determine if a native floating point value is "not a number",
     returning non-zero if it is, or zero if it is not.

 -- Function: jit_int jit_nfloat_is_inf (jit_nfloat VALUE)
     Determine if a native floating point value is infinite or not.
     Returns -1 for negative infinity, 1 for positive infinity, and 0
     for everything else.

     Note: this function is preferable to the system `isinf' intrinsic
     because some systems have a broken `isinf' function that returns 1
     for both positive and negative infinity.

 -- Function: jit_int jit_int_to_sbyte (jit_int VALUE)
 -- Function: jit_int jit_int_to_ubyte (jit_int VALUE)
 -- Function: jit_int jit_int_to_short (jit_int VALUE)
 -- Function: jit_int jit_int_to_ushort (jit_int VALUE)
 -- Function: jit_int jit_int_to_int (jit_int VALUE)
 -- Function: jit_uint jit_int_to_uint (jit_int VALUE)
 -- Function: jit_long jit_int_to_long (jit_int VALUE)
 -- Function: jit_ulong jit_int_to_ulong (jit_int VALUE)
 -- Function: jit_int jit_uint_to_int (jit_uint VALUE)
 -- Function: jit_uint jit_uint_to_uint (jit_uint VALUE)
 -- Function: jit_long jit_uint_to_long (jit_uint VALUE)
 -- Function: jit_ulong jit_uint_to_ulong (jit_uint VALUE)
 -- Function: jit_int jit_long_to_int (jit_long VALUE)
 -- Function: jit_uint jit_long_to_uint (jit_long VALUE)
 -- Function: jit_long jit_long_to_long (jit_long VALUE)
 -- Function: jit_ulong jit_long_to_ulong (jit_long VALUE)
 -- Function: jit_int jit_ulong_to_int (jit_ulong VALUE)
 -- Function: jit_uint jit_ulong_to_uint (jit_ulong VALUE)
 -- Function: jit_long jit_ulong_to_long (jit_ulong VALUE)
 -- Function: jit_ulong jit_ulong_to_ulong (jit_ulong VALUE)
     Convert between integer types.

 -- Function: jit_int jit_int_to_sbyte_ovf (jit_int *RESULT, jit_int
          VALUE)
 -- Function: jit_int jit_int_to_ubyte_ovf (jit_int *RESULT, jit_int
          VALUE)
 -- Function: jit_int jit_int_to_short_ovf (jit_int *RESULT, jit_int
          VALUE)
 -- Function: jit_int jit_int_to_ushort_ovf (jit_int *RESULT, jit_int
          VALUE)
 -- Function: jit_int jit_int_to_int_ovf (jit_int *RESULT, jit_int
          VALUE)
 -- Function: jit_int jit_int_to_uint_ovf (jit_uint *RESULT, jit_int
          VALUE)
 -- Function: jit_int jit_int_to_long_ovf (jit_long *RESULT, jit_int
          VALUE)
 -- Function: jit_int jit_int_to_ulong_ovf (jit_ulong *RESULT, jit_int
          VALUE)
 -- Function: jit_int jit_uint_to_int_ovf (jit_int *RESULT, jit_uint
          VALUE)
 -- Function: jit_int jit_uint_to_uint_ovf (jit_uint *RESULT, jit_uint
          VALUE)
 -- Function: jit_int jit_uint_to_long_ovf (jit_long *RESULT, jit_uint
          VALUE)
 -- Function: jit_int jit_uint_to_ulong_ovf (jit_ulong *RESULT,
          jit_uint VALUE)
 -- Function: jit_int jit_long_to_int_ovf (jit_int *RESULT, jit_long
          VALUE)
 -- Function: jit_int jit_long_to_uint_ovf (jit_uint *RESULT, jit_long
          VALUE)
 -- Function: jit_int jit_long_to_long_ovf (jit_long *RESULT, jit_long
          VALUE)
 -- Function: jit_int jit_long_to_ulong_ovf (jit_ulong *RESULT,
          jit_long VALUE)
 -- Function: jit_int jit_ulong_to_int_ovf (jit_int *RESULT, jit_ulong
          VALUE)
 -- Function: jit_int jit_ulong_to_uint_ovf (jit_uint *RESULT,
          jit_ulong VALUE)
 -- Function: jit_int jit_ulong_to_long_ovf (jit_long *RESULT,
          jit_ulong VALUE)
 -- Function: jit_int jit_ulong_to_ulong_ovf (jit_ulong *RESULT,
          jit_ulong VALUE)
     Convert between integer types with overflow detection.

 -- Function: jit_int jit_nfloat_to_int (jit_nfloat VALUE)
 -- Function: jit_uint jit_nfloat_to_uint (jit_nfloat VALUE)
 -- Function: jit_long jit_nfloat_to_long (jit_nfloat VALUE)
 -- Function: jit_ulong jit_nfloat_to_ulong (jit_nfloat VALUE)
     Convert a native floating-point value into an integer.

 -- Function: jit_int jit_nfloat_to_int_ovf (jit_int *RESULT,
          jit_nfloat VALUE)
 -- Function: jit_uint jit_nfloat_to_uint_ovf (jit_uint *RESULT,
          jit_nfloat VALUE)
 -- Function: jit_long jit_nfloat_to_long_ovf (jit_long *RESULT,
          jit_nfloat VALUE)
 -- Function: jit_ulong jit_nfloat_to_ulong_ovf (jit_ulong *RESULT,
          jit_nfloat VALUE)
     Convert a native floating-point value into an integer, with
     overflow detection.  Returns `JIT_RESULT_OK' if the conversion was
     successful or `JIT_RESULT_OVERFLOW' if an overflow occurred.

 -- Function: jit_nfloat jit_int_to_nfloat (jit_int VALUE)
 -- Function: jit_nfloat jit_uint_to_nfloat (jit_uint VALUE)
 -- Function: jit_nfloat jit_long_to_nfloat (jit_long VALUE)
 -- Function: jit_nfloat jit_ulong_to_nfloat (jit_ulong VALUE)
     Convert an integer into native floating-point value.

 -- Function: jit_nfloat jit_float32_to_nfloat (jit_float32 VALUE)
 -- Function: jit_nfloat jit_float64_to_nfloat (jit_float64 VALUE)
 -- Function: jit_float32 jit_nfloat_to_float32 (jit_nfloat VALUE)
 -- Function: jit_float64 jit_nfloat_to_float64 (jit_nfloat VALUE)
     Convert between floating-point types.


File: libjit.info,  Node: Exceptions,  Next: Breakpoint Debugging,  Prev: Intrinsics,  Up: Top

11 Handling exceptions
**********************

 -- Function: void * jit_exception_get_last (void)
     Get the last exception object that occurred on this thread, or NULL
     if there is no exception object on this thread.  As far as `libjit'
     is concerned, an exception is just a pointer.  The precise meaning
     of the data at the pointer is determined by the front end.

 -- Function: void * jit_exception_get_last_and_clear (void)
     Get the last exception object that occurred on this thread and also
     clear the exception state to NULL.  This combines the effect of
     both `jit_exception_get_last' and `jit_exception_clear_last'.

 -- Function: void jit_exception_set_last (void *OBJECT)
     Set the last exception object that occurred on this thread, so that
     it can be retrieved by a later call to `jit_exception_get_last'.
     This is normally used by `jit_function_apply' to save the
     exception object before returning to regular code.

 -- Function: void jit_exception_clear_last (void)
     Clear the last exception object that occurred on this thread.
     This is equivalent to calling `jit_exception_set_last' with a
     parameter of NULL.

 -- Function: void jit_exception_throw (void *OBJECT)
     Throw an exception object within the current thread.  As far as
     `libjit' is concerned, the exception object is just a pointer.
     The precise meaning of the data at the pointer is determined by
     the front end.

     Note: as an exception object works its way back up the stack, it
     may be temporarily stored in memory that is not normally visible
     to a garbage collector.  The front-end is responsible for taking
     steps to "pin" the object so that it is uncollectable until
     explicitly copied back into a location that is visible to the
     collector once more.

 -- Function: void jit_exception_builtin (int EXCEPTION_TYPE)
     This function is called to report a builtin exception.  The JIT
     will automatically embed calls to this function wherever a builtin
     exception needs to be reported.

     When a builtin exception occurs, the current thread's exception
     handler is called to construct an appropriate object, which is
     then thrown.

     If there is no exception handler set, or the handler returns NULL,
     then `libjit' will print an error message to stderr and cause the
     program to exit with a status of 1.  You normally don't want this
     behavior and you should override it if possible.

     The following builtin exception types are currently supported:

    `JIT_RESULT_OK'
          The operation was performed successfully (value is 1).

    `JIT_RESULT_OVERFLOW'
          The operation resulted in an overflow exception (value is 0).

    `JIT_RESULT_ARITHMETIC'
          The operation resulted in an arithmetic exception.  i.e. an
          attempt was made to divide the minimum integer value by -1
          (value is -1).

    `JIT_RESULT_DIVISION_BY_ZERO'
          The operation resulted in a division by zero exception (value
          is -2).

    `JIT_RESULT_COMPILE_ERROR'
          An error occurred when attempting to dynamically compile a
          function (value is -3).

    `JIT_RESULT_OUT_OF_MEMORY'
          The system ran out of memory while performing an operation
          (value is -4).

    `JIT_RESULT_NULL_REFERENCE'
          An attempt was made to dereference a NULL pointer (value is
          -5).

    `JIT_RESULT_NULL_FUNCTION'
          An attempt was made to call a function with a NULL function
          pointer (value is -6).

    `JIT_RESULT_CALLED_NESTED'
          An attempt was made to call a nested function from a
          non-nested context (value is -7).

 -- Function: jit_exception_func jit_exception_set_handler
          (jit_exception_func HANDLER)
     Set the builtin exception handler for the current thread.  Returns
     the previous exception handler.

 -- Function: jit_exception_func jit_exception_get_handler (void)
     Get the builtin exception handler for the current thread.

 -- Function: jit_stack_trace_t jit_exception_get_stack_trace (void)
     Create an object that represents the current call stack.  This is
     normally used to indicate the location of an exception.  Returns
     NULL if a stack trace is not available, or there is insufficient
     memory to create it.

 -- Function: unsigned int jit_stack_trace_get_size (jit_stack_trace_t
          TRACE)
     Get the size of a stack trace.

 -- Function: jit_function_t jit_stack_trace_get_function
          (jit_context_t CONTEXT, jit_stack_trace_t TRACE, unsigned int
          POSN)
     Get the function that is at position POSN within a stack trace.
     Position 0 is the function that created the stack trace.  If this
     returns NULL, then it indicates that there is a native callout at
     POSN within the stack trace.

 -- Function: void * jit_stack_trace_get_pc (jit_stack_trace_t TRACE,
          unsigned int POSN)
     Get the program counter that corresponds to position POSN within a
     stack trace.  This is the point within the function where
     execution had reached at the time of the trace.

 -- Function: unsigned int jit_stack_trace_get_offset
          (jit_stack_trace_t TRACE, unsigned int POSN)
     Get the bytecode offset that is recorded for position POSN within
     a stack trace.  This will be `JIT_NO_OFFSET' if there is no
     bytecode offset associated with POSN.

 -- Function: void jit_stack_trace_free (jit_stack_trace_t TRACE)
     Free the memory associated with a stack trace.


File: libjit.info,  Node: Breakpoint Debugging,  Next: ELF Binaries,  Prev: Exceptions,  Up: Top

12 Hooking a breakpoint debugger into libjit
********************************************

The `libjit' library provides support routines for breakpoint-based
single-step debugging.  It isn't a full debugger, but provides the
infrastructure necessary to support one.

   The front end virtual machine is responsible for inserting "potential
breakpoints" into the code when functions are built and compiled.  This
is performed using `jit_insn_mark_breakpoint':

 -- Function: int jit_insn_mark_breakpoint (jit_function_t FUNC,
          jit_nint DATA1, jit_nint DATA2)
     Mark the current position in FUNC as corresponding to a breakpoint
     location.  When a break occurs, the debugging routines are passed
     FUNC, DATA1, and DATA2 as arguments.  By convention, DATA1 is the
     type of breakpoint (source line, function entry, function exit,
     etc).

   There are two ways for a front end to receive notification about
breakpoints.  The bulk of this chapter describes the `jit_debugger_t'
interface, which handles most of the ugly details.  In addition, a
low-level "debug hook mechanism" is provided for front ends that wish
more control over the process.  The debug hook mechanism is described
below, under the `jit_debugger_set_hook' function.

   This debugger implementation requires a threading system to work
successfully.  At least two threads are required, in addition to those
of the program being debugged:

  1. Event thread which calls `jit_debugger_wait_event' to receive
     notifications of breakpoints and other interesting events.

  2. User interface thread which calls functions like
     `jit_debugger_run', `jit_debugger_step', etc, to control the debug
     process.

   These two threads should be set to "unbreakable" with a call to
`jit_debugger_set_breakable'.  This prevents them from accidentally
stopping at a breakpoint, which would cause a system deadlock.  Other
housekeeping threads, such as a finalization thread, should also be set
to "unbreakable" for the same reason.

Events have the following members:

`type'
     The type of event (see the next table for details).

`thread'
     The thread that the event occurred on.

`function'
     The function that the breakpoint occurred within.

`data1'
`data2'
     The data values at the breakpoint.  These values are inserted into
     the function's code with `jit_insn_mark_breakpoint'.

`id'
     The identifier for the breakpoint.

`trace'
     The stack trace corresponding to the location where the breakpoint
     occurred.  This value is automatically freed upon the next call to
     `jit_debugger_wait_event'.  If you wish to preserve the value,
     then you must call `jit_stack_trace_copy'.

The following event types are currently supported:

`JIT_DEBUGGER_TYPE_QUIT'
     A thread called `jit_debugger_quit', indicating that it wanted the
     event thread to terminate.

`JIT_DEBUGGER_TYPE_HARD_BREAKPOINT'
     A thread stopped at a hard breakpoint.  That is, a breakpoint
     defined by a call to `jit_debugger_add_breakpoint'.

`JIT_DEBUGGER_TYPE_SOFT_BREAKPOINT'
     A thread stopped at a breakpoint that wasn't explicitly defined by
     a call to `jit_debugger_add_breakpoint'.  This typicaly results
     from a call to a "step" function like `jit_debugger_step', where
     execution stopped at the next line but there isn't an explicit
     breakpoint on that line.

`JIT_DEBUGGER_TYPE_USER_BREAKPOINT'
     A thread stopped because of a call to `jit_debugger_break'.

`JIT_DEBUGGER_TYPE_ATTACH_THREAD'
     A thread called `jit_debugger_attach_self'.  The `data1' field of
     the event is set to the value of `stop_immediately' for the call.

`JIT_DEBUGGER_TYPE_DETACH_THREAD'
     A thread called `jit_debugger_detach_self'.

 -- Function: int jit_insn_mark_breakpoint_variable (jit_function_t
          FUNC, jit_value_t DATA1, jit_value_t DATA2)
     This function is similar to `jit_insn_mark_breakpoint' except that
     values in DATA1 and DATA2 can be computed at runtime. You can use
     this function for example to get address of local variable.

 -- Function: int jit_debugging_possible (void)
     Determine if debugging is possible.  i.e. that threading is
     available and compatible with the debugger's requirements.

 -- Function: jit_debugger_t jit_debugger_create (jit_context_t CONTEXT)
     Create a new debugger instance and attach it to a JIT CONTEXT.  If
     the context already has a debugger associated with it, then this
     function will return the previous debugger.

 -- Function: void jit_debugger_destroy (jit_debugger_t DBG)
     Destroy a debugger instance.

 -- Function: jit_context_t jit_debugger_get_context (jit_debugger_t
          DBG)
     Get the JIT context that is associated with a debugger instance.

 -- Function: jit_debugger_t jit_debugger_from_context (jit_context_t
          CONTEXT)
     Get the debugger that is currently associated with a JIT CONTEXT,
     or NULL if there is no debugger associated with the context.

 -- Function: jit_debugger_thread_id_t jit_debugger_get_self
          (jit_debugger_t DBG)
     Get the thread identifier associated with the current thread.  The
     return values are normally values like 1, 2, 3, etc, allowing the
     user interface to report messages like "thread 3 has stopped at a
     breakpoint".

 -- Function: jit_debugger_thread_id_t jit_debugger_get_thread
          (jit_debugger_t DBG, const void *NATIVE_THREAD)
     Get the thread identifier for a specific native thread.  The
     NATIVE_THREAD pointer is assumed to point at a block of memory
     containing a native thread handle.  This would be a `pthread_t' on
     Pthreads platforms or a `HANDLE' on Win32 platforms.  If the
     native thread has not been seen previously, then a new thread
     identifier is allocated.

 -- Function: int jit_debugger_get_native_thread (jit_debugger_t DBG,
          jit_debugger_thread_id_t THREAD, void *NATIVE_THREAD)
     Get the native thread handle associated with a debugger thread
     identifier.  Returns non-zero if OK, or zero if the debugger
     thread identifier is not yet associated with a native thread
     handle.

 -- Function: void jit_debugger_set_breakable (jit_debugger_t DBG,
          const void *NATIVE_THREAD, int FLAG)
     Set a flag that indicates if a native thread can stop at
     breakpoints.  If set to 1 (the default), breakpoints will be
     active on the thread.  If set to 0, breakpoints will be ignored on
     the thread.  Typically this is used to mark threads associated
     with the debugger's user interface, or the virtual machine's
     finalization thread, so that they aren't accidentally suspended by
     the debugger (which might cause a deadlock).

 -- Function: void jit_debugger_attach_self (jit_debugger_t DBG, int
          STOP_IMMEDIATELY)
     Attach the current thread to a debugger.  If STOP_IMMEDIATELY is
     non-zero, then the current thread immediately suspends, waiting for
     the user to start it with `jit_debugger_run'.  This function is
     typically called in a thread's startup code just before any "real
     work" is performed.

 -- Function: void jit_debugger_detach_self (jit_debugger_t DBG)
     Detach the current thread from the debugger.  This is typically
     called just before the thread exits.

 -- Function: int jit_debugger_wait_event (jit_debugger_t DBG,
          jit_debugger_event_t *EVENT, jit_nint TIMEOUT)
     Wait for the next debugger event to arrive.  Debugger events
     typically indicate breakpoints that have occurred.  The TIMEOUT is
     in milliseconds, or -1 for an infinite timeout period.  Returns
     non-zero if an event has arrived, or zero on timeout.

 -- Function: jit_debugger_breakpoint_id_t jit_debugger_add_breakpoint
          (jit_debugger_t DBG, jit_debugger_breakpoint_info_t INFO)
     Add a hard breakpoint to a debugger instance.  The INFO structure
     defines the conditions under which the breakpoint should fire.
     The fields of INFO are as follows:

    `flags'
          Flags that indicate which of the following fields should be
          matched.  If a flag is not present, then all possible values
          of the field will match.  Valid flags are
          `JIT_DEBUGGER_FLAG_THREAD', `JIT_DEBUGGER_FLAG_FUNCTION',
          `JIT_DEBUGGER_FLAG_DATA1', and `JIT_DEBUGGER_FLAG_DATA2'.

    `thread'
          The thread to match against, if `JIT_DEBUGGER_FLAG_THREAD' is
          set.

    `function'
          The function to match against, if
          `JIT_DEBUGGER_FLAG_FUNCTION' is set.

    `data1'
          The `data1' value to match against, if
          `JIT_DEBUGGER_FLAG_DATA1' is set.

    `data2'
          The `data2' value to match against, if
          `JIT_DEBUGGER_FLAG_DATA2' is set.

     The following special values for `data1' are recommended for
     marking breakpoint locations with `jit_insn_mark_breakpoint':

    `JIT_DEBUGGER_DATA1_LINE'
          Breakpoint location that corresponds to a source line.  This
          is used to determine where to continue to upon a "step".

    `JIT_DEBUGGER_DATA1_ENTER'
          Breakpoint location that corresponds to the start of a
          function.

    `JIT_DEBUGGER_DATA1_LEAVE'
          Breakpoint location that corresponds to the end of a
          function, just prior to a `return' statement.  This is used
          to determine where to continue to upon a "finish".

    `JIT_DEBUGGER_DATA1_THROW'
          Breakpoint location that corresponds to an exception throw.

 -- Function: void jit_debugger_remove_breakpoint (jit_debugger_t DBG,
          jit_debugger_breakpoint_id_t ID)
     Remove a previously defined breakpoint from a debugger instance.

 -- Function: void jit_debugger_remove_all_breakpoints (jit_debugger_t
          DBG)
     Remove all breakpoints from a debugger instance.

 -- Function: int jit_debugger_is_alive (jit_debugger_t DBG,
          jit_debugger_thread_id_t THREAD)
     Determine if a particular thread is still alive.

 -- Function: int jit_debugger_is_running (jit_debugger_t DBG,
          jit_debugger_thread_id_t THREAD)
     Determine if a particular thread is currently running (non-zero) or
     stopped (zero).

 -- Function: void jit_debugger_run (jit_debugger_t DBG,
          jit_debugger_thread_id_t THREAD)
     Start the specified thread running, or continue from the last
     breakpoint.

     This function, and the others that follow, sends a request to the
     specified thread and then returns to the caller immediately.

 -- Function: void jit_debugger_step (jit_debugger_t DBG,
          jit_debugger_thread_id_t THREAD)
     Step over a single line of code.  If the line performs a method
     call, then this will step into the call.  The request will be
     ignored if the thread is currently running.

 -- Function: void jit_debugger_next (jit_debugger_t DBG,
          jit_debugger_thread_id_t THREAD)
     Step over a single line of code but do not step into method calls.
     The request will be ignored if the thread is currently running.

 -- Function: void jit_debugger_finish (jit_debugger_t DBG,
          jit_debugger_thread_id_t THREAD)
     Keep running until the end of the current function.  The request
     will be ignored if the thread is currently running.

 -- Function: void jit_debugger_break (jit_debugger_t DBG)
     Force an explicit user breakpoint at the current location within
     the current thread.  Control returns to the caller when the
     debugger calls one of the above "run" or "step" functions in
     another thread.

 -- Function: void jit_debugger_quit (jit_debugger_t DBG)
     Sends a request to the thread that called `jit_debugger_wait_event'
     indicating that the debugger should quit.

 -- Function: jit_debugger_hook_func jit_debugger_set_hook
          (jit_context_t CONTEXT, jit_debugger_hook_func HOOK)
     Set a debugger hook on a JIT context.  Returns the previous hook.

     Debug hooks are a very low-level breakpoint mechanism.  Upon
     reaching each breakpoint in a function, a user-supplied hook
     function is called.  It is up to the hook function to decide
     whether to stop execution or to ignore the breakpoint.  The hook
     function has the following prototype:

          void hook(jit_function_t func, jit_nint data1, jit_nint data2);

     The `func' argument indicates the function that the breakpoint
     occurred within.  The `data1' and `data2' arguments are those
     supplied to `jit_insn_mark_breakpoint'.  The debugger can use
     these values to indicate information about the breakpoint's type
     and location.

     Hook functions can be used for other purposes besides breakpoint
     debugging.  For example, a program could be instrumented with hooks
     that tally up the number of times that each function is called, or
     which profile the amount of time spent in each function.

     By convention, `data1' values less than 10000 are intended for use
     by user-defined hook functions.  Values of 10000 and greater are
     reserved for the full-blown debugger system described earlier.


File: libjit.info,  Node: ELF Binaries,  Next: Utility Routines,  Prev: Breakpoint Debugging,  Up: Top

13 Manipulating ELF binaries
****************************

The `libjit' library contains routines that permit pre-compiling JIT'ed
functions into an on-disk representation.  This representation can be
loaded at some future time, to avoid the overhead of compiling the
functions at runtime.

   We use the ELF format for this purpose, which is a common binary
format used by modern operating systems and compilers.

   It isn't necessary for your operating system to be based on ELF
natively.  We use our own routines to read and write ELF binaries.  We
chose ELF because it has all of the features that we require, and
reusing an existing format was better than inventing a completely new
one.

13.1 Reading ELF binaries
=========================

 -- Function: int jit_readelf_open (jit_readelf_t *READELF, const char
          *FILENAME, int FORCE)
     Open the specified FILENAME and load the ELF binary that is
     contained within it.  Returns one of the following result codes:

    `JIT_READELF_OK'
          The ELF binary was opened successfully.

    `JIT_READELF_CANNOT_OPEN'
          Could not open the file at the filesystem level (reason in
          `errno').

    `JIT_READELF_NOT_ELF'
          The file was opened, but it is not an ELF binary.

    `JIT_READELF_WRONG_ARCH'
          The file is an ELF binary, but it does not pertain to the
          architecture of this machine.

    `JIT_READELF_BAD_FORMAT'
          The file is an ELF binary, but the format is corrupted in
          some fashion.

    `JIT_READELF_MEMORY'
          There is insufficient memory to open the ELF binary.

     The following flags may be supplied to alter the manner in which
     the ELF binary is loaded:

    `JIT_READELF_FLAG_FORCE'
          Force `jit_readelf_open' to open the ELF binary, even if the
          architecture does not match this machine.  Useful for
          debugging.

    `JIT_READELF_FLAG_DEBUG'
          Print additional debug information to stdout.

 -- Function: void jit_readelf_close (jit_readelf_t READELF)
     Close an ELF reader, reclaiming all of the memory that was used.

 -- Function: const char * jit_readelf_get_name (jit_readelf_t READELF)
     Get the library name that is embedded inside an ELF binary.  ELF
     binaries can refer to each other using this name.

 -- Function: void *jit_readelf_get_symbol (jit_readelf_t READELF,
          const char *NAME)
     Look up the symbol called NAME in the ELF binary represented by
     READELF.  Returns NULL if the symbol is not present.

     External references from this ELF binary to others are not resolved
     until the ELF binary is loaded into a JIT context using
     `jit_readelf_add_to_context' and `jit_readelf_resolve_all'.  You
     should not call functions within this ELF binary until after you
     have fully resolved it.

 -- Function: void * jit_readelf_get_section (jit_readelf_t READELF,
          const char *NAME, jit_nuint *SIZE)
     Get the address and size of a particular section from an ELF
     binary.  Returns NULL if the section is not present in the ELF
     binary.

     The virtual machine may have stored auxillary information in the
     section when the binary was first generated.  This function allows
     the virtual machine to retrieve its auxillary information.

     Examples of such information may be version numbers, timestamps,
     checksums, and other identifying information for the bytecode that
     was previously compiled by the virtual machine.  The virtual
     machine can use this to determine if the ELF binary is up to date
     and relevant to its needs.

     It is recommended that virtual machines prefix their special
     sections with a unique string (e.g. `.foovm') to prevent clashes
     with system-defined section names.  The prefix `.libjit' is
     reserved for use by `libjit' itself.

 -- Function: void * jit_readelf_get_section_by_type (jit_readelf_t
          READELF, jit_int TYPE, jit_nuint *SIZE)
     Get a particular section using its raw ELF section type (i.e. one
     of the `SHT_*' constants in `jit-elf-defs.h').  This is mostly for
     internal use, but some virtual machines may find it useful for
     debugging purposes.

 -- Function: void * jit_readelf_map_vaddr (jit_readelf_t READELF,
          jit_nuint VADDR)
     Map a virtual address to an actual address in a loaded ELF binary.
     Returns NULL if VADDR could not be mapped.

 -- Function: unsigned int jit_readelf_num_needed (jit_readelf_t
          READELF)
     Get the number of dependent libraries that are needed by this ELF
     binary.  The virtual machine will normally need to arrange to load
     these libraries with `jit_readelf_open' as well, so that all of
     the necessary symbols can be resolved.

 -- Function: const char * jit_readelf_get_needed (jit_readelf_t
          READELF, unsigned int INDEX)
     Get the name of the dependent library at position INDEX within the
     needed libraries list of this ELF binary.  Returns NULL if the
     INDEX is invalid.

 -- Function: void jit_readelf_add_to_context (jit_readelf_t READELF,
          jit_context_t CONTEXT)
     Add this ELF binary to a JIT context, so that its contents can be
     used when executing JIT-managed code.  The binary will be closed
     automatically if the context is destroyed and `jit_readelf_close'
     has not been called explicitly yet.

     The functions in the ELF binary cannot be used until you also call
     `jit_readelf_resolve_all' to resolve cross-library symbol
     references.  The reason why adding and resolution are separate
     steps is to allow for resolving circular dependencies between ELF
     binaries.

 -- Function: int jit_readelf_resolve_all (jit_context_t CONTEXT, int
          PRINT_FAILURES)
     Resolve all of the cross-library symbol references in ELF binaries
     that have been added to CONTEXT but which were not resolved in the
     previous call to this function.  If PRINT_FAILURES is non-zero,
     then diagnostic messages will be written to stdout for any symbol
     resolutions that fail.

     Returns zero on failure, or non-zero if all symbols were
     successfully resolved.  If there are no ELF binaries awaiting
     resolution, then this function will return a non-zero result.

 -- Function: int jit_readelf_register_symbol (jit_context_t CONTEXT,
          const char *NAME, void *VALUE, int AFTER)
     Register VALUE with NAME on the specified CONTEXT.  Whenever
     symbols are resolved with `jit_readelf_resolve_all', and the
     symbol NAME is encountered, VALUE will be substituted.  Returns
     zero if out of memory or there is something wrong with the
     parameters.

     If AFTER is non-zero, then NAME will be resolved after all other
     ELF libraries; otherwise it will be resolved before the ELF
     libraries.

     This function is used to register intrinsic symbols that are
     specific to the front end virtual machine.  References to
     intrinsics within `libjit' itself are resolved automatically.


File: libjit.info,  Node: Utility Routines,  Next: Diagnostic Routines,  Prev: ELF Binaries,  Up: Top

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.

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.

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.

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.

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.

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.

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.

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.


File: libjit.info,  Node: Diagnostic Routines,  Next: C++ Interface,  Prev: Utility Routines,  Up: Top

15 Diagnostic routines
**********************

 -- Function: void jit_dump_type (FILE *STREAM, jit_type_t TYPE)
     Dump the name of a type to a stdio stream.

 -- Function: void jit_dump_value (FILE *STREAM, jit_function_t FUNC,
          jit_value_t VALUE, const char *PREFIX)
     Dump the name of a value to a stdio stream.  If PREFIX is not
     NULL, then it indicates a type prefix to add to the value name.
     If PREFIX is NULL, then this function intuits the type prefix.

 -- Function: void jit_dump_insn (FILE *STREAM, jit_function_t FUNC,
          jit_value_t VALUE)
     Dump the contents of an instruction to a stdio stream.

 -- Function: void jit_dump_function (FILE *STREAM, jit_function_t
          FUNC, const char *NAME)
     Dump the three-address instructions within a function to a stream.
     The NAME is attached to the output as a friendly label, but has no
     other significance.

     If the function has not been compiled yet, then this will dump the
     three address instructions from the build process.  Otherwise it
     will disassemble and dump the compiled native code.


File: libjit.info,  Node: C++ Interface,  Next: C++ Contexts,  Prev: Diagnostic Routines,  Up: Top

16 Using libjit from C++
************************

This chapter describes the classes and methods that are available in
the `libjitplus' library.  To use this library, you must include the
header `<jit/jit-plus.h>' and link with the `-ljitplus' and `-ljit'
options.

* Menu:

* C++ Contexts::            Contexts in C++
* C++ Values::              Values in C++
* C++ Functions::           Functions in C++


File: libjit.info,  Node: C++ Contexts,  Next: C++ Values,  Prev: C++ Interface,  Up: C++ Interface

17 Contexts in C++
******************

The `jit_context' class provides a C++ counterpart to the C
`jit_context_t' type.  *Note Initialization::, for more information on
creating and managing contexts.

 -- Constructor on jit_context: jit_context ()
     Construct a new JIT context.  This is equivalent to calling
     `jit_context_create' in the C API.  The raw C context is destroyed
     when the `jit_context' object is destructed.

 -- Constructor on jit_context: jit_context (jit_context_t CONTEXT)
     Construct a new JIT context by wrapping up an existing raw C
     context.  This is useful for importing a context from third party
     C code into a program that prefers to use C++.

     When you use this form of construction, `jit_context_destroy' will
     not be called on the context when the `jit_context' object is
     destructed.  You will need to arrange for that manually.

 -- Destructor on jit_context: ~jit_context ()
     Destruct a JIT context.

 -- Method on jit_context: void build_start ()
     Start an explicit build process.  Not needed if you will be using
     on-demand compilation.

 -- Method on jit_context: void build_end ()
     End an explicit build process.

 -- Method on jit_context: jit_context_t raw () const
     Get the raw C context pointer that underlies this object.


File: libjit.info,  Node: C++ Values,  Next: C++ Functions,  Prev: C++ Contexts,  Up: C++ Interface

18 Values in C++
****************

The `jit_value' class provides a C++ counterpart to the `jit_value_t'
type.  Values normally result by calling methods on the `jit_function'
class during the function building process.  *Note Values::, for more
information on creating and managing values.

 -- Constructor on jit_value: jit_value ()
     Construct an empty value.

 -- Constructor on jit_value: jit_value (jit_value_t VALUE)
     Construct a value by wrapping up a raw C `jit_value_t' object.

 -- Constructor on jit_value: jit_value (const jit_value& VALUE)
     Create a copy of VALUE.

 -- Destructor on jit_value: ~jit_value ()
     Destroy the C++ value wrapper, but leave the underlying raw C
     value alone.

 -- Operator on jit_value: jit_value& operator= (const jit_value& VALUE)
     Copy `jit_value' objects.

 -- Method on jit_value: jit_value_t raw () const
     Get the raw C `jit_value_t' value that underlies this object.

 -- Method on jit_value: int is_valid () const
     Determine if this `jit_value' object contains a valid raw C
     `jit_value_t' value.

 -- Method on jit_value: int is_temporary () const
 -- Method on jit_value: int is_local () const
 -- Method on jit_value: int is_constant () const
     Determine if this `jit_value' is temporary, local, or constant.

 -- Method on jit_value: void set_volatile ()
 -- Method on jit_value: int is_volatile () const
     Set or check the "volatile" state on this value.

 -- Method on jit_value: void set_addressable ()
 -- Method on jit_value: int is_addressable () const
     Set or check the "addressable" state on this value.

 -- Method on jit_value: jit_type_t type () const
     Get the type of this value.

 -- Method on jit_value: jit_function_t function () const
 -- Method on jit_value: jit_block_t block () const
 -- Method on jit_value: jit_context_t context () const
     Get the owning function, block, or context for this value.

 -- Method on jit_value: jit_constant_t constant () const
 -- Method on jit_value: jit_nint nint_constant () const
 -- Method on jit_value: jit_long long_constant () const
 -- Method on jit_value: jit_float32 float32_constant () const
 -- Method on jit_value: jit_float64 float64_constant () const
 -- Method on jit_value: jit_nfloat nfloat_constant () const
     Extract the constant stored in this value.

 -- Operator on jit_value: jit_value operator+ (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator- (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator* (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator/ (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator% (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator- (const jit_value& VALUE1)
 -- Operator on jit_value: jit_value operator& (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator| (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator^ (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator~ (const jit_value& VALUE1)
 -- Operator on jit_value: jit_value operator<< (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator>> (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator== (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator!= (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator< (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator<= (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator> (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Operator on jit_value: jit_value operator>= (const jit_value&
          VALUE1, const jit_value& VALUE2)
     Generate an arithmetic, bitwise, or comparison instruction based on
     one or two `jit_value' objects.  These operators are shortcuts for
     calling `insn_add', `insn_sub', etc on the `jit_function' object.


File: libjit.info,  Node: C++ Functions,  Next: Porting,  Prev: C++ Values,  Up: C++ Interface

19 Functions in C++
*******************

The `jit_function' class provides a C++ counterpart to the C
`jit_function_t' type.  *Note Functions::, for more information on
creating and managing functions.

   The `jit_function' class also provides a large number of methods for
creating the instructions within a function body.  *Note Instructions::,
for more information on creating and managing instructions.

 -- Constructor on jit_function: jit_function (jit_context& CONTEXT,
          jit_type_t SIGNATURE)
     Constructs a new function handler with the specified SIGNATURE in
     the given CONTEXT.  It then calls `create(SIGNATURE)' to create
     the actual function.

 -- Constructor on jit_function: jit_function (jit_context& CONTEXT)
     Constructs a new function handler in the specified CONTEXT.  The
     actual function is not created until you call `create()'.

 -- Constructor on jit_function: jit_function (jit_function_t FUNC)
     Constructs a new function handler and wraps it around the specified
     raw C `jit_function_t' object.  This can be useful for layering
     the C++ on-demand building facility on top of an existing C
     function.

 -- Destructor on jit_function: ~jit_function ()
     Destroy this function handler.  The raw function will persist
     until the context is destroyed.

 -- Method on jit_function: jit_function_t raw () const
     Get the raw C `jit_function_t' value that underlies this object.

 -- Method on jit_function: int is_valid () const
     Determine if the raw C `jit_function_t' value that underlies this
     object is valid.

 -- Method on jit_function: static jit_function * from_raw
          (jit_function_t FUNC)
     Find the C++ `jit_function' object that is associated with a raw C
     `jit_function_t' pointer.  Returns NULL if there is no such object.

 -- Method on jit_function: jit_type_t signature () const
     Get the signature type for this function.

 -- Method on jit_function: void create (jit_type_t SIGNATURE)
     Create this function if it doesn't already exist.

 -- Method on jit_function: void create ()
     Create this function if it doesn't already exist.  This version
     will call the virtual `create_signature()' method to obtain the
     signature from the subclass.

 -- Method on jit_function: int compile ()
     Compile this function explicity.  You normally don't need to use
     this method because the function will be compiled on-demand.  If
     you do choose to build the function manually, then the correct
     sequence of operations is as follows:

       1. Invoke the `build_start' method to lock down the function
          builder.

       2. Build the function by calling the value-related and
          instruction-related methods within `jit_function'.

       3. Compile the function with the `compile' method.

       4. Unlock the function builder by invoking `build_end'.

 -- Method on jit_function: int is_compiled () const
     Determine if this function has already been compiled.

 -- Method on jit_function: void set_optimization_level (unsigned int
          LEVEL)
 -- Method on jit_function: unsigned int optimization_level () const
     Set or get the optimization level for this function.

 -- Method on jit_function: static unsigned int max_optimization_level
          ()
     Get the maximum optimization level for `libjit'.

 -- Method on jit_function: void * closure () const
 -- Method on jit_function: void * vtable_pointer () const
     Get the closure or vtable pointer form of this function.

 -- Method on jit_function: int apply (void** ARGS, void* RESULT)
 -- Method on jit_function: int apply (jit_type_t SIGNATURE, void**
          ARGS, void* RETURN_AREA)
     Call this function, applying the specified arguments.

 -- Method on jit_function: static jit_type_t signature_helper
          (jit_type_t RETURN_TYPE, ...)
     You can call this method from `create_signature()' to help build
     the correct signature for your function.  The first parameter is
     the return type, following by zero or more types for the
     parameters.  The parameter list is terminated with the special
     value `jit_function::end_params'.

     A maximum of 32 parameter types can be supplied, and the signature
     ABI is always set to `jit_abi_cdecl'.

 -- Method on jit_function: void build ()
     This method is called when the function has to be build on-demand,
     or in response to an explicit `recompile' request.  You build the
     function by calling the value-related and instruction-related
     methods within `jit_function' that are described below.

     The default implementation of `build' will fail, so you must
     override it if you didn't build the function manually and call
     `compile'.

 -- Method on jit_function: jit_type_t create_signature ()
     This method is called by `create()' to create the function's
     signature.  The default implementation creates a signature that
     returns `void' and has no parameters.

 -- Method on jit_function: void fail ()
     This method can be called by `build' to fail the on-demand
     compilation process.  It throws an exception to unwind the build.

 -- Method on jit_function: void out_of_memory ()
     This method can be called by `build' to indicate that the on-demand
     compilation process ran out of memory.  It throws an exception to
     unwind the build.

 -- Method on jit_function: void build_start ()
     Start an explicit build process.  Not needed if you will be using
     on-demand compilation.

 -- Method on jit_function: void build_end ()
     End an explicit build process.

 -- Method on jit_function: jit_value new_value (jit_type_t TYPE)
     Create a new temporary value.  This is the C++ counterpart to
     `jit_value_create'.

 -- Method on jit_function: jit_value new_constant (jit_sbyte VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (jit_ubyte VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (jit_short VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (jit_ushort VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (jit_int VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (jit_uint VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (jit_long VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (jit_ulong VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (jit_float32 VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (jit_float64 VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (jit_nfloat VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (void* VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: jit_value new_constant (const
          jit_constant_t& VALUE)
     Create constant values of various kinds.  *Note Values::, for more
     information on creating and managing constants.

 -- Method on jit_function: jit_value get_param (unsigned int PARAM)
     Get the value that corresponds to parameter PARAM.

 -- Method on jit_function: jit_value get_struct_pointer ()
     Get the value that corresponds to the structure pointer parameter,
     if this function has one.  Returns an empty value if it does not.

 -- Method on jit_function: jit_label new_label ()
     Create a new label.  This is the C++ counterpart to
     `jit_function_reserve_label'.

 -- Method on jit_function: void insn_label (jit_label& LABEL)
 -- Method on jit_function: void insn_new_block ()
 -- Method on jit_function: jit_value insn_load (const jit_value& VALUE)
 -- Method on jit_function: jit_value insn_dup (const jit_value& VALUE)
 -- Method on jit_function: jit_value insn_load_small (const jit_value&
          VALUE)
 -- Method on jit_function: void store (const jit_value& DEST, const
          jit_value& VALUE)
 -- Method on jit_function: jit_value insn_load_relative (const
          jit_value& VALUE, jit_nint OFFSET, jit_type_t TYPE)
 -- Method on jit_function: void insn_store_relative (const jit_value&
          DEST, jit_nint OFFSET, const jit_value& VALUE)
 -- Method on jit_function: jit_value insn_add_relative (const
          jit_value& VALUE, jit_nint OFFSET)
 -- Method on jit_function: jit_value insn_load_elem (const jit_value&
          BASE_ADDR, const jit_value& INDEX, jit_type_t ELEM_TYPE)
 -- Method on jit_function: jit_value insn_load_elem_address (const
          jit_value& BASE_ADDR, const jit_value& INDEX, jit_type_t
          ELEM_TYPE)
 -- Method on jit_function: void insn_store_elem (const jit_value&
          BASE_ADDR, const jit_value& INDEX, const jit_value& VALUE)
 -- Method on jit_function: void insn_check_null (const jit_value&
          VALUE)
 -- Method on jit_function: jit_value insn_add (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_add_ovf (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_sub (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_sub_ovf (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_mul (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_mul_ovf (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_div (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_rem (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_rem_ieee (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_neg (const jit_value& VALUE1)
 -- Method on jit_function: jit_value insn_and (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_or (const jit_value& VALUE1,
          const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_xor (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_not (const jit_value& VALUE1)
 -- Method on jit_function: jit_value insn_shl (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_shr (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_ushr (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_sshr (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_eq (const jit_value& VALUE1,
          const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_ne (const jit_value& VALUE1,
          const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_lt (const jit_value& VALUE1,
          const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_le (const jit_value& VALUE1,
          const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_gt (const jit_value& VALUE1,
          const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_ge (const jit_value& VALUE1,
          const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_cmpl (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_cmpg (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_to_bool (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_to_not_bool (const
          jit_value& VALUE1)
 -- Method on jit_function: jit_value insn_acos (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_asin (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_atan (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_atan2 (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_ceil (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_cos (const jit_value& VALUE1)
 -- Method on jit_function: jit_value insn_cosh (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_exp (const jit_value& VALUE1)
 -- Method on jit_function: jit_value insn_floor (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_log (const jit_value& VALUE1)
 -- Method on jit_function: jit_value insn_log10 (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_pow (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_rint (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_round (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_sin (const jit_value& VALUE1)
 -- Method on jit_function: jit_value insn_sinh (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_sqrt (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_tan (const jit_value& VALUE1)
 -- Method on jit_function: jit_value insn_tanh (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_is_nan (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_is_finite (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_is_inf (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_abs (const jit_value& VALUE1)
 -- Method on jit_function: jit_value insn_min (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_max (const jit_value&
          VALUE1, const jit_value& VALUE2)
 -- Method on jit_function: jit_value insn_sign (const jit_value&
          VALUE1)
 -- Method on jit_function: void insn_branch (jit_label& LABEL)
 -- Method on jit_function: void insn_branch_if (const jit_value&
          VALUE, jit_label& LABEL)
 -- Method on jit_function: void insn_branch_if_not (const jit_value&
          value, jit_label& LABEL)
 -- Method on jit_function: jit_value insn_address_of (const jit_value&
          VALUE1)
 -- Method on jit_function: jit_value insn_address_of_label (jit_label&
          LABEL)
 -- Method on jit_function: jit_value insn_convert (const jit_value&
          VALUE, jit_type_t TYPE, int OVERFLOW_CHECK)
 -- Method on jit_function: jit_value insn_call (const char* NAME,
          jit_function_t JIT_FUNC, jit_type_t SIGNATURE, jit_value_t*
          ARGS, unsigned int NUM_ARGS, int FLAGS)
 -- Method on jit_function: jit_value insn_call_indirect (const
          jit_value& VALUE, jit_type_t SIGNATURE, jit_value_t* ARGS,
          unsigned int NUM_ARGS, int FLAGS)
 -- Method on jit_function: jit_value insn_call_indirect_vtable (const
          jit_value& VALUE, jit_type_t SIGNATURE, jit_value_t * ARGS,
          unsigned int NUM_ARGS, int FLAGS)
 -- Method on jit_function: jit_value insn_call_native (const char*
          NAME, void* NATIVE_FUNC, jit_type_t SIGNATURE, jit_value_t*
          ARGS, unsigned int NUM_ARGS, int FLAGS)
 -- Method on jit_function: jit_value insn_call_intrinsic (const char*
          NAME, void* INTRINSIC_FUNC, const jit_intrinsic_descr_t&
          DESCRIPTOR, const jit_value& ARG1, const jit_value& ARG2)
 -- Method on jit_function: void insn_incoming_reg (const jit_value&
          VALUE, int REG)
 -- Method on jit_function: void insn_incoming_frame_posn (const
          jit_value& VALUE, jit_nint POSN)
 -- Method on jit_function: void insn_outgoing_reg (const jit_value&
          VALUE, int REG)
 -- Method on jit_function: void insn_outgoing_frame_posn (const
          jit_value& VALUE, jit_nint POSN)
 -- Method on jit_function: void insn_return_reg (const jit_value&
          VALUE, int REG)
 -- Method on jit_function: void insn_setup_for_nested (int
          NESTED_LEVEL, int REG)
 -- Method on jit_function: void insn_flush_struct (const jit_value&
          VALUE)
 -- Method on jit_function: jit_value insn_import (jit_value VALUE)
 -- Method on jit_function: void insn_push (const jit_value& VALUE)
 -- Method on jit_function: void insn_push_ptr (const jit_value& VALUE,
          jit_type_t TYPE)
 -- Method on jit_function: void insn_set_param (const jit_value&
          VALUE, jit_nint OFFSET)
 -- Method on jit_function: void insn_set_param_ptr (const jit_value&
          VALUE, jit_type_t TYPE, jit_nint OFFSET)
 -- Method on jit_function: void insn_push_return_area_ptr ()
 -- Method on jit_function: void insn_return (const jit_value& VALUE)
 -- Method on jit_function: void insn_return ()
 -- Method on jit_function: void insn_return_ptr (const jit_value&
          VALUE, jit_type_t TYPE)
 -- Method on jit_function: void insn_default_return ()
 -- Method on jit_function: void insn_throw (const jit_value& VALUE)
 -- Method on jit_function: jit_value insn_get_call_stack ()
 -- Method on jit_function: jit_value insn_thrown_exception ()
 -- Method on jit_function: void insn_uses_catcher ()
 -- Method on jit_function: jit_value insn_start_catcher ()
 -- Method on jit_function: void insn_branch_if_pc_not_in_range (const
          jit_label& START_LABEL, const jit_label& END_LABEL,
          jit_label& LABEL)
 -- Method on jit_function: void insn_rethrow_unhandled ()
 -- Method on jit_function: void insn_start_finally (jit_label& LABEL)
 -- Method on jit_function: void insn_return_from_finally ()
 -- Method on jit_function: void insn_call_finally (jit_label& LABEL)
 -- Method on jit_function: jit_value insn_start_filter (jit_label&
          LABEL, jit_type_t TYPE)
 -- Method on jit_function: void insn_return_from_filter (const
          jit_value& VALUE)
 -- Method on jit_function: jit_value insn_call_filter (jit_label&
          LABEL, const jit_value& VALUE, jit_type_t TYPE)
 -- Method on jit_function: void insn_memcpy (const jit_value& DEST,
          const jit_value& SRC, const jit_value& SIZE)
 -- Method on jit_function: void insn_memmove (const jit_value& DEST,
          const jit_value& SRC, const jit_value& SIZE)
 -- Method on jit_function: void jit_insn_memset (const jit_value&
          DEST, const jit_value& VALUE, const jit_value& SIZE)
 -- Method on jit_function: jit_value jit_insn_alloca (const jit_value&
          SIZE)
 -- Method on jit_function: void insn_move_blocks_to_end (const
          jit_label& FROM_LABEL, const jit_label& TO_LABEL)
 -- Method on jit_function: void insn_move_blocks_to_start (const
          jit_label& FROM_LABEL, const jit_label& TO_LABEL)
 -- Method on jit_function: void insn_mark_offset (jit_int OFFSET)
 -- Method on jit_function: void insn_mark_breakpoint (jit_nint DATA1,
          jit_nint DATA2)
     Create instructions of various kinds.  *Note Instructions::, for
     more information on the individual instructions and their
     arguments.


File: libjit.info,  Node: Porting,  Next: Porting Apply,  Prev: C++ Functions,  Up: Top

20 Porting libjit to new architectures
**************************************

This chapter describes what needs to be done to port `libjit' to a new
CPU architecture.  It is assumed that the reader is familiar with
compiler implementation techniques and the particulars of their target
CPU's instruction set.

   We will use `ARCH' to represent the name of the architecture in the
sections that follow.  It is usually the name of the CPU in lower case
(e.g. `x86', `arm', `ppc', etc).  By convention, all back end functions
should be prefixed with `_jit', because they are not part of the public
API.

* Menu:

* Porting Apply::           Porting the function apply facility
* Instruction Generation::  Creating the instruction generation macros
* Architecture Rules::      Writing the architecture definition rules
* Register Allocation::     Allocating registers in the back end


File: libjit.info,  Node: Porting Apply,  Next: Instruction Generation,  Prev: Porting,  Up: Porting

20.1 Porting the function apply facility
========================================

The first step in porting `libjit' to a new architecture is to port the
`jit_apply' facility.  This provides support for calling arbitrary C
functions from your application or from JIT'ed code.  If you are
familiar with `libffi' or `ffcall', then `jit_apply' provides a similar
facility.

   Even if you don't intend to write a native code generator, you will
probably still need to port `jit_apply' to each new architecture.

   The `libjit' library makes use of gcc's `__builtin_apply' facility
to do most of the hard work of function application.  This gcc facility
takes three arguments: a pointer to the function to invoke, a structure
containing register arguments, and a size value that indicates the
number of bytes to push onto the stack for the call.

   Unfortunately, the register argument structure is very system
dependent.  There is no standard format for it, but it usually looks
something like this:

`stack_args'
     Pointer to an array of argument values to push onto the stack.

`struct_ptr'
     Pointer to the buffer to receive a `struct' return value.  The
     `struct_ptr' field is only present if the architecture passes
     `struct' pointers in a special register.

`word_reg[0..N]'
     Values for the word registers.  Platforms that pass values in
     registers will populate these fields.  Not present if the
     architecture does not use word registers for function calls.

`float_reg[0..N]'
     Values for the floating-point registers.  Not present if the
     architecture does not use floating-point registers for function
     calls.

   It is possible to automatically detect the particulars of this
structure by making test function calls and inspecting where the
arguments end up in the structure.  The `gen-apply' program in
`libjit/tools' takes care of this.  It outputs the `jit-apply-rules.h'
file, which tells `jit_apply' how to operate.

   The `gen-apply' program will normally "just work", but it is possible
that some architectures will be stranger than usual.  You will need to
modify `gen-apply' to detect this additional strangeness, and perhaps
also modify `libjit/jit/jit-apply.c'.

   If you aren't using gcc to compile `libjit', then things may not be
quite this easy.  You may have to write some inline assembly code to
emulate `__builtin_apply'.  See the file `jit-apply-x86.h' for an
example of how to do this.  Be sure to add an `#include' line to
`jit-apply-func.h' once you do this.

   The other half of `jit_apply' is closure and redirector support.
Closures are used to wrap up interpreted functions so that they can be
called as regular C functions.  Redirectors are used to help compile a
JIT'ed function on-demand, and then redirect control to it.

   Unfortunately, you will have to write some assembly code to support
closures and redirectors.  The builtin gcc facilities are not complete
enough to handle the task.  See `jit-apply-x86.c' and `jit-apply-arm.c'
for some examples from existing architectures.  You may be able to get
some ideas from the `libffi' and `ffcall' libraries as to what you need
to do on your architecture.


File: libjit.info,  Node: Instruction Generation,  Next: Architecture Rules,  Prev: Porting Apply,  Up: Porting

20.2 Creating the instruction generation macros
===============================================

You will need a large number of macros and support functions to
generate the raw instructions for your chosen CPU.  These macros are
fairly generic and are not necessarily specific to `libjit'.  There may
already be a suitable set of macros for your CPU in some other Free
Software project.

   Typically, the macros are placed into a file called `jit-gen-ARCH.h'
in the `libjit/jit' directory.  If some of the macros are complicated,
you can place helper functions into the file `jit-gen-ARCH.c'.
Remember to add both `jit-gen-ARCH.h' and `jit-gen-ARCH.c' to
`Makefile.am' in `libjit/jit'.

   Existing examples that you can look at for ideas are `jit-gen-x86.h'
and `jit-gen-arm.h'.  The macros in these existing files assume that
instructions can be output to a buffer in a linear fashion, and that
each instruction is relatively independent of the next.

   This independence principle may not be true of all CPU's.  For
example, the `ia64' packs up to three instructions into a single
"bundle" for parallel execution.  We recommend that the macros should
appear to use linear output, but call helper functions to pack bundles
after the fact.  This will make it easier to write the architecture
definition rules.  A similar approach could be used for performing
instruction scheduling on platforms that require it.


File: libjit.info,  Node: Architecture Rules,  Next: Register Allocation,  Prev: Instruction Generation,  Up: Porting

20.3 Writing the architecture definition rules
==============================================

The architecture definition rules for a CPU are placed into the files
`jit-rules-ARCH.h' and `jit-rules-ARCH.c'.  You should add both of
these files to `Makefile.am' in `libjit/jit'.

   You will also need to edit `jit-rules.h' in two places.  First,
place detection logic at the top of the file to detect your platform
and define `JIT_BACKEND_ARCH' to 1.  Further down the file, you should
add the following two lines to the include file logic:

     #elif defined(JIT_BACKEND_ARCH)
     #include "jit-rules-ARCH.h"

20.3.1 Defining the registers
-----------------------------

Every rule header file needs to define the macro `JIT_REG_INFO' to an
array of values that represents the properties of the CPU's registers.
The `_jit_reg_info' array is populated with these values.
`JIT_NUM_REGS' defines the number of elements in the array.  Each
element in the array has the following members:

`name'
     The name of the register.  This is used for debugging purposes.

`cpu_reg'
     The raw CPU register number.  Registers in `libjit' are referred
     to by their pseudo register numbers, corresponding to their index
     within `JIT_REG_INFO'.  However, these pseudo register numbers may
     not necessarily correspond to the register numbers used by the
     actual CPU.  This field provides a mapping.

`other_reg'
     The second pseudo register in a 64-bit register pair, or -1 if the
     current register cannot be used as the first pseudo register in a
     64-bit register pair.  This field only has meaning on 32-bit
     platforms, and should always be set to -1 on 64-bit platforms.

`flags'
     Flag bits that describe the pseudo register's properties.

The following flags may be present:

`JIT_REG_WORD'
     This register can hold an integer word value.

`JIT_REG_LONG'
     This register can hold a 64-bit long value without needing a
     second register.  Normally only used on 64-bit platforms.

`JIT_REG_FLOAT32'
     This register can hold a 32-bit floating-point value.

`JIT_REG_FLOAT64'
     This register can hold a 64-bit floating-point value.

`JIT_REG_NFLOAT'
     This register can hold a native floating-point value.

`JIT_REG_FRAME'
     This register holds the frame pointer.  You will almost always
     supply `JIT_REG_FIXED' for this register.

`JIT_REG_STACK_PTR'
     This register holds the stack pointer.  You will almost always
     supply `JIT_REG_FIXED' for this register.

`JIT_REG_FIXED'
     This register has a fixed meaning and cannot be used for general
     allocation.

`JIT_REG_CALL_USED'
     This register will be destroyed by a function call.

`JIT_REG_IN_STACK'
     This register is in a stack-like arrangement.

`JIT_REG_GLOBAL'
     This register is a candidate for global register allocation.

   A CPU may have some registers arranged into a stack.  In this case
operations can typically only occur at the top of the stack, and may
automatically pop values as a side-effect of the operation.  An example
of such architecture is x87 floating point unit.  Such CPU requires
three additional macros.

`JIT_REG_STACK'
     If defined, this indicates the presence of the register stack.

`JIT_REG_STACK_START'
     The index of the first register in the `JIT_REG_INFO' array that
     is used in a stack-like arrangement.

`JIT_REG_STACK_END'
     The index of the last register in the `JIT_REG_INFO' array that is
     used in a stack-like arrangement.


   The entries in the `JIT_REG_INFO' array from `JIT_REG_STACK_START'
up to `JIT_REG_STACK_END' must also have the `JIT_REG_IN_STACK' flag
set.

20.3.2 Other architecture macros
--------------------------------

The rule file may also have definitions of the following macros:

`JIT_NUM_GLOBAL_REGS'
     The number of registers that are used for global register
     allocation.  Set to zero if global register allocation should not
     be used.

`JIT_ALWAYS_REG_REG'
     Define this to 1 if arithmetic operations must always be performed
     on registers.  Define this to 0 if register/memory and
     memory/register operations are possible.

`JIT_PROLOG_SIZE'
     If defined, this indicates the maximum size of the function prolog.

`JIT_FUNCTION_ALIGNMENT'
     This value indicates the alignment required for the start of a
     function.  e.g. define this to 32 if functions should be aligned
     on a 32-byte boundary.

`JIT_ALIGN_OVERRIDES'
     Define this to 1 if the platform allows reads and writes on any
     byte boundary.  Define to 0 if only properly-aligned memory
     accesses are allowed.  Normally only defined to 1 under x86.

`jit_extra_gen_state'
`jit_extra_gen_init'
`jit_extra_gen_cleanup'
     The `jit_extra_gen_state' macro can be supplied to add extra fields
     to the `struct jit_gencode' type in `jit-rules.h', for extra
     CPU-specific code generation state information.

     The `jit_extra_gen_init' macro initializes this extra information,
     and the `jit_extra_gen_cleanup' macro cleans it up when code
     generation is complete.

20.3.3 Architecture-dependent functions
---------------------------------------

 -- Function: void _jit_init_backend (void)
     Initialize the backend.  This is normally used to configure
     registers that may not appear on all CPU's in a given family.  For
     example, only some ARM cores have floating-point registers.

 -- Function: void _jit_gen_get_elf_info (jit_elf_info_t *INFO)
     Get the ELF machine and ABI type information for this platform.
     The `machine' field should be set to one of the `EM_*' values in
     `jit-elf-defs.h'.  The `abi' field should be set to one of the
     `ELFOSABI_*' values in `jit-elf-defs.h' (`ELFOSABI_SYSV' will
     normally suffice if you are unsure).  The `abi_version' field
     should be set to the ABI version, which is usually zero.

 -- Function: int _jit_create_entry_insns (jit_function_t FUNC)
     Create instructions in the entry block to initialize the registers
     and frame offsets that contain the parameters.  Returns zero if
     out of memory.

     This function is called when a builder is initialized.  It should
     scan the signature and decide which register or frame position
     contains each of the parameters and then call either
     `jit_insn_incoming_reg' or `jit_insn_incoming_frame_posn' to
     notify `libjit' of the location.

 -- Function: int _jit_create_call_setup_insns (jit_function_t FUNC,
          jit_type_t SIGNATURE, jit_value_t *ARGS, unsigned int
          NUM_ARGS, int IS_NESTED, int NESTED_LEVEL, jit_value_t
          *STRUCT_RETURN, int FLAGS)
     Create instructions within FUNC necessary to set up for a function
     call to a function with the specified SIGNATURE.  Use
     `jit_insn_push' to push values onto the system stack, or
     `jit_insn_outgoing_reg' to copy values into call registers.

     If IS_NESTED is non-zero, then it indicates that we are calling a
     nested function within the current function's nested relationship
     tree.  The NESTED_LEVEL value will be -1 to call a child, zero to
     call a sibling of FUNC, 1 to call a sibling of the parent, 2 to
     call a sibling of the grandparent, etc.  The
     `jit_insn_setup_for_nested' instruction should be used to create
     the nested function setup code.

     If the function returns a structure by pointer, then STRUCT_RETURN
     must be set to a new local variable that will contain the returned
     structure.  Otherwise it should be set to NULL.

 -- Function: int _jit_setup_indirect_pointer (jit_function_t FUNC,
          jit_value_t VALUE)
     Place the indirect function pointer VALUE into a suitable register
     or stack location for a subsequent indirect call.

 -- Function: int _jit_create_call_return_insns (jit_function_t FUNC,
          jit_type_t SIGNATURE, jit_value_t *ARGS, unsigned int
          NUM_ARGS, jit_value_t RETURN_VALUE, int IS_NESTED)
     Create instructions within FUNC to clean up after a function call
     and to place the function's result into RETURN_VALUE.  This should
     use `jit_insn_pop_stack' to pop values off the system stack and
     `jit_insn_return_reg' to tell `libjit' which register contains the
     return value.  In the case of a `void' function, RETURN_VALUE will
     be NULL.

     Note: the argument values are passed again because it may not be
     possible to determine how many bytes to pop from the stack from
     the SIGNATURE alone; especially if the called function is vararg.

 -- Function: int _jit_opcode_is_supported (int OPCODE)
     Not all CPU's support all arithmetic, conversion, bitwise, or
     comparison operators natively.  For example, most ARM platforms
     need to call out to helper functions to perform floating-point.

     If this function returns zero, then `jit-insn.c' will output a
     call to an intrinsic function that is equivalent to the desired
     opcode.  This is how you tell `libjit' that you cannot handle the
     opcode natively.

     This function can also help you develop your back end
     incrementally.  Initially, you can report that only integer
     operations are supported, and then once you have them working you
     can move on to the floating point operations.

 -- Function: void * _jit_gen_prolog (jit_gencode_t GEN, jit_function_t
          FUNC, void *BUF)
     Generate the prolog for a function into a previously-prepared
     buffer area of `JIT_PROLOG_SIZE' bytes in size.  Returns the start
     of the prolog, which may be different than BUF.

     This function is called at the end of the code generation process,
     not the beginning.  At this point, it is known which callee save
     registers must be preserved, allowing the back end to output the
     most compact prolog possible.

 -- Function: void _jit_gen_epilog (jit_gencode_t GEN, jit_function_t
          FUNC)
     Generate a function epilog, restoring the registers that were
     saved on entry to the function, and then returning.

     Only one epilog is generated per function.  Functions with multiple
     `jit_insn_return' instructions will all jump to the common epilog.
     This is needed because the code generator may not know which callee
     save registers need to be restored by the epilog until the full
     function has been processed.

 -- Function: void * _jit_gen_redirector (jit_gencode_t GEN,
          jit_function_t FUNC)
     Generate code for a redirector, which makes an indirect jump to
     the contents of `FUNC->entry_point'.  Redirectors are used on
     recompilable functions in place of the regular entry point.  This
     allows `libjit' to redirect existing calls to the new version
     after recompilation.

 -- Function: void _jit_gen_spill_reg (jit_gencode_t GEN, int REG, int
          OTHER_REG, jit_value_t VALUE)
     Generate instructions to spill a pseudo register to the local
     variable frame.  If OTHER_REG is not -1, then it indicates the
     second register in a 64-bit register pair.

     This function will typically call `_jit_gen_fix_value' to fix the
     value's frame position, and will then generate the appropriate
     spill instructions.

 -- Function: void _jit_gen_free_reg (jit_gencode_t GEN, int REG, int
          OTHER_REG, int VALUE_USED)
     Generate instructions to free a register without spilling its
     value.  This is called when a register's contents become invalid,
     or its value is no longer required.  If VALUE_USED is set to a
     non-zero value, then it indicates that the register's value was
     just used.  Otherwise, there is a value in the register but it was
     never used.

     On most platforms, this function won't need to do anything to free
     the register.  But some do need to take explicit action.  For
     example, x86 needs an explicit instruction to remove a
     floating-point value from the FPU's stack if its value has not
     been used yet.

 -- Function: void _jit_gen_load_value (jit_gencode_t GEN, int REG, int
          OTHER_REG, jit_value_t VALUE)
     Generate instructions to load a value into a register.  The value
     will either be a constant or a slot in the frame.  You should fix
     frame slots with `_jit_gen_fix_value'.

 -- Function: void _jit_gen_spill_global (jit_gencode_t GEN, int REG,
          jit_value_t VALUE)
     Spill the contents of VALUE from its corresponding global register.
     This is used in rare cases when a machine instruction requires its
     operand to be in the specific register that happens to be global.
     In such cases the register is spilled just before the instruction
     and loaded back immediately after it.

 -- Function: void _jit_gen_load_global (jit_gencode_t GEN, int REG,
          jit_value_t VALUE)
     Load the contents of VALUE into its corresponding global register.
     This is used at the head of a function to pull parameters out of
     stack slots into their global register copies.

 -- Function: void _jit_gen_exch_top (jit_gencode_t GEN, int REG)
     Generate instructions to exchange the contents of the top stack
     register with a stack register specified by the REG argument.

     It needs to be implemented only by backends that support stack
     registers.

 -- Function: void _jit_gen_move_top (jit_gencode_t GEN, int REG)
     Generate instructions to copy the contents of the top stack
     register into a stack register specified by the `reg' argument and
     pop the top register after this. If `reg' is equal to the top
     register then the top register is just popped without copying it.

     It needs to be implemented only by backends that support stack
     registers.

 -- Function: void _jit_gen_spill_top (jit_gencode_t GEN, int REG,
          jit_value_t VALUE, int POP)
     Generate instructions to spill the top stack register to the local
     variable frame. The POP argument indicates if the top register is
     popped from the stack.

     It needs to be implemented only by backends that support stack
     registers.

 -- Function: void _jit_gen_fix_value (jit_value_t VALUE)
     Fix the position of a value within the local variable frame.  If
     it doesn't already have a position, then assign one for it.

 -- Function: void _jit_gen_insn (jit_gencode_t GEN, jit_function_t
          FUNC, jit_block_t BLOCK, jit_insn_t INSN)
     Generate native code for the specified INSN.  This function should
     call the appropriate register allocation routines, output the
     instruction, and then arrange for the result to be placed in an
     appropriate register or memory destination.

 -- Function: void _jit_gen_start_block (jit_gencode_t GEN, jit_block_t
          BLOCK)
     Called to notify the back end that the start of a basic block has
     been reached.

 -- Function: void _jit_gen_end_block (jit_gencode_t GEN)
     Called to notify the back end that the end of a basic block has
     been reached.

 -- Function: int _jit_gen_is_global_candidate (jit_type_t TYPE)
     Determine if TYPE is a candidate for allocation within global
     registers.


File: libjit.info,  Node: Register Allocation,  Next: Index,  Prev: Architecture Rules,  Up: Porting

20.4 Allocating registers in the back end
=========================================

The `libjit' library provides a number of functions for performing
register allocation within basic blocks so that you mostly don't have
to worry about it:

 -- Function: void _jit_regs_lookup (char *name)
     Get the pseudo register by its name.

 -- Function: int _jit_regs_needs_long_pair (jit_type_t type)
     Determine if a type requires a long register pair.

 -- Function: int _jit_regs_get_cpu (jit_gencode_t gen, int reg, int
          *other_reg)
     Get the CPU register that corresponds to a pseudo register.
     "other_reg" will be set to the other register in a pair, or -1 if
     the register is not part of a pair.

 -- Function: void _jit_regs_alloc_global (jit_gencode_t gen,
          jit_function_t func)
     Perform global register allocation on the values in `func'.  This
     is called during function compilation just after variable liveness
     has been computed.

 -- Function: void _jit_regs_init_for_block (jit_gencode_t gen)
     Initialize the register allocation state for a new block.

 -- Function: void _jit_regs_spill_all (jit_gencode_t gen)
     Spill all of the temporary registers to memory locations.
     Normally used at the end of a block, but may also be used in
     situations where a value must be in a certain register and it is
     too hard to swap things around to put it there.

 -- Function: void _jit_regs_set_incoming (jit_gencode_t gen, int reg,
          jit_value_t value)
     Set pseudo register `reg' to record that it currently holds the
     contents of `value'.  The register must not contain any other live
     value at this point.

 -- Function: void _jit_regs_set_outgoing (jit_gencode_t gen, int reg,
          jit_value_t value)
     Load the contents of `value' into pseudo register `reg', spilling
     out the current contents.  This is used to set up outgoing
     parameters for a function call.

 -- Function: void _jit_regs_force_out (jit_gencode_t gen, jit_value_t
          value, int is_dest)
     If `value' is currently in a register, then force its value out
     into the stack frame.  The `is_dest' flag indicates that the value
     will be a destination, so we don't care about the original value.

 -- Function: int _jit_regs_load_value (jit_gencode_t gen, jit_value_t
          value, int destroy, int used_again)
     Load a value into any register that is suitable and return that
     register.  If the value needs a long pair, then this will return
     the first register in the pair.  Returns -1 if the value will not
     fit into any register.

     If `destroy' is non-zero, then we are about to destroy the
     register, so the system must make sure that such destruction will
     not side-effect `value' or any of the other values currently in
     that register.

     If `used_again' is non-zero, then it indicates that the value is
     used again further down the block.

