]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Initial revision
authorRhys Weatherley <rweather@southern-storm.com.au>
Fri, 30 Apr 2004 23:29:28 +0000 (23:29 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Fri, 30 Apr 2004 23:29:28 +0000 (23:29 +0000)
126 files changed:
.cvsignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
auto_gen.sh [new file with mode: 0755]
config.guess [new file with mode: 0755]
config.sub [new file with mode: 0755]
configure.in [new file with mode: 0644]
doc/.cvsignore [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/extract-docs.sh [new file with mode: 0755]
doc/libjit.3 [new file with mode: 0644]
doc/libjit.texi [new file with mode: 0644]
doc/mkhtml.sh [new file with mode: 0755]
doc/mkpdf.sh [new file with mode: 0755]
doc/texinfo.tex [new file with mode: 0644]
dpas/.cvsignore [new file with mode: 0644]
dpas/Makefile.am [new file with mode: 0644]
dpas/README [new file with mode: 0644]
dpas/dpas-function.c [new file with mode: 0644]
dpas/dpas-internal.h [new file with mode: 0644]
dpas/dpas-main.c [new file with mode: 0644]
dpas/dpas-parser.y [new file with mode: 0644]
dpas/dpas-scanner.l [new file with mode: 0644]
dpas/dpas-scope.c [new file with mode: 0644]
dpas/dpas-scope.h [new file with mode: 0644]
dpas/dpas-semantics.h [new file with mode: 0644]
dpas/dpas-types.c [new file with mode: 0644]
dpas/dpas-types.h [new file with mode: 0644]
include/.cvsignore [new file with mode: 0644]
include/Makefile.am [new file with mode: 0644]
include/jit/.cvsignore [new file with mode: 0644]
include/jit/Makefile.am [new file with mode: 0644]
include/jit/jit-apply.h [new file with mode: 0644]
include/jit/jit-block.h [new file with mode: 0644]
include/jit/jit-common.h [new file with mode: 0644]
include/jit/jit-context.h [new file with mode: 0644]
include/jit/jit-defs.h.in [new file with mode: 0644]
include/jit/jit-dump.h [new file with mode: 0644]
include/jit/jit-elf.h [new file with mode: 0644]
include/jit/jit-except.h [new file with mode: 0644]
include/jit/jit-function.h [new file with mode: 0644]
include/jit/jit-init.h [new file with mode: 0644]
include/jit/jit-insn.h [new file with mode: 0644]
include/jit/jit-intrinsic.h [new file with mode: 0644]
include/jit/jit-meta.h [new file with mode: 0644]
include/jit/jit-opcode.h [new file with mode: 0644]
include/jit/jit-plus.h [new file with mode: 0644]
include/jit/jit-type.h [new file with mode: 0644]
include/jit/jit-util.h [new file with mode: 0644]
include/jit/jit-value.h [new file with mode: 0644]
include/jit/jit-walk.h [new file with mode: 0644]
include/jit/jit.h [new file with mode: 0644]
install-sh [new file with mode: 0755]
jit/.cvsignore [new file with mode: 0644]
jit/Makefile.am [new file with mode: 0644]
jit/jit-alloc.c [new file with mode: 0644]
jit/jit-apply-arm.c [new file with mode: 0644]
jit/jit-apply-arm.h [new file with mode: 0644]
jit/jit-apply-func.h [new file with mode: 0644]
jit/jit-apply-x86.c [new file with mode: 0644]
jit/jit-apply-x86.h [new file with mode: 0644]
jit/jit-apply.c [new file with mode: 0644]
jit/jit-block.c [new file with mode: 0644]
jit/jit-cache.c [new file with mode: 0644]
jit/jit-cache.h [new file with mode: 0644]
jit/jit-context.c [new file with mode: 0644]
jit/jit-dump.c [new file with mode: 0644]
jit/jit-dynlib.c [new file with mode: 0644]
jit/jit-elf-defs.h [new file with mode: 0644]
jit/jit-elf-read.c [new file with mode: 0644]
jit/jit-elf-write.c [new file with mode: 0644]
jit/jit-except.cpp [new file with mode: 0644]
jit/jit-function.c [new file with mode: 0644]
jit/jit-gen-arm.c [new file with mode: 0644]
jit/jit-gen-arm.h [new file with mode: 0644]
jit/jit-gen-x86.h [new file with mode: 0644]
jit/jit-init.c [new file with mode: 0644]
jit/jit-insn.c [new file with mode: 0644]
jit/jit-internal.h [new file with mode: 0644]
jit/jit-interp.cpp [new file with mode: 0644]
jit/jit-interp.h [new file with mode: 0644]
jit/jit-intrinsic.c [new file with mode: 0644]
jit/jit-live.c [new file with mode: 0644]
jit/jit-memory.c [new file with mode: 0644]
jit/jit-memory.h [new file with mode: 0644]
jit/jit-meta.c [new file with mode: 0644]
jit/jit-opcode.c [new file with mode: 0644]
jit/jit-pool.c [new file with mode: 0644]
jit/jit-reg-alloc.c [new file with mode: 0644]
jit/jit-reg-alloc.h [new file with mode: 0644]
jit/jit-rules-arm.c [new file with mode: 0644]
jit/jit-rules-arm.h [new file with mode: 0644]
jit/jit-rules-interp.c [new file with mode: 0644]
jit/jit-rules-interp.h [new file with mode: 0644]
jit/jit-rules-x86.c [new file with mode: 0644]
jit/jit-rules-x86.h [new file with mode: 0644]
jit/jit-rules.c [new file with mode: 0644]
jit/jit-rules.h [new file with mode: 0644]
jit/jit-string.c [new file with mode: 0644]
jit/jit-thread.c [new file with mode: 0644]
jit/jit-thread.h [new file with mode: 0644]
jit/jit-type.c [new file with mode: 0644]
jit/jit-value.c [new file with mode: 0644]
jit/jit-walk.c [new file with mode: 0644]
jitplus/.cvsignore [new file with mode: 0644]
jitplus/Makefile.am [new file with mode: 0644]
jitplus/jit-plus-context.cpp [new file with mode: 0644]
jitplus/jit-plus-function.cpp [new file with mode: 0644]
jitplus/jit-plus-value.cpp [new file with mode: 0644]
missing [new file with mode: 0755]
mkinstalldirs [new file with mode: 0755]
tools/.cvsignore [new file with mode: 0644]
tools/Makefile.am [new file with mode: 0644]
tools/gen-apply.c [new file with mode: 0644]
tutorial/.cvsignore [new file with mode: 0644]
tutorial/Makefile.am [new file with mode: 0644]
tutorial/README [new file with mode: 0644]
tutorial/t1.c [new file with mode: 0644]
tutorial/t2.c [new file with mode: 0644]
tutorial/t3.c [new file with mode: 0644]
tutorial/t4.cpp [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..3ae6b91
--- /dev/null
@@ -0,0 +1,13 @@
+Makefile
+Makefile.in
+.deps
+configure
+config.log
+config.cache
+config.status
+aclocal.m4
+confdefs.h
+config.h
+config.h.in
+stamp-h
+stamp-h.in
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..e7ba620
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Rhys Weatherley <rweather@southern-storm.com.au>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..b326cf6
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,106 @@
+
+2004-05-01  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * jit/jit-apply-x86.c, jit/jit-rules-x86.c, tools/gen-apply.c:
+       fix function prolog and epilog handling for structure returns
+       under x86/cdecl.
+
+2004-04-30  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * include/jit/jit-function.h, include/jit/jit-insn.h,
+       include/jit/jit-opcode.h, include/jit/jit-plus.h, jit/jit-except.cpp,
+       jit/jit-function.c, jit/jit-insn.c, jit/jit-internal.h,
+       jit/jit-interp.cpp, jit/jit-interp.h, jit/jit-opcode.c,
+       jit/jit-rules-arm.c, jit/jit-rules-interp.c, jit/jit-rules-x86.c,
+       jit/jit-rules.h, jitplus/jit-plus-function.cpp: put some
+       infrastructure in place to support "try"-related instructions.
+
+       * dpas/dpas-parser.y, dpas/dpas-scope.h, dpas/dpas-semantics.h:
+       introduce effective address based l-values into dpas.
+
+2004-04-27  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * jit/jit-dump.c, jit/jit-reg-alloc.c: fix a register stack bug
+       in "_jit_regs_set_value"; add some more debug code.
+
+       * include/jit/jit-opcode.h, jit/jit-insn.c, jit/jit-internal.h,
+       jit/jit-interp.cpp, jit/jit-opcode.c: wrap function calls
+       with code to set up and remove exception frame information.
+
+       * jit/jit-function.c, jit/jit-insn.c, jit/jit-internal.h:
+       intuit "nothrow" and "noreturn" flags for compiled functions.
+
+       * include/jit/jit-insn.h, include/jit/jit-plus.h, jit/jit-insn.c,
+       jitplus/jit-plus-function.cpp: add "jit_insn_throw",
+       "jit_insn_rethrow", and "jit_insn_get_call_stack" to assist
+       with throwing exceptions.
+
+       * include/jit/jit-insn.h, jit/jit-block.c, jit/jit-insn.c,
+       jit/jit-internal.h: add some instructions for managing "try" blocks.
+
+       * include/jit/jit-opcode.h, jit/jit-block.c, jit/jit-insn.c,
+       jit/jit-internal.h, jit/jit-opcode.c: more work on "try" blocks.
+
+2004-04-26  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * jit/jit-reg-alloc.c, jit/jit-reg-alloc.h: add functions to
+       assist with register allocation on stack-based architectures.
+
+       * jit/jit-rules-interp.c: implement "_jit_gen_load_value" for
+       the interpreter backend.
+
+       * jit/jit-interp.cpp, jit/jit-interp.h: fix some opcode names that
+       should be prefixed with "JIT_OP".
+
+       * jit/jit-function.c, jit/jit-internal.h, jit/jit-reg-alloc.c,
+       jit/jit-reg-alloc.h, jit/jit-rules-arm.c, jit/jit-rules-interp.c,
+       jit/jit-rules-interp.h, jit/jit-rules-x86.c, jit/jit-rules.h:
+       interpreter back end code generation for binary, unary, and
+       branch opcodes.
+
+       * doc/libjit.texi, jit/jit-rules-interp.c: fix the Texinfo section
+       markers in the "Porting" chapter.
+
+       * jit/jit-rules-interp.c: code generation for interpreter return's.
+
+       * include/jit/jit-except.h, include/jit/jit-function.h,
+       include/jit/jit-plus.h, jit/jit-except.cpp, jit/jit-function.c,
+       jit/jit-interp.cpp, jit/jit-interp.h, jit/jit-rules-interp.c,
+       jitplus/jit-plus-function.cpp: implement "jit_function_apply"
+       and "jit_function_apply_vararg" for the interpreter back end.
+
+       * jitplus/jit-plus-function.cpp: initialization errors in
+       the C++ binding.
+
+       * jit/jit-function.c, jit/jit-insn.c, jit/jit-interp.cpp,
+       jit/jit-rules-interp.c: work on code generation for function calls.
+
+       * doc/libjit.texi, include/jit/jit-insn.h, include/jit/jit-plus.h,
+       jit/jit-insn.c, jitplus/jit-plus-function.cpp, tutorial/t2.c:
+       add a "flags" parmeter to "jit_insn_call" and friends, so that
+       "nothrow", "noreturn", and "tail" options can be supplied.
+
+       * jit/jit-dump.c, jit/jit-interp.cpp, jit/jit-interp.h,
+       jit/jit-opcode.c, jit/jit-rules-interp.c: dump the translated
+       native code from "jit_dump_function" are compilation.
+
+       * jit/jit-interp.cpp, jit/jit-rules-interp.c: argument variable
+       offsets should in item units, not byte units.
+
+       * jit/jit-insn.c, jit/jit-reg-alloc.c, jit/jit-reg-alloc.h,
+       jit/jit-rules-interp.c: improve register allocation in stacks.
+
+2004-04-25  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * jit/jit-apply-func.h, jit/jit-apply-x86.c, jit/jit-apply-x86.h,
+       jit/jit-cache.c: use CPU-specifc padding for aligning code
+       areas with NOP's, for greater runtime efficiency.
+
+       * include/jit/jit-elf.h, jit/Makefile.am, jit/jit-elf-write.c:
+       add the skeleton of the ELF writing routines.
+
+       * jit/jit-interp.cpp: modify VM_BR_TARGET so that it is PIC-friendly.
+
+2004-04-24  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * */*: Initial public release.  Most of the skeleton code is in place.
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  You can give `configure'
+initial values for variables by setting them in the environment.  Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory.  After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on.  Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+     CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+   If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+     Use and save the results of the tests in FILE instead of
+     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
+     debugging `configure'.
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..5e82876
--- /dev/null
@@ -0,0 +1,2 @@
+
+SUBDIRS = include tools jit jitplus dpas tutorial doc
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..a524a8b
--- /dev/null
+++ b/README
@@ -0,0 +1,65 @@
+
+libjit
+------
+
+This library in this distribution implements Just-In-Time compilation
+functionality.  Unlike other JIT's, this one is designed to be independent
+of any particular virtual machine bytecode format or language.  The hope
+is that Free Software projects can get a leg-up on proprietry VM vendors
+by using this library rather than spending large amounts of time writing
+their own JIT from scratch.
+
+This JIT is also designed to be portable to multiple archictures.
+If you run libjit on a machine for which a native code generator is
+not yet available, then libjit will fall back to interpreting the code.
+This way, you don't need to write your own interpreter for your
+bytecode format if you don't want to.
+
+The library is distributed under the terms of the GNU General Public
+License.  See the COPYING file for details.
+
+The documentation for libjit is in Texinfo format.  A general overview
+is in "doc/libjit.texi" with the remainder of the function documentation
+in the source files themselves.
+
+Building libjit
+---------------
+
+You will need GNU make, Bison, and Flex to build libjit, and it is
+also highly recommended that you use gcc.  To configure, build,
+and install, you would do the following:
+
+        ./configure
+        make
+        make install
+
+Compiler notes
+--------------
+
+It is highly recommended that you build libjit with gcc and not
+some other C compiler, even if you plan to use some other C
+compiler to access the library.  We make use of a number of gcc
+builtins to assist with stack walking, dynamic function calls,
+and closures.
+
+It is also recommended that you don't use the "-fomit-frame-pointer"
+option when compiling programs that use libjit.  Otherwise stack walking
+may not work correctly, leading to problems when throwing exceptions.
+The configure script for libjit will detect the presence of this
+option in CFLAGS and remove it when building libjit itself.
+
+Contacting the authors
+----------------------
+
+The primary author is Rhys Weatherley at Southern Storm Software, Pty Ltd.
+He can be reached via e-mail at "rweather@southern-storm.com.au".
+
+The latest version of libjit will always be available from the Southern
+Storm Web site:
+
+        http://www.southern-storm.com.au/libjit/
+
+Discussions about libjit can be carried out on the DotGNU Portable.NET
+mailing list, "pnet-developers@dotgnu.org".  Visit "www.dotgnu.org"
+for details on how to subscribe to this list.  A separate mailing list
+will be created if there is demand for it.
diff --git a/auto_gen.sh b/auto_gen.sh
new file mode 100755 (executable)
index 0000000..766ba35
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# auto_gen.sh - Make the Makefile.in and configure files.
+#
+# Copyright (C) 2001, 2002  Southern Storm Software, Pty Ltd.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+# Run aclocal to update the macros.
+aclocal
+
+# Run autoheader to generate config.h.in.
+autoheader
+
+# Get extra options to use depending upon the automake version.
+AM_VERSION=`automake --version`
+case "$AM_VERSION" in
+    automake*1.4*) AM_FLAGS="" ;;
+                *) AM_FLAGS="--ignore-deps" ;;
+esac
+
+# Run automake and autoconf.
+automake --add-missing --copy $AM_FLAGS
+autoconf
+exit 0
diff --git a/config.guess b/config.guess
new file mode 100755 (executable)
index 0000000..78f6b92
--- /dev/null
@@ -0,0 +1,1409 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-01-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+       for c in cc gcc c89 c99 ; do
+         if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+            CC_FOR_BUILD="$c"; break ;
+         fi ;
+       done ;
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found ;
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # NetBSD (nbsd) targets should (where applicable) match one or
+       # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       #
+       # Note: NetBSD doesn't particularly care about the vendor
+       # portion of the name.  We always set it to "unknown".
+       sysctl="sysctl -n hw.machine_arch"
+       UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+       case "${UNAME_MACHINE_ARCH}" in
+           armeb) machine=armeb-unknown ;;
+           arm*) machine=arm-unknown ;;
+           sh3el) machine=shl-unknown ;;
+           sh3eb) machine=sh-unknown ;;
+           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE_ARCH}" in
+           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+               eval $set_cc_for_build
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep __ELF__ >/dev/null
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # The OS release
+       # Debian GNU/NetBSD machines have a different userland, and
+       # thus, need a distinct triplet. However, they do not need
+       # kernel version information, so it can be replaced with a
+       # suitable tag, in the style of linux-gnu.
+       case "${UNAME_VERSION}" in
+           Debian*)
+               release='-gnu'
+               ;;
+           *)
+               release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+               ;;
+       esac
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit 0 ;;
+    amiga:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hp300:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    macppc:OpenBSD:*:*)
+       echo powerpc-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvmeppc:OpenBSD:*:*)
+       echo powerpc-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    pmax:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sgi:OpenBSD:*:*)
+       echo mipseb-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sun3:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:MicroBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-microbsd${UNAME_RELEASE}
+       exit 0 ;;
+    alpha:OSF1:*:*)
+       if test $UNAME_RELEASE = "V4.0"; then
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+       fi
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       eval $set_cc_for_build
+       cat <<EOF >$dummy.s
+       .data
+\$Lformat:
+       .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+
+       .text
+       .globl main
+       .align 4
+       .ent main
+main:
+       .frame \$30,16,\$26,0
+       ldgp \$29,0(\$27)
+       .prologue 1
+       .long 0x47e03d80 # implver \$0
+       lda \$2,-1
+       .long 0x47e20c21 # amask \$2,\$1
+       lda \$16,\$Lformat
+       mov \$0,\$17
+       not \$1,\$18
+       jsr \$26,printf
+       ldgp \$29,0(\$26)
+       mov 0,\$16
+       jsr \$26,exit
+       .end main
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.s 2>/dev/null
+       if test "$?" = 0 ; then
+               case `$dummy` in
+                       0-0)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       1-0)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       1-1)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       1-101)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       2-303)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+                       2-307)
+                               UNAME_MACHINE="alphaev67"
+                               ;;
+                       2-1307)
+                               UNAME_MACHINE="alphaev68"
+                               ;;
+                       3-1307)
+                               UNAME_MACHINE="alphaev7"
+                               ;;
+               esac
+       fi
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit 0 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit 0;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit 0 ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-morphos
+       exit 0 ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit 0;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit 0 ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit 0 ;;
+    DRS?6000:UNIX_SV:4.2*:7*)
+       case `/usr/bin/uname -p` in
+           sparc) echo sparc-icl-nx7 && exit 0 ;;
+       esac ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit 0 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit 0 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit 0 ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit 0 ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c \
+         && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && exit 0
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit 0 ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit 0 ;;
+    Motorola:*:4.3:PL8-*)
+       echo powerpc-harris-powermax
+       exit 0 ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+       echo powerpc-harris-powermax
+       exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit 0 ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit 0 ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit 0 ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit 0 ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit 0 ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+       echo i386-ibm-aix
+       exit 0 ;;
+    ia64:AIX:*:*)
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               eval $set_cc_for_build
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+               echo rs6000-ibm-aix3.2.5
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit 0 ;;
+    *:AIX:*:[45])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+               if [ -x /usr/bin/getconf ]; then
+                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+               fi
+               if [ "${HP_ARCH}" = "" ]; then
+                   eval $set_cc_for_build
+                   sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+               {
+               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+               case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+                   switch (bits)
+                       {
+                       case 64: puts ("hppa2.0w"); break;
+                       case 32: puts ("hppa2.0n"); break;
+                       default: puts ("hppa2.0"); break;
+                       } break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+                   puts ("hppa2.0"); break;
+              #endif
+               default: puts ("hppa1.0"); break;
+               }
+                  exit (0);
+              }
+EOF
+                   (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+                   test -z "$HP_ARCH" && HP_ARCH=hppa
+               fi ;;
+       esac
+       if [ ${HP_ARCH} = "hppa2.0w" ]
+       then
+           # avoid double evaluation of $set_cc_for_build
+           test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+           if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+           then
+               HP_ARCH="hppa2.0w"
+           else
+               HP_ARCH="hppa64"
+           fi
+       fi
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    3050*:HI-UX:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+       echo unknown-hitachi-hiuxwe2
+       exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit 0 ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit 0 ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit 0 ;;
+    i*86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit 0 ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+             -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    *:UNICOS/mp:*:*)
+       echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' 
+       exit 0 ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:FreeBSD:*:*)
+       # Determine whether the default compiler uses glibc.
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <features.h>
+       #if __GLIBC__ >= 2
+       LIBC=gnu
+       #else
+       LIBC=
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
+       exit 0 ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit 0 ;;
+    i*:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit 0 ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit 0 ;;
+    x86:Interix*:3*)
+       echo i586-pc-interix3
+       exit 0 ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+       echo i${UNAME_MACHINE}-pc-mks
+       exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i586-pc-interix
+       exit 0 ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit 0 ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit 0 ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    *:GNU:*:*)
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit 0 ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit 0 ;;
+    arm*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    mips:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef mips
+       #undef mipsel
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=mipsel
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=mips
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+       test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+       ;;
+    mips64:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef mips64
+       #undef mips64el
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=mips64el
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=mips64
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+       test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+       ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-gnu
+       exit 0 ;;
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-gnu
+       exit 0 ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+       objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit 0 ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-gnu ;;
+         PA8*) echo hppa2.0-unknown-linux-gnu ;;
+         *)    echo hppa-unknown-linux-gnu ;;
+       esac
+       exit 0 ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
+       exit 0 ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux
+       exit 0 ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    x86_64:Linux:*:*)
+       echo x86_64-unknown-linux-gnu
+       exit 0 ;;
+    i*86:Linux:*:*)
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us. cd to the root directory to prevent
+       # problems with other programs or directories called `ld' in the path.
+       # Set LC_ALL=C to ensure ld outputs messages in English.
+       ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+                        | sed -ne '/supported targets:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported targets: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_targets" in
+         elf32-i386)
+               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+               ;;
+         a.out-i386-linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit 0 ;;
+         coff-i386)
+               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+               exit 0 ;;
+         "")
+               # Either a pre-BFD a.out linker (linux-gnuoldld) or
+               # one that does not give us useful --help.
+               echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+               exit 0 ;;
+       esac
+       # Determine whether the default compiler is a.out or elf
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <features.h>
+       #ifdef __ELF__
+       # ifdef __GLIBC__
+       #  if __GLIBC__ >= 2
+       LIBC=gnu
+       #  else
+       LIBC=gnulibc1
+       #  endif
+       # else
+       LIBC=gnulibc1
+       # endif
+       #else
+       #ifdef __INTEL_COMPILER
+       LIBC=gnu
+       #else
+       LIBC=gnuaout
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+       test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
+       test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+       ;;
+    i*86:DYNIX/ptx:4*:*)
+       # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+       # earlier versions are messed up and put the nodename in both
+       # sysname and nodename.
+       echo i386-sequent-sysv4
+       exit 0 ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit 0 ;;
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit 0 ;;
+    i*86:XTS-300:*:STOP)
+       echo ${UNAME_MACHINE}-unknown-stop
+       exit 0 ;;
+    i*86:atheos:*:*)
+       echo ${UNAME_MACHINE}-unknown-atheos
+       exit 0 ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit 0 ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit 0 ;;
+    i*86:*:5:[78]*)
+       case `/bin/uname -X | grep "^Machine"` in
+           *486*)           UNAME_MACHINE=i486 ;;
+           *Pentium)        UNAME_MACHINE=i586 ;;
+           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+       esac
+       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       exit 0 ;;
+    i*86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit 0 ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+       echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit 0 ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit 0 ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+       echo m68k-convergent-sysv
+       exit 0 ;;
+    M680?0:D-NIX:5.3:*)
+       echo m68k-diab-dnix
+       exit 0 ;;
+    M68*:*:R3V[567]*:*)
+       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit 0 ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit 0 ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit 0 ;;
+    *:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo hppa1.1-stratus-vos
+       exit 0 ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit 0 ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit 0 ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit 0 ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-6:SUPER-UX:*:*)
+       echo sx6-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Darwin:*:*)
+       case `uname -p` in
+           *86) UNAME_PROCESSOR=i686 ;;
+           powerpc) UNAME_PROCESSOR=powerpc ;;
+       esac
+       echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+       exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       UNAME_PROCESSOR=`uname -p`
+       if test "$UNAME_PROCESSOR" = "x86"; then
+               UNAME_PROCESSOR=i386
+               UNAME_MACHINE=pc
+       fi
+       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+       exit 0 ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit 0 ;;
+    NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit 0 ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit 0 ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit 0 ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit 0 ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit 0 ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit 0 ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit 0 ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit 0 ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit 0 ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit 0 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit 0 ;;
+    c34*)
+       echo c34-convex-bsd
+       exit 0 ;;
+    c38*)
+       echo c38-convex-bsd
+       exit 0 ;;
+    c4*)
+       echo c4-convex-bsd
+       exit 0 ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.sub b/config.sub
new file mode 100755 (executable)
index 0000000..04baf3d
--- /dev/null
@@ -0,0 +1,1473 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-01-03'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit 0;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis)
+               os=
+               basic_machine=$1
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -chorusos*)
+               os=-chorusos
+               basic_machine=$1
+               ;;
+       -chorusrdb)
+               os=-chorusrdb
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       1750a | 580 \
+       | a29k \
+       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+       | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+       | clipper \
+       | d10v | d30v | dlx | dsp16xx \
+       | fr30 | frv \
+       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+       | i370 | i860 | i960 | ia64 \
+       | ip2k \
+       | m32r | m68000 | m68k | m88k | mcore \
+       | mips | mipsbe | mipseb | mipsel | mipsle \
+       | mips16 \
+       | mips64 | mips64el \
+       | mips64vr | mips64vrel \
+       | mips64orion | mips64orionel \
+       | mips64vr4100 | mips64vr4100el \
+       | mips64vr4300 | mips64vr4300el \
+       | mips64vr5000 | mips64vr5000el \
+       | mipsisa32 | mipsisa32el \
+       | mipsisa32r2 | mipsisa32r2el \
+       | mipsisa64 | mipsisa64el \
+       | mipsisa64sb1 | mipsisa64sb1el \
+       | mipsisa64sr71k | mipsisa64sr71kel \
+       | mipstx39 | mipstx39el \
+       | mn10200 | mn10300 \
+       | msp430 \
+       | ns16k | ns32k \
+       | openrisc | or32 \
+       | pdp10 | pdp11 | pj | pjl \
+       | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+       | pyramid \
+       | sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+       | sh64 | sh64le \
+       | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
+       | strongarm \
+       | tahoe | thumb | tic80 | tron \
+       | v850 | v850e \
+       | we32k \
+       | x86 | xscale | xstormy16 | xtensa \
+       | z8k)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12)
+               # Motorola 68HC11/12.
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i*86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       580-* \
+       | a29k-* \
+       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+       | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+       | avr-* \
+       | bs2000-* \
+       | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* \
+       | clipper-* | cydra-* \
+       | d10v-* | d30v-* | dlx-* \
+       | elxsi-* \
+       | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+       | h8300-* | h8500-* \
+       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+       | i*86-* | i860-* | i960-* | ia64-* \
+       | ip2k-* \
+       | m32r-* \
+       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+       | m88110-* | m88k-* | mcore-* \
+       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+       | mips16-* \
+       | mips64-* | mips64el-* \
+       | mips64vr-* | mips64vrel-* \
+       | mips64orion-* | mips64orionel-* \
+       | mips64vr4100-* | mips64vr4100el-* \
+       | mips64vr4300-* | mips64vr4300el-* \
+       | mips64vr5000-* | mips64vr5000el-* \
+       | mipsisa32-* | mipsisa32el-* \
+       | mipsisa32r2-* | mipsisa32r2el-* \
+       | mipsisa64-* | mipsisa64el-* \
+       | mipsisa64sb1-* | mipsisa64sb1el-* \
+       | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+       | mipstx39-* | mipstx39el-* \
+       | msp430-* \
+       | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
+       | orion-* \
+       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+       | pyramid-* \
+       | romp-* | rs6000-* \
+       | sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \
+       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+       | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+       | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+       | tahoe-* | thumb-* | tic30-* | tic4x-* | tic54x-* | tic80-* | tron-* \
+       | v850-* | v850e-* | vax-* \
+       | we32k-* \
+       | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+       | xtensa-* \
+       | ymp-* \
+       | z8k-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       c90)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | j90)
+               basic_machine=j90-cray
+               os=-unicos
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       decsystem10* | dec10*)
+               basic_machine=pdp10-dec
+               os=-tops10
+               ;;
+       decsystem20* | dec20*)
+               basic_machine=pdp10-dec
+               os=-tops20
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i*86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i*86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i*86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i*86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       mingw32)
+               basic_machine=i386-pc
+               os=-mingw32
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       mmix*)
+               basic_machine=mmix-knuth
+               os=-mmixware
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       morphos)
+               basic_machine=powerpc-unknown
+               os=-morphos
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       nv1)
+               basic_machine=nv1-cray
+               os=-unicosmp
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       or32 | or32-*)
+               basic_machine=or32-unknown
+               os=-coff
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+       pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pentium | p5 | k5 | k6 | nexgen | viac3)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon | athlon_*)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2)
+               basic_machine=i686-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+               basic_machine=powerpc64le-unknown
+               ;;
+       ppc64le-* | powerpc64little-*)
+               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       s390 | s390-*)
+               basic_machine=s390-ibm
+               ;;
+       s390x | s390x-*)
+               basic_machine=s390x-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sb1)
+               basic_machine=mipsisa64sb1-unknown
+               ;;
+       sb1el)
+               basic_machine=mipsisa64sb1el-unknown
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sparclite-wrs | simso-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=alphaev5-cray
+               os=-unicos
+               ;;
+       t90)
+               basic_machine=t90-cray
+               os=-unicos
+               ;;
+        tic4x | c4x*)
+               basic_machine=tic4x-unknown
+               os=-coff
+               ;;
+       tic54x | c54x*)
+               basic_machine=tic54x-unknown
+               os=-coff
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       toad1)
+               basic_machine=pdp10-xkl
+               os=-tops20
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh3 | sh4 | sh3eb | sh4eb | sh[1234]le | sh3ele)
+               basic_machine=sh-unknown
+               ;;
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparc | sparcv9 | sparcv9b)
+               basic_machine=sparc-sun
+               ;;
+       cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -chorusos* | -chorusrdb* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+             | -powermax* | -dnix* | -microbsd*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto-qnx*)
+               ;;
+       -nto*)
+               os=`echo $os | sed -e 's|nto|nto-qnx|'`
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -atheos*)
+               os=-atheos
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -nova*)
+               os=-rtmk-nova
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+       # This must come before the *-dec entry.
+       pdp10-*)
+               os=-tops20
+               ;;
+       pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       or32-*)
+               os=-coff
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+       *-gould)
+               os=-sysv
+               ;;
+       *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+       *-sgi)
+               os=-irix
+               ;;
+       *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -vxsim* | -vxworks* | -windiss*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+                       -vos*)
+                               vendor=stratus
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..35d3069
--- /dev/null
@@ -0,0 +1,378 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(include/jit/jit.h)
+
+dnl Determine the build, host, and target system types.
+AC_CANONICAL_SYSTEM
+
+dnl Initialize automake.
+AM_INIT_AUTOMAKE(libjit, 0.0.0)
+AM_CONFIG_HEADER(config.h)
+
+dnl Turn off the cygwin library if building for Win32.
+dnl Note: We have to include <stdlib.h> if we will be using "__int64"
+dnl because otherwise the mingw32 compiler won't define it correctly.
+AC_MSG_CHECKING([if building for some Win32 platform])
+AC_SUBST(JIT_INT64_INCLUDE)
+case "$host" in
+       *-*-cygwin*)
+               platform_win32=yes
+               if test "x$CC" = "x" ; then
+                       CC="gcc -mno-cygwin"
+               fi
+               if test "x$CXX" = "x" ; then
+                       if test "x$CC" = "xcl" ; then
+                               CXX="cl"
+                       else
+                               CXX="g++ -mno-cygwin"
+                       fi
+               fi
+               suppress_libm=yes
+               JIT_INT64_INCLUDE='#include <stdlib.h>'
+               ;;
+       *-*-mingw*)
+               platform_win32=yes
+               if test "x$CC" = "xcl" ; then
+                       if test "x$CXX" = "x" ; then
+                               CXX="cl"
+                       fi
+               fi
+               suppress_libm=yes
+               JIT_INT64_INCLUDE='#include <stdlib.h>'
+               ;;
+       *)
+               platform_win32=no
+               suppress_libm=no
+               JIT_INT64_INCLUDE=
+               ;;
+esac
+AC_MSG_RESULT($platform_win32)
+
+dnl Checks for programs.
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+AC_PROG_YACC
+AM_PROG_LEX
+
+dnl Set the correct flags for compiling with MSVC.  "/QIfist" is needed
+dnl on systems with both VC 6.0 and VC 7.0 installed: sometimes VC 7.0
+dnl picks up the wrong intrinsic libraries (particularly for __ftol2).
+dnl The "/EHs" option is required to enable exception handling in C++.
+if test "x$CC" = "xcl" ; then
+       CFLAGS="/nologo /QIfist"
+       CXXFLAGS="/nologo /QIfist /EHs"
+fi
+
+dnl Check for file extensions.
+AC_EXEEXT
+AC_OBJEXT
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(string.h strings.h memory.h stdlib.h stdarg.h varargs.h)
+AC_CHECK_HEADERS(tgmath.h math.h ieeefp.h pthread.h unistd.h sys/types.h)
+AC_CHECK_HEADERS(sys/mman.h fcntl.h dlfcn.h sys/cygwin.h sys/stat.h)
+
+dnl A macro that helps detect the size of types in a cross-compile environment.
+AC_DEFUN([AC_COMPILE_CHECK_SIZEOF],
+[changequote(<<, >>)dnl
+dnl The name to #define.
+define(<<AC_TYPE_NAME>>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl
+dnl The cache variable name.
+define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl
+changequote([, ])dnl
+AC_MSG_CHECKING(size of $1)
+AC_CACHE_VAL(AC_CV_NAME,
+[for ac_size in 4 8 1 2 12 16 $2 ; do # List sizes in rough order of prevalence.
+  AC_TRY_COMPILE([#include "confdefs.h"
+#include <sys/types.h>
+], [switch (0) case 0: case (sizeof ($1) == $ac_size):;], AC_CV_NAME=$ac_size)
+  if test x$AC_CV_NAME != x ; then break; fi
+done
+])
+if test x$AC_CV_NAME = x ; then
+  AC_CV_NAME=0
+fi
+AC_MSG_RESULT($AC_CV_NAME)
+AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [The number of bytes in type $1])
+undefine([AC_TYPE_NAME])dnl
+undefine([AC_CV_NAME])dnl
+])
+
+dnl A macro that detects if "char" is unsigned in a cross-compile environment.
+AC_DEFUN([AC_COMPILE_CHAR_UNSIGNED],
+[AC_MSG_CHECKING(if char is unsigned)
+AC_CACHE_VAL(ac_cv_c_char_unsigned,
+AC_TRY_COMPILE([#include "confdefs.h"
+], [switch (-1) case -1: case (char)255:;], ac_cv_c_char_unsigned=yes))
+if test x$ac_cv_c_char_unsigned = x ; then
+  ac_cv_c_char_unsigned=no
+fi
+AC_MSG_RESULT($ac_cv_c_char_unsigned)
+if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then
+  AC_DEFINE(__CHAR_UNSIGNED__, 1, [Define to 1 if "char" is unsigned])
+fi
+])
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_COMPILE_CHAR_UNSIGNED
+AC_COMPILE_CHECK_SIZEOF(char, 1)
+AC_COMPILE_CHECK_SIZEOF(short, 2)
+AC_COMPILE_CHECK_SIZEOF(int, 4)
+AC_COMPILE_CHECK_SIZEOF(long, 4)
+AC_COMPILE_CHECK_SIZEOF(long long, 8)
+AC_COMPILE_CHECK_SIZEOF(__int64, 8)
+AC_COMPILE_CHECK_SIZEOF(float, 4)
+AC_COMPILE_CHECK_SIZEOF(double, 8)
+AC_COMPILE_CHECK_SIZEOF(long double, 12)
+AC_COMPILE_CHECK_SIZEOF(void *, 4)
+
+dnl Determine the types to use for specific sizes of integers and floats.
+AC_SUBST(JITINT8)
+AC_SUBST(JITUINT8)
+AC_SUBST(JITINT16)
+AC_SUBST(JITINT32)
+AC_SUBST(JITINT64)
+AC_SUBST(JITINT64CXX)
+AC_SUBST(JITNATIVEINT)
+AC_SUBST(JITFLOAT32)
+AC_SUBST(JITFLOAT64)
+AC_SUBST(JITNATIVEFLOAT)
+AC_SUBST(JITNATIVEINTDEFINE)
+AC_SUBST(JITNFLOATISDOUBLE)
+AC_MSG_CHECKING(for the 8-bit integer types)
+if test "$ac_cv_sizeof_char" = 1 ; then
+       if test "x$ac_cv_c_char_unsigned" = "xyes" ; then
+               JITINT8="signed char"
+       else
+               JITINT8=char
+       fi
+       JITUINT8="unsigned char"
+elif test "$ac_cv_sizeof_short" = 1 ; then
+       JITINT8=short
+       JITUINT8="unsigned short"
+elif test "$ac_cv_sizeof_int" = 1 ; then
+       JITINT8=int
+       JITUINT8="unsigned int"
+elif test "$ac_cv_sizeof_long" = 1 ; then
+       JITINT8=long
+       JITUINT8="unsigned long"
+else
+       AC_MSG_ERROR(unknown)
+fi
+AC_MSG_RESULT([$JITINT8, $JITUINT8])
+AC_MSG_CHECKING(for the 16-bit integer types)
+if test "$ac_cv_sizeof_short" = 2 ; then
+       JITINT16=short
+elif test "$ac_cv_sizeof_int" = 2 ; then
+       JITINT16=int
+elif test "$ac_cv_sizeof_long" = 2 ; then
+       JITINT16=long
+else
+       AC_MSG_ERROR(unknown)
+fi
+AC_MSG_RESULT([$JITINT16, unsigned $JITINT16])
+AC_MSG_CHECKING(for the 32-bit integer types)
+if test "$ac_cv_sizeof_int" = 4 ; then
+       JITINT32=int
+elif test "$ac_cv_sizeof_long" = 4 ; then
+       JITINT32=long
+elif test "$ac_cv_sizeof_short" = 4 ; then
+       JITINT32=short
+else
+       AC_MSG_ERROR(unknown)
+fi
+AC_MSG_RESULT([$JITINT32, unsigned $JITINT32])
+AC_MSG_CHECKING(for the 64-bit integer types)
+JITINT64CXX=
+if test "$ac_cv_sizeof___int64" = 8 ; then
+       if test "x$JIT_INT64_INCLUDE" = "x" ; then
+               JITINT64='long long'
+       else
+               dnl __int64 doesn't work with g++, although it does with gcc.
+               JITINT64='__int64'
+               JITINT64CXX='long long'
+       fi
+elif test "$ac_cv_sizeof_int" = 8 ; then
+       JITINT64=int
+elif test "$ac_cv_sizeof_long" = 8 ; then
+       JITINT64=long
+elif test "$ac_cv_sizeof_long_long" = 8 ; then
+       JITINT64='long long'
+else
+       AC_MSG_ERROR(unknown)
+fi
+if test "x$JITINT64CXX" = "x" ; then
+       JITINT64CXX="$JITINT64"
+fi
+AC_MSG_RESULT([$JITINT64, unsigned $JITINT64])
+AC_MSG_CHECKING(for the native integer types)
+if test "$ac_cv_sizeof_void_p" = 4 ; then
+       JITNATIVEINT="$JITINT32"
+       JITNATIVEINTDEFINE="JIT_NATIVE_INT32"
+elif test "$ac_cv_sizeof_void_p" = 8 ; then
+       JITNATIVEINT="$JITINT64"
+       JITNATIVEINTDEFINE="JIT_NATIVE_INT64"
+else
+       AC_MSG_ERROR(unknown)
+fi
+AC_MSG_RESULT([$JITNATIVEINT, unsigned $JITNATIVEINT])
+AC_MSG_CHECKING(for the 32-bit floating-point type)
+if test "$ac_cv_sizeof_float" = 4 ; then
+       JITFLOAT32=float
+elif test "$ac_cv_sizeof_double" = 4 ; then
+       JITFLOAT32=double
+else
+       AC_MSG_ERROR(unknown)
+fi
+AC_MSG_RESULT($JITFLOAT32)
+AC_MSG_CHECKING(for the 64-bit floating-point type)
+if test "$ac_cv_sizeof_float" = 8 ; then
+       JITFLOAT64=float
+elif test "$ac_cv_sizeof_double" = 8 ; then
+       JITFLOAT64=double
+else
+       AC_MSG_ERROR(unknown)
+fi
+AC_MSG_RESULT($JITFLOAT64)
+AC_MSG_CHECKING(for the native floating-point type)
+JITNFLOATISDOUBLE=''
+if test "x$platform_win32" = "xyes" ; then
+       dnl MSVC's "long double" is the same as "double", so we make sure
+       dnl to preserve compatibility between MSVC and gcc.
+       JITNATIVEFLOAT='double'
+       JITNFLOATISDOUBLE='#define JIT_NFLOAT_IS_DOUBLE 1'
+elif test "$ac_cv_sizeof_long_double" != 0 ; then
+       if test "$ac_cv_sizeof_long_double" = "$ac_cv_sizeof_double" ; then
+               JITNATIVEFLOAT='double'
+               JITNFLOATISDOUBLE='#define JIT_NFLOAT_IS_DOUBLE 1'
+       else
+               JITNATIVEFLOAT='long double'
+       fi
+elif test "$ac_cv_sizeof_double" != 0 ; then
+       JITNATIVEFLOAT=double
+       JITNFLOATISDOUBLE='#define JIT_NFLOAT_IS_DOUBLE 1'
+elif test "$ac_cv_sizeof_float" != 0 ; then
+       JITNATIVEFLOAT=float
+else
+       AC_MSG_ERROR(unknown)
+fi
+AC_MSG_RESULT($JITNATIVEFLOAT)
+
+dnl Check to see if we are using gcc or not.
+if test x$GCC = xyes ; then
+       CFLAGS="$CFLAGS -Wall"
+fi
+if test x$GXX = xyes ; then
+       CXXFLAGS="$CXXFLAGS -Wall"
+fi
+
+dnl If CFLAGS contains "-fomit-frame-pointer", then remove it.
+dnl We need to have frame pointers to perform stack walking.
+case "x$CFLAGS" in
+       *-fomit-frame-pointer*)
+               CFLAGS=`echo "$CFLAGS" | sed 's/-fomit-frame-pointer//'` ;;
+       *)      ;;
+esac
+case "x$CXXFLAGS" in
+       *-fomit-frame-pointer*)
+               CXXFLAGS=`echo "$CXXFLAGS" | sed 's/-fomit-frame-pointer//'` ;;
+       *)      ;;
+esac
+
+dnl Find the option to use to turn on C++ exception handling.
+AC_CACHE_CHECK(for C++ exception handling option, ac_cv_prog_cxx_exceptions,
+[echo 'int main(int argc, char **argv){try { throw 1; } catch(int i) { return i; } return 0;}' > conftest.c
+if test -z "`${CXX-c++} -o conftest conftest.c 2>&1`"; then
+  ac_cv_prog_cxx_exceptions='none needed'
+else
+  if test -z "`${CXX-c++} -fexceptions -o conftest conftest.c 2>&1`"; then
+    ac_cv_prog_cxx_exceptions=-fexceptions
+  else
+    if test -z "`${CXX-c++} -fhandle-exceptions -o conftest conftest.c 2>&1`"; then
+      ac_cv_prog_cxx_exceptions=-fhandle-exceptions
+    else
+      ac_cv_prog_cxx_exceptions='none needed'
+    fi
+  fi
+fi
+rm -f conftest*
+])
+if test "x$ac_cv_prog_cxx_exceptions" != "xnone needed" ; then
+       CXXFLAGS="$ac_cv_prog_cxx_exceptions $CXXFLAGS"
+fi
+
+dnl Determine if the C++ compiler understands the "throw()" idiom.
+AC_CACHE_CHECK(for C++ throw() idiom, ac_cv_prog_cxx_throw_idiom,
+[echo 'extern "C" void func(void) throw(); int main(int argc, char **argv){return 0;}' > conftest.c
+if test -z "`${CXX-c++} -o conftest conftest.c 2>&1`"; then
+  ac_cv_prog_cxx_throw_idiom=yes
+else
+  ac_cv_prog_cxx_throw_idiom=no
+fi
+rm -f conftest*
+])
+AC_SUBST(JITTHROWIDIOM)
+if test "x$ac_cv_prog_cxx_throw_idiom" = "xyes" ; then
+       JITTHROWIDIOM='throw()'
+else
+       JITTHROWIDIOM=''
+fi
+
+dnl Determine if the C++ compiler understands the "-fno-gcse" option.
+dnl We will get better code in the interpreter if we use this option.
+AC_CACHE_CHECK(for -fno-gcse option, ac_cv_prog_no_gcse,
+[echo 'int main(int argc, char **argv){ return 0;}' > conftest.c
+if test -z "`${CXX-c++} -fno-gcse -o conftest conftest.c 2>&1`"; then
+  ac_cv_prog_no_gcse=yes
+else
+  ac_cv_prog_no_gcse=no
+fi
+rm -f conftest*
+])
+if test "x$ac_cv_prog_no_gcse" = "xyes" ; then
+       CXXFLAGS="-fno-gcse $CXXFLAGS"
+fi
+
+dnl Checks for library functions.
+if test "x$suppress_libm" = "xno" ; then
+       AC_CHECK_LIB(m, sin)
+fi
+if test "x$platform_win32" = "xno" ; then
+       AC_CHECK_LIB(dl, dlopen)
+       AC_CHECK_LIB(pthread, pthread_create)
+fi
+AC_FUNC_MEMCMP
+AC_CHECK_FUNCS(memset memcmp memchr memcpy memmove bcopy bzero bcmp)
+AC_CHECK_FUNCS(strlen strcpy strcat strncpy strcmp strncmp)
+AC_CHECK_FUNCS(strcoll _strcoll stricoll _stricoll strcasecmp)
+AC_CHECK_FUNCS(strncoll _strncoll strnicoll _strnicoll strncasecmp)
+AC_CHECK_FUNCS(strchr strrchr vsprintf vsnprintf _vsnprintf getpagesize)
+AC_CHECK_FUNCS(isnan isinf finite fmod remainder drem ceil floor)
+AC_CHECK_FUNCS(acos asin atan atan2 cos cosh exp log log10 pow)
+AC_CHECK_FUNCS(sin sinh sqrt tan tanh)
+AC_CHECK_FUNCS(isnanf isinff finitef fmodf remainderf dremf ceilf floorf)
+AC_CHECK_FUNCS(acosf asinf atanf atan2f cosf coshf expf logf log10f powf)
+AC_CHECK_FUNCS(sinf sinhf sqrtf tanf tanhf)
+AC_CHECK_FUNCS(isnanl isinfl finitel fmodl remainderl dreml ceill floorl)
+AC_CHECK_FUNCS(acosl asinl atanl atan2l cosl coshl expl logl log10l powl)
+AC_CHECK_FUNCS(sinl sinhl sqrtl tanl tanhl)
+AC_CHECK_FUNCS(dlopen cygwin_conv_to_win32_path mmap munmap mprotect)
+AC_FUNC_ALLOCA
+
+AC_OUTPUT([
+Makefile
+include/Makefile
+include/jit/Makefile
+include/jit/jit-defs.h
+tools/Makefile
+jit/Makefile
+jitplus/Makefile
+dpas/Makefile
+tutorial/Makefile
+doc/Makefile])
diff --git a/doc/.cvsignore b/doc/.cvsignore
new file mode 100644 (file)
index 0000000..ef955d2
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+.deps
+libjit.info*
+libjitext-*
+*.pdf
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..d24d152
--- /dev/null
@@ -0,0 +1,100 @@
+
+man_MANS        = libjit.3
+EXTRA_DIST      = $(man_MANS)
+
+info_TEXINFOS   = libjit.texi
+libjit_TEXINFOS = \
+       $(srcdir)/libjitext-alloc.texi \
+       $(srcdir)/libjitext-apply.texi \
+       $(srcdir)/libjitext-block.texi \
+       $(srcdir)/libjitext-context.texi \
+       $(srcdir)/libjitext-dynlib.texi \
+       $(srcdir)/libjitext-elf-read.texi \
+       $(srcdir)/libjitext-except.texi \
+       $(srcdir)/libjitext-function.texi \
+       $(srcdir)/libjitext-init.texi \
+       $(srcdir)/libjitext-insn.texi \
+       $(srcdir)/libjitext-intrinsic.texi \
+       $(srcdir)/libjitext-memory.texi \
+       $(srcdir)/libjitext-meta.texi \
+       $(srcdir)/libjitext-reg-alloc.texi \
+       $(srcdir)/libjitext-rules-interp.texi \
+       $(srcdir)/libjitext-string.texi \
+       $(srcdir)/libjitext-type.texi \
+       $(srcdir)/libjitext-value.texi \
+       $(srcdir)/libjitext-walk.texi \
+       $(srcdir)/libjitext-plus-context.texi \
+       $(srcdir)/libjitext-plus-function.texi \
+       $(srcdir)/libjitext-plus-value.texi
+
+$(srcdir)/libjitext-alloc.texi: $(top_srcdir)/jit/jit-alloc.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-apply.texi: $(top_srcdir)/jit/jit-apply.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-block.texi: $(top_srcdir)/jit/jit-block.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-context.texi: $(top_srcdir)/jit/jit-context.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-dynlib.texi: $(top_srcdir)/jit/jit-dynlib.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-elf-read.texi: $(top_srcdir)/jit/jit-elf-read.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-except.texi: $(top_srcdir)/jit/jit-except.cpp
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-function.texi: $(top_srcdir)/jit/jit-function.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-init.texi: $(top_srcdir)/jit/jit-init.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-insn.texi: $(top_srcdir)/jit/jit-insn.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-intrinsic.texi: $(top_srcdir)/jit/jit-intrinsic.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-memory.texi: $(top_srcdir)/jit/jit-memory.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-meta.texi: $(top_srcdir)/jit/jit-meta.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-reg-alloc.texi: $(top_srcdir)/jit/jit-reg-alloc.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-rules-interp.texi: $(top_srcdir)/jit/jit-rules-interp.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-string.texi: $(top_srcdir)/jit/jit-string.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-type.texi: $(top_srcdir)/jit/jit-type.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-value.texi: $(top_srcdir)/jit/jit-value.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-walk.texi: $(top_srcdir)/jit/jit-walk.c
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-plus-context.texi: \
+               $(top_srcdir)/jitplus/jit-plus-context.cpp
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-plus-function.texi: \
+               $(top_srcdir)/jitplus/jit-plus-function.cpp
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+$(srcdir)/libjitext-plus-value.texi: \
+               $(top_srcdir)/jitplus/jit-plus-value.cpp
+       $(SHELL) $(srcdir)/extract-docs.sh $< >$@
+
+CLEANFILES = $(srcdir)/libjit.info $(srcdir)/libjit.info-* \
+                        $(srcdir)/libjitext-*.texi
diff --git a/doc/extract-docs.sh b/doc/extract-docs.sh
new file mode 100755 (executable)
index 0000000..ccc8311
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# extract-docs.sh - Extract texinfo documentation from a source file.
+#
+# Usage: extract-docs.sh source.c >output.texi
+#
+# Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+in_doc=false
+echo ''
+echo "@c Extracted automatically from $1 - DO NOT EDIT"
+echo ''
+while read LINE ; do
+       case "$LINE" in
+               /\*@*)  in_doc=true ;;
+               @\*/*)  echo ''
+                               in_doc=false ;;
+                   *)  if test "$in_doc" = true ; then
+                                       echo "$LINE"
+                               fi ;;
+       esac
+done < "$1" | sed -e '1,$s/^ *\* *//'
+
+exit 0
diff --git a/doc/libjit.3 b/doc/libjit.3
new file mode 100644 (file)
index 0000000..fe31480
--- /dev/null
@@ -0,0 +1,49 @@
+.\" Copyright (c) 2004 Southern Storm Software, Pty Ltd.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+.TH libjit 3 "18 April 2004" "Southern Storm Software" "Just-In-Time Compiler Library"
+.SH NAME
+libjit \- Just-In-Time Compiler Library
+.SH SYNOPSIS
+.ll +8
+.B #include <jit/jit.h>
+
+Link with
+.B -ljit
+.SH DESCRIPTION
+The \fBlibjit\fR library has an extensive set of routines that takes care
+of the bulk of the Just-In-Time compilation process, without tying the
+programmer down with language or bytecode specifics.
+
+Unlike other systems such as the JVM, .NET, Parrot, and LLVM, \fBlibjit\fR
+is not a virtual machine in its own right.  It is the foundation upon which a
+number of different virtual machines, dynamic scripting languages, etc,
+can be built.
+.SH "AUTHOR"
+Written by Southern Storm Software, Pty Ltd.
+
+http://www.southern-storm.com.au/
+.SH "SEE ALSO"
+The full documentation for
+.B libjit
+is maintained as a Texinfo manual.  If the
+.B info
+and
+.B libjit
+programs are properly installed at your site, the command
+.IP
+.B info libjit
+.PP
+should give you access to the complete manual.
diff --git a/doc/libjit.texi b/doc/libjit.texi
new file mode 100644 (file)
index 0000000..8fd4c35
--- /dev/null
@@ -0,0 +1,1247 @@
+\input texinfo @c -*-texinfo-*-
+@c %** start of header
+@setfilename libjit.info
+@settitle Just-In-Time Compiler Library
+@setchapternewpage off
+@c %** end of header
+
+@dircategory Libraries
+@direntry
+* Libjit: (libjit).                Just-In-Time Compiler Library
+@end direntry
+
+@ifinfo
+The libjit library assists with the process of building
+Just-In-Time compilers for languages, virtual machines,
+and emulators.
+
+Copyright @copyright{} 2004 Southern Storm Software, Pty Ltd
+@end ifinfo
+
+@titlepage
+@sp 10
+@center @titlefont{Just-In-Time Compiler Library}
+
+@vskip 0pt plus 1fill
+@center{Copyright @copyright{} 2004 Southern Storm Software, Pty Ltd}
+@end titlepage
+
+@syncodeindex fn cp
+@syncodeindex vr cp
+@syncodeindex tp cp
+
+@c -----------------------------------------------------------------------
+
+@node Top, Introduction, , (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
+* ELF Binaries::            Manipulating ELF binaries
+* Utility Routines::        Miscellaneous utility routines
+* C++ Interface::           Using libjit from C++
+* Porting::                 Porting libjit to new architectures
+* Why GPL?::                Why we use GPL and not LGPL for libjit
+* Index::                   Index of concepts and facilities
+@end menu
+
+@c -----------------------------------------------------------------------
+
+@node Introduction, Features, Top, Top
+@chapter Introduction and rationale for libjit
+@cindex Introduction
+
+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 @code{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, Parrot, and LLVM, @code{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.
+
+This 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
+@code{libjit}, broken down by function category.
+
+@section Obtaining libjit
+
+The latest version of @code{libjit} can be obtained from Southern
+Storm Software, Pty Ltd's Web site:
+
+@quotation
+@uref{http://www.southern-storm.com.au/libjit.html}
+@end quotation
+
+@section Further reading
+
+While it isn't strictly necessary to know about compiler internals
+to use @code{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:
+
+@quotation
+Alfred V. Aho, Ravi Sethi, and Jeffrey D. Ullman, "Compilers:
+Principles, Techniques, and Tools", Addison-Wesley, 1986.
+@end quotation
+
+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 @code{libjit}, then you may want to make yourself familiar
+with the relevant literature (this is by no means a complete list):
+
+@quotation
+IBM's Jikes RVM (Research Virtual Machine), @*
+@uref{http://www-124.ibm.com/developerworks/oss/jikesrvm/}.
+
+Intel's ORP (Open Runtime Platform), @*
+@uref{http://orp.sourceforge.net/}.
+@end quotation
+
+@c -----------------------------------------------------------------------
+
+@node Features, Tutorials, Introduction, Top
+@chapter Features of libjit
+@cindex Features
+
+@itemize
+@item
+The primary interface is in C, for maximal reusability.  Class
+interfaces are available for programmers who prefer C++.
+
+@item
+Designed for portability to all major 32-bit and 64-bit platforms.
+
+@item
+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.
+
+@item
+Up-front or on-demand compilation of any function.
+
+@item
+In-built support to re-compile functions with greater optimization,
+automatically redirecting previous callers to the new version.
+
+@item
+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.
+
+@item
+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.
+
+@item
+Large set of mathematical and trigonometric operations
+(sqrt, sin, cos, min, abs, etc) for inlining floating-point library functions.
+
+@item
+Simplified type layout and exception handling mechanisms, upon which a
+variety of different object models can be built.
+
+@item
+Support for nested functions, able to access their parent's local variables
+(for implementing Pascal-style languages).
+@end itemize
+
+@c -----------------------------------------------------------------------
+
+@node Tutorials, Tutorial 1, Features, Top
+@chapter Tutorials in using libjit
+@cindex Tutorials
+
+In this chapter, we describe how to use @code{libjit} with a number of
+short tutorial exercises.  Full source for these tutorials can be found
+in the @code{tutorial} directory of the @code{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
+* Dynamic Pascal::          Dynamic Pascal - A full JIT example
+@end menu
+
+@c -----------------------------------------------------------------------
+
+@node Tutorial 1, Tutorial 2, Tutorials, Tutorials
+@section Tutorial 1 - mul_add
+@cindex mul_add tutorial
+
+In the first tutorial, we will build and compile the following function
+(the source code can be found in @code{tutorial/t1.c}):
+
+@example
+int mul_add(int x, int y, int z)
+@{
+    return x * y + z;
+@}
+@end example
+
+@noindent
+To use the JIT, we first include the @code{<jit/jit.h>} file:
+
+@example
+#include <jit/jit.h>
+@end example
+
+All of the header files are placed into the @code{jit} sub-directory,
+to separate them out from regular system headers.  When @code{libjit}
+is installed, you will typically find these headers in
+@code{/usr/local/include/jit} or @code{/usr/include/jit}, depending upon
+how your system is configured.
+
+You should also link with the @code{-ljit} option and use a C++ linker,
+not a C linker (because @code{libjit} contains a small amount of C++ code).
+If you are using Autotools, then you can force the use of a C++ linker
+by adding @code{AC_PROG_CXX} to @code{configure.in} and adding the
+following line to your @code{Makefile.am}:
+
+@example
+CCLD = $(CXX)
+@end example
+
+@noindent
+Every program that uses @code{libjit} needs to call @code{jit_context_create}:
+
+@example
+jit_context_t context;
+...
+context = jit_context_create();
+@end example
+
+Almost everything that is done with @code{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:
+
+@example
+jit_context_build_start(context);
+@end example
+
+The next step is to construct the function object that will represent
+our @code{mul_add} function:
+
+@example
+jit_function_t function;
+...
+function = jit_function_create(context, signature);
+@end example
+
+The @code{signature} is a @code{jit_type_t} object that describes the
+function's parameters and return value.  This tells @code{libjit} how
+to generate the proper calling conventions for the function:
+
+@example
+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);
+@end example
+
+This declares a function that takes three parameters of type
+@code{int} and returns a result of type @code{int}.  We've requested
+that the function use the @code{cdecl} application binary interface (ABI),
+which indicates normal C calling conventions.  @xref{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:
+
+@example
+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);
+@end example
+
+Values are one of the two cornerstones of the @code{libjit} process.
+Values represent parameters, local variables, and intermediate
+temporary results.  Once we have the parameters, we compute
+the result of @code{x * y + z} as follows:
+
+@example
+jit_value_t temp1, temp2;
+...
+temp1 = jit_insn_mul(function, x, y);
+temp2 = jit_insn_add(function, temp1, z);
+@end example
+
+This demonstrates the other cornerstone of the @code{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
+@code{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.  @xref{Instructions}, for
+a complete list of all instructions that are supported by @code{libjit}.
+
+Now that we have computed the desired result, we return it to the caller
+using @code{jit_insn_return}:
+
+@example
+jit_insn_return(function, temp2);
+@end example
+
+We have completed the process of building the function body.  Now we
+compile it into its executable form:
+
+@example
+jit_function_compile(function);
+jit_context_build_end(context);
+@end example
+
+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 @code{mul_add} function.
+All we have done is build and compile it, ready for execution.  To execute it,
+we call @code{jit_function_apply}:
+
+@example
+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);
+@end example
+
+We pass an array of pointers to @code{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 @code{libjit}.  If all went well, the
+program should print the following:
+
+@example
+mul_add(3, 5, 2) = 17
+@end example
+
+You will notice that we used @code{jit_int} as the type of the arguments,
+not @code{int}.  The @code{jit_int} type is guaranteed to be 32 bits
+in size on all platforms, whereas @code{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 @code{int} type, you would use
+@code{jit_type_sys_int} instead of @code{jit_type_int} when you
+created the function's signature.  The @code{jit_type_sys_int} type
+is guaranteed to match the local system's @code{int} precision.
+
+@noindent
+Finally, we clean up the context and all of the memory that was used:
+
+@example
+jit_context_destroy(context);
+@end example
+
+@c -----------------------------------------------------------------------
+
+@node Tutorial 2, Tutorial 3, Tutorial 1, Tutorials
+@section Tutorial 2 - gcd
+@cindex gcd tutorial
+
+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 @code{gcd} function
+is as follows:
+
+@example
+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);
+    @}
+@}
+@end example
+
+The source code for this tutorial can be found in @code{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.
+@xref{Tutorial 1}, for more information.
+
+@noindent
+We start by checking the condition @code{x == y}:
+
+@example
+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);
+@end example
+
+This is very similar to our previous tutorial, except that we are using
+the @code{eq} operator this time.  If the condition is not true, we
+want to skip the @code{return} statement.  We achieve this with the
+@code{jit_insn_branch_if_not} instruction:
+
+@example
+jit_label_t label1 = jit_label_undefined;
+...
+jit_insn_branch_if_not(function, temp1, &label1);
+@end example
+
+The label must be initialized to @code{jit_label_undefined}.  It will be
+updated by @code{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 @code{x} to the caller:
+
+@example
+jit_insn_return(function, x);
+@end example
+
+If the condition was not true, then we branched to @code{label1} above.
+We fix the location of the label using @code{jit_insn_label}:
+
+@example
+jit_insn_label(function, &label1);
+@end example
+
+@noindent
+We use similar code to check the condition @code{x < y}, and branch
+to @code{label2} if it is not true:
+
+@example
+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);
+@end example
+
+At this point, we need to call the @code{gcd} function with the
+arguments @code{x} and @code{y - x}.  The code for this is
+fairly straight-forward.  The @code{jit_insn_call} instruction calls
+the function listed in its third argument.  In this case, we are calling
+ourselves recursively:
+
+@example
+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);
+@end example
+
+The string @code{"gcd"} in the second argument is for diagnostic purposes
+only.  It can be helpful when debugging, but the @code{libjit} library
+otherwise makes no use of it.  You can set it to NULL if you wish.
+
+In general, @code{libjit} does not maintain mappings from names to
+@code{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.
+
+@noindent
+The final part of the @code{gcd} function is similar to the previous one:
+
+@example
+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);
+@end example
+
+@noindent
+We can now compile the function and execute it in the usual manner.
+
+@c -----------------------------------------------------------------------
+
+@node Tutorial 3, Tutorial 4, Tutorial 2, Tutorials
+@section Tutorial 3 - compiling on-demand
+@cindex On-demand compilation tutorial
+
+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 @code{tutorial/t3.c}.
+
+When the @code{mul_add} function is created, we don't create its function
+body or call @code{jit_function_compile}.  We instead provide a
+C function called @code{compile_mul_add} that performs on-demand
+compilation:
+
+@example
+jit_function_t function;
+...
+function = jit_function_create(context, signature);
+jit_function_set_on_demand_compiler(function, compile_mul_add);
+@end example
+
+We can now call this function with @code{jit_function_apply}, and the
+system will automatically call @code{compile_mul_add} for us if the
+function hasn't been built yet.  The contents of @code{compile_mul_add}
+are fairly obvious:
+
+@example
+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;
+@}
+@end example
+
+When the on-demand compiler returns, @code{libjit} will call
+@code{jit_function_compile} and then jump to the newly compiled code.
+Upon the second and subsequent calls to the function, @code{libjit}
+will bypass the on-demand compiler and call the compiled code directly.
+
+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:
+
+@example
+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);
+@end example
+
+Then, you force the function to be recompiled with a call to
+@code{jit_function_recompile}:
+
+@example
+jit_function_recompile(function);
+@end example
+
+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 @code{mul_add}.  In a real program, you would probably call
+@code{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
+@code{jit_function_clear_recompilable} so that @code{libjit} can
+manage the function more efficiently from then on.
+
+The exact conditions under which a function should be recompiled
+are not specified by @code{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.
+
+@c -----------------------------------------------------------------------
+
+@node Tutorial 4, Dynamic Pascal, Tutorial 3, Tutorials
+@section Tutorial 4 - mul_add, C++ version
+@cindex mul_add C++ tutorial
+
+While @code{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 @code{libjitplus} library.
+
+@noindent
+To use the @code{libjitplus} library, we first include
+the @code{<jit/jit-plus.h>} file:
+
+@example
+#include <jit/jit-plus.h>
+@end example
+
+This file incorporates all of the definitions from @code{<jit/jit.h>},
+so you have full access to the underlying C API if you need it.
+
+This time, instead of building the @code{mul_add} function with
+@code{jit_function_create} and friends, we define a class to represent it:
+
+@example
+class mul_add_function : public jit_function
+@{
+public:
+    mul_add_function(jit_context& context) : jit_function(context)
+    @{
+        create();
+        set_recompilable();
+    @}
+
+protected:
+    virtual jit_type_t create_signature();
+    virtual void build();
+@};
+@end example
+
+Where we used @code{jit_function_t} and @code{jit_context_t} before,
+we now use the C++ @code{jit_function} and @code{jit_context} classes.
+
+In our constructor, we attach ourselves to the context and then call
+the @code{create()} method.  This is in turn will call our overridden
+virtual method @code{create_signature()} to obtain the signature:
+
+@example
+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);
+@}
+@end example
+
+The @code{signature_helper()} method is provided for your convenience,
+to help with building function signatures.  You can create your own
+signature manually using @code{jit_type_create_signature} if you wish.
+
+The final thing we do in the constructor is call @code{set_recompilable()}
+to mark the @code{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 @code{build()} method to build the function's body on-demand:
+
+@example
+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);
+@}
+@end example
+
+This is similar to the first version that we wrote in Tutorial 1.
+Instructions are created with @code{insn_*} methods that correspond
+to their @code{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 @code{jit_value} objects.
+This can simplify the function build process considerably when we
+have lots of expressions to compile.  We could have used @code{insn_mul}
+and @code{insn_add} instead in this example and the result would have
+been the same.
+
+Now that we have our @code{mul_add_function} class, we can create
+an instance of the function and apply it as follows:
+
+@example
+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);
+@end example
+
+@noindent
+@xref{C++ Interface}, for more information on the @code{libjitplus}
+library.
+
+@c -----------------------------------------------------------------------
+
+@node Dynamic Pascal, Initialization, Tutorial 4, Tutorials
+@section Dynamic Pascal - A full JIT example
+@cindex Dynamic Pascal
+
+This @code{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 @code{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 @code{dpas name.pas}.  You may also
+need to pass the @code{-I} option to specify the location of the system
+library if you have used an @code{import} clause in your program.  e.g.
+@code{dpas -I$HOME/libjit/dpas/library name.pas}.
+
+@noindent
+This Pascal grammar is based on the EBNF description at the following URL:
+
+@uref{http://www.cs.qub.ac.uk/~S.Fitzpatrick/Teaching/Pascal/EBNF.html}
+
+@noindent
+There are a few differences to "Standard Pascal":
+
+@enumerate
+@item
+Identifiers are case-insensitive, but case-preserving.
+
+@item
+Program headings are normally @code{program Name (Input, Output);}.  This can
+be abbreviated to @code{program Name;} as the program modifiers are ignored.
+
+@item
+Some GNU Pascal operators like @code{xor}, @code{shl}, @code{@@}, etc
+have been added.
+
+@item
+The integer type names (@code{Integer}, @code{Cardinal}, @code{LongInt}, etc)
+follow those used in GNU Pascal also.  The @code{Integer} type is always
+32-bits in size, while @code{LongInt} is always 64-bits in size.
+
+@item
+The types @code{SysInt}, @code{SysCard}, @code{SysLong}, @code{SysLongCard},
+@code{SysLongestInt}, and @code{SysLongestCard} are guaranteed to be the
+same size as the underlying C system's @code{int}, @code{unsigned int},
+@code{long}, @code{unsigned long}, @code{long long}, and
+@code{unsigned long long} types.
+
+@item
+The type @code{Address} is logically equivalent to C's @code{void *}.
+Any pointer or array can be implicitly cast to @code{Address}.  An explicit
+cast is required to cast back to a typed pointer (you cannot cast back
+to an array).
+
+@item
+The @code{String} type is declared as @code{^Char}.  Single-dimensional
+arrays of @code{Char} can be implicitly cast to any @code{String}
+destination.  Strings are not bounds-checked, so be careful.  Arrays
+are bounds-checked.
+
+@item
+Pointers can be used as arrays.  e.g. @code{p[n]} will access the n'th
+item of an unbounded array located at @code{p}.  Use with care.
+
+@item
+We don't support @code{file of} types.  Data can be written to stdout
+using @code{Write} and @code{WriteLn}, but that is the extent of
+the I/O facilities.
+
+@item
+The declaration @code{import Name1, Name2, ...;} can be used at the head of a
+program to declare additional files to include.  e.g. @code{import stdio} will
+import the contents of @code{stdio.pas}.  We don't support units.
+
+@item
+The idiom @code{; ..} 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 @code{va_arg(Type)} is used to extract the arguments.
+
+@item
+The directive @code{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 @code{puts} and @code{printf} functions:
+
+@example
+function puts (str : String) : SysInt; import ("libc")
+function printf (format : String; ..) : SysInt; import ("libc")
+@end example
+
+Functions that are imported in this manner have case-sensitive names.
+i.e. using @code{Printf} above will fail.
+
+@item
+The @code{throw} keyword can be used to throw an exception.  The argument
+must be a pointer.  The @code{try}, @code{catch}, and @code{finally}
+keywords are used to manage such exceptions further up the stack.  e.g.
+
+@example
+try
+    ...
+catch Name : Type
+    ...
+finally
+    ...
+end
+@end example
+
+The @code{catch} block will be invoked with the exception pointer that was
+supplied to @code{throw}, after casting it to @code{Type} (which must
+be a pointer type).  Specifying @code{throw} on its own without an argument
+will rethrow the current exception pointer, and can only be used inside a
+@code{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 @code{^Name}
+to see what the indicator says.
+
+@item
+The @code{exit} keyword can be used to break out of a loop.
+
+@item
+Function calls can be used as procedure calls.  The return value is ignored.
+
+@item
+Hexadecimal constants can be expressed as @code{XXH}.  The first digit
+must be between 0 and 9, but the remaining digits can be any hex digit.
+
+@item
+Ternary conditionals can be expressed as @code{(if e1 then e2 else e3)}.
+The brackets are required.  This is equivalent to C's @code{e1 ? e2 : e3}.
+
+@item
+Assigning to a function result will immediately return.  i.e. it is
+similar to @code{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.
+
+@item
+The term @code{sizeof(Type)} can be used to get the size of a type.
+
+@item
+Procedure and function headings can appear in a record type to declare a
+field with a @code{pointer to procedure/function} type.
+@end enumerate
+
+@c -----------------------------------------------------------------------
+
+@node Initialization, Functions, Dynamic Pascal, Top
+@chapter Initializing the JIT
+@cindex Initialization
+@cindex Contexts
+
+@include libjitext-init.texi
+@include libjitext-context.texi
+
+@c -----------------------------------------------------------------------
+
+@node Functions, Types, Initialization, Top
+@chapter Building and compiling functions with the JIT
+@cindex Building functions
+@cindex Compiling functions
+
+@include libjitext-function.texi
+
+@c -----------------------------------------------------------------------
+
+@node Types, Values, Functions, Top
+@chapter Manipulating system types
+@cindex Manipulating system types
+
+@include libjitext-type.texi
+
+@c -----------------------------------------------------------------------
+
+@node Values, Instructions, Types, Top
+@chapter Working with temporary values in the JIT
+@cindex Working with values
+
+@include libjitext-value.texi
+
+@c -----------------------------------------------------------------------
+
+@node Instructions, Basic Blocks, Values, Top
+@chapter Working with instructions in the JIT
+@cindex Working with instructions
+
+@include libjitext-insn.texi
+
+@c -----------------------------------------------------------------------
+
+@node Basic Blocks, Intrinsics, Instructions, Top
+@chapter Working with basic blocks in the JIT
+@cindex Working with basic blocks
+
+@include libjitext-block.texi
+
+@c -----------------------------------------------------------------------
+
+@node Intrinsics, Exceptions, Basic Blocks, Top
+@chapter Intrinsic functions available to libjit users
+@cindex Intrinsics
+
+@include libjitext-intrinsic.texi
+
+@c -----------------------------------------------------------------------
+
+@node Exceptions, ELF Binaries, Intrinsics, Top
+@chapter Handling exceptions
+@cindex Handling exceptions
+
+@include libjitext-except.texi
+
+@c -----------------------------------------------------------------------
+
+@node ELF Binaries, Utility Routines, Exceptions, Top
+@chapter Manipulating ELF binaries
+@cindex ELF binaries
+
+@include libjitext-elf-read.texi
+
+@c -----------------------------------------------------------------------
+
+@node Utility Routines, C++ Interface, ELF Binaries, Top
+@chapter Miscellaneous utility routines
+@cindex Utility routines
+@cindex jit-util.h
+
+The @code{libjit} library provides a number of utility routines
+that it itself uses internally, but which may also be useful to front ends.
+
+@include libjitext-alloc.texi
+@include libjitext-memory.texi
+@include libjitext-string.texi
+@include libjitext-meta.texi
+@include libjitext-apply.texi
+@include libjitext-walk.texi
+@include libjitext-dynlib.texi
+
+@c -----------------------------------------------------------------------
+
+@node C++ Interface, C++ Contexts, Utility Routines, Top
+@chapter Using libjit from C++
+@cindex Using libjit from C++
+
+This chapter describes the classes and methods that are available
+in the @code{libjitplus} library.  To use this library, you must
+include the header @code{<jit/jit-plus.h>} and link with the
+@code{-ljitplus} and @code{-ljit} options.
+
+@menu
+* C++ Contexts::            Contexts in C++
+* C++ Values::              Values in C++
+* C++ Functions::           Functions in C++
+@end menu
+
+@c -----------------------------------------------------------------------
+
+@node C++ Contexts, C++ Values, C++ Interface, C++ Interface
+@chapter Contexts in C++
+@cindex C++ contexts
+
+@include libjitext-plus-context.texi
+
+@c -----------------------------------------------------------------------
+
+@node C++ Values, C++ Functions, C++ Contexts, C++ Interface
+@chapter Values in C++
+@cindex C++ values
+
+@include libjitext-plus-value.texi
+
+@c -----------------------------------------------------------------------
+
+@node C++ Functions, Porting, C++ Values, C++ Interface
+@chapter Functions in C++
+@cindex C++ functions
+
+@include libjitext-plus-function.texi
+
+@c -----------------------------------------------------------------------
+
+@node Porting, Porting Apply, C++ Functions, Top
+@chapter Porting libjit to new architectures
+@cindex Porting libjit
+
+This chapter describes what needs to be done to port @code{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 @code{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. @code{x86}, @code{arm}, @code{ppc}, etc).  By
+convention, all back end functions should be prefixed with @code{_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
+@end menu
+
+@c -----------------------------------------------------------------------
+
+@node Porting Apply, Instruction Generation, Porting, Porting
+@section Porting the function apply facility
+@cindex Porting apply
+
+The first step in porting @code{libjit} to a new architecture is to port
+the @code{jit_apply} facility.  This provides support for calling
+arbitrary C functions from your application or from JIT'ed code.
+If you are familiar with @code{libffi} or @code{ffcall}, then
+@code{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 @code{jit_apply} to each new architecture.
+
+The @code{libjit} library makes use of gcc's @code{__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:
+
+@table @code
+@item stack_args
+Pointer to an array of argument values to push onto the stack.
+
+@item struct_ptr
+Pointer to the buffer to receive a @code{struct} return value.
+The @code{struct_ptr} field is only present if the architecture
+passes @code{struct} pointers in a special register.
+
+@item 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.
+
+@item float_reg[0..N]
+Values for the floating-point registers.  Not present if the architecture
+does not use floating-point registers for function calls.
+@end table
+
+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 @code{gen-apply} program in @code{libjit/tools}
+takes care of this.  It outputs the @code{jit-apply-rules.h} file,
+which tells @code{jit_apply} how to operate.
+
+The @code{gen-apply} program will normally "just work", but it is possible
+that some architectures will be stranger than usual.  You will need to modify
+@code{gen-apply} to detect this additional strangeness, and perhaps
+also modify @code{libjit/jit/jit-apply.c}.
+
+If you aren't using gcc to compile @code{libjit}, then things may
+not be quite this easy.  You may have to write some inline assembly
+code to emulate @code{__builtin_apply}.  See the file
+@code{jit-apply-x86.h} for an example of how to do this.
+Be sure to add an @code{#include} line to @code{jit-apply-func.h}
+once you do this.
+
+The other half of @code{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 @code{jit-apply-x86.c} and
+@code{jit-apply-arm.c} for some examples from existing architectures.
+You may be able to get some ideas from the @code{libffi} and
+@code{ffcall} libraries as to what you need to do on your architecture.
+
+@c -----------------------------------------------------------------------
+
+@node Instruction Generation, Architecture Rules, Porting Apply, Porting
+@section Creating the instruction generation macros
+@cindex 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 @code{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 @code{jit-gen-ARCH.h}
+in the @code{libjit/jit} directory.  If some of the macros are complicated,
+you can place helper functions into the file @code{jit-gen-ARCH.c}.
+Remember to add both @code{jit-gen-ARCH.h} and @code{jit-gen-ARCH.c}
+to @code{Makefile.am} in @code{libjit/jit}.
+
+Existing examples that you can look at for ideas are @code{jit-gen-x86.h}
+and @code{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 @code{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.
+
+@c -----------------------------------------------------------------------
+
+@node Architecture Rules, Register Allocation, Instruction Generation, Porting
+@section Writing the architecture definition rules
+@cindex Architecture definition rules
+
+@include libjitext-rules-interp.texi
+
+@c -----------------------------------------------------------------------
+
+@node Register Allocation, Why GPL?, Architecture Rules, Porting
+@section Allocating registers in the back end
+@cindex Register allocation
+
+@include libjitext-reg-alloc.texi
+
+@c -----------------------------------------------------------------------
+
+@node Why GPL?, Index, Register Allocation, Top
+@chapter Why we use GPL and not LGPL for libjit
+@cindex Why GPL?
+
+A common question about @code{libjit} is likely to be why we use the
+GNU General Public License instead of the GNU Lesser General Public
+License.
+
+At its core, the issue is "Who are we helping gain extra value?".  We wish
+to help the authors of other Free Software projects, as well as those who
+are working on Open Source projects with licenses that are compatible with
+the GPL.  But we do not wish to help proprietary software companies
+without adequate compensation to the community.
+
+Consider the following scenario: a proprietary software company devises
+a new programming language and a new virtual machine to go with it.
+However, their implementation isn't very compelling to customers
+because its bytecode interpreter is too slow.
+
+If @code{libjit} was distributed under the terms of the LGPL, the
+company could link against the library and get a compelling implementation.
+This would increase the sale value of their software considerably.
+However, they wouldn't be compelled to give anything back to the
+Free Software community in exchange for this extra value.
+
+Under the GPL, the company must either GPL their own code, write their
+own JIT from scratch, or negotiate a separate license with the authors
+of @code{libjit}.  In the first instance, they give back to the community
+the value they have used.  In the second instance, they neither give value
+to nor take value from the community.  In the third instance, the authors
+are compensated for their work, which allows those authors to continue
+contributing Free Software to the community.
+
+For more information on why we have taken this stance, please read the
+document "Why you shouldn't use the Library GPL for your next library" on
+the Free Software Foundation's Web site:
+
+@quotation
+@uref{http://www.gnu.org/licenses/why-not-lgpl.html}.
+@end quotation
+
+@c -----------------------------------------------------------------------
+
+@page
+
+@node Index, , Why GPL?, Top
+@unnumbered Index of concepts and facilities
+
+@printindex cp
+
+@contents
+@bye
diff --git a/doc/mkhtml.sh b/doc/mkhtml.sh
new file mode 100755 (executable)
index 0000000..0af42f8
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# mkhtml.sh - Make html documentation from Texinfo input.
+#
+# Usage: mkhtml outdir
+
+# Check the command-line.
+if [ -z "$1" ]; then
+       echo "Usage: $0 outdir"
+       exit 1
+fi
+
+# Check that we are executed in the correct directory.
+if [ ! -f libjit.texi ]; then
+       echo "Cannot find libjit.texi"
+       exit 1
+fi
+
+# Create the output directory.
+if [ ! -d "$1" ]; then
+       mkdir "$1"
+fi
+
+# Get the full pathname of the input file.
+PATHNAME=`pwd`/libjit.texi
+
+# Change to the output directory and execute "texi2html".
+cd "$1"
+exec texi2html -split_chapter "$PATHNAME"
diff --git a/doc/mkpdf.sh b/doc/mkpdf.sh
new file mode 100755 (executable)
index 0000000..84eae06
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+#
+# mkpdf - Make the PDF version of texinfo documentation
+
+exec texi2dvi --pdf libjit.texi
diff --git a/doc/texinfo.tex b/doc/texinfo.tex
new file mode 100644 (file)
index 0000000..aa52853
--- /dev/null
@@ -0,0 +1,5484 @@
+% texinfo.tex -- TeX macros to handle Texinfo files.
+%
+% Load plain if necessary, i.e., if running under initex.
+\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
+%
+\def\texinfoversion{1999-01-05}%
+%
+% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98
+% Free Software Foundation, Inc.
+%
+% This texinfo.tex file is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License as
+% published by the Free Software Foundation; either version 2, or (at
+% your option) any later version.
+%
+% This texinfo.tex file is distributed in the hope that it will be
+% useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+% General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this texinfo.tex file; see the file COPYING.  If not, write
+% to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+% Boston, MA 02111-1307, USA.
+%
+% In other words, you are welcome to use, share and improve this program.
+% You are forbidden to forbid anyone else to use, share and improve
+% what you give them.   Help stamp out software-hoarding!
+%
+% Please try the latest version of texinfo.tex before submitting bug
+% reports; you can get the latest version from:
+%   ftp://ftp.gnu.org/pub/gnu/texinfo.tex
+%   /home/gd/gnu/doc/texinfo.tex on the GNU machines.
+%   (and all GNU mirrors, see http://www.gnu.org/order/ftp.html)
+%   ftp://tug.org/tex/texinfo.tex
+%   ftp://ctan.org/macros/texinfo/texinfo.tex
+%   (and all CTAN mirrors, finger ctan@ctan.org for a list).
+% The texinfo.tex in the texinfo distribution itself could well be out
+% of date, so if that's what you're using, please check.
+% 
+% Send bug reports to bug-texinfo@gnu.org.
+% Please include a precise test case in each bug report,
+% including a complete document with which we can reproduce the problem.
+% 
+% To process a Texinfo manual with TeX, it's most reliable to use the
+% texi2dvi shell script that comes with the distribution.  For simple
+% manuals, however, you can get away with:
+%   tex foo.texi
+%   texindex foo.??
+%   tex foo.texi
+%   tex foo.texi
+%   dvips foo.dvi -o # or whatever, to process the dvi file.
+% The extra runs of TeX get the cross-reference information correct.
+% Sometimes one run after texindex suffices, and sometimes you need more
+% than two; texi2dvi does it as many times as necessary.
+
+\message{Loading texinfo [version \texinfoversion]:}
+
+% If in a .fmt file, print the version number
+% and turn on active characters that we couldn't do earlier because
+% they might have appeared in the input file name.
+\everyjob{\message{[Texinfo version \texinfoversion]}%
+  \catcode`+=\active \catcode`\_=\active}
+
+% Save some parts of plain tex whose names we will redefine.
+
+\let\ptexb=\b
+\let\ptexbullet=\bullet
+\let\ptexc=\c
+\let\ptexcomma=\,
+\let\ptexdot=\.
+\let\ptexdots=\dots
+\let\ptexend=\end
+\let\ptexequiv=\equiv
+\let\ptexexclam=\!
+\let\ptexi=\i
+\let\ptexlbrace=\{
+\let\ptexrbrace=\}
+\let\ptexstar=\*
+\let\ptext=\t
+
+% We never want plain's outer \+ definition in Texinfo.
+% For @tex, we can use \tabalign.
+\let\+ = \relax
+
+
+\message{Basics,}
+\chardef\other=12
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Set up fixed words for English if not already set.
+\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi
+\ifx\putwordChapter\undefined  \gdef\putwordChapter{Chapter}\fi
+\ifx\putwordfile\undefined     \gdef\putwordfile{file}\fi
+\ifx\putwordInfo\undefined     \gdef\putwordInfo{Info}\fi
+\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi
+\ifx\putwordon\undefined       \gdef\putwordon{on}\fi
+\ifx\putwordpage\undefined     \gdef\putwordpage{page}\fi
+\ifx\putwordsection\undefined  \gdef\putwordsection{section}\fi
+\ifx\putwordSection\undefined  \gdef\putwordSection{Section}\fi
+\ifx\putwordsee\undefined      \gdef\putwordsee{see}\fi
+\ifx\putwordSee\undefined      \gdef\putwordSee{See}\fi
+\ifx\putwordShortContents\undefined  \gdef\putwordShortContents{Short Contents}\fi
+\ifx\putwordTableofContents\undefined\gdef\putwordTableofContents{Table of Contents}\fi
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+\hyphenation{ap-pen-dix}
+\hyphenation{mini-buf-fer mini-buf-fers}
+\hyphenation{eshell}
+\hyphenation{white-space}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen \bindingoffset
+\newdimen \normaloffset
+\newdimen\pagewidth \newdimen\pageheight
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal.  We don't just call \tracingall here,
+% since that produces some useless output on the terminal.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\ifx\eTeXversion\undefined
+\def\loggingall{\tracingcommands2 \tracingstats2
+   \tracingpages1 \tracingoutput1 \tracinglostchars1
+   \tracingmacros2 \tracingparagraphs1 \tracingrestores1
+   \showboxbreadth\maxdimen\showboxdepth\maxdimen
+}%
+\else
+\def\loggingall{\tracingcommands3 \tracingstats2
+   \tracingpages1 \tracingoutput1 \tracinglostchars1
+   \tracingmacros2 \tracingparagraphs1 \tracingrestores1
+   \tracingscantokens1 \tracingassigns1 \tracingifs1
+   \tracinggroups1 \tracingnesting2
+   \showboxbreadth\maxdimen\showboxdepth\maxdimen
+}%
+\fi
+
+% For @cropmarks command.
+% Do @cropmarks to get crop marks.
+% 
+\newif\ifcropmarks
+\let\cropmarks = \cropmarkstrue
+%
+% Dimensions to add cropmarks at corners.
+% Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines
+\newdimen\cornerlong  \cornerlong=1pc
+\newdimen\cornerthick \cornerthick=.3pt
+\newdimen\topandbottommargin \topandbottommargin=.75in
+
+% Main output routine.
+\chardef\PAGE = 255
+\output = {\onepageout{\pagecontents\PAGE}}
+
+\newbox\headlinebox
+\newbox\footlinebox
+
+% \onepageout takes a vbox as an argument.  Note that \pagecontents
+% does insertions, but you have to call it yourself.
+\def\onepageout#1{%
+  \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi
+  %
+  \ifodd\pageno  \advance\hoffset by \bindingoffset
+  \else \advance\hoffset by -\bindingoffset\fi
+  %
+  % Do this outside of the \shipout so @code etc. will be expanded in
+  % the headline as they should be, not taken literally (outputting ''code).
+  \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}%
+  \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}%
+  %
+  {%
+    % Have to do this stuff outside the \shipout because we want it to
+    % take effect in \write's, yet the group defined by the \vbox ends
+    % before the \shipout runs.
+    %
+    \escapechar = `\\     % use backslash in output files.
+    \indexdummies         % don't expand commands in the output.
+    \normalturnoffactive  % \ in index entries must not stay \, e.g., if
+                   % the page break happens to be in the middle of an example.
+    \shipout\vbox{%
+      \ifcropmarks \vbox to \outervsize\bgroup
+        \hsize = \outerhsize
+        \vskip-\topandbottommargin
+        \vtop to0pt{%
+          \line{\ewtop\hfil\ewtop}%
+          \nointerlineskip
+          \line{%
+            \vbox{\moveleft\cornerthick\nstop}%
+            \hfill
+            \vbox{\moveright\cornerthick\nstop}%
+          }%
+          \vss}%
+        \vskip\topandbottommargin
+        \line\bgroup
+          \hfil % center the page within the outer (page) hsize.
+          \ifodd\pageno\hskip\bindingoffset\fi
+          \vbox\bgroup
+      \fi
+      %
+      \unvbox\headlinebox
+      \pagebody{#1}%
+      \ifdim\ht\footlinebox > 0pt
+        % Only leave this space if the footline is nonempty.
+        % (We lessened \vsize for it in \oddfootingxxx.)
+        % The \baselineskip=24pt in plain's \makefootline has no effect.
+        \vskip 2\baselineskip
+        \unvbox\footlinebox
+      \fi
+      %
+      \ifcropmarks
+          \egroup % end of \vbox\bgroup
+        \hfil\egroup % end of (centering) \line\bgroup
+        \vskip\topandbottommargin plus1fill minus1fill
+        \boxmaxdepth = \cornerthick
+        \vbox to0pt{\vss
+          \line{%
+            \vbox{\moveleft\cornerthick\nsbot}%
+            \hfill
+            \vbox{\moveright\cornerthick\nsbot}%
+          }%
+          \nointerlineskip
+          \line{\ewbot\hfil\ewbot}%
+        }%
+      \egroup % \vbox from first cropmarks clause
+      \fi
+    }% end of \shipout\vbox
+  }% end of group with \turnoffactive
+  \advancepageno
+  \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+}
+
+\newinsert\margin \dimen\margin=\maxdimen
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+% marginal hacks, juha@viisa.uucp (Juha Takala)
+\ifvoid\margin\else % marginal info is present
+  \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi
+\dimen@=\dp#1 \unvbox#1
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+% Here are the rules for the cropmarks.  Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+  {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+  {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1.  The argument is the rest of
+% the input line (except we remove a trailing comment).  #1 should be a
+% macro which expects an ordinary undelimited TeX argument.
+%
+\def\parsearg#1{%
+  \let\next = #1%
+  \begingroup
+    \obeylines
+    \futurelet\temp\parseargx
+}
+
+% If the next token is an obeyed space (from an @example environment or
+% the like), remove it and recurse.  Otherwise, we're done.
+\def\parseargx{%
+  % \obeyedspace is defined far below, after the definition of \sepspaces.
+  \ifx\obeyedspace\temp
+    \expandafter\parseargdiscardspace
+  \else
+    \expandafter\parseargline
+  \fi
+}
+
+% Remove a single space (as the delimiter token to the macro call).
+{\obeyspaces %
+ \gdef\parseargdiscardspace {\futurelet\temp\parseargx}}
+
+{\obeylines %
+  \gdef\parseargline#1^^M{%
+    \endgroup % End of the group started in \parsearg.
+    %
+    % First remove any @c comment, then any @comment.
+    % Result of each macro is put in \toks0.
+    \argremovec #1\c\relax %
+    \expandafter\argremovecomment \the\toks0 \comment\relax %
+    %
+    % Call the caller's macro, saved as \next in \parsearg.
+    \expandafter\next\expandafter{\the\toks0}%
+  }%
+}
+
+% Since all \c{,omment} does is throw away the argument, we can let TeX
+% do that for us.  The \relax here is matched by the \relax in the call
+% in \parseargline; it could be more or less anything, its purpose is
+% just to delimit the argument to the \c.
+\def\argremovec#1\c#2\relax{\toks0 = {#1}}
+\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}}
+
+% \argremovec{,omment} might leave us with trailing spaces, though; e.g.,
+%    @end itemize  @c foo
+% will have two active spaces as part of the argument with the
+% `itemize'.  Here we remove all active spaces from #1, and assign the
+% result to \toks0.
+%
+% This loses if there are any *other* active characters besides spaces
+% in the argument -- _ ^ +, for example -- since they get expanded.
+% Fortunately, Texinfo does not define any such commands.  (If it ever
+% does, the catcode of the characters in questionwill have to be changed
+% here.)  But this means we cannot call \removeactivespaces as part of
+% \argremovec{,omment}, since @c uses \parsearg, and thus the argument
+% that \parsearg gets might well have any character at all in it.
+%
+\def\removeactivespaces#1{%
+  \begingroup
+    \ignoreactivespaces
+    \edef\temp{#1}%
+    \global\toks0 = \expandafter{\temp}%
+  \endgroup
+}
+
+% Change the active space to expand to nothing.
+%
+\begingroup
+  \obeyspaces
+  \gdef\ignoreactivespaces{\obeyspaces\let =\empty}
+\endgroup
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+%% These are used to keep @begin/@end levels from running away
+%% Call \inENV within environments (after a \begingroup)
+\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
+\def\ENVcheck{%
+\ifENV\errmessage{Still within an environment; press RETURN to continue}
+\endgroup\fi} % This is not perfect, but it should reduce lossage
+
+% @begin foo  is the same as @foo, for now.
+\newhelp\EMsimple{Press RETURN to continue.}
+
+\outer\def\begin{\parsearg\beginxxx}
+
+\def\beginxxx #1{%
+\expandafter\ifx\csname #1\endcsname\relax
+{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
+\csname #1\endcsname\fi}
+
+% @end foo executes the definition of \Efoo.
+%
+\def\end{\parsearg\endxxx}
+\def\endxxx #1{%
+  \removeactivespaces{#1}%
+  \edef\endthing{\the\toks0}%
+  %
+  \expandafter\ifx\csname E\endthing\endcsname\relax
+    \expandafter\ifx\csname \endthing\endcsname\relax
+      % There's no \foo, i.e., no ``environment'' foo.
+      \errhelp = \EMsimple
+      \errmessage{Undefined command `@end \endthing'}%
+    \else
+      \unmatchedenderror\endthing
+    \fi
+  \else
+    % Everything's ok; the right environment has been started.
+    \csname E\endthing\endcsname
+  \fi
+}
+
+% There is an environment #1, but it hasn't been started.  Give an error.
+%
+\def\unmatchedenderror#1{%
+  \errhelp = \EMsimple
+  \errmessage{This `@end #1' doesn't have a matching `@#1'}%
+}
+
+% Define the control sequence \E#1 to give an unmatched @end error.
+%
+\def\defineunmatchedend#1{%
+  \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}%
+}
+
+
+% Single-spacing is done by various environments (specifically, in
+% \nonfillstart and \quotations).
+\newskip\singlespaceskip \singlespaceskip = 12.5pt
+\def\singlespace{%
+  % Why was this kern here?  It messes up equalizing space above and below
+  % environments.  --karl, 6may93
+  %{\advance \baselineskip by -\singlespaceskip
+  %\kern \baselineskip}%
+  \setleading \singlespaceskip
+}
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\tt\char64}}
+
+% This is turned off because it was never documented
+% and you can use @w{...} around a quote to suppress ligatures.
+%% Define @` and @' to be the same as ` and '
+%% but suppressing ligatures.
+%\def\`{{`}}
+%\def\'{{'}}
+
+% Used to generate quoted braces.
+\def\mylbrace {{\tt\char123}}
+\def\myrbrace {{\tt\char125}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+\begingroup
+  % Definitions to produce actual \{ & \} command in an index.
+  \catcode`\{ = 12 \catcode`\} = 12
+  \catcode`\[ = 1 \catcode`\] = 2
+  \catcode`\@ = 0 \catcode`\\ = 12
+  @gdef@lbracecmd[\{]%
+  @gdef@rbracecmd[\}]%
+@endgroup
+
+% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent
+% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H.
+\let\, = \c
+\let\dotaccent = \.
+\def\ringaccent#1{{\accent23 #1}}
+\let\tieaccent = \t
+\let\ubaraccent = \b
+\let\udotaccent = \d
+
+% Other special characters: @questiondown @exclamdown
+% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss.
+\def\questiondown{?`}
+\def\exclamdown{!`}
+
+% Dotless i and dotless j, used for accents.
+\def\imacro{i}
+\def\jmacro{j}
+\def\dotless#1{%
+  \def\temp{#1}%
+  \ifx\temp\imacro \ptexi
+  \else\ifx\temp\jmacro \j
+  \else \errmessage{@dotless can be used only with i or j}%
+  \fi\fi
+}
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ % Avoid using \@M directly, because that causes trouble
+ % if the definition is written into an index file.
+ \global\let\tiepenalty = \@M
+ \gdef\tie{\leavevmode\penalty\tiepenalty\ }
+}
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break\hbox{}\ignorespaces}
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=3000 }
+
+% @! is an end-of-sentence bang.
+\def\!{!\spacefactor=3000 }
+
+% @? is an end-of-sentence query.
+\def\?{?\spacefactor=3000 }
+
+% @w prevents a word break.  Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox.  We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line.  According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0).  If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+\def\group{\begingroup
+  \ifnum\catcode13=\active \else
+    \errhelp = \groupinvalidhelp
+    \errmessage{@group invalid in context where filling is enabled}%
+  \fi
+  %
+  % The \vtop we start below produces a box with normal height and large
+  % depth; thus, TeX puts \baselineskip glue before it, and (when the
+  % next line of text is done) \lineskip glue after it.  (See p.82 of
+  % the TeXbook.)  Thus, space below is not quite equal to space
+  % above.  But it's pretty close.
+  \def\Egroup{%
+    \egroup           % End the \vtop.
+    \endgroup         % End the \group.
+  }%
+  %
+  \vtop\bgroup
+    % We have to put a strut on the last line in case the @group is in
+    % the midst of an example, rather than completely enclosing it.
+    % Otherwise, the interline space between the last line of the group
+    % and the first line afterwards is too small.  But we can't put the
+    % strut in \Egroup, since there it would be on a line by itself.
+    % Hence this just inserts a strut at the beginning of each line.
+    \everypar = {\strut}%
+    %
+    % Since we have a strut on every line, we don't need any of TeX's
+    % normal interline spacing.
+    \offinterlineskip
+    %
+    % OK, but now we have to do something about blank
+    % lines in the input in @example-like environments, which normally
+    % just turn into \lisppar, which will insert no space now that we've
+    % turned off the interline space.  Simplest is to make them be an
+    % empty paragraph.
+    \ifx\par\lisppar
+      \edef\par{\leavevmode \par}%
+      %
+      % Reset ^^M's definition to new definition of \par.
+      \obeylines
+    \fi
+    %
+    % Do @comment since we are called inside an environment such as
+    % @example, where each end-of-line in the input causes an
+    % end-of-line in the output.  We don't want the end-of-line after
+    % the `@group' to put extra space in the output.  Since @group
+    % should appear on a line by itself (according to the Texinfo
+    % manual), we don't worry about eating any user text.
+    \comment
+}
+%
+% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
+% message, so this ends up printing `@group can only ...'.
+%
+\newhelp\groupinvalidhelp{%
+group can only be used in environments such as @example,^^J%
+where each line of input produces a line of output.}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil  \mil=0.001in
+
+\def\need{\parsearg\needx}
+
+% Old definition--didn't work.
+%\def\needx #1{\par %
+%% This method tries to make TeX break the page naturally
+%% if the depth of the box does not fit.
+%{\baselineskip=0pt%
+%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak
+%\prevdepth=-1000pt
+%}}
+
+\def\needx#1{%
+  % Go into vertical mode, so we don't make a big box in the middle of a
+  % paragraph.
+  \par
+  %
+  % Don't add any leading before our big empty box, but allow a page
+  % break, since the best break might be right here.
+  \allowbreak
+  \nointerlineskip
+  \vtop to #1\mil{\vfil}%
+  %
+  % TeX does not even consider page breaks if a penalty added to the
+  % main vertical list is 10000 or more.  But in order to see if the
+  % empty box we just added fits on the page, we must make it consider
+  % page breaks.  On the other hand, we don't want to actually break the
+  % page after the empty box.  So we use a penalty of 9999.
+  %
+  % There is an extremely small chance that TeX will actually break the
+  % page at this \penalty, if there are no other feasible breakpoints in
+  % sight.  (If the user is using lots of big @group commands, which
+  % almost-but-not-quite fill up a page, TeX will have a hard time doing
+  % good page breaking, for example.)  However, I could not construct an
+  % example where a page broke at this \penalty; if it happens in a real
+  % document, then we can reconsider our strategy.
+  \penalty9999
+  %
+  % Back up by the size of the box, whether we did a page break or not.
+  \kern -#1\mil
+  %
+  % Do not allow a page break right after this kern.
+  \nobreak
+}
+
+% @br   forces paragraph break
+
+\let\br = \par
+
+% @dots{} output an ellipsis using the current font.
+% We do .5em per period so that it has the same spacing in a typewriter
+% font as three actual period characters.
+%
+\def\dots{%
+  \leavevmode
+  \hbox to 1.5em{%
+    \hskip 0pt plus 0.25fil minus 0.25fil
+    .\hss.\hss.%
+    \hskip 0pt plus 0.5fil minus 0.5fil
+  }%
+}
+
+% @enddots{} is an end-of-sentence ellipsis.
+% 
+\def\enddots{%
+  \leavevmode
+  \hbox to 2em{%
+    \hskip 0pt plus 0.25fil minus 0.25fil
+    .\hss.\hss.\hss.%
+    \hskip 0pt plus 0.5fil minus 0.5fil
+  }%
+  \spacefactor=3000
+}
+
+
+% @page    forces the start of a new page
+%
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\def\exdent{\parsearg\exdentyyy}
+\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}}
+
+% This defn is used inside nofill environments such as @example.
+\def\nofillexdent{\parsearg\nofillexdentyyy}
+\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount
+\leftline{\hskip\leftskip{\rm#1}}}}
+
+% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph.
+
+\def\inmargin#1{%
+\strut\vadjust{\nobreak\kern-\strutdepth
+  \vtop to \strutdepth{\baselineskip\strutdepth\vss
+  \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}}
+\newskip\inmarginspacing \inmarginspacing=1cm
+\def\strutdepth{\dp\strutbox}
+
+%\hbox{{\rm#1}}\hfil\break}}
+
+% @include file    insert text of that file as input.
+% Allow normal characters that  we make active in the argument (a file name).
+\def\include{\begingroup
+  \catcode`\\=12
+  \catcode`~=12
+  \catcode`^=12
+  \catcode`_=12
+  \catcode`|=12
+  \catcode`<=12
+  \catcode`>=12
+  \catcode`+=12
+  \parsearg\includezzz}
+% Restore active chars for included file.
+\def\includezzz#1{\endgroup\begingroup
+  % Read the included file in a group so nested @include's work.
+  \def\thisfile{#1}%
+  \input\thisfile
+\endgroup}
+
+\def\thisfile{}
+
+% @center line   outputs that line, centered
+
+\def\center{\parsearg\centerzzz}
+\def\centerzzz #1{{\advance\hsize by -\leftskip
+\advance\hsize by -\rightskip
+\centerline{#1}}}
+
+% @sp n   outputs n lines of vertical space
+
+\def\sp{\parsearg\spxxx}
+\def\spxxx #1{\vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore  is another way to write a comment
+
+\def\comment{\begingroup \catcode`\^^M=\other%
+\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other%
+\commentxxx}
+{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}}
+
+\let\c=\comment
+
+% @paragraphindent  is defined for the Info formatting commands only.
+\let\paragraphindent=\comment
+
+% Prevent errors for section commands.
+% Used in @ignore and in failing conditionals.
+\def\ignoresections{%
+\let\chapter=\relax
+\let\unnumbered=\relax
+\let\top=\relax
+\let\unnumberedsec=\relax
+\let\unnumberedsection=\relax
+\let\unnumberedsubsec=\relax
+\let\unnumberedsubsection=\relax
+\let\unnumberedsubsubsec=\relax
+\let\unnumberedsubsubsection=\relax
+\let\section=\relax
+\let\subsec=\relax
+\let\subsubsec=\relax
+\let\subsection=\relax
+\let\subsubsection=\relax
+\let\appendix=\relax
+\let\appendixsec=\relax
+\let\appendixsection=\relax
+\let\appendixsubsec=\relax
+\let\appendixsubsection=\relax
+\let\appendixsubsubsec=\relax
+\let\appendixsubsubsection=\relax
+\let\contents=\relax
+\let\smallbook=\relax
+\let\titlepage=\relax
+}
+
+% Used in nested conditionals, where we have to parse the Texinfo source
+% and so want to turn off most commands, in case they are used
+% incorrectly.
+%
+\def\ignoremorecommands{%
+  \let\defcodeindex = \relax
+  \let\defcv = \relax
+  \let\deffn = \relax
+  \let\deffnx = \relax
+  \let\defindex = \relax
+  \let\defivar = \relax
+  \let\defmac = \relax
+  \let\defmethod = \relax
+  \let\defop = \relax
+  \let\defopt = \relax
+  \let\defspec = \relax
+  \let\deftp = \relax
+  \let\deftypefn = \relax
+  \let\deftypefun = \relax
+  \let\deftypevar = \relax
+  \let\deftypevr = \relax
+  \let\defun = \relax
+  \let\defvar = \relax
+  \let\defvr = \relax
+  \let\ref = \relax
+  \let\xref = \relax
+  \let\printindex = \relax
+  \let\pxref = \relax
+  \let\settitle = \relax
+  \let\setchapternewpage = \relax
+  \let\setchapterstyle = \relax
+  \let\everyheading = \relax
+  \let\evenheading = \relax
+  \let\oddheading = \relax
+  \let\everyfooting = \relax
+  \let\evenfooting = \relax
+  \let\oddfooting = \relax
+  \let\headings = \relax
+  \let\include = \relax
+  \let\lowersections = \relax
+  \let\down = \relax
+  \let\raisesections = \relax
+  \let\up = \relax
+  \let\set = \relax
+  \let\clear = \relax
+  \let\item = \relax
+}
+
+% Ignore @ignore ... @end ignore.
+%
+\def\ignore{\doignore{ignore}}
+
+% Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text.
+%
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\ifnottex{\doignore{ifnottex}}
+\def\html{\doignore{html}}
+\def\menu{\doignore{menu}}
+\def\direntry{\doignore{direntry}}
+
+% @dircategory CATEGORY  -- specify a category of the dir file
+% which this file should belong to.  Ignore this in TeX.
+\let\dircategory = \comment
+
+% Ignore text until a line `@end #1'.
+%
+\def\doignore#1{\begingroup
+  % Don't complain about control sequences we have declared \outer.
+  \ignoresections
+  %
+  % Define a command to swallow text until we reach `@end #1'.
+  % This @ is a catcode 12 token (that is the normal catcode of @ in
+  % this texinfo.tex file).  We change the catcode of @ below to match.
+  \long\def\doignoretext##1@end #1{\enddoignore}%
+  %
+  % Make sure that spaces turn into tokens that match what \doignoretext wants.
+  \catcode32 = 10
+  %
+  % Ignore braces, too, so mismatched braces don't cause trouble.
+  \catcode`\{ = 9
+  \catcode`\} = 9
+  %
+  % We must not have @c interpreted as a control sequence.
+  \catcode`\@ = 12
+  %
+  % Make the letter c a comment character so that the rest of the line
+  % will be ignored. This way, the document can have (for example)
+  %   @c @end ifinfo
+  % and the @end ifinfo will be properly ignored.
+  % (We've just changed @ to catcode 12.)
+  \catcode`\c = 14
+  %
+  % And now expand that command.
+  \doignoretext
+}
+
+% What we do to finish off ignored text.
+%
+\def\enddoignore{\endgroup\ignorespaces}%
+
+\newif\ifwarnedobs\warnedobsfalse
+\def\obstexwarn{%
+  \ifwarnedobs\relax\else
+  % We need to warn folks that they may have trouble with TeX 3.0.
+  % This uses \immediate\write16 rather than \message to get newlines.
+    \immediate\write16{}
+    \immediate\write16{***WARNING*** for users of Unix TeX 3.0!}
+    \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).}
+    \immediate\write16{If you are running another version of TeX, relax.}
+    \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.}
+    \immediate\write16{  Then upgrade your TeX installation if you can.}
+    \immediate\write16{  (See ftp://ftp.gnu.org/pub/gnu/TeX.README.)}
+    \immediate\write16{If you are stuck with version 3.0, run the}
+    \immediate\write16{  script ``tex3patch'' from the Texinfo distribution}
+    \immediate\write16{  to use a workaround.}
+    \immediate\write16{}
+    \global\warnedobstrue
+    \fi
+}
+
+% **In TeX 3.0, setting text in \nullfont hangs tex.  For a
+% workaround (which requires the file ``dummy.tfm'' to be installed),
+% uncomment the following line:
+%%%%%\font\nullfont=dummy\let\obstexwarn=\relax
+
+% Ignore text, except that we keep track of conditional commands for
+% purposes of nesting, up to an `@end #1' command.
+%
+\def\nestedignore#1{%
+  \obstexwarn
+  % We must actually expand the ignored text to look for the @end
+  % command, so that nested ignore constructs work.  Thus, we put the
+  % text into a \vbox and then do nothing with the result.  To minimize
+  % the change of memory overflow, we follow the approach outlined on
+  % page 401 of the TeXbook: make the current font be a dummy font.
+  %
+  \setbox0 = \vbox\bgroup
+    % Don't complain about control sequences we have declared \outer.
+    \ignoresections
+    %
+    % Define `@end #1' to end the box, which will in turn undefine the
+    % @end command again.
+    \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}%
+    %
+    % We are going to be parsing Texinfo commands.  Most cause no
+    % trouble when they are used incorrectly, but some commands do
+    % complicated argument parsing or otherwise get confused, so we
+    % undefine them.
+    %
+    % We can't do anything about stray @-signs, unfortunately;
+    % they'll produce `undefined control sequence' errors.
+    \ignoremorecommands
+    %
+    % Set the current font to be \nullfont, a TeX primitive, and define
+    % all the font commands to also use \nullfont.  We don't use
+    % dummy.tfm, as suggested in the TeXbook, because not all sites
+    % might have that installed.  Therefore, math mode will still
+    % produce output, but that should be an extremely small amount of
+    % stuff compared to the main input.
+    %
+    \nullfont
+    \let\tenrm = \nullfont  \let\tenit = \nullfont  \let\tensl = \nullfont
+    \let\tenbf = \nullfont  \let\tentt = \nullfont  \let\smallcaps = \nullfont
+    \let\tensf = \nullfont
+    % Similarly for index fonts (mostly for their use in
+    % smallexample)
+    \let\indrm = \nullfont  \let\indit = \nullfont  \let\indsl = \nullfont
+    \let\indbf = \nullfont  \let\indtt = \nullfont  \let\indsc = \nullfont
+    \let\indsf = \nullfont
+    %
+    % Don't complain when characters are missing from the fonts.
+    \tracinglostchars = 0
+    %
+    % Don't bother to do space factor calculations.
+    \frenchspacing
+    %
+    % Don't report underfull hboxes.
+    \hbadness = 10000
+    %
+    % Do minimal line-breaking.
+    \pretolerance = 10000
+    %
+    % Do not execute instructions in @tex
+    \def\tex{\doignore{tex}}%
+    % Do not execute macro definitions.
+    % `c' is a comment character, so the word `macro' will get cut off.
+    \def\macro{\doignore{ma}}%
+}
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it.  Make sure the catcode of space is correct to avoid
+% losing inside @example, for instance.
+%
+\def\set{\begingroup\catcode` =10
+  \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR.
+  \parsearg\setxxx}
+\def\setxxx#1{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+  \def\temp{#2}%
+  \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty
+  \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted.
+  \fi
+  \endgroup
+}
+% Can't use \xdef to pre-expand #2 and save some time, since \temp or
+% \next or other control sequences that we've defined might get us into
+% an infinite loop. Consider `@set foo @cite{bar}'.
+\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\def\clear{\parsearg\clearxxx}
+\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax}
+
+% @value{foo} gets the text saved in variable foo.
+%
+{
+  \catcode`\_ = \active
+  %
+  % We might end up with active _ or - characters in the argument if
+  % we're called from @code, as @code{@value{foo-bar_}}.  So \let any
+  % such active characters to their normal equivalents.
+  \gdef\value{\begingroup
+    \catcode`\-=12 \catcode`\_=12
+    \indexbreaks \let_\normalunderscore
+    \valuexxx}
+}
+\def\valuexxx#1{\expandablevalue{#1}\endgroup}
+
+% We have this subroutine so that we can handle at least some @value's
+% properly in indexes (we \let\value to this in \indexdummies).  Ones
+% whose names contain - or _ still won't work, but we can't do anything
+% about that.  The command has to be fully expandable, since the result
+% winds up in the index file.  This means that if the variable's value
+% contains other Texinfo commands, it's almost certain it will fail
+% (although perhaps we could fix that with sufficient work to do a
+% one-level expansion on the result, instead of complete).
+% 
+\def\expandablevalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    {[No value for ``#1'']}%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+\def\ifset{\parsearg\ifsetxxx}
+\def\ifsetxxx #1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    \expandafter\ifsetfail
+  \else
+    \expandafter\ifsetsucceed
+  \fi
+}
+\def\ifsetsucceed{\conditionalsucceed{ifset}}
+\def\ifsetfail{\nestedignore{ifset}}
+\defineunmatchedend{ifset}
+
+% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+\def\ifclear{\parsearg\ifclearxxx}
+\def\ifclearxxx #1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    \expandafter\ifclearsucceed
+  \else
+    \expandafter\ifclearfail
+  \fi
+}
+\def\ifclearsucceed{\conditionalsucceed{ifclear}}
+\def\ifclearfail{\nestedignore{ifclear}}
+\defineunmatchedend{ifclear}
+
+% @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text
+% following, through the first @end iftex (etc.).  Make `@end iftex'
+% (etc.) valid only after an @iftex.
+%
+\def\iftex{\conditionalsucceed{iftex}}
+\def\ifnothtml{\conditionalsucceed{ifnothtml}}
+\def\ifnotinfo{\conditionalsucceed{ifnotinfo}}
+\defineunmatchedend{iftex}
+\defineunmatchedend{ifnothtml}
+\defineunmatchedend{ifnotinfo}
+
+% We can't just want to start a group at @iftex (for example) and end it
+% at @end iftex, since then @set commands inside the conditional have no
+% effect (they'd get reverted at the end of the group).  So we must
+% define \Eiftex to redefine itself to be its previous value.  (We can't
+% just define it to fail again with an ``unmatched end'' error, since
+% the @ifset might be nested.)
+%
+\def\conditionalsucceed#1{%
+  \edef\temp{%
+    % Remember the current value of \E#1.
+    \let\nece{prevE#1} = \nece{E#1}%
+    %
+    % At the `@end #1', redefine \E#1 to be its previous value.
+    \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}%
+  }%
+  \temp
+}
+
+% We need to expand lots of \csname's, but we don't want to expand the
+% control sequences after we've constructed them.
+%
+\def\nece#1{\expandafter\noexpand\csname#1\endcsname}
+
+% @asis just yields its argument.  Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math means output in math mode.
+% We don't use $'s directly in the definition of \math because control
+% sequences like \math are expanded when the toc file is written.  Then,
+% we read the toc file back, the $'s will be normal characters (as they
+% should be, according to the definition of Texinfo).  So we must use a
+% control sequence to switch into and out of math mode.
+%
+% This isn't quite enough for @math to work properly in indices, but it
+% seems unlikely it will ever be needed there.
+%
+\let\implicitmath = $
+\def\math#1{\implicitmath #1\implicitmath}
+
+% @bullet and @minus need the same treatment as @math, just above.
+\def\bullet{\implicitmath\ptexbullet\implicitmath}
+\def\minus{\implicitmath-\implicitmath}
+
+% @refill is a no-op.
+\let\refill=\relax
+
+% If working on a large document in chapters, it is convenient to
+% be able to disable indexing, cross-referencing, and contents, for test runs.
+% This is done with @novalidate (before @setfilename).
+%
+\newif\iflinks \linkstrue % by default we want the aux files.
+\let\novalidate = \linksfalse
+
+% @setfilename is done at the beginning of every texinfo file.
+% So open here the files we need to have open while reading the input.
+% This makes it possible to make a .fmt file for texinfo.
+\def\setfilename{%
+   \iflinks 
+     \readauxfile
+   \fi % \openindices needs to do some work in any case.
+   \openindices
+   \fixbackslash  % Turn off hack to swallow `\input texinfo'.
+   \global\let\setfilename=\comment % Ignore extra @setfilename cmds.
+   %
+   % If texinfo.cnf is present on the system, read it.
+   % Useful for site-wide @afourpaper, etc.
+   % Just to be on the safe side, close the input stream before the \input.
+   \openin 1 texinfo.cnf
+   \ifeof1 \let\temp=\relax \else \def\temp{\input texinfo.cnf }\fi
+   \closein1
+   \temp
+   %
+   \comment % Ignore the actual filename.
+}
+
+% Called from \setfilename.
+% 
+\def\openindices{%
+  \newindex{cp}%
+  \newcodeindex{fn}%
+  \newcodeindex{vr}%
+  \newcodeindex{tp}%
+  \newcodeindex{ky}%
+  \newcodeindex{pg}%
+}
+
+% @bye.
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+
+\message{fonts,}
+% Font-change commands.
+
+% Texinfo sort of supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf analogous to plain's \rm, etc.
+\newfam\sffam
+\def\sf{\fam=\sffam \tensf}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+% We don't need math for this one.
+\def\ttsl{\tenttsl}
+
+% Use Computer Modern fonts at \magstephalf (11pt).
+\newcount\mainmagstep
+\mainmagstep=\magstephalf
+
+% Set the font macro #1 to the font named #2, adding on the
+% specified font prefix (normally `cm').
+% #3 is the font's design size, #4 is a scale factor
+\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4}
+
+% Use cm as the default font prefix.
+% To specify the font prefix, you must define \fontprefix
+% before you read in texinfo.tex.
+\ifx\fontprefix\undefined
+\def\fontprefix{cm}
+\fi
+% Support font families that don't use the same naming scheme as CM.
+\def\rmshape{r}
+\def\rmbshape{bx}               %where the normal face is bold
+\def\bfshape{b}
+\def\bxshape{bx}
+\def\ttshape{tt}
+\def\ttbshape{tt}
+\def\ttslshape{sltt}
+\def\itshape{ti}
+\def\itbshape{bxti}
+\def\slshape{sl}
+\def\slbshape{bxsl}
+\def\sfshape{ss}
+\def\sfbshape{ss}
+\def\scshape{csc}
+\def\scbshape{csc}
+
+\ifx\bigger\relax
+\let\mainmagstep=\magstep1
+\setfont\textrm\rmshape{12}{1000}
+\setfont\texttt\ttshape{12}{1000}
+\else
+\setfont\textrm\rmshape{10}{\mainmagstep}
+\setfont\texttt\ttshape{10}{\mainmagstep}
+\fi
+% Instead of cmb10, you many want to use cmbx10.
+% cmbx10 is a prettier font on its own, but cmb10
+% looks better when embedded in a line with cmr10.
+\setfont\textbf\bfshape{10}{\mainmagstep}
+\setfont\textit\itshape{10}{\mainmagstep}
+\setfont\textsl\slshape{10}{\mainmagstep}
+\setfont\textsf\sfshape{10}{\mainmagstep}
+\setfont\textsc\scshape{10}{\mainmagstep}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+
+% A few fonts for @defun, etc.
+\setfont\defbf\bxshape{10}{\magstep1} %was 1314
+\setfont\deftt\ttshape{10}{\magstep1}
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf}
+
+% Fonts for indices and small examples (9pt).
+% We actually use the slanted font rather than the italic,
+% because texinfo normally uses the slanted fonts for that.
+% Do not make many font distinctions in general in the index, since they
+% aren't very useful.
+\setfont\ninett\ttshape{9}{1000}
+\setfont\ninettsl\ttslshape{10}{900}
+\setfont\indrm\rmshape{9}{1000}
+\setfont\indit\itshape{9}{1000}
+\setfont\indsl\slshape{9}{1000}
+\let\indtt=\ninett
+\let\indttsl=\ninettsl
+\let\indsf=\indrm
+\let\indbf=\indrm
+\setfont\indsc\scshape{10}{900}
+\font\indi=cmmi9
+\font\indsy=cmsy9
+
+% Fonts for title page:
+\setfont\titlerm\rmbshape{12}{\magstep3}
+\setfont\titleit\itbshape{10}{\magstep4}
+\setfont\titlesl\slbshape{10}{\magstep4}
+\setfont\titlett\ttbshape{12}{\magstep3}
+\setfont\titlettsl\ttslshape{10}{\magstep4}
+\setfont\titlesf\sfbshape{17}{\magstep1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\authorrm{\secrm}
+
+% Chapter (and unnumbered) fonts (17.28pt).
+\setfont\chaprm\rmbshape{12}{\magstep2}
+\setfont\chapit\itbshape{10}{\magstep3}
+\setfont\chapsl\slbshape{10}{\magstep3}
+\setfont\chaptt\ttbshape{12}{\magstep2}
+\setfont\chapttsl\ttslshape{10}{\magstep3}
+\setfont\chapsf\sfbshape{17}{1000}
+\let\chapbf=\chaprm
+\setfont\chapsc\scbshape{10}{\magstep3}
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+
+% Section fonts (14.4pt).
+\setfont\secrm\rmbshape{12}{\magstep1}
+\setfont\secit\itbshape{10}{\magstep2}
+\setfont\secsl\slbshape{10}{\magstep2}
+\setfont\sectt\ttbshape{12}{\magstep1}
+\setfont\secttsl\ttslshape{10}{\magstep2}
+\setfont\secsf\sfbshape{12}{\magstep1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep2}
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+
+% \setfont\ssecrm\bxshape{10}{\magstep1}    % This size an font looked bad.
+% \setfont\ssecit\itshape{10}{\magstep1}    % The letters were too crowded.
+% \setfont\ssecsl\slshape{10}{\magstep1}
+% \setfont\ssectt\ttshape{10}{\magstep1}
+% \setfont\ssecsf\sfshape{10}{\magstep1}
+
+%\setfont\ssecrm\bfshape{10}{1315}      % Note the use of cmb rather than cmbx.
+%\setfont\ssecit\itshape{10}{1315}      % Also, the size is a little larger than
+%\setfont\ssecsl\slshape{10}{1315}      % being scaled magstep1.
+%\setfont\ssectt\ttshape{10}{1315}
+%\setfont\ssecsf\sfshape{10}{1315}
+
+%\let\ssecbf=\ssecrm
+
+% Subsection fonts (13.15pt).
+\setfont\ssecrm\rmbshape{12}{\magstephalf}
+\setfont\ssecit\itbshape{10}{1315}
+\setfont\ssecsl\slbshape{10}{1315}
+\setfont\ssectt\ttbshape{12}{\magstephalf}
+\setfont\ssecttsl\ttslshape{10}{1315}
+\setfont\ssecsf\sfbshape{12}{\magstephalf}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{\magstep1}
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled 1315
+% The smallcaps and symbol fonts should actually be scaled \magstep1.5,
+% but that is not a standard magnification.
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families.  Since
+% texinfo doesn't allow for producing subscripts and superscripts, we
+% don't bother to reset \scriptfont and \scriptscriptfont (which would
+% also require loading a lot more fonts).
+%
+\def\resetmathfonts{%
+  \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy
+  \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf
+  \textfont\ttfam = \tentt \textfont\sffam = \tensf
+}
+
+
+% The font-changing commands redefine the meanings of \tenSTYLE, instead
+% of just \STYLE.  We do this so that font changes will continue to work
+% in math mode, where it is the current \fam that is relevant in most
+% cases, not the current font.  Plain TeX does \def\bf{\fam=\bffam
+% \tenbf}, for example.  By redefining \tenbf, we obviate the need to
+% redefine \bf itself.
+\def\textfonts{%
+  \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
+  \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
+  \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl
+  \resetmathfonts}
+\def\titlefonts{%
+  \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl
+  \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc
+  \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy
+  \let\tenttsl=\titlettsl
+  \resetmathfonts \setleading{25pt}}
+\def\titlefont#1{{\titlefonts\rm #1}}
+\def\chapfonts{%
+  \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
+  \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
+  \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl
+  \resetmathfonts \setleading{19pt}}
+\def\secfonts{%
+  \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
+  \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
+  \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl
+  \resetmathfonts \setleading{16pt}}
+\def\subsecfonts{%
+  \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
+  \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
+  \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl
+  \resetmathfonts \setleading{15pt}}
+\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf?
+\def\indexfonts{%
+  \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl
+  \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc
+  \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl
+  \resetmathfonts \setleading{12pt}}
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\textfonts
+
+% Define these so they can be easily changed for other fonts.
+\def\angleleft{$\langle$}
+\def\angleright{$\rangle$}
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Fonts for short table of contents.
+\setfont\shortcontrm\rmshape{12}{1000}
+\setfont\shortcontbf\bxshape{12}{1000}
+\setfont\shortcontsl\slshape{12}{1000}
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+% \smartitalic{ARG} outputs arg in italics, followed by an italic correction
+% unless the following character is such as not to need one.
+\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi}
+\def\smartslanted#1{{\sl #1}\futurelet\next\smartitalicx}
+\def\smartitalic#1{{\it #1}\futurelet\next\smartitalicx}
+
+\let\i=\smartitalic
+\let\var=\smartslanted
+\let\dfn=\smartslanted
+\let\emph=\smartitalic
+\let\cite=\smartslanted
+
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph.  Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1  \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+\def\t#1{%
+  {\tt \rawbackslash \frenchspacing #1}%
+  \null
+}
+\let\ttfont=\t
+\def\samp#1{`\tclose{#1}'\null}
+\setfont\smallrm\rmshape{8}{1000}
+\font\smallsy=cmsy9
+\def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{%
+  \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{%
+    \vbox{\hrule\kern-0.4pt
+     \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}%
+    \kern-0.4pt\hrule}%
+  \kern-.06em\raise0.4pt\hbox{\angleright}}}}
+% The old definition, with no lozenge:
+%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+% @file, @option are the same as @samp.
+\let\file=\samp
+\let\option=\samp
+
+% @code is a modification of @t,
+% which makes spaces the same size as normal in the surrounding text.
+\def\tclose#1{%
+  {%
+    % Change normal interword space to be same as for the current font.
+    \spaceskip = \fontdimen2\font
+    %
+    % Switch to typewriter.
+    \tt
+    %
+    % But `\ ' produces the large typewriter interword space.
+    \def\ {{\spaceskip = 0pt{} }}%
+    %
+    % Turn off hyphenation.
+    \nohyphenation
+    %
+    \rawbackslash
+    \frenchspacing
+    #1%
+  }%
+  \null
+}
+
+% We *must* turn on hyphenation at `-' and `_' in \code.
+% Otherwise, it is too hard to avoid overfull hboxes
+% in the Emacs manual, the Library manual, etc.
+
+% Unfortunately, TeX uses one parameter (\hyphenchar) to control
+% both hyphenation at - and hyphenation within words.
+% We must therefore turn them both off (\tclose does that)
+% and arrange explicitly to hyphenate at a dash.
+%  -- rms.
+{
+  \catcode`\-=\active
+  \catcode`\_=\active
+  %
+  \global\def\code{\begingroup
+    \catcode`\-=\active \let-\codedash
+    \catcode`\_=\active \let_\codeunder
+    \codex
+  }
+  %
+  % If we end up with any active - characters when handling the index,
+  % just treat them as a normal -.
+  \global\def\indexbreaks{\catcode`\-=\active \let-\realdash}
+}
+
+\def\realdash{-}
+\def\codedash{-\discretionary{}{}{}}
+\def\codeunder{\ifusingtt{\normalunderscore\discretionary{}{}{}}{\_}}
+\def\codex #1{\tclose{#1}\endgroup}
+
+%\let\exp=\tclose  %Was temporary
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+
+% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always),
+%   `example' (@kbd uses ttsl only inside of @example and friends),
+%   or `code' (@kbd uses normal tty font always).
+\def\kbdinputstyle{\parsearg\kbdinputstylexxx}
+\def\kbdinputstylexxx#1{%
+  \def\arg{#1}%
+  \ifx\arg\worddistinct
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}%
+  \else\ifx\arg\wordexample
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}%
+  \else\ifx\arg\wordcode
+    \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}%
+  \fi\fi\fi
+}
+\def\worddistinct{distinct}
+\def\wordexample{example}
+\def\wordcode{code}
+
+% Default is kbdinputdistinct.  (Too much of a hassle to call the macro,
+% the catcodes are wrong for parsearg to work.)
+\gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}
+
+\def\xkey{\key}
+\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}%
+\ifx\one\xkey\ifx\threex\three \key{#2}%
+\else{\tclose{\kbdfont\look}}\fi
+\else{\tclose{\kbdfont\look}}\fi}
+
+% For @url, @env, @command quotes seem unnecessary, so use \code.
+\let\url=\code
+\let\env=\code
+\let\command=\code
+
+% @uref (abbreviation for `urlref') takes an optional second argument
+% specifying the text to display.  First (mandatory) arg is the url.
+% Perhaps eventually put in a hypertex \special here.
+% 
+\def\uref#1{\urefxxx #1,,\finish}
+\def\urefxxx#1,#2,#3\finish{%
+  \setbox0 = \hbox{\ignorespaces #2}%
+  \ifdim\wd0 > 0pt
+    \unhbox0\ (\code{#1})%
+  \else
+    \code{#1}%
+  \fi
+}
+
+% rms does not like the angle brackets --karl, 17may97.
+% So now @email is just like @uref.
+%\def\email#1{\angleleft{\tt #1}\angleright}
+\let\email=\uref
+
+% Check if we are currently using a typewriter font.  Since all the
+% Computer Modern typewriter fonts have zero interword stretch (and
+% shrink), and it is reasonable to expect all typewriter fonts to have
+% this property, we can check that font parameter.
+%
+\def\ifmonospace{\ifdim\fontdimen3\font=0pt }
+
+% Typeset a dimension, e.g., `in' or `pt'.  The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par}
+
+% @l was never documented to mean ``switch to the Lisp font'',
+% and it is not used as such in any manual I can find.  We need it for
+% Polish suppressed-l.  --karl, 22sep96.
+%\def\l#1{{\li #1}\null}
+
+% Explicit font changes: @r, @sc, undocumented @ii.
+\def\r#1{{\rm #1}}              % roman font
+\def\sc#1{{\smallcaps#1}}       % smallcaps font
+\def\ii#1{{\it #1}}             % italic font
+
+% @acronym downcases the argument and prints in smallcaps.
+\def\acronym#1{{\smallcaps \lowercase{#1}}}
+
+% @pounds{} is a sterling sign.
+\def\pounds{{\it\$}}
+
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page.  Must do @settitle before @titlepage.
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+% Do an implicit @contents or @shortcontents after @end titlepage if the
+% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage.
+% 
+\newif\ifsetcontentsaftertitlepage
+ \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue
+\newif\ifsetshortcontentsaftertitlepage
+ \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue
+
+\def\shorttitlepage{\parsearg\shorttitlepagezzz}
+\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+        \endgroup\page\hbox{}\page}
+
+\def\titlepage{\begingroup \parindent=0pt \textfonts
+   \let\subtitlerm=\tenrm
+   \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}%
+   %
+   \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}%
+   %
+   % Leave some space at the very top of the page.
+   \vglue\titlepagetopglue
+   %
+   % Now you can print the title using @title.
+   \def\title{\parsearg\titlezzz}%
+   \def\titlezzz##1{\leftline{\titlefonts\rm ##1}
+                    % print a rule at the page bottom also.
+                    \finishedtitlepagefalse
+                    \vskip4pt \hrule height 4pt width \hsize \vskip4pt}%
+   % No rule at page bottom unless we print one at the top with @title.
+   \finishedtitlepagetrue
+   %
+   % Now you can put text using @subtitle.
+   \def\subtitle{\parsearg\subtitlezzz}%
+   \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}%
+   %
+   % @author should come last, but may come many times.
+   \def\author{\parsearg\authorzzz}%
+   \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi
+      {\authorfont \leftline{##1}}}%
+   %
+   % Most title ``pages'' are actually two pages long, with space
+   % at the top of the second.  We don't want the ragged left on the second.
+   \let\oldpage = \page
+   \def\page{%
+      \iffinishedtitlepage\else
+         \finishtitlepage
+      \fi
+      \oldpage
+      \let\page = \oldpage
+      \hbox{}}%
+%   \def\page{\oldpage \hbox{}}
+}
+
+\def\Etitlepage{%
+   \iffinishedtitlepage\else
+      \finishtitlepage
+   \fi
+   % It is important to do the page break before ending the group,
+   % because the headline and footline are only empty inside the group.
+   % If we use the new definition of \page, we always get a blank page
+   % after the title page, which we certainly don't want.
+   \oldpage
+   \endgroup
+   %
+   % If they want short, they certainly want long too.
+   \ifsetshortcontentsaftertitlepage
+     \shortcontents
+     \contents
+     \global\let\shortcontents = \relax
+     \global\let\contents = \relax
+   \fi
+   %
+   \ifsetcontentsaftertitlepage
+     \contents
+     \global\let\contents = \relax
+     \global\let\shortcontents = \relax
+   \fi
+   %
+   \HEADINGSon
+}
+
+\def\finishtitlepage{%
+   \vskip4pt \hrule height 2pt width \hsize
+   \vskip\titlepagebottomglue
+   \finishedtitlepagetrue
+}
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks\evenheadline    % headline on even pages
+\newtoks\oddheadline     % headline on odd pages
+\newtoks\evenfootline    % footline on even pages
+\newtoks\oddfootline     % footline on odd pages
+
+% Now make Tex use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+                            \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+                            \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what  @headings on  does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\everyheading{\parsearg\everyheadingxxx}
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\everyfooting{\parsearg\everyfootingxxx}
+
+{\catcode`\@=0 %
+
+\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
+\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
+\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyheadingxxx#1{\oddheadingxxx{#1}\evenheadingxxx{#1}}%
+
+\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
+\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
+\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
+  \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}%
+  %
+  % Leave some space for the footline.  Hopefully ok to assume
+  % @evenfooting will not be used by itself.
+  \global\advance\pageheight by -\baselineskip
+  \global\advance\vsize by -\baselineskip
+}
+
+\gdef\everyfootingxxx#1{\oddfootingxxx{#1}\evenfootingxxx{#1}}
+%
+}% unbind the catcode of @.
+
+% @headings double      turns headings on for double-sided printing.
+% @headings single      turns headings on for single-sided printing.
+% @headings off         turns them off.
+% @headings on          same as @headings double, retained for compatibility.
+% @headings after       turns on double-sided headings after this page.
+% @headings doubleafter turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off at the start of a document,
+% and turned `on' after @end titlepage.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+\let\contentsalignmacro = \chappager
+
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+
+% Subroutines used in generating headings
+% Produces Day Month Year style of output.
+\def\today{\number\day\space
+\ifcase\month\or
+January\or February\or March\or April\or May\or June\or
+July\or August\or September\or October\or November\or December\fi
+\space\number\year}
+
+% Use this if you want the Month Day, Year style of output.
+%\def\today{\ifcase\month\or
+%January\or February\or March\or April\or May\or June\or
+%July\or August\or September\or October\or November\or December\fi
+%\space\number\day, \number\year}
+
+% @settitle line...  specifies the title of the document, for headings
+% It generates no output of its own
+
+\def\thistitle{No Title}
+\def\settitle{\parsearg\settitlezzz}
+\def\settitlezzz #1{\gdef\thistitle{#1}}
+
+
+\message{tables,}
+% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent  \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin  \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @vtable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
+\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz}
+
+\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
+\def\internalBkitemx{\itemxpar \parsearg\kitemzzz}
+
+\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}%
+                 \itemzzz {#1}}
+
+\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}%
+                 \itemzzz {#1}}
+
+\def\itemzzz #1{\begingroup %
+  \advance\hsize by -\rightskip
+  \advance\hsize by -\tableindent
+  \setbox0=\hbox{\itemfont{#1}}%
+  \itemindex{#1}%
+  \nobreak % This prevents a break before @itemx.
+  %
+  % If the item text does not fit in the space we have, put it on a line
+  % by itself, and do not allow a page break either before or after that
+  % line.  We do not start a paragraph here because then if the next
+  % command is, e.g., @kindex, the whatsit would get put into the
+  % horizontal list on a line by itself, resulting in extra blank space.
+  \ifdim \wd0>\itemmax
+    %
+    % Make this a paragraph so we get the \parskip glue and wrapping,
+    % but leave it ragged-right.
+    \begingroup
+      \advance\leftskip by-\tableindent
+      \advance\hsize by\tableindent
+      \advance\rightskip by0pt plus1fil
+      \leavevmode\unhbox0\par
+    \endgroup
+    %
+    % We're going to be starting a paragraph, but we don't want the
+    % \parskip glue -- logically it's part of the @item we just started.
+    \nobreak \vskip-\parskip
+    %
+    % Stop a page break at the \parskip glue coming up.  Unfortunately
+    % we can't prevent a possible page break at the following
+    % \baselineskip glue.
+    \nobreak
+    \endgroup
+    \itemxneedsnegativevskipfalse
+  \else
+    % The item text fits into the space.  Start a paragraph, so that the
+    % following text (if any) will end up on the same line.  
+    \noindent
+    % Do this with kerns and \unhbox so that if there is a footnote in
+    % the item text, it can migrate to the main vertical list and
+    % eventually be printed.
+    \nobreak\kern-\tableindent
+    \dimen0 = \itemmax  \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0
+    \unhbox0
+    \nobreak\kern\dimen0
+    \endgroup
+    \itemxneedsnegativevskiptrue
+  \fi
+}
+
+\def\item{\errmessage{@item while not in a table}}
+\def\itemx{\errmessage{@itemx while not in a table}}
+\def\kitem{\errmessage{@kitem while not in a table}}
+\def\kitemx{\errmessage{@kitemx while not in a table}}
+\def\xitem{\errmessage{@xitem while not in a table}}
+\def\xitemx{\errmessage{@xitemx while not in a table}}
+
+% Contains a kludge to get @end[description] to work.
+\def\description{\tablez{\dontindex}{1}{}{}{}{}}
+
+% @table, @ftable, @vtable.
+\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
+{\obeylines\obeyspaces%
+\gdef\tablex #1^^M{%
+\tabley\dontindex#1        \endtabley}}
+
+\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
+{\obeylines\obeyspaces%
+\gdef\ftablex #1^^M{%
+\tabley\fnitemindex#1        \endtabley
+\def\Eftable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex}
+{\obeylines\obeyspaces%
+\gdef\vtablex #1^^M{%
+\tabley\vritemindex#1        \endtabley
+\def\Evtable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\dontindex #1{}
+\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
+\def\vritemindex #1{\doind {vr}{\code{#1}}}%
+
+{\obeyspaces %
+\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
+\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\def\tablez #1#2#3#4#5#6{%
+\aboveenvbreak %
+\begingroup %
+\def\Edescription{\Etable}% Necessary kludge.
+\let\itemindex=#1%
+\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
+\ifnum 0#4>0 \tableindent=#4\mil \fi %
+\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
+\def\itemfont{#2}%
+\itemmax=\tableindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \tableindent %
+\exdentamount=\tableindent
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def\Etable{\endgraf\afterenvbreak\endgroup}%
+\let\item = \internalBitem %
+\let\itemx = \internalBitemx %
+\let\kitem = \internalBkitem %
+\let\kitemx = \internalBkitemx %
+\let\xitem = \internalBxitem %
+\let\xitemx = \internalBxitemx %
+}
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\def\itemize{\parsearg\itemizezzz}
+
+\def\itemizezzz #1{%
+  \begingroup % ended by the @end itemize
+  \itemizey {#1}{\Eitemize}
+}
+
+\def\itemizey #1#2{%
+\aboveenvbreak %
+\itemmax=\itemindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \itemindent %
+\exdentamount=\itemindent
+\parindent = 0pt %
+\parskip = \smallskipamount %
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def#2{\endgraf\afterenvbreak\endgroup}%
+\def\itemcontents{#1}%
+\let\item=\itemizeitem}
+
+% Set sfcode to normal for the chars that usually have another value.
+% These are `.?!:;,'
+\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000
+  \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 }
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list.  No
+% argument is the same as `1'.
+%
+\def\enumerate{\parsearg\enumeratezzz}
+\def\enumeratezzz #1{\enumeratey #1  \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+  \begingroup % ended by the @end enumerate
+  %
+  % If we were given no argument, pretend we were given `1'.
+  \def\thearg{#1}%
+  \ifx\thearg\empty \def\thearg{1}\fi
+  %
+  % Detect if the argument is a single token.  If so, it might be a
+  % letter.  Otherwise, the only valid thing it can be is a number.
+  % (We will always have one token, because of the test we just made.
+  % This is a good thing, since \splitoff doesn't work given nothing at
+  % all -- the first parameter is undelimited.)
+  \expandafter\splitoff\thearg\endmark
+  \ifx\rest\empty
+    % Only one token in the argument.  It could still be anything.
+    % A ``lowercase letter'' is one whose \lccode is nonzero.
+    % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+    %   not equal to itself.
+    % Otherwise, we assume it's a number.
+    %
+    % We need the \relax at the end of the \ifnum lines to stop TeX from
+    % continuing to look for a <number>.
+    %
+    \ifnum\lccode\expandafter`\thearg=0\relax
+      \numericenumerate % a number (we hope)
+    \else
+      % It's a letter.
+      \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+        \lowercaseenumerate % lowercase letter
+      \else
+        \uppercaseenumerate % uppercase letter
+      \fi
+    \fi
+  \else
+    % Multiple tokens in the argument.  We hope it's a number.
+    \numericenumerate
+  \fi
+}
+
+% An @enumerate whose labels are integers.  The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+  \itemno = \thearg
+  \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more lowercase letters in @enumerate; get a bigger
+                  alphabet}%
+    \fi
+    \char\lccode\itemno
+  }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more uppercase letters in @enumerate; get a bigger
+                  alphabet}
+    \fi
+    \char\uccode\itemno
+  }%
+}
+
+% Call itemizey, adding a period to the first argument and supplying the
+% common last two arguments.  Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+  \advance\itemno by -1
+  \itemizey{#1.}\Eenumerate\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{In hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 1200}}%
+\flushcr}
+
+% @multitable macros
+% Amy Hendrickson, 8/18/94, 3/6/96
+%
+% @multitable ... @end multitable will make as many columns as desired.
+% Contents of each column will wrap at width given in preamble.  Width
+% can be specified either with sample text given in a template line,
+% or in percent of \hsize, the current width of text on page.
+
+% Table can continue over pages but will only break between lines.
+
+% To make preamble:
+%
+% Either define widths of columns in terms of percent of \hsize:
+%   @multitable @columnfractions .25 .3 .45
+%   @item ...
+%
+%   Numbers following @columnfractions are the percent of the total
+%   current hsize to be used for each column. You may use as many
+%   columns as desired.
+
+
+% Or use a template:
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item ...
+%   using the widest term desired in each column.
+%
+% For those who want to use more than one line's worth of words in
+% the preamble, break the line within one argument and it
+% will parse correctly, i.e.,
+%
+%     @multitable {Column 1 template} {Column 2 template} {Column 3
+%      template}
+% Not:
+%     @multitable {Column 1 template} {Column 2 template}
+%      {Column 3 template}
+
+% Each new table line starts with @item, each subsequent new column
+% starts with @tab. Empty columns may be produced by supplying @tab's
+% with nothing between them for as many times as empty columns are needed,
+% ie, @tab@tab@tab will produce two empty columns.
+
+% @item, @tab, @multitable or @end multitable do not need to be on their
+% own lines, but it will not hurt if they are.
+
+% Sample multitable:
+
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item first col stuff @tab second col stuff @tab third col
+%   @item
+%   first col stuff
+%   @tab
+%   second col stuff
+%   @tab
+%   third col
+%   @item first col stuff @tab second col stuff
+%   @tab Many paragraphs of text may be used in any column.
+%
+%         They will wrap at the width determined by the template.
+%   @item@tab@tab This will be in third column.
+%   @end multitable
+
+% Default dimensions may be reset by user.
+% @multitableparskip is vertical space between paragraphs in table.
+% @multitableparindent is paragraph indent in table.
+% @multitablecolmargin is horizontal space to be left between columns.
+% @multitablelinespace is space to leave between table items, baseline
+%                                                            to baseline.
+%   0pt means it depends on current normal line spacing.
+%
+\newskip\multitableparskip
+\newskip\multitableparindent
+\newdimen\multitablecolspace
+\newskip\multitablelinespace
+\multitableparskip=0pt
+\multitableparindent=6pt
+\multitablecolspace=12pt
+\multitablelinespace=0pt
+
+% Macros used to set up halign preamble:
+% 
+\let\endsetuptable\relax
+\def\xendsetuptable{\endsetuptable}
+\let\columnfractions\relax
+\def\xcolumnfractions{\columnfractions}
+\newif\ifsetpercent
+
+% #1 is the part of the @columnfraction before the decimal point, which
+% is presumably either 0 or the empty string (but we don't check, we
+% just throw it away).  #2 is the decimal part, which we use as the
+% percent of \hsize for this column.
+\def\pickupwholefraction#1.#2 {%
+  \global\advance\colcount by 1
+  \expandafter\xdef\csname col\the\colcount\endcsname{.#2\hsize}%
+  \setuptable
+}
+
+\newcount\colcount
+\def\setuptable#1{%
+  \def\firstarg{#1}%
+  \ifx\firstarg\xendsetuptable
+    \let\go = \relax
+  \else
+    \ifx\firstarg\xcolumnfractions
+      \global\setpercenttrue
+    \else
+      \ifsetpercent
+         \let\go\pickupwholefraction
+      \else
+         \global\advance\colcount by 1
+         \setbox0=\hbox{#1\unskip }% Add a normal word space as a separator;
+                            % typically that is always in the input, anyway.
+         \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
+      \fi
+    \fi
+    \ifx\go\pickupwholefraction
+      % Put the argument back for the \pickupwholefraction call, so
+      % we'll always have a period there to be parsed.
+      \def\go{\pickupwholefraction#1}%
+    \else
+      \let\go = \setuptable
+    \fi%
+  \fi
+  \go
+}
+
+% multitable syntax
+\def\tab{&\hskip1sp\relax} % 2/2/96
+                           % tiny skip here makes sure this column space is
+                           % maintained, even if it is never used.
+
+% @multitable ... @end multitable definitions:
+%
+\def\multitable{\parsearg\dotable}
+\def\dotable#1{\bgroup
+  \vskip\parskip
+  \let\item\crcr
+  \tolerance=9500
+  \hbadness=9500
+  \setmultitablespacing
+  \parskip=\multitableparskip
+  \parindent=\multitableparindent
+  \overfullrule=0pt
+  \global\colcount=0
+  \def\Emultitable{\global\setpercentfalse\cr\egroup\egroup}%
+  %
+  % To parse everything between @multitable and @item:
+  \setuptable#1 \endsetuptable
+  %
+  % \everycr will reset column counter, \colcount, at the end of
+  % each line. Every column entry will cause \colcount to advance by one.
+  % The table preamble
+  % looks at the current \colcount to find the correct column width.
+  \everycr{\noalign{%
+  %
+  % \filbreak%% keeps underfull box messages off when table breaks over pages.
+  % Maybe so, but it also creates really weird page breaks when the table
+  % breaks over pages. Wouldn't \vfil be better?  Wait until the problem
+  % manifests itself, so it can be fixed for real --karl.
+    \global\colcount=0\relax}}%
+  %
+  % This preamble sets up a generic column definition, which will
+  % be used as many times as user calls for columns.
+  % \vtop will set a single line and will also let text wrap and
+  % continue for many paragraphs if desired.
+  \halign\bgroup&\global\advance\colcount by 1\relax
+    \multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname
+  %
+  % In order to keep entries from bumping into each other
+  % we will add a \leftskip of \multitablecolspace to all columns after
+  % the first one.
+  % 
+  % If a template has been used, we will add \multitablecolspace
+  % to the width of each template entry.
+  % 
+  % If the user has set preamble in terms of percent of \hsize we will
+  % use that dimension as the width of the column, and the \leftskip
+  % will keep entries from bumping into each other.  Table will start at
+  % left margin and final column will justify at right margin.
+  % 
+  % Make sure we don't inherit \rightskip from the outer environment.
+  \rightskip=0pt
+  \ifnum\colcount=1
+    % The first column will be indented with the surrounding text.
+    \advance\hsize by\leftskip
+  \else
+    \ifsetpercent \else
+      % If user has not set preamble in terms of percent of \hsize
+      % we will advance \hsize by \multitablecolspace.
+      \advance\hsize by \multitablecolspace
+    \fi
+   % In either case we will make \leftskip=\multitablecolspace:
+  \leftskip=\multitablecolspace
+  \fi
+  % Ignoring space at the beginning and end avoids an occasional spurious
+  % blank line, when TeX decides to break the line at the space before the
+  % box from the multistrut, so the strut ends up on a line by itself.
+  % For example:
+  % @multitable @columnfractions .11 .89
+  % @item @code{#}
+  % @tab Legal holiday which is valid in major parts of the whole country.
+  % Is automatically provided with highlighting sequences respectively marking
+  % characters.
+  \noindent\ignorespaces##\unskip\multistrut}\cr
+}
+
+\def\setmultitablespacing{% test to see if user has set \multitablelinespace.
+% If so, do nothing. If not, give it an appropriate dimension based on
+% current baselineskip.
+\ifdim\multitablelinespace=0pt
+%% strut to put in table in case some entry doesn't have descenders,
+%% to keep lines equally spaced
+\let\multistrut = \strut
+%% Test to see if parskip is larger than space between lines of
+%% table. If not, do nothing.
+%%        If so, set to same dimension as multitablelinespace.
+\else
+\gdef\multistrut{\vrule height\multitablelinespace depth\dp0
+width0pt\relax} \fi
+\ifdim\multitableparskip>\multitablelinespace
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+                                      %% than skip between lines in the table.
+\fi%
+\ifdim\multitableparskip=0pt
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+                                      %% than skip between lines in the table.
+\fi}
+
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that accumulates this index.  The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+%
+\def\newindex#1{%
+  \iflinks
+    \expandafter\newwrite \csname#1indfile\endcsname
+    \openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+  \fi
+  \expandafter\xdef\csname#1index\endcsname{%     % Define @#1index
+    \noexpand\doindex{#1}}
+}
+
+% @defindex foo  ==  \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex#1{%
+  \iflinks
+    \expandafter\newwrite \csname#1indfile\endcsname
+    \openout \csname#1indfile\endcsname \jobname.#1
+  \fi
+  \expandafter\xdef\csname#1index\endcsname{%
+    \noexpand\docodeindex{#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @synindex foo bar    makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+% The \closeout helps reduce unnecessary open files; the limit on the
+% Acorn RISC OS is a mere 16 files.
+\def\synindex#1 #2 {%
+  \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+  \expandafter\closeout\csname#1indfile\endcsname
+  \expandafter\let\csname#1indfile\endcsname=\synindexfoo
+  \expandafter\xdef\csname#1index\endcsname{% define \xxxindex
+    \noexpand\doindex{#2}}%
+}
+
+% @syncodeindex foo bar   similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex#1 #2 {%
+  \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+  \expandafter\closeout\csname#1indfile\endcsname
+  \expandafter\let\csname#1indfile\endcsname=\synindexfoo
+  \expandafter\xdef\csname#1index\endcsname{% define \xxxindex
+    \noexpand\docodeindex{#2}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+%  and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+\def\indexdummies{%
+\def\ { }%
+% Take care of the plain tex accent commands.
+\def\"{\realbackslash "}%
+\def\`{\realbackslash `}%
+\def\'{\realbackslash '}%
+\def\^{\realbackslash ^}%
+\def\~{\realbackslash ~}%
+\def\={\realbackslash =}%
+\def\b{\realbackslash b}%
+\def\c{\realbackslash c}%
+\def\d{\realbackslash d}%
+\def\u{\realbackslash u}%
+\def\v{\realbackslash v}%
+\def\H{\realbackslash H}%
+% Take care of the plain tex special European modified letters.
+\def\oe{\realbackslash oe}%
+\def\ae{\realbackslash ae}%
+\def\aa{\realbackslash aa}%
+\def\OE{\realbackslash OE}%
+\def\AE{\realbackslash AE}%
+\def\AA{\realbackslash AA}%
+\def\o{\realbackslash o}%
+\def\O{\realbackslash O}%
+\def\l{\realbackslash l}%
+\def\L{\realbackslash L}%
+\def\ss{\realbackslash ss}%
+% Take care of texinfo commands likely to appear in an index entry.
+% (Must be a way to avoid doing expansion at all, and thus not have to
+% laboriously list every single command here.)
+\def\@{@}% will be @@ when we switch to @ as escape char.
+% Need these in case \tex is in effect and \{ is a \delimiter again.
+% But can't use \lbracecmd and \rbracecmd because texindex assumes
+% braces and backslashes are used only as delimiters.
+\let\{ = \mylbrace
+\let\} = \myrbrace
+\def\_{{\realbackslash _}}%
+\def\w{\realbackslash w }%
+\def\bf{\realbackslash bf }%
+%\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\sf{\realbackslash sf}%
+\def\tt{\realbackslash tt}%
+\def\gtr{\realbackslash gtr}%
+\def\less{\realbackslash less}%
+\def\hat{\realbackslash hat}%
+\def\TeX{\realbackslash TeX}%
+\def\dots{\realbackslash dots }%
+\def\result{\realbackslash result}%
+\def\equiv{\realbackslash equiv}%
+\def\expansion{\realbackslash expansion}%
+\def\print{\realbackslash print}%
+\def\error{\realbackslash error}%
+\def\point{\realbackslash point}%
+\def\copyright{\realbackslash copyright}%
+\def\tclose##1{\realbackslash tclose {##1}}%
+\def\code##1{\realbackslash code {##1}}%
+\def\uref##1{\realbackslash uref {##1}}%
+\def\url##1{\realbackslash url {##1}}%
+\def\env##1{\realbackslash env {##1}}%
+\def\command##1{\realbackslash command {##1}}%
+\def\option##1{\realbackslash option {##1}}%
+\def\dotless##1{\realbackslash dotless {##1}}%
+\def\samp##1{\realbackslash samp {##1}}%
+\def\,##1{\realbackslash ,{##1}}%
+\def\t##1{\realbackslash t {##1}}%
+\def\r##1{\realbackslash r {##1}}%
+\def\i##1{\realbackslash i {##1}}%
+\def\b##1{\realbackslash b {##1}}%
+\def\sc##1{\realbackslash sc {##1}}%
+\def\cite##1{\realbackslash cite {##1}}%
+\def\key##1{\realbackslash key {##1}}%
+\def\file##1{\realbackslash file {##1}}%
+\def\var##1{\realbackslash var {##1}}%
+\def\kbd##1{\realbackslash kbd {##1}}%
+\def\dfn##1{\realbackslash dfn {##1}}%
+\def\emph##1{\realbackslash emph {##1}}%
+\def\acronym##1{\realbackslash acronym {##1}}%
+%
+% Handle some cases of @value -- where the variable name does not
+% contain - or _, and the value does not contain any
+% (non-fully-expandable) commands.
+\let\value = \expandablevalue
+%
+\unsepspaces
+}
+
+% If an index command is used in an @example environment, any spaces
+% therein should become regular spaces in the raw index file, not the
+% expansion of \tie (\\leavevmode \penalty \@M \ ).
+{\obeyspaces
+ \gdef\unsepspaces{\obeyspaces\let =\space}}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexdummytex{TeX}
+\def\indexdummydots{...}
+
+\def\indexnofonts{%
+% Just ignore accents.
+\let\,=\indexdummyfont
+\let\"=\indexdummyfont
+\let\`=\indexdummyfont
+\let\'=\indexdummyfont
+\let\^=\indexdummyfont
+\let\~=\indexdummyfont
+\let\==\indexdummyfont
+\let\b=\indexdummyfont
+\let\c=\indexdummyfont
+\let\d=\indexdummyfont
+\let\u=\indexdummyfont
+\let\v=\indexdummyfont
+\let\H=\indexdummyfont
+\let\dotless=\indexdummyfont
+% Take care of the plain tex special European modified letters.
+\def\oe{oe}%
+\def\ae{ae}%
+\def\aa{aa}%
+\def\OE{OE}%
+\def\AE{AE}%
+\def\AA{AA}%
+\def\o{o}%
+\def\O{O}%
+\def\l{l}%
+\def\L{L}%
+\def\ss{ss}%
+\let\w=\indexdummyfont
+\let\t=\indexdummyfont
+\let\r=\indexdummyfont
+\let\i=\indexdummyfont
+\let\b=\indexdummyfont
+\let\emph=\indexdummyfont
+\let\strong=\indexdummyfont
+\let\cite=\indexdummyfont
+\let\sc=\indexdummyfont
+%Don't no-op \tt, since it isn't a user-level command
+% and is used in the definitions of the active chars like <, >, |...
+%\let\tt=\indexdummyfont
+\let\tclose=\indexdummyfont
+\let\code=\indexdummyfont
+\let\url=\indexdummyfont
+\let\uref=\indexdummyfont
+\let\env=\indexdummyfont
+\let\command=\indexdummyfont
+\let\option=\indexdummyfont
+\let\file=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+\let\TeX=\indexdummytex
+\let\dots=\indexdummydots
+\def\@{@}%
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+ @gdef@realbackslash{\}}
+
+\let\indexbackslash=0  %overridden during \printindex.
+\let\SETmarginindex=\relax % put index entries in margin (undocumented)?
+
+% For \ifx comparisons.
+\def\emptymacro{\empty}
+
+% Most index entries go through here, but \dosubind is the general case.
+% 
+\def\doind#1#2{\dosubind{#1}{#2}\empty}
+
+% Workhorse for all \fooindexes.
+% #1 is name of index, #2 is stuff to put there, #3 is subentry --
+% \empty if called from \doind, as we usually are.  The main exception
+% is with defuns, which call us directly.
+% 
+\def\dosubind#1#2#3{%
+  % Put the index entry in the margin if desired.
+  \ifx\SETmarginindex\relax\else
+    \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}%
+  \fi
+  {%
+    \count255=\lastpenalty
+    {%
+      \indexdummies % Must do this here, since \bf, etc expand at this stage
+      \escapechar=`\\
+      {%
+        \let\folio = 0% We will expand all macros now EXCEPT \folio.
+        \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+        % so it will be output as is; and it will print as backslash.
+        %
+        \def\thirdarg{#3}%
+        %
+        % If third arg is present, precede it with space in sort key.
+        \ifx\thirdarg\emptymacro
+          \let\subentry = \empty
+        \else
+          \def\subentry{ #3}%
+        \fi
+        %
+        % First process the index-string with all font commands turned off
+        % to get the string to sort by.
+        {\indexnofonts \xdef\indexsorttmp{#2\subentry}}%
+        %
+        % Now produce the complete index entry, with both the sort key and the
+        % original text, including any font commands.
+        \toks0 = {#2}%
+        \edef\temp{%
+          \write\csname#1indfile\endcsname{%
+            \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}%
+        }%
+        %
+        % If third (subentry) arg is present, add it to the index string.
+        \ifx\thirdarg\emptymacro \else
+          \toks0 = {#3}%
+          \edef\temp{\temp{\the\toks0}}%
+        \fi
+        %
+        % If a skip is the last thing on the list now, preserve it
+        % by backing up by \lastskip, doing the \write, then inserting
+        % the skip again.  Otherwise, the whatsit generated by the
+        % \write will make \lastskip zero.  The result is that sequences
+        % like this:
+        % @end defun
+        % @tindex whatever
+        % @defun ...
+        % will have extra space inserted, because the \medbreak in the
+        % start of the @defun won't see the skip inserted by the @end of
+        % the previous defun.
+        % 
+        % But don't do any of this if we're not in vertical mode.  We
+        % don't want to do a \vskip and prematurely end a paragraph.
+        % 
+        % Avoid page breaks due to these extra skips, too.
+        % 
+        \iflinks
+          \ifvmode
+            \skip0 = \lastskip
+            \ifdim\lastskip = 0pt \else \nobreak\vskip-\lastskip \fi
+          \fi
+          %
+          \temp % do the write
+          %
+          % 
+          \ifvmode \ifdim\skip0 = 0pt \else \nobreak\vskip\skip0 \fi \fi
+        \fi
+      }%
+    }%
+    \penalty\count255
+  }%
+}
+
+% The index entry written in the file actually looks like
+%  \entry {sortstring}{page}{topic}
+% or
+%  \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+%  \initial {c}
+%     before the first topic whose initial is c
+%  \entry {topic}{pagelist}
+%     for a topic that is used without subtopics
+%  \primary {topic}
+%     for the beginning of a topic that is used with subtopics
+%  \secondary {subtopic}{pagelist}
+%     for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% @printindex causes a particular index (the ??s file) to get printed.
+% It does not print any chapter heading (usually an @unnumbered).
+%
+\def\printindex{\parsearg\doprintindex}
+\def\doprintindex#1{\begingroup
+  \dobreak \chapheadingskip{10000}%
+  %
+  \indexfonts \rm
+  \tolerance = 9500
+  \indexbreaks
+  %
+  % See if the index file exists and is nonempty.
+  % Change catcode of @ here so that if the index file contains
+  % \initial {@}
+  % as its first line, TeX doesn't complain about mismatched braces
+  % (because it thinks @} is a control sequence).
+  \catcode`\@ = 11
+  \openin 1 \jobname.#1s
+  \ifeof 1
+    % \enddoublecolumns gets confused if there is no text in the index,
+    % and it loses the chapter title and the aux file entries for the
+    % index.  The easiest way to prevent this problem is to make sure
+    % there is some text.
+    (Index is nonexistent)
+  \else
+    %
+    % If the index file exists but is empty, then \openin leaves \ifeof
+    % false.  We have to make TeX try to read something from the file, so
+    % it can discover if there is anything in it.
+    \read 1 to \temp
+    \ifeof 1
+      (Index is empty)
+    \else
+      % Index files are almost Texinfo source, but we use \ as the escape
+      % character.  It would be better to use @, but that's too big a change
+      % to make right now.
+      \def\indexbackslash{\rawbackslashxx}%
+      \catcode`\\ = 0
+      \escapechar = `\\
+      \begindoublecolumns
+      \input \jobname.#1s
+      \enddoublecolumns
+    \fi
+  \fi
+  \closein 1
+\endgroup}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+\def\initial#1{{%
+  % Some minor font changes for the special characters.
+  \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+  %
+  % Remove any glue we may have, we'll be inserting our own.
+  \removelastskip
+  % 
+  % We like breaks before the index initials, so insert a bonus.
+  \penalty -300
+  %
+  % Typeset the initial.  Making this add up to a whole number of
+  % baselineskips increases the chance of the dots lining up from column
+  % to column.  It still won't often be perfect, because of the stretch
+  % we need before each entry, but it's better.
+  % 
+  % No shrink because it confuses \balancecolumns.
+  \vskip 1.67\baselineskip plus .5\baselineskip
+  \leftline{\secbf #1}%
+  \vskip .33\baselineskip plus .1\baselineskip
+  %
+  % Do our best not to break after the initial.
+  \nobreak
+}}
+
+% This typesets a paragraph consisting of #1, dot leaders, and then #2
+% flush to the right margin.  It is used for index and table of contents
+% entries.  The paragraph is indented by \leftskip.
+%
+\def\entry#1#2{\begingroup
+  %
+  % Start a new paragraph if necessary, so our assignments below can't
+  % affect previous text.
+  \par
+  %
+  % Do not fill out the last line with white space.
+  \parfillskip = 0in
+  %
+  % No extra space above this paragraph.
+  \parskip = 0in
+  %
+  % Do not prefer a separate line ending with a hyphen to fewer lines.
+  \finalhyphendemerits = 0
+  %
+  % \hangindent is only relevant when the entry text and page number
+  % don't both fit on one line.  In that case, bob suggests starting the
+  % dots pretty far over on the line.  Unfortunately, a large
+  % indentation looks wrong when the entry text itself is broken across
+  % lines.  So we use a small indentation and put up with long leaders.
+  %
+  % \hangafter is reset to 1 (which is the value we want) at the start
+  % of each paragraph, so we need not do anything with that.
+  \hangindent = 2em
+  %
+  % When the entry text needs to be broken, just fill out the first line
+  % with blank space.
+  \rightskip = 0pt plus1fil
+  %
+  % A bit of stretch before each entry for the benefit of balancing columns.
+  \vskip 0pt plus1pt
+  %
+  % Start a ``paragraph'' for the index entry so the line breaking
+  % parameters we've set above will have an effect.
+  \noindent
+  %
+  % Insert the text of the index entry.  TeX will do line-breaking on it.
+  #1%
+  % The following is kludged to not output a line of dots in the index if
+  % there are no page numbers.  The next person who breaks this will be
+  % cursed by a Unix daemon.
+  \def\tempa{{\rm }}%
+  \def\tempb{#2}%
+  \edef\tempc{\tempa}%
+  \edef\tempd{\tempb}%
+  \ifx\tempc\tempd\ \else%
+    %
+    % If we must, put the page number on a line of its own, and fill out
+    % this line with blank space.  (The \hfil is overwhelmed with the
+    % fill leaders glue in \indexdotfill if the page number does fit.)
+    \hfil\penalty50
+    \null\nobreak\indexdotfill % Have leaders before the page number.
+    %
+    % The `\ ' here is removed by the implicit \unskip that TeX does as
+    % part of (the primitive) \par.  Without it, a spurious underfull
+    % \hbox ensues.
+    \ #2% The page number ends the paragraph.
+  \fi%
+  \par
+\endgroup}
+
+% Like \dotfill except takes at least 1 em.
+\def\indexdotfill{\cleaders
+  \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+
+\def\secondary #1#2{
+{\parfillskip=0in \parskip=0in
+\hangindent =1in \hangafter=1
+\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par
+}}
+
+% Define two-column mode, which we use to typeset indexes.
+% Adapted from the TeXbook, page 416, which is to say,
+% the manmac.tex format used to print the TeXbook itself.
+\catcode`\@=11
+
+\newbox\partialpage
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns
+  % Grab any single-column material above us.
+  \output = {\global\setbox\partialpage = \vbox{%
+    % 
+    % Here is a possibility not foreseen in manmac: if we accumulate a
+    % whole lot of material, we might end up calling this \output
+    % routine twice in a row (see the doublecol-lose test, which is
+    % essentially a couple of indexes with @setchapternewpage off).  In
+    % that case, we must prevent the second \partialpage from
+    % simply overwriting the first, causing us to lose the page.
+    % This will preserve it until a real output routine can ship it
+    % out.  Generally, \partialpage will be empty when this runs and
+    % this will be a no-op.
+    \unvbox\partialpage
+    %
+    % Unvbox the main output page.
+    \unvbox255
+    \kern-\topskip \kern\baselineskip
+  }}%
+  \eject % run that output routine to set \partialpage
+  %
+  % Use the double-column output routine for subsequent pages.
+  \output = {\doublecolumnout}%
+  %
+  % Change the page size parameters.  We could do this once outside this
+  % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+  % format, but then we repeat the same computation.  Repeating a couple
+  % of assignments once per index is clearly meaningless for the
+  % execution time, so we may as well do it in one place.
+  %
+  % First we halve the line length, less a little for the gutter between
+  % the columns.  We compute the gutter based on the line length, so it
+  % changes automatically with the paper format.  The magic constant
+  % below is chosen so that the gutter has the same value (well, +-<1pt)
+  % as it did when we hard-coded it.
+  %
+  % We put the result in a separate register, \doublecolumhsize, so we
+  % can restore it in \pagesofar, after \hsize itself has (potentially)
+  % been clobbered.
+  %
+  \doublecolumnhsize = \hsize
+    \advance\doublecolumnhsize by -.04154\hsize
+    \divide\doublecolumnhsize by 2
+  \hsize = \doublecolumnhsize
+  %
+  % Double the \vsize as well.  (We don't need a separate register here,
+  % since nobody clobbers \vsize.)
+  \advance\vsize by -\ht\partialpage
+  \vsize = 2\vsize
+}
+
+% The double-column output routine for all double-column pages except
+% the last.
+% 
+\def\doublecolumnout{%
+  \splittopskip=\topskip \splitmaxdepth=\maxdepth
+  % Get the available space for the double columns -- the normal
+  % (undoubled) page height minus any material left over from the
+  % previous page.
+  \dimen@ = \vsize
+  \divide\dimen@ by 2
+  %
+  % box0 will be the left-hand column, box2 the right.
+  \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+  \onepageout\pagesofar
+  \unvbox255
+  \penalty\outputpenalty
+}
+\def\pagesofar{%
+  % Re-output the contents of the output page -- any previous material,
+  % followed by the two boxes we just split, in box0 and box2.
+  \advance\vsize by \ht\partialpage
+  \unvbox\partialpage
+  %
+  \hsize = \doublecolumnhsize
+  \wd0=\hsize \wd2=\hsize
+  \hbox to\pagewidth{\box0\hfil\box2}%
+}
+\def\enddoublecolumns{%
+  \output = {%
+    % Split the last of the double-column material.  Leave it on the
+    % current page, no automatic page break.
+    \balancecolumns
+    %
+    % If we end up splitting too much material for the current page,
+    % though, there will be another page break right after this \output
+    % invocation ends.  Having called \balancecolumns once, we do not
+    % want to call it again.  Therefore, reset \output to its normal
+    % definition right away.  (We hope \balancecolumns will never be
+    % called on to balance too much material, but if it is, this makes
+    % the output somewhat more palatable.)
+    \global\output = {\onepageout{\pagecontents\PAGE}}%
+  }%
+  \eject
+  \endgroup % started in \begindoublecolumns
+  %
+  % \pagegoal was set to the doubled \vsize above, since we restarted
+  % the current page.  We're now back to normal single-column
+  % typesetting, so reset \pagegoal to the normal \vsize (after the
+  % \endgroup where \vsize got restored).
+  \pagegoal = \vsize
+}
+\def\balancecolumns{%
+  % Called at the end of the double column material.
+  \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120.
+  \dimen@ = \ht0
+  \advance\dimen@ by \topskip
+  \advance\dimen@ by-\baselineskip
+  \divide\dimen@ by 2 % target to split to
+  %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}%
+  \splittopskip = \topskip
+  % Loop until we get a decent breakpoint.
+  {%
+    \vbadness = 10000
+    \loop
+      \global\setbox3 = \copy0
+      \global\setbox1 = \vsplit3 to \dimen@
+    \ifdim\ht3>\dimen@
+      \global\advance\dimen@ by 1pt
+    \repeat
+  }%
+  %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}%
+  \setbox0=\vbox to\dimen@{\unvbox1}%
+  \setbox2=\vbox to\dimen@{\unvbox3}%
+  %
+  \pagesofar
+}
+\catcode`\@ = \other
+
+
+\message{sectioning,}
+% Define chapters, sections, etc.
+
+\newcount\chapno
+\newcount\secno        \secno=0
+\newcount\subsecno     \subsecno=0
+\newcount\subsubsecno  \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount\appendixno  \appendixno = `\@
+\def\appendixletter{\char\the\appendixno}
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it.  @section does likewise.
+\def\thischapter{}
+\def\thissection{}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raise/lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+\let\up=\raisesections % original BFox name
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+\let\down=\lowersections % original BFox name
+
+% Choose a numbered-heading macro
+% #1 is heading level if unmodified by @raisesections or @lowersections
+% #2 is text for heading
+\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+  \chapterzzz{#2}
+\or
+  \seczzz{#2}
+\or
+  \numberedsubseczzz{#2}
+\or
+  \numberedsubsubseczzz{#2}
+\else
+  \ifnum \absseclevel<0
+    \chapterzzz{#2}
+  \else
+    \numberedsubsubseczzz{#2}
+  \fi
+\fi
+}
+
+% like \numhead, but chooses appendix heading levels
+\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+  \appendixzzz{#2}
+\or
+  \appendixsectionzzz{#2}
+\or
+  \appendixsubseczzz{#2}
+\or
+  \appendixsubsubseczzz{#2}
+\else
+  \ifnum \absseclevel<0
+    \appendixzzz{#2}
+  \else
+    \appendixsubsubseczzz{#2}
+  \fi
+\fi
+}
+
+% like \numhead, but chooses numberless heading levels
+\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+  \unnumberedzzz{#2}
+\or
+  \unnumberedseczzz{#2}
+\or
+  \unnumberedsubseczzz{#2}
+\or
+  \unnumberedsubsubseczzz{#2}
+\else
+  \ifnum \absseclevel<0
+    \unnumberedzzz{#2}
+  \else
+    \unnumberedsubsubseczzz{#2}
+  \fi
+\fi
+}
+
+% @chapter, @appendix, @unnumbered.
+\def\thischaptername{No Chapter Title}
+\outer\def\chapter{\parsearg\chapteryyy}
+\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \chapno by 1 \message{\putwordChapter\space \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+% We don't substitute the actual chapter name into \thischapter
+% because we don't want its macros evaluated now.
+\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}%
+                                  {\the\chapno}}}%
+\temp
+\donoderef
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+}
+
+\outer\def\appendix{\parsearg\appendixyyy}
+\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz
+\def\appendixzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \appendixno by 1
+\message{\putwordAppendix\space \appendixletter}%
+\chapmacro {#1}{\putwordAppendix{} \appendixletter}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}%
+                       {\putwordAppendix{} \appendixletter}}}%
+\temp
+\appendixnoderef
+\global\let\section = \appendixsec
+\global\let\subsection = \appendixsubsec
+\global\let\subsubsection = \appendixsubsubsec
+}
+
+% @centerchap is like @unnumbered, but the heading is centered.
+\outer\def\centerchap{\parsearg\centerchapyyy}
+\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}}
+
+% @top is like @unnumbered.
+\outer\def\top{\parsearg\unnumberedyyy}
+
+\outer\def\unnumbered{\parsearg\unnumberedyyy}
+\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz
+\def\unnumberedzzz #1{%
+\secno=0 \subsecno=0 \subsubsecno=0
+%
+% This used to be simply \message{#1}, but TeX fully expands the
+% argument to \message.  Therefore, if #1 contained @-commands, TeX
+% expanded them.  For example, in `@unnumbered The @cite{Book}', TeX
+% expanded @cite (which turns out to cause errors because \cite is meant
+% to be executed, not expanded).
+%
+% Anyway, we don't want the fully-expanded definition of @cite to appear
+% as a result of the \message, we just want `@cite' itself.  We use
+% \the<toks register> to achieve this: TeX expands \the<toks> only once,
+% simply yielding the contents of <toks register>.  (We also do this for
+% the toc entries.)
+\toks0 = {#1}\message{(\the\toks0)}%
+%
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbchapentry{\the\toks0}}}%
+\temp
+\unnumbnoderef
+\global\let\section = \unnumberedsec
+\global\let\subsection = \unnumberedsubsec
+\global\let\subsubsection = \unnumberedsubsubsec
+}
+
+% Sections.
+\outer\def\numberedsec{\parsearg\secyyy}
+\def\secyyy #1{\numhead1{#1}} % normally calls seczzz
+\def\seczzz #1{%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}%
+                                  {\the\chapno}{\the\secno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsection{\parsearg\appendixsecyyy}
+\outer\def\appendixsec{\parsearg\appendixsecyyy}
+\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz
+\def\appendixsectionzzz #1{%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}%
+                                  {\appendixletter}{\the\secno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy}
+\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz
+\def\unnumberedseczzz #1{%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsecentry{\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% Subsections.
+\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy}
+\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz
+\def\numberedsubseczzz #1{%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}%
+                                    {\the\chapno}{\the\secno}{\the\subsecno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy}
+\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz
+\def\appendixsubseczzz #1{%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}%
+                                {\appendixletter}{\the\secno}{\the\subsecno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy}
+\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz
+\def\unnumberedsubseczzz #1{%
+\plainsubsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsecentry%
+                                    {\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% Subsubsections.
+\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy}
+\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz
+\def\numberedsubsubseczzz #1{%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+  {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}%
+  {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}%
+\temp
+\donoderef
+\nobreak
+}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy}
+\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz
+\def\appendixsubsubseczzz #1{%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+  {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}%
+  {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}%
+\temp
+\appendixnoderef
+\nobreak
+}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy}
+\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz
+\def\unnumberedsubsubseczzz #1{%
+\plainsubsubsecheading {#1}\gdef\thissection{#1}%
+\toks0 = {#1}%
+\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsubsecentry%
+                                    {\the\toks0}}}%
+\temp
+\unnumbnoderef
+\nobreak
+}
+
+% These are variants which are not "outer", so they can appear in @ifinfo.
+% Actually, they should now be obsolete; ordinary section commands should work.
+\def\infotop{\parsearg\unnumberedzzz}
+\def\infounnumbered{\parsearg\unnumberedzzz}
+\def\infounnumberedsec{\parsearg\unnumberedseczzz}
+\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+
+\def\infoappendix{\parsearg\appendixzzz}
+\def\infoappendixsec{\parsearg\appendixseczzz}
+\def\infoappendixsubsec{\parsearg\appendixsubseczzz}
+\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz}
+
+\def\infochapter{\parsearg\chapterzzz}
+\def\infosection{\parsearg\sectionzzz}
+\def\infosubsection{\parsearg\subsectionzzz}
+\def\infosubsubsection{\parsearg\subsubsectionzzz}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+% NOTE on use of \vbox for chapter headings, section headings, and such:
+%       1) We use \vbox rather than the earlier \line to permit
+%          overlong headings to fold.
+%       2) \hyphenpenalty is set to 10000 because hyphenation in a
+%          heading is obnoxious; this forbids it.
+%       3) Likewise, headings look best if no \parindent is used, and
+%          if justification is not attempted.  Hence \raggedright.
+
+
+\def\majorheading{\parsearg\majorheadingzzz}
+\def\majorheadingzzz #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                  \parindent=0pt\raggedright
+                  \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\chapheading{\parsearg\chapheadingzzz}
+\def\chapheadingzzz #1{\chapbreak %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                  \parindent=0pt\raggedright
+                  \rm #1\hfill}}\bigskip \par\penalty 200}
+
+% @heading, @subheading, @subsubheading.
+\def\heading{\parsearg\plainsecheading}
+\def\subheading{\parsearg\plainsubsecheading}
+\def\subsubheading{\parsearg\plainsubsubsecheading}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip\chapheadingskip
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{
+\global\let\contentsalignmacro = \chapoddpage
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain
+\global\let\centerchapmacro=\centerchfplain}
+
+% Plain chapter opening.
+% #1 is the text, #2 the chapter number or empty if unnumbered.
+\def\chfplain#1#2{%
+  \pchapsepmacro
+  {%
+    \chapfonts \rm
+    \def\chapnum{#2}%
+    \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}%
+    \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright
+          \hangindent = \wd0 \centerparametersmaybe
+          \unhbox0 #1\par}%
+  }%
+  \nobreak\bigskip % no page break after a chapter title
+  \nobreak
+}
+
+% Plain opening for unnumbered.
+\def\unnchfplain#1{\chfplain{#1}{}}
+
+% @centerchap -- centered and unnumbered.
+\let\centerparametersmaybe = \relax
+\def\centerchfplain#1{{%
+  \def\centerparametersmaybe{%
+    \advance\rightskip by 3\rightskip
+    \leftskip = \rightskip
+    \parfillskip = 0pt
+  }%
+  \chfplain{#1}{}%
+}}
+
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                       \parindent=0pt\raggedright
+                       \rm #1\hfill}}\bigskip \par\nobreak
+}
+
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+
+\def\centerchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                       \parindent=0pt
+                       \hfill {\rm #1}\hfill}}\bigskip \par\nobreak
+}
+
+\def\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen
+\global\let\centerchapmacro=\centerchfopen}
+
+
+% Section titles.
+\newskip\secheadingskip
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}}
+\def\plainsecheading#1{\sectionheading{sec}{}{#1}}
+
+% Subsection titles.
+\newskip \subsecheadingskip
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}}
+\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}}
+
+% Subsubsection titles.
+\let\subsubsecheadingskip = \subsecheadingskip
+\let\subsubsecheadingbreak = \subsecheadingbreak
+\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}}
+\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}}
+
+
+% Print any size section title.
+%
+% #1 is the section type (sec/subsec/subsubsec), #2 is the section
+% number (maybe empty), #3 the text.
+\def\sectionheading#1#2#3{%
+  {%
+    \expandafter\advance\csname #1headingskip\endcsname by \parskip
+    \csname #1headingbreak\endcsname
+  }%
+  {%
+    % Switch to the right set of fonts.
+    \csname #1fonts\endcsname \rm
+    %
+    % Only insert the separating space if we have a section number.
+    \def\secnum{#2}%
+    \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}%
+    %
+    \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright
+          \hangindent = \wd0 % zero if no section number
+          \unhbox0 #3}%
+  }%
+  \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak
+}
+
+
+\message{toc,}
+\newwrite\tocfile
+
+% Write an entry to the toc file, opening it if necessary.
+% Called from @chapter, etc.  We supply {\folio} at the end of the
+% argument, which will end up as the last argument to the \...entry macro.
+% 
+% We open the .toc file here instead of at @setfilename or any other
+% given time so that @contents can be put in the document anywhere.
+% 
+\newif\iftocfileopened
+\def\writetocentry#1{%
+  \iftocfileopened\else
+    \immediate\openout\tocfile = \jobname.toc
+    \global\tocfileopenedtrue
+  \fi
+  \iflinks \write\tocfile{#1{\folio}}\fi
+}
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\newcount\savepageno
+\newcount\lastnegativepageno \lastnegativepageno = -1
+
+% Finish up the main text and prepare to read what we've written
+% to \tocfile.
+% 
+\def\startcontents#1{%
+   % If @setchapternewpage on, and @headings double, the contents should
+   % start on an odd page, unlike chapters.  Thus, we maintain
+   % \contentsalignmacro in parallel with \pagealignmacro.
+   % From: Torbjorn Granlund <tege@matematik.su.se>
+   \contentsalignmacro
+   \immediate\closeout\tocfile
+   %
+   % Don't need to put `Contents' or `Short Contents' in the headline.
+   % It is abundantly clear what they are.
+   \unnumbchapmacro{#1}\def\thischapter{}%
+   \savepageno = \pageno
+   \begingroup                  % Set up to handle contents files properly.
+      \catcode`\\=0  \catcode`\{=1  \catcode`\}=2  \catcode`\@=11
+      % We can't do this, because then an actual ^ in a section
+      % title fails, e.g., @chapter ^ -- exponentiation.  --karl, 9jul97.
+      %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi
+      \raggedbottom             % Worry more about breakpoints than the bottom.
+      \advance\hsize by -\contentsrightmargin % Don't use the full line length.
+      %
+      % Roman numerals for page numbers.
+      \ifnum \pageno>0 \pageno = \lastnegativepageno \fi
+}
+
+
+% Normal (long) toc.
+\def\contents{%
+   \startcontents{\putwordTableofContents}%
+     \openin 1 \jobname.toc
+     \ifeof 1 \else
+       \closein 1
+       \input \jobname.toc
+     \fi
+     \vfill \eject
+   \endgroup
+   \lastnegativepageno = \pageno
+   \pageno = \savepageno
+}
+
+% And just the chapters.
+\def\summarycontents{%
+   \startcontents{\putwordShortContents}%
+      %
+      \let\chapentry = \shortchapentry
+      \let\unnumbchapentry = \shortunnumberedentry
+      % We want a true roman here for the page numbers.
+      \secfonts
+      \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl
+      \rm
+      \hyphenpenalty = 10000
+      \advance\baselineskip by 1pt % Open it up a little.
+      \def\secentry ##1##2##3##4{}
+      \def\unnumbsecentry ##1##2{}
+      \def\subsecentry ##1##2##3##4##5{}
+      \def\unnumbsubsecentry ##1##2{}
+      \def\subsubsecentry ##1##2##3##4##5##6{}
+      \def\unnumbsubsubsecentry ##1##2{}
+      \openin 1 \jobname.toc
+      \ifeof 1 \else
+        \closein 1
+        \input \jobname.toc
+      \fi
+     \vfill \eject
+   \endgroup
+   \lastnegativepageno = \pageno
+   \pageno = \savepageno
+}
+\let\shortcontents = \summarycontents
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Chapter-level things, for both the long and short contents.
+\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}}
+
+% See comments in \dochapentry re vbox and related settings
+\def\shortchapentry#1#2#3{%
+  \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}%
+}
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter.
+% We could simplify the code here by writing out an \appendixentry
+% command in the toc file for appendices, instead of using \chapentry
+% for both, but it doesn't seem worth it.
+\setbox0 = \hbox{\shortcontrm \putwordAppendix }
+\newdimen\shortappendixwidth \shortappendixwidth = \wd0
+
+\def\shortchaplabel#1{%
+  % We typeset #1 in a box of constant width, regardless of the text of
+  % #1, so the chapter titles will come out aligned.
+  \setbox0 = \hbox{#1}%
+  \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi
+  %
+  % This space should be plenty, since a single number is .5em, and the
+  % widest letter (M) is 1em, at least in the Computer Modern fonts.
+  % (This space doesn't include the extra space that gets added after
+  % the label; that gets put in by \shortchapentry above.)
+  \advance\dimen0 by 1.1em
+  \hbox to \dimen0{#1\hfil}%
+}
+
+\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}}
+\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}}
+
+% Sections.
+\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}}
+\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}}
+
+% Subsections.
+\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}}
+\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}}
+
+% And subsubsections.
+\def\subsubsecentry#1#2#3#4#5#6{%
+  \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}}
+\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}}
+
+% This parameter controls the indentation of the various levels.
+\newdimen\tocindent \tocindent = 3pc
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we want it to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+   \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip
+   \begingroup
+     \chapentryfonts
+     \tocentry{#1}{\dopageno{#2}}%
+   \endgroup
+   \nobreak\vskip .25\baselineskip plus.1\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+  \secentryfonts \leftskip=\tocindent
+  \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+  \subsecentryfonts \leftskip=2\tocindent
+  \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+  \subsubsecentryfonts \leftskip=3\tocindent
+  \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+% Final typesetting of a toc entry; we use the same \entry macro as for
+% the index entries, but we want to suppress hyphenation here.  (We
+% can't do that in the \entry macro, since index entries might consist
+% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.)
+\def\tocentry#1#2{\begingroup
+  \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks
+  % Do not use \turnoffactive in these arguments.  Since the toc is
+  % typeset in cmr, so characters such as _ would come out wrong; we
+  % have to do the usual translation tricks.
+  \entry{#1}{#2}%
+\endgroup}
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\let\subsecentryfonts = \textfonts
+\let\subsubsecentryfonts = \textfonts
+
+
+\message{environments,}
+
+% Since these characters are used in examples, it should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+% Furthermore, these definitions must come after we define our fonts.
+\newbox\dblarrowbox    \newbox\longdblarrowbox
+\newbox\pushcharbox    \newbox\bullbox
+\newbox\equivbox       \newbox\errorbox
+
+%{\tentt
+%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil}
+%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil}
+%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil}
+%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil}
+% Adapted from the manmac format (p.420 of TeXbook)
+%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex
+%                                      depth .1ex\hfil}
+%}
+
+% @point{}, @result{}, @expansion{}, @print{}, @equiv{}.
+\def\point{$\star$}
+\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% Adapted from the TeXbook's \boxit.
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt}
+
+\global\setbox\errorbox=\hbox to \dimen0{\hfil
+   \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+   \advance\hsize by -2\dimen2 % Rules.
+   \vbox{
+      \hrule height\dimen2
+      \hbox{\vrule width\dimen2 \kern3pt          % Space to left of text.
+         \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+         \kern3pt\vrule width\dimen2}% Space to right.
+      \hrule height\dimen2}
+    \hfil}
+
+% The @error{} command.
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @tex ... @end tex    escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\def\tex{\begingroup
+  \catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+  \catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+  \catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+  \catcode `\%=14
+  \catcode 43=12 % plus
+  \catcode`\"=12
+  \catcode`\==12
+  \catcode`\|=12
+  \catcode`\<=12
+  \catcode`\>=12
+  \escapechar=`\\
+  %
+  \let\b=\ptexb
+  \let\bullet=\ptexbullet
+  \let\c=\ptexc
+  \let\,=\ptexcomma
+  \let\.=\ptexdot
+  \let\dots=\ptexdots
+  \let\equiv=\ptexequiv
+  \let\!=\ptexexclam
+  \let\i=\ptexi
+  \let\{=\ptexlbrace
+  \let\+=\tabalign
+  \let\}=\ptexrbrace
+  \let\*=\ptexstar
+  \let\t=\ptext
+  %
+  \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}%
+  \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}%
+  \def\@{@}%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments.  \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% Make each space character in the input produce a normal interword
+% space in the output.  Don't allow a line break at this space, as this
+% is used only in environments like @example, where each line of input
+% should produce a line of output anyway.
+%
+{\obeyspaces %
+\gdef\sepspaces{\obeyspaces\let =\tie}}
+
+% Define \obeyedspace to be our active space, whatever it is.  This is
+% for use in \parsearg.
+{\sepspaces%
+\global\let\obeyedspace= }
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical.  We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip
+%
+\def\aboveenvbreak{{\advance\envskipamount by \parskip
+\endgraf \ifdim\lastskip<\envskipamount
+\removelastskip \penalty-50 \vskip\envskipamount \fi}}
+
+\let\afterenvbreak = \aboveenvbreak
+
+% \nonarrowing is a flag.  If "set", @lisp etc don't narrow margins.
+\let\nonarrowing=\relax
+
+% @cartouche ... @end cartouche: draw rectangle w/rounded corners around
+% environment contents.
+\font\circle=lcircle10
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+\circthick=\fontdimen8\circle
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+        \ctl\leaders\hrule height\circthick\hfil\ctr
+        \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+        \cbl\leaders\hrule height\circthick\hfil\cbr
+        \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+\long\def\cartouche{%
+\begingroup
+        \lskip=\leftskip \rskip=\rightskip
+        \leftskip=0pt\rightskip=0pt %we want these *outside*.
+        \cartinner=\hsize \advance\cartinner by-\lskip
+                          \advance\cartinner by-\rskip
+        \cartouter=\hsize
+        \advance\cartouter by 18.4pt % allow for 3pt kerns on either
+%                                    side, and for 6pt waste from
+%                                    each corner char, and rule thickness
+        \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+        % Flag to tell @lisp, etc., not to narrow margin.
+        \let\nonarrowing=\comment
+        \vbox\bgroup
+                \baselineskip=0pt\parskip=0pt\lineskip=0pt
+                \carttop
+                \hbox\bgroup
+                        \hskip\lskip
+                        \vrule\kern3pt
+                        \vbox\bgroup
+                                \hsize=\cartinner
+                                \kern3pt
+                                \begingroup
+                                        \baselineskip=\normbskip
+                                        \lineskip=\normlskip
+                                        \parskip=\normpskip
+                                        \vskip -\parskip
+\def\Ecartouche{%
+                                \endgroup
+                                \kern3pt
+                        \egroup
+                        \kern3pt\vrule
+                        \hskip\rskip
+                \egroup
+                \cartbot
+        \egroup
+\endgroup
+}}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\def\nonfillstart{%
+  \aboveenvbreak
+  \inENV % This group ends at the end of the body
+  \hfuzz = 12pt % Don't be fussy
+  \sepspaces % Make spaces be word-separators rather than space tokens.
+  \singlespace
+  \let\par = \lisppar % don't ignore blank lines
+  \obeylines % each line of input is a line of output
+  \parskip = 0pt
+  \parindent = 0pt
+  \emergencystretch = 0pt % don't try to avoid overfull boxes
+  % @cartouche defines \nonarrowing to inhibit narrowing
+  % at next level down.
+  \ifx\nonarrowing\relax
+    \advance \leftskip by \lispnarrowing
+    \exdentamount=\lispnarrowing
+    \let\exdent=\nofillexdent
+    \let\nonarrowing=\relax
+  \fi
+}
+
+% Define the \E... control sequence only if we are inside the particular
+% environment, so the error checking in \end will work.
+% 
+% To end an @example-like environment, we first end the paragraph (via
+% \afterenvbreak's vertical glue), and then the group.  That way we keep
+% the zero \parskip that the environments set -- \parskip glue will be
+% inserted at the beginning of the next paragraph in the document, after
+% the environment.
+%
+\def\nonfillfinish{\afterenvbreak\endgroup}
+
+% @lisp: indented, narrowed, typewriter font.
+\def\lisp{\begingroup
+  \nonfillstart
+  \let\Elisp = \nonfillfinish
+  \tt
+  \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special.
+  \gobble       % eat return
+}
+
+% @example: Same as @lisp.
+\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp}
+
+% @small... is usually equivalent to the non-small (@smallbook
+% redefines).  We must call \example (or whatever) last in the
+% definition, since it reads the return following the @example (or
+% whatever) command.
+% 
+% This actually allows (for example) @end display inside an
+% @smalldisplay.  Too bad, but makeinfo will catch the error anyway.
+%
+\def\smalldisplay{\begingroup\def\Esmalldisplay{\nonfillfinish\endgroup}\display}
+\def\smallexample{\begingroup\def\Esmallexample{\nonfillfinish\endgroup}\lisp}
+\def\smallformat{\begingroup\def\Esmallformat{\nonfillfinish\endgroup}\format}
+\def\smalllisp{\begingroup\def\Esmalllisp{\nonfillfinish\endgroup}\lisp}
+
+% Real @smallexample and @smalllisp (when @smallbook): use smaller fonts.
+% Originally contributed by Pavel@xerox.
+\def\smalllispx{\begingroup
+  \def\Esmalllisp{\nonfillfinish\endgroup}%
+  \def\Esmallexample{\nonfillfinish\endgroup}%
+  \indexfonts
+  \lisp
+}
+
+% @display: same as @lisp except keep current font.
+%
+\def\display{\begingroup
+  \nonfillstart
+  \let\Edisplay = \nonfillfinish
+  \gobble
+}
+
+% @smalldisplay (when @smallbook): @display plus smaller fonts.
+%
+\def\smalldisplayx{\begingroup
+  \def\Esmalldisplay{\nonfillfinish\endgroup}%
+  \indexfonts \rm
+  \display
+}
+
+% @format: same as @display except don't narrow margins.
+%
+\def\format{\begingroup
+  \let\nonarrowing = t
+  \nonfillstart
+  \let\Eformat = \nonfillfinish
+  \gobble
+}
+
+% @smallformat (when @smallbook): @format plus smaller fonts.
+%
+\def\smallformatx{\begingroup
+  \def\Esmallformat{\nonfillfinish\endgroup}%
+  \indexfonts \rm
+  \format
+}
+
+% @flushleft (same as @format).
+%
+\def\flushleft{\begingroup \def\Eflushleft{\nonfillfinish\endgroup}\format}
+
+% @flushright.
+% 
+\def\flushright{\begingroup
+  \let\nonarrowing = t
+  \nonfillstart
+  \let\Eflushright = \nonfillfinish
+  \advance\leftskip by 0pt plus 1fill
+  \gobble
+}
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins.
+%
+\def\quotation{%
+  \begingroup\inENV %This group ends at the end of the @quotation body
+  {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+  \singlespace
+  \parindent=0pt
+  % We have retained a nonzero parskip for the environment, since we're
+  % doing normal filling. So to avoid extra space below the environment...
+  \def\Equotation{\parskip = 0pt \nonfillfinish}%
+  %
+  % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+  \ifx\nonarrowing\relax
+    \advance\leftskip by \lispnarrowing
+    \advance\rightskip by \lispnarrowing
+    \exdentamount = \lispnarrowing
+    \let\nonarrowing = \relax
+  \fi
+}
+
+
+\message{defuns,}
+% Define formatter for defuns
+% First, allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\def\activeparens{%
+\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
+\catcode`\[=\active \catcode`\]=\active}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+
+% Be sure that we always have a definition for `(', etc.  For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+\global\let(=\lparen \global\let)=\rparen
+\global\let[=\lbrack \global\let]=\rbrack
+
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+% This is used to turn on special parens
+% but make & act ordinary (given that it's active).
+\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested
+  \global\advance\parencount by 1
+}
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+  % also in that case restore the outer-level definition of (.
+  \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+  \global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\&#1}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text.  This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}\global\advance\parencount by 1 }
+\def\clnr{{\sf\char`\)}\global\advance\parencount by -1 }
+\def\ampnr{\&}
+\def\lbrb{{\bf\char`\[}}
+\def\rbrb{{\bf\char`\]}}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+% Get the values of \leftskip and \rightskip as they were
+% outside the @def...
+\dimen2=\leftskip
+\advance\dimen2 by -\defbodyindent
+\noindent
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+{% Adjust \hsize to exclude the ambient margins,
+% so that \rightline will obey them.
+\advance \hsize by -\dimen2
+\rlap{\rightline{{\rm #2}\hskip -1.25pc }}}%
+% Make all lines underfull and no complaints:
+\tolerance=10000 \hbadness=10000
+\advance\leftskip by -\defbodyindent
+\exdentamount=\defbodyindent
+{\df #1}\enskip        % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+%    such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active % 61 is `='
+\obeylines\activeparens\spacesplit#3}
+
+% #1 is the \E... control sequence to end the definition (which we define).
+% #2 is the \...x control sequence for consecutive fns (which we define).
+% #3 is the control sequence to call to resume processing.
+% #4, delimited by the space, is the class name.
+% 
+\def\defmethparsebody#1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+% @deftypemethod has an extra argument that nothing else does.  Sigh.
+% #1 is the \E... control sequence to end the definition (which we define).
+% #2 is the \...x control sequence for consecutive fns (which we define).
+% #3 is the control sequence to call to resume processing.
+% #4, delimited by the space, is the class name.
+% #5 is the method's return type.
+% 
+\def\deftypemethparsebody#1#2#3#4 #5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}{#5}}}
+
+\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#5}}}
+
+% These parsing functions are similar to the preceding ones
+% except that they do not make parens into active characters.
+% These are used for "variables" since they have no arguments.
+
+\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active %
+\obeylines\spacesplit#3}
+
+% This is used for \def{tp,vr}parsebody.  It could probably be used for
+% some of the others, too, with some judicious conditionals.
+%
+\def\parsebodycommon#1#2#3{%
+  \begingroup\inENV %
+  \medbreak %
+  % Define the end token that this defining construct specifies
+  % so that it will exit this group.
+  \def#1{\endgraf\endgroup\medbreak}%
+  \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}%
+  \parindent=0in
+  \advance\leftskip by \defbodyindent
+  \exdentamount=\defbodyindent
+  \begingroup\obeylines
+}
+
+\def\defvrparsebody#1#2#3#4 {%
+  \parsebodycommon{#1}{#2}{#3}%
+  \spacesplit{#3{#4}}%
+}
+
+% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the
+% type is just `struct', because we lose the braces in `{struct
+% termios}' when \spacesplit reads its undelimited argument.  Sigh.
+% \let\deftpparsebody=\defvrparsebody
+%
+% So, to get around this, we put \empty in with the type name.  That
+% way, TeX won't find exactly `{...}' as an undelimited argument, and
+% won't strip off the braces.
+%
+\def\deftpparsebody #1#2#3#4 {%
+  \parsebodycommon{#1}{#2}{#3}%
+  \spacesplit{\parsetpheaderline{#3{#4}}}\empty
+}
+
+% Fine, but then we have to eventually remove the \empty *and* the
+% braces (if any).  That's what this does.
+%
+\def\removeemptybraces\empty#1\relax{#1}
+
+% After \spacesplit has done its work, this is called -- #1 is the final
+% thing to call, #2 the type name (which starts with \empty), and #3
+% (which might be empty) the arguments.
+%
+\def\parsetpheaderline#1#2#3{%
+  #1{\removeemptybraces#2\relax}{#3}%
+}%
+
+\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\spacesplit{#3{#5}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+%  the first is all of #2 before the space token,
+%  the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs #1{\functionparens \sl
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\hyphenchar\tensl=0
+#1%
+\hyphenchar\tensl=45
+\ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\nobreak\vskip -\parskip\nobreak
+}
+
+\def\deftypefunargs #1{%
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+% Use \boldbraxnoamp, not \functionparens, so that & is not special.
+\boldbraxnoamp
+\tclose{#1}% avoid \code because of side effects on active chars
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\nobreak\vskip -\parskip\nobreak
+}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Function}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefun int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader}
+
+% #1 is the data type.  #2 is the name and args.
+\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax}
+% #1 is the data type, #2 the name, #3 the args.
+\def\deftypefunheaderx #1#2 #3\relax{%
+\doind {fn}{\code{#2}}% Make entry in function index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}%
+\deftypefunargs {#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader}
+
+% \defheaderxcond#1\relax$$$
+% puts #1 in @code, followed by a space, but does nothing if #1 is null.
+\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi}
+
+% #1 is the classification.  #2 is the data type.  #3 is the name and args.
+\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax}
+% #1 is the classification, #2 the data type, #3 the name, #4 the args.
+\def\deftypefnheaderx #1#2#3 #4\relax{%
+\doind {fn}{\code{#3}}% Make entry in function index
+\begingroup
+\normalparens % notably, turn off `&' magic, which prevents
+%               at least some C++ text from working
+\defname {\defheaderxcond#2\relax$$$#3}{#1}%
+\deftypefunargs {#4}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Macro}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Special Form}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% This definition is run if you use @defunx
+% anywhere other than immediately after a @defun or @defunx.
+
+\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
+\def\defunx #1 {\errmessage{@defunx in invalid context}}
+\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
+\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
+\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}}
+\def\deftypemethodx #1 {\errmessage{@deftypemethodx in invalid context}}
+\def\deftypefunx #1 {\errmessage{@deftypefunx in invalid context}}
+
+% @defmethod, and so on
+
+% @defop CATEGORY CLASS OPERATION ARG...
+
+\def\defop #1 {\def\defoptype{#1}%
+\defopparsebody\Edefop\defopx\defopheader\defoptype}
+
+\def\defopheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{\putwordon\ #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype{} on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @deftypemethod CLASS RETURN-TYPE METHOD ARG...
+%
+\def\deftypemethod{%
+  \deftypemethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader}
+%
+% #1 is the class name, #2 the data type, #3 the method name, #4 the args.
+\def\deftypemethodheader#1#2#3#4{%
+  \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index
+  \begingroup
+    \defname{\defheaderxcond#2\relax$$$#3}{\putwordMethodon\ \code{#1}}%
+    \deftypefunargs{#4}%
+  \endgroup
+}
+
+% @defmethod == @defop Method
+%
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+%
+% #1 is the class name, #2 the method name, #3 the args.
+\def\defmethodheader#1#2#3{%
+  \dosubind{fn}{\code{#2}}{\putwordon\ \code{#1}}% entry in function index
+  \begingroup
+    \defname{#2}{\putwordMethodon\ \code{#1}}%
+    \defunargs{#3}%
+  \endgroup
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype{} of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar == @defcv {Instance Variable}
+
+\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader}
+
+\def\defivarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{Instance Variable of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% These definitions are run if you use @defmethodx, etc.,
+% anywhere other than immediately after a @defmethod, etc.
+
+\def\defopx #1 {\errmessage{@defopx in invalid context}}
+\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
+\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
+\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
+
+% Now @defvar
+
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{Variable}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{User Option}%
+\defvarargs {#2}\endgroup %
+}
+
+% @deftypevar int foobar
+
+\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader}
+
+% #1 is the data type.  #2 is the name, perhaps followed by text that
+% is actually part of the data type, which should not be put into the index.
+\def\deftypevarheader #1#2{%
+\dovarind#2 \relax% Make entry in variables index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}%
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak
+\endgroup}
+\def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}}
+
+% @deftypevr {Global Flag} int enable
+
+\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader}
+
+\def\deftypevrheader #1#2#3{\dovarind#3 \relax%
+\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1}
+\interlinepenalty=10000
+\endgraf\nobreak\vskip -\parskip\nobreak
+\endgroup}
+
+% This definition is run if you use @defvarx
+% anywhere other than immediately after a @defvar or @defvarx.
+
+\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
+\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}}
+\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% This definition is run if you use @deftpx, etc
+% anywhere other than immediately after a @deftp, etc.
+
+\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
+
+
+\message{macros,}
+% @macro.
+
+% To do this right we need a feature of e-TeX, \scantokens, 
+% which we arrange to emulate with a temporary file in ordinary TeX.
+\ifx\eTeXversion\undefined
+ \newwrite\macscribble
+ \def\scanmacro#1{%
+   \begingroup \newlinechar`\^^M
+   \immediate\openout\macscribble=\jobname.tmp
+   \immediate\write\macscribble{#1}%
+   \immediate\closeout\macscribble
+   \let\xeatspaces\eatspaces
+   \input \jobname.tmp
+   \endgroup
+}
+\else
+\def\scanmacro#1{%
+\begingroup \newlinechar`\^^M
+\let\xeatspaces\eatspaces\scantokens{#1}\endgroup}
+\fi
+
+\newcount\paramno   % Count of parameters
+\newtoks\macname    % Macro name
+\newif\ifrecursive  % Is it recursive?
+
+% Utility routines.
+% Thisdoes \let #1 = #2, except with \csnames.
+\def\cslet#1#2{%
+\expandafter\expandafter
+\expandafter\let
+\expandafter\expandafter
+\csname#1\endcsname
+\csname#2\endcsname}
+
+% Trim leading and trailing spaces off a string.
+% Concepts from aro-bend problem 15 (see CTAN).
+{\catcode`\@=11
+\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }}
+\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@}
+\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @}
+\def\unbrace#1{#1}
+\unbrace{\gdef\trim@@@ #1 } #2@{#1}
+}
+
+% Trim a single trailing ^^M off a string.
+{\catcode`\^^M=12\catcode`\Q=3%
+\gdef\eatcr #1{\eatcra #1Q^^MQ}%
+\gdef\eatcra#1^^MQ{\eatcrb#1Q}%
+\gdef\eatcrb#1Q#2Q{#1}%
+}
+
+% Macro bodies are absorbed as an argument in a context where
+% all characters are catcode 10, 11 or 12, except \ which is active
+% (as in normal texinfo). It is necessary to change the definition of \.
+
+% It's necessary to have hard CRs when the macro is executed. This is 
+% done by  making ^^M (\endlinechar) catcode 12 when reading the macro 
+% body, and then making it the \newlinechar in \scanmacro.
+
+\def\macrobodyctxt{%
+  \catcode`\~=12
+  \catcode`\^=12
+  \catcode`\_=12
+  \catcode`\|=12
+  \catcode`\<=12
+  \catcode`\>=12
+  \catcode`\+=12
+  \catcode`\{=12
+  \catcode`\}=12
+  \catcode`\@=12
+  \catcode`\^^M=12
+  \usembodybackslash}
+
+\def\macroargctxt{%
+  \catcode`\~=12
+  \catcode`\^=12
+  \catcode`\_=12
+  \catcode`\|=12
+  \catcode`\<=12
+  \catcode`\>=12
+  \catcode`\+=12
+  \catcode`\@=12
+  \catcode`\\=12}
+
+% \mbodybackslash is the definition of \ in @macro bodies.
+% It maps \foo\ => \csname macarg.foo\endcsname => #N 
+% where N is the macro parameter number.
+% We define \csname macarg.\endcsname to be \realbackslash, so
+% \\ in macro replacement text gets you a backslash.
+
+{\catcode`@=0 @catcode`@\=@active
+ @gdef@usembodybackslash{@let\=@mbodybackslash}
+ @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
+}
+\expandafter\def\csname macarg.\endcsname{\realbackslash}
+
+\def\macro{\recursivefalse\parsearg\macroxxx}
+\def\rmacro{\recursivetrue\parsearg\macroxxx}
+
+\def\macroxxx#1{%
+  \getargs{#1}%           now \macname is the macname and \argl the arglist
+  \ifx\argl\empty       % no arguments
+     \paramno=0%
+  \else
+     \expandafter\parsemargdef \argl;% 
+  \fi
+  \expandafter\ifx \csname macsave.\the\macname\endcsname \relax
+     \cslet{macsave.\the\macname}{\the\macname}%
+  \else
+     \message{Warning: redefining \the\macname}%
+  \fi
+  \begingroup \macrobodyctxt
+  \ifrecursive \expandafter\parsermacbody
+  \else \expandafter\parsemacbody 
+  \fi}
+
+\def\unmacro{\parsearg\unmacroxxx}
+\def\unmacroxxx#1{%
+  \expandafter\ifx \csname macsave.\the\macname\endcsname \relax
+    \errmessage{Macro \the\macname\ not defined.}%
+  \else
+    \cslet{#1}{macsave.#1}%
+    \expandafter\let \csname macsave.\the\macname\endcsname \undefined
+  \fi
+}
+
+% This makes use of the obscure feature that if the last token of a
+% <parameter list> is #, then the preceding argument is delimited by
+% an opening brace, and that opening brace is not consumed.
+\def\getargs#1{\getargsxxx#1{}}
+\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs}
+\def\getmacname #1 #2\relax{\macname={#1}}
+\def\getmacargs#1{\def\argl{#1}}
+
+% Parse the optional {params} list.  Set up \paramno and \paramlist
+% so \defmacro knows what to do.  Define \macarg.blah for each blah
+% in the params list, to be ##N where N is the position in that list.
+% That gets used by \mbodybackslash (above).
+
+% We need to get `macro parameter char #' into several definitions.
+% The technique used is stolen from LaTeX:  let \hash be something
+% unexpandable, insert that wherever you need a #, and then redefine
+% it to # just before using the token list produced.
+%
+% The same technique is used to protect \eatspaces till just before
+% the macro is used.
+
+\def\parsemargdef#1;{\paramno=0\def\paramlist{}%
+        \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,}
+\def\parsemargdefxxx#1,{%
+  \if#1;\let\next=\relax
+  \else \let\next=\parsemargdefxxx
+    \advance\paramno by 1%
+    \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
+        {\xeatspaces{\hash\the\paramno}}%
+    \edef\paramlist{\paramlist\hash\the\paramno,}%
+  \fi\next}
+
+% These two commands read recursive and nonrecursive macro bodies.
+% (They're different since rec and nonrec macros end differently.)
+
+\long\def\parsemacbody#1@end macro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+\long\def\parsermacbody#1@end rmacro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+
+% This defines the macro itself. There are six cases: recursive and
+% nonrecursive macros of zero, one, and many arguments.
+% Much magic with \expandafter here.
+% \xdef is used so that macro definitions will survive the file
+% they're defined in; @include reads the file inside a group.
+\def\defmacro{%
+  \let\hash=##% convert placeholders to macro parameter chars
+  \ifrecursive
+    \ifcase\paramno
+    % 0
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \noexpand\scanmacro{\temp}}%
+    \or % 1
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\braceorline\csname\the\macname xxx\endcsname}%
+      \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+         \egroup\noexpand\scanmacro{\temp}}%
+    \else % many
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\csname\the\macname xx\endcsname}
+      \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+          \csname\the\macname xxx\endcsname ##1,}%
+      \expandafter\expandafter
+      \expandafter\xdef
+      \expandafter\expandafter
+        \csname\the\macname xxx\endcsname 
+          \paramlist{\egroup\noexpand\scanmacro{\temp}}%
+    \fi
+  \else
+    \ifcase\paramno
+    % 0
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \noexpand\norecurse{\the\macname}%
+        \noexpand\scanmacro{\temp}\egroup}%
+    \or % 1
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\braceorline\csname\the\macname xxx\endcsname}%
+      \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+        \egroup
+        \noexpand\norecurse{\the\macname}%
+        \noexpand\scanmacro{\temp}\egroup}%
+    \else % many
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\csname\the\macname xx\endcsname}
+      \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+          \csname\the\macname xxx\endcsname ##1,}%
+      \expandafter\expandafter
+      \expandafter\xdef
+      \expandafter\expandafter
+      \csname\the\macname xxx\endcsname
+      \paramlist{%
+          \egroup
+          \noexpand\norecurse{\the\macname}%
+          \noexpand\scanmacro{\temp}\egroup}%
+    \fi
+  \fi}
+
+\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
+
+% \braceorline decides whether the next nonwhitespace character is a
+% {.  If so it reads up to the closing }, if not, it reads the whole
+% line.  Whatever was read is then fed to the next control sequence
+% as an argument (by \parsebrace or \parsearg)
+\def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx}
+\def\braceorlinexxx{%
+  \ifx\nchar\bgroup\else
+    \expandafter\parsearg 
+  \fi \next}
+
+
+\message{cross references,}
+\newwrite\auxfile
+
+\newif\ifhavexrefs    % True if xref values are known.
+\newif\ifwarnedxrefs  % True if we warned once that they aren't known.
+
+% @inforef is relatively simple.
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+  node \samp{\ignorespaces#1{}}}
+
+% @node's job is to define \lastnode.
+\def\node{\ENVcheck\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\nwnode=\node
+\let\lastnode=\relax
+
+% The sectioning commands (@chapter, etc.) call these.
+\def\donoderef{%
+  \ifx\lastnode\relax\else
+    \expandafter\expandafter\expandafter\setref{\lastnode}%
+      {Ysectionnumberandtype}%
+    \global\let\lastnode=\relax
+  \fi
+}
+\def\unnumbnoderef{%
+  \ifx\lastnode\relax\else
+    \expandafter\expandafter\expandafter\setref{\lastnode}{Ynothing}%
+    \global\let\lastnode=\relax
+  \fi
+}
+\def\appendixnoderef{%
+  \ifx\lastnode\relax\else
+    \expandafter\expandafter\expandafter\setref{\lastnode}%
+      {Yappendixletterandtype}%
+    \global\let\lastnode=\relax
+  \fi
+}
+
+
+% @anchor{NAME} -- define xref target at arbitrary point.
+% 
+\def\anchor#1{\setref{#1}{Ynothing}}
+
+
+% \setref{NAME}{SNT} defines a cross-reference point NAME, namely
+% NAME-title, NAME-pg, and NAME-SNT.  Called from \foonoderef.  We have
+% to set \indexdummies so commands such as @code in a section title
+% aren't expanded.  It would be nicer not to expand the titles in the
+% first place, but there's so many layers that that is hard to do.
+% 
+\def\setref#1#2{{%
+  \indexdummies
+  \dosetq{#1-title}{Ytitle}%
+  \dosetq{#1-pg}{Ypagenumber}%
+  \dosetq{#1-snt}{#2}
+}}
+
+% @xref, @pxref, and @ref generate cross-references.  For \xrefX, #1 is
+% the node name, #2 the name of the Info cross-reference, #3 the printed
+% node name, #4 the name of the Info file, #5 the name of the printed
+% manual.  All but the node name can be omitted.
+%
+\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]}
+\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+  \def\printedmanual{\ignorespaces #5}%
+  \def\printednodename{\ignorespaces #3}%
+  \setbox1=\hbox{\printedmanual}%
+  \setbox0=\hbox{\printednodename}%
+  \ifdim \wd0 = 0pt
+    % No printed node name was explicitly given.
+    \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax
+      % Use the node name inside the square brackets.
+      \def\printednodename{\ignorespaces #1}%
+    \else
+      % Use the actual chapter/section title appear inside
+      % the square brackets.  Use the real section title if we have it.
+      \ifdim \wd1 > 0pt
+        % It is in another manual, so we don't have it.
+        \def\printednodename{\ignorespaces #1}%
+      \else
+        \ifhavexrefs
+          % We know the real title if we have the xref values.
+          \def\printednodename{\refx{#1-title}{}}%
+        \else
+          % Otherwise just copy the Info node name.
+          \def\printednodename{\ignorespaces #1}%
+        \fi%
+      \fi
+    \fi
+  \fi
+  %
+  % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not
+  % insert empty discretionaries after hyphens, which means that it will
+  % not find a line break at a hyphen in a node names.  Since some manuals
+  % are best written with fairly long node names, containing hyphens, this
+  % is a loss.  Therefore, we give the text of the node name again, so it
+  % is as if TeX is seeing it for the first time.
+  \ifdim \wd1 > 0pt
+    \putwordsection{} ``\printednodename'' in \cite{\printedmanual}%
+  \else
+    % _ (for example) has to be the character _ for the purposes of the
+    % control sequence corresponding to the node, but it has to expand
+    % into the usual \leavevmode...\vrule stuff for purposes of
+    % printing. So we \turnoffactive for the \refx-snt, back on for the
+    % printing, back off for the \refx-pg.
+    {\normalturnoffactive
+     % Only output a following space if the -snt ref is nonempty; for
+     % @unnumbered and @anchor, it won't be.
+     \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}%
+     \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
+    }%
+    % [mynode], 
+    [\printednodename],\space
+    % page 3
+    \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+  \fi
+\endgroup}
+
+% \dosetq is the interface for calls from other macros
+
+% Use \normalturnoffactive so that punctuation chars such as underscore
+% and backslash work in node names.  (\turnoffactive doesn't do \.)
+\def\dosetq#1#2{%
+  {\let\folio=0
+   \normalturnoffactive
+   \edef\next{\write\auxfile{\internalsetq{#1}{#2}}}%
+   \iflinks
+     \next
+   \fi
+  }%
+}
+
+% \internalsetq {foo}{page} expands into
+% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ytitle{\thissection}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 \putwordChapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\def\Yappendixletterandtype{%
+\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}%
+\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+  \let\linenumber = \empty % Non-3.0.
+\else
+  \def\linenumber{\the\inputlineno:\space}
+\fi
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+
+\def\refx#1#2{%
+  \expandafter\ifx\csname X#1\endcsname\relax
+    % If not defined, say something at least.
+    \angleleft un\-de\-fined\angleright
+    \iflinks
+      \ifhavexrefs
+        \message{\linenumber Undefined cross reference `#1'.}%
+      \else
+        \ifwarnedxrefs\else
+          \global\warnedxrefstrue
+          \message{Cross reference values unknown; you must run TeX again.}%
+        \fi
+      \fi
+    \fi
+  \else
+    % It's defined, so just use it.
+    \csname X#1\endcsname
+  \fi
+  #2% Output the suffix in any case.
+}
+
+% This is the macro invoked by entries in the aux file.
+% 
+\def\xrdef#1{\begingroup
+  % Reenable \ as an escape while reading the second argument.
+  \catcode`\\ = 0
+  \afterassignment\endgroup
+  \expandafter\gdef\csname X#1\endcsname
+}
+
+% Read the last existing aux file, if any.  No error if none exists.
+\def\readauxfile{\begingroup
+  \catcode`\^^@=\other
+  \catcode`\^^A=\other
+  \catcode`\^^B=\other
+  \catcode`\^^C=\other
+  \catcode`\^^D=\other
+  \catcode`\^^E=\other
+  \catcode`\^^F=\other
+  \catcode`\^^G=\other
+  \catcode`\^^H=\other
+  \catcode`\^^K=\other
+  \catcode`\^^L=\other
+  \catcode`\^^N=\other
+  \catcode`\^^P=\other
+  \catcode`\^^Q=\other
+  \catcode`\^^R=\other
+  \catcode`\^^S=\other
+  \catcode`\^^T=\other
+  \catcode`\^^U=\other
+  \catcode`\^^V=\other
+  \catcode`\^^W=\other
+  \catcode`\^^X=\other
+  \catcode`\^^Z=\other
+  \catcode`\^^[=\other
+  \catcode`\^^\=\other
+  \catcode`\^^]=\other
+  \catcode`\^^^=\other
+  \catcode`\^^_=\other
+  \catcode`\@=\other
+  \catcode`\^=\other
+  % It was suggested to define this as 7, which would allow ^^e4 etc.
+  % in xref tags, i.e., node names.  But since ^^e4 notation isn't
+  % supported in the main text, it doesn't seem desirable.  Furthermore,
+  % that is not enough: for node names that actually contain a ^
+  % character, we would end up writing a line like this: 'xrdef {'hat
+  % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first
+  % argument, and \hat is not an expandable control sequence.  It could
+  % all be worked out, but why?  Either we support ^^ or we don't.
+  %
+  % The other change necessary for this was to define \auxhat:
+  % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter
+  % and then to call \auxhat in \setq.
+  %
+  \catcode`\~=\other
+  \catcode`\[=\other
+  \catcode`\]=\other
+  \catcode`\"=\other
+  \catcode`\_=\other
+  \catcode`\|=\other
+  \catcode`\<=\other
+  \catcode`\>=\other
+  \catcode`\$=\other
+  \catcode`\#=\other
+  \catcode`\&=\other
+  \catcode`+=\other % avoid \+ for paranoia even though we've turned it off
+  % Make the characters 128-255 be printing characters
+  {%
+    \count 1=128
+    \def\loop{%
+      \catcode\count 1=\other
+      \advance\count 1 by 1
+      \ifnum \count 1<256 \loop \fi
+    }%
+  }%
+  % The aux file uses ' as the escape (for now).
+  % Turn off \ as an escape so we do not lose on
+  % entries which were dumped with control sequences in their names.
+  % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+  % Reference to such entries still does not work the way one would wish,
+  % but at least they do not bomb out when the aux file is read in.
+  \catcode`\{=1
+  \catcode`\}=2
+  \catcode`\%=\other
+  \catcode`\'=0
+  \catcode`\\=\other
+  %
+  \openin 1 \jobname.aux
+  \ifeof 1 \else
+    \closein 1
+    \input \jobname.aux
+    \global\havexrefstrue
+    \global\warnedobstrue
+  \fi
+  % Open the new aux file.  TeX will close it automatically at exit.
+  \openout\auxfile=\jobname.aux
+\endgroup}
+
+
+% Footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed. (Generally, numeric constants should always be followed by a
+% space to prevent strange expansion errors.)
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for info output only.
+\let\footnotestyle=\comment
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+%
+% Auto-number footnotes.  Otherwise like plain.
+\gdef\footnote{%
+  \global\advance\footnoteno by \@ne
+  \edef\thisfootno{$^{\the\footnoteno}$}%
+  %
+  % In case the footnote comes at the end of a sentence, preserve the
+  % extra spacing after we do the footnote number.
+  \let\@sf\empty
+  \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+  %
+  % Remove inadvertent blank space before typesetting the footnote number.
+  \unskip
+  \thisfootno\@sf
+  \footnotezzz
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter.  Our footnotes don't need to be so general.
+%
+% Oh yes, they do; otherwise, @ifset and anything else that uses
+% \parseargline fail inside footnotes because the tokens are fixed when
+% the footnote is read.  --karl, 16nov96.
+%
+\long\gdef\footnotezzz{\insert\footins\bgroup
+  % We want to typeset this text as a normal paragraph, even if the
+  % footnote reference occurs in (for example) a display environment.
+  % So reset some parameters.
+  \interlinepenalty\interfootnotelinepenalty
+  \splittopskip\ht\strutbox % top baseline for broken footnotes
+  \splitmaxdepth\dp\strutbox
+  \floatingpenalty\@MM
+  \leftskip\z@skip
+  \rightskip\z@skip
+  \spaceskip\z@skip
+  \xspaceskip\z@skip
+  \parindent\defaultparindent
+  %
+  % Hang the footnote text off the number.
+  \hang
+  \textindent{\thisfootno}%
+  %
+  % Don't crash into the line above the footnote text.  Since this
+  % expands into a box, it must come within the paragraph, lest it
+  % provide a place where TeX can split the footnote.
+  \footstrut
+  \futurelet\next\fo@t
+}
+\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t
+  \else\let\next\f@t\fi \next}
+\def\f@@t{\bgroup\aftergroup\@foot\let\next}
+\def\f@t#1{#1\@foot}
+\def\@foot{\strut\egroup}
+
+}%end \catcode `\@=11
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly.  There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+\def\setleading#1{%
+  \normalbaselineskip = #1\relax
+  \normallineskip = \lineskipfactor\normalbaselineskip
+  \normalbaselines
+  \setbox\strutbox =\hbox{%
+    \vrule width0pt height\strutheightpercent\baselineskip
+                    depth \strutdepthpercent \baselineskip
+  }%
+}
+
+% @| inserts a changebar to the left of the current line.  It should
+% surround any changed text.  This approach does *not* work if the
+% change spans more than two lines of output.  To handle that, we would
+% have adopt a much more difficult approach (putting marks into the main
+% vertical list for the beginning and end of each change).
+%
+\def\|{%
+  % \vadjust can only be used in horizontal mode.
+  \leavevmode
+  %
+  % Append this vertical mode material after the current line in the output.
+  \vadjust{%
+    % We want to insert a rule with the height and depth of the current
+    % leading; that is exactly what \strutbox is supposed to record.
+    \vskip-\baselineskip
+    %
+    % \vadjust-items are inserted at the left edge of the type.  So
+    % the \llap here moves out into the left-hand margin.
+    \llap{%
+      %
+      % For a thicker or thinner bar, change the `1pt'.
+      \vrule height\baselineskip width1pt
+      %
+      % This is the space between the bar and the text.
+      \hskip 12pt
+    }%
+  }%
+}
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt}
+
+% @image.  We use the macros from epsf.tex to support this.
+% If epsf.tex is not installed and @image is used, we complain.
+% 
+% Check for and read epsf.tex up front.  If we read it only at @image
+% time, we might be inside a group, and then its definitions would get
+% undone and the next image would fail.
+\openin 1 = epsf.tex
+\ifeof 1 \else
+  \closein 1
+  % Do not bother showing banner with post-v2.7 epsf.tex (available in
+  % doc/epsf.tex until it shows up on ctan).
+  \def\epsfannounce{\toks0 = }%
+  \input epsf.tex
+\fi
+%
+\newif\ifwarnednoepsf
+\newhelp\noepsfhelp{epsf.tex must be installed for images to
+  work.  It is also included in the Texinfo distribution, or you can get
+  it from ftp://ftp.tug.org/tex/epsf.tex.}
+%
+% Only complain once about lack of epsf.tex.
+\def\image#1{%
+  \ifx\epsfbox\undefined
+    \ifwarnednoepsf \else
+      \errhelp = \noepsfhelp
+      \errmessage{epsf.tex not found, images will be ignored}%
+      \global\warnednoepsftrue
+    \fi
+  \else
+    \imagexxx #1,,,\finish
+  \fi
+}
+%
+% Arguments to @image:
+% #1 is (mandatory) image filename; we tack on .eps extension.
+% #2 is (optional) width, #3 is (optional) height.
+% #4 is just the usual extra ignored arg for parsing this stuff.
+\def\imagexxx#1,#2,#3,#4\finish{%
+  % \epsfbox itself resets \epsf?size at each figure.
+  \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi
+  \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi
+  % If the image is by itself, center it.
+  \ifvmode
+    \nobreak\medskip
+    \nobreak
+    \centerline{\epsfbox{#1.eps}}%
+    \bigbreak
+  \else
+    \epsfbox{#1.eps}%
+  \fi
+}
+
+
+\message{paper sizes,}
+% And other related parameters.
+
+\newdimen\defaultparindent \defaultparindent = 15pt
+
+\chapheadingskip = 15pt plus 4pt minus 2pt
+\secheadingskip = 12pt plus 3pt minus 2pt
+\subsecheadingskip = 9pt plus 2pt minus 2pt
+
+% Prevent underfull vbox error messages.
+\vbadness = 10000
+
+% Don't be so finicky about underfull hboxes, either.
+\hbadness = 2000
+
+% Following George Bush, just get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything.  We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize.  This makes it come to about 9pt for the 8.5x11 format.  We
+% call this whenever the paper size is set.
+%
+\def\setemergencystretch{%
+  \ifx\emergencystretch\thisisundefined
+    % Allow us to assign to \emergencystretch anyway.
+    \def\emergencystretch{\dimen0}%
+  \else
+    \emergencystretch = \hsize
+    \divide\emergencystretch by 45
+  \fi
+}
+
+% Parameters in order: 1) textheight; 2) textwidth; 3) voffset;
+% 4) hoffset; 5) binding offset; 6) topskip.  Then whoever calls us can
+% set \parskip and call \setleading for \baselineskip.
+%
+\def\internalpagesizes#1#2#3#4#5#6{%
+  \voffset = #3\relax
+  \topskip = #6\relax
+  \splittopskip = \topskip
+  %
+  \vsize = #1\relax
+  \advance\vsize by \topskip
+  \outervsize = \vsize
+  \advance\outervsize by 2\topandbottommargin
+  \pageheight = \vsize
+  %
+  \hsize = #2\relax
+  \outerhsize = \hsize
+  \advance\outerhsize by 0.5in
+  \pagewidth = \hsize
+  %
+  \normaloffset = #4\relax
+  \bindingoffset = #5\relax
+  %
+  \parindent = \defaultparindent
+  \setemergencystretch
+}
+
+% @letterpaper (the default).
+\def\letterpaper{{\globaldefs = 1
+  \parskip = 3pt plus 2pt minus 1pt
+  \setleading{13.2pt}%
+  %
+  % If page is nothing but text, make it come out even.
+  \internalpagesizes{46\baselineskip}{6in}{\voffset}{.25in}{\bindingoffset}{36pt}%
+}}
+
+% Use @smallbook to reset parameters for 7x9.5 (or so) format.
+\def\smallbook{{\globaldefs = 1
+  \parskip = 2pt plus 1pt
+  \setleading{12pt}%
+  %
+  \internalpagesizes{7.5in}{5.in}{\voffset}{.25in}{\bindingoffset}{16pt}%
+  %
+  \lispnarrowing = 0.3in
+  \tolerance = 700
+  \hfuzz = 1pt
+  \contentsrightmargin = 0pt
+  \deftypemargin = 0pt
+  \defbodyindent = .5cm
+  %
+  \let\smalldisplay = \smalldisplayx
+  \let\smallexample = \smalllispx
+  \let\smallformat = \smallformatx
+  \let\smalllisp = \smalllispx
+}}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{{\globaldefs = 1
+  \setleading{12pt}%
+  \parskip = 3pt plus 2pt minus 1pt
+  %
+  \internalpagesizes{53\baselineskip}{160mm}{\voffset}{4mm}{\bindingoffset}{44pt}%
+  %
+  \tolerance = 700
+  \hfuzz = 1pt
+}}
+
+% A specific text layout, 24x15cm overall, intended for A4 paper.  Top margin
+% 29mm, hence bottom margin 28mm, nominal side margin 3cm.
+\def\afourlatex{{\globaldefs = 1
+  \setleading{13.6pt}%
+  %
+  \afourpaper
+  \internalpagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm}%
+  %
+  \globaldefs = 0
+}}
+
+% Use @afourwide to print on European A4 paper in wide format.
+\def\afourwide{%
+  \afourpaper
+  \internalpagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}%
+  %
+  \globaldefs = 0
+}
+
+% @pagesizes TEXTHEIGHT[,TEXTWIDTH]
+% Perhaps we should allow setting the margins, \topskip, \parskip,
+% and/or leading, also. Or perhaps we should compute them somehow.
+% 
+\def\pagesizes{\parsearg\pagesizesxxx}
+\def\pagesizesxxx#1{\pagesizesyyy #1,,\finish}
+\def\pagesizesyyy#1,#2,#3\finish{{%
+  \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi
+  \globaldefs = 1
+  %
+  \parskip = 3pt plus 2pt minus 1pt
+  \setleading{13.2pt}%
+  %
+  \internalpagesizes{#1}{\hsize}{\voffset}{\normaloffset}{\bindingoffset}{44pt}%
+}}
+
+% Set default to letter.
+% 
+\letterpaper
+
+\message{and turning on texinfo input format.}
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other
+\catcode`\~=\other
+\catcode`\^=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode`\+=\other
+\def\normaldoublequote{"}
+\def\normaltilde{~}
+\def\normalcaret{^}
+\def\normalunderscore{_}
+\def\normalverticalbar{|}
+\def\normalless{<}
+\def\normalgreater{>}
+\def\normalplus{+}
+
+% This macro is used to make a character print one way in ttfont
+% where it can probably just be output, and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise.  Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary).
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt\char34}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt\char126}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+% Subroutine for the previous macro.
+\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}}
+
+\catcode`\|=\active
+\def|{{\tt\char124}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+%\catcode 27=\active
+%\def^^[{$\diamondsuit$}
+
+% Set up an active definition for =, but don't enable it most of the time.
+{\catcode`\==\active
+\global\def={{\tt \char 61}}}
+
+\catcode`+=\active
+\catcode`\_=\active
+
+% If a .fmt file is being used, characters that might appear in a file
+% name cannot be active until we have parsed the command line.
+% So turn them off again, and have \everyjob (or @setfilename) turn them on.
+% \otherifyactive is called near the end of this file.
+\def\otherifyactive{\catcode`+=\other \catcode`\_=\other}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+\global\chardef\rawbackslashxx=`\\
+%{\catcode`\\=\other
+%@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% Say @foo, not \foo, in error messages.
+\escapechar=`\@
+
+% \catcode 17=0   % Define control-q
+\catcode`\\=\active
+
+% Used sometimes to turn off (effectively) the active characters
+% even after parsing them.
+@def@turnoffactive{@let"=@normaldoublequote
+@let\=@realbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus}
+
+@def@normalturnoffactive{@let"=@normaldoublequote
+@let\=@normalbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus}
+
+% Make _ and + \other characters, temporarily.
+% This is canceled by @fixbackslash.
+@otherifyactive
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\{ in the file would cause an error. This macro tries to fix
+% that, assuming it is called before the first `\' could plausibly occur.
+% Also back turn on active characters that might appear in the input
+% file name, in case not using a pre-dumped format.
+%
+@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi
+  @catcode`+=@active @catcode`@_=@active}
+
+% These look ok in all fonts, so just make them not special.  The @rm below
+% makes sure that the current font starts out as the newly loaded cmr10
+@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other
+
+@textfonts
+@rm
+
+@c Local variables:
+@c eval: (add-hook 'write-file-hooks 'time-stamp)
+@c page-delimiter: "^\\\\message"
+@c time-stamp-start: "def\\\\texinfoversion{"
+@c time-stamp-format: "%:y-%02m-%02d"
+@c time-stamp-end: "}"
+@c End:
diff --git a/dpas/.cvsignore b/dpas/.cvsignore
new file mode 100644 (file)
index 0000000..8722e93
--- /dev/null
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+.deps
+dpas-parser.h
+dpas-parser.c
+dpas-scanner.c
+dpas
diff --git a/dpas/Makefile.am b/dpas/Makefile.am
new file mode 100644 (file)
index 0000000..c405af3
--- /dev/null
@@ -0,0 +1,25 @@
+
+noinst_PROGRAMS = dpas
+
+dpas_SOURCES = \
+       dpas-internal.h \
+       dpas-main.c \
+       dpas-function.c \
+       dpas-parser.y \
+       dpas-scanner.l \
+       dpas-scope.c \
+       dpas-scope.h \
+       dpas-types.c \
+       dpas-types.h
+
+AM_YFLAGS = -d
+
+CCLD = $(CXX)
+
+dpas_LDADD = $(top_builddir)/jit/libjit.a
+dpas_DEPENDENCIES = $(top_builddir)/jit/libjit.a
+
+AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I. -I$(srcdir) \
+                       -DDPAS_INCLUDE_DIR=\"$(datadir)/dpas\"
+
+CLEANFILES = dpas-parser.c dpas-scanner.c dpas-parser.h
diff --git a/dpas/README b/dpas/README
new file mode 100644 (file)
index 0000000..be6f196
--- /dev/null
@@ -0,0 +1,8 @@
+
+This 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 environment.  We also use it to write test programs that
+exercise the JIT's capabilities.
+
+More information on Dynamic Pascal can be found in libjit's Texinfo
+documentation, "libjit/doc/libjit.texi".
diff --git a/dpas/dpas-function.c b/dpas/dpas-function.c
new file mode 100644 (file)
index 0000000..98511d3
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * dpas-function.c - Special handling for Dynamic Pascal functions.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "dpas-internal.h"
+
+static jit_context_t current_context;
+static jit_function_t *function_stack = 0;
+static int function_stack_size = 0;
+
+jit_context_t dpas_current_context(void)
+{
+       if(!current_context)
+       {
+               current_context = jit_context_create();
+               if(!current_context)
+               {
+                       dpas_out_of_memory();
+               }
+       }
+       return current_context;
+}
+
+jit_function_t dpas_current_function(void)
+{
+       if(function_stack_size > 0)
+       {
+               return function_stack[function_stack_size - 1];
+       }
+       else
+       {
+               /* We are probably compiling the "main" method for this module */
+               jit_type_t signature = jit_type_create_signature
+                       (jit_abi_cdecl, jit_type_void, 0, 0, 1);
+               if(!signature)
+               {
+                       dpas_out_of_memory();
+               }
+               return dpas_new_function(signature);
+       }
+}
+
+jit_function_t dpas_new_function(jit_type_t signature)
+{
+       jit_function_t func;
+       func = jit_function_create(dpas_current_context(), signature);
+       if(!func)
+       {
+               dpas_out_of_memory();
+       }
+       function_stack = (jit_function_t *)jit_realloc
+               (function_stack, sizeof(jit_function_t) * (function_stack_size + 1));
+       if(!function_stack)
+       {
+               dpas_out_of_memory();
+       }
+       function_stack[function_stack_size++] = func;
+       return func;
+}
+
+void dpas_pop_function(void)
+{
+       if(function_stack_size > 0)
+       {
+               --function_stack_size;
+       }
+}
+
+int dpas_function_is_nested(void)
+{
+       return (function_stack_size > 1);
+}
diff --git a/dpas/dpas-internal.h b/dpas/dpas-internal.h
new file mode 100644 (file)
index 0000000..db7bc1b
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * dpas-internal.h - Internal definitions for the Dynamic Pascal compiler.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _DPAS_INTERNAL_H
+#define        _DPAS_INTERNAL_H
+
+#include <jit/jit.h>
+#include <stdio.h>
+
+#include "dpas-scope.h"
+#include "dpas-types.h"
+#include "dpas-semantics.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Current filename and line number.
+ */
+extern char *dpas_filename;
+extern long dpas_linenum;
+
+/*
+ * Information about a parameter list (also used for record fields).
+ */
+typedef struct
+{
+       char              **names;
+       jit_type_t         *types;
+       int                             len;
+       int                             has_vararg;
+
+} dpas_params;
+
+/*
+ * Flag that is set when an error is encountered.
+ */
+extern int dpas_error_reported;
+
+/*
+ * Function that is called when the system runs out of memory.
+ */
+void dpas_out_of_memory(void);
+
+/*
+ * Process an "import" clause within a program.
+ */
+void dpas_import(const char *name);
+
+/*
+ * Load the contents of a source file.
+ */
+void dpas_load_file(char *filename, FILE *file);
+
+/*
+ * Report an error on the current line.
+ */
+void dpas_error(const char *format, ...);
+
+/*
+ * Report a warning on the current line.
+ */
+void dpas_warning(const char *format, ...);
+
+/*
+ * Report an error on a specific line.
+ */
+void dpas_error_on_line(const char *filename, long linenum,
+                        const char *format, ...);
+
+/*
+ * Get the JIT context that we are using to compile functions.
+ */
+jit_context_t dpas_current_context(void);
+
+/*
+ * Get the current function that is being compiled.  Returns NULL
+ * if we are currently at the global level.
+ */
+jit_function_t dpas_current_function(void);
+
+/*
+ * Create a new function and push it onto the context stack.
+ * The function is initialized to read parameters that are
+ * compatible with the supplied signature.
+ */
+jit_function_t dpas_new_function(jit_type_t signature);
+
+/*
+ * Pop out of the current function.
+ */
+void dpas_pop_function(void);
+
+/*
+ * Determine if the current function is nested.
+ */
+int dpas_function_is_nested(void);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _DPAS_INTERNAL_H */
diff --git a/dpas/dpas-main.c b/dpas/dpas-main.c
new file mode 100644 (file)
index 0000000..b0d8c2f
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * dpas-main.c - Main entry point for the Dyanmic Pascal Compiler.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "dpas-internal.h"
+#include <config.h>
+#include <stdlib.h>
+
+/*
+ * Command-line options.
+ */
+static char *progname = 0;
+static char *filename = 0;
+static char **include_dirs = 0;
+static int num_include_dirs = 0;
+static char **using_seen = 0;
+static int num_using_seen = 0;
+
+/*
+ * Forward declarations.
+ */
+static void version(void);
+static void usage(void);
+static void add_include_dir(char *dir);
+static void initialize(void);
+
+int main(int argc, char **argv)
+{
+       FILE *file;
+
+       /* Parse the command-line options */
+       progname = argv[0];
+       while(argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0')
+       {
+               if(!jit_strncmp(argv[1], "-I", 2))
+               {
+                       if(argv[1][2] == '\0')
+                       {
+                               ++argv;
+                               --argc;
+                               if(argc > 1)
+                               {
+                                       add_include_dir(argv[1]);
+                               }
+                               else
+                               {
+                                       usage();
+                               }
+                       }
+                       else
+                       {
+                               add_include_dir(argv[1] + 2);
+                       }
+               }
+               else if(!jit_strcmp(argv[1], "-v") ||
+                       !jit_strcmp(argv[1], "--version"))
+               {
+                       version();
+               }
+               else
+               {
+                       usage();
+               }
+               ++argv;
+               --argc;
+       }
+       if(argc <= 1)
+       {
+               usage();
+       }
+       filename = argv[1];
+       ++argv;
+       --argc;
+
+       /* Add the system-wide include directories to the list */
+#ifdef DPAS_INCLUDE_DIR
+       add_include_dir(DPAS_INCLUDE_DIR);
+#endif
+       add_include_dir("/usr/local/share/dpas");
+       add_include_dir("/usr/share/dpas");
+
+       /* Initialize the pre-defined types, constants, procedures, etc */
+       initialize();
+
+       /* Load the specified program file */
+       if(!jit_strcmp(filename, "-"))
+       {
+               dpas_load_file("(stdin)", stdin);
+       }
+       else if((file = fopen(filename, "r")) != NULL)
+       {
+               dpas_load_file(filename, file);
+               fclose(file);
+       }
+       else
+       {
+               perror(filename);
+               return 1;
+       }
+
+       /* Bail out if we had errors during the compilation phase */
+       if(dpas_error_reported)
+       {
+               return 1;
+       }
+
+       /* TODO: JIT and execute the program */
+
+       /* Done */
+       return 0;
+}
+
+static void version(void)
+{
+       printf("Dynamic Pascal Version " VERSION "\n");
+       printf("Copyright (c) 2004 Southern Storm Software, Pty Ltd.\n");
+       exit(0);
+}
+
+static void usage(void)
+{
+       printf("Dynamic Pascal Version " VERSION "\n");
+       printf("Copyright (c) 2004 Southern Storm Software, Pty Ltd.\n");
+       printf("\n");
+       printf("Usage: %s [-Idir] file.pas [args]\n", progname);
+       exit(1);
+}
+
+static void add_include_dir(char *dir)
+{
+       include_dirs = (char **)jit_realloc
+               (include_dirs, (num_include_dirs + 1) * sizeof(char *));
+       if(!include_dirs)
+       {
+               dpas_out_of_memory();
+       }
+       include_dirs[num_include_dirs++] = dir;
+}
+
+void dpas_out_of_memory(void)
+{
+       fputs(progname, stderr);
+       fputs(": virtual memory exhausted\n", stderr);
+       exit(1);
+}
+
+void dpas_import(const char *name)
+{
+       int posn;
+       char *pathname;
+       FILE *file;
+
+       /* Bail out if we've already included this name before */
+       for(posn = 0; posn < num_using_seen; ++posn)
+       {
+               if(!jit_strcmp(using_seen[posn], name))
+               {
+                       return;
+               }
+       }
+
+       /* Add the name to the "seen" list */
+       using_seen = (char **)jit_realloc
+               (using_seen, (num_using_seen + 1) * sizeof(char *));
+       if(!using_seen)
+       {
+               dpas_out_of_memory();
+       }
+       using_seen[num_using_seen] = jit_strdup(name);
+       if(!(using_seen[num_using_seen]))
+       {
+               dpas_out_of_memory();
+       }
+       ++num_using_seen;
+
+       /* Look in the same directory as the including source file first */
+       posn = jit_strlen(dpas_filename);
+       while(posn > 0 && dpas_filename[posn - 1] != '/' &&
+             dpas_filename[posn - 1] != '\\')
+       {
+               --posn;
+       }
+       if(posn > 0)
+       {
+               pathname = (char *)jit_malloc(posn + jit_strlen(name) + 5);
+               if(!pathname)
+               {
+                       dpas_out_of_memory();
+               }
+               jit_strncpy(pathname, dpas_filename, posn);
+               jit_strcpy(pathname + posn, name);
+               jit_strcat(pathname, ".pas");
+       }
+       else
+       {
+               pathname = (char *)jit_malloc(jit_strlen(name) + 5);
+               if(!pathname)
+               {
+                       dpas_out_of_memory();
+               }
+               jit_strcpy(pathname, name);
+               jit_strcat(pathname, ".pas");
+       }
+       if((file = fopen(pathname, "r")) != NULL)
+       {
+               dpas_load_file(pathname, file);
+               fclose(file);
+               jit_free(pathname);
+               return;
+       }
+       jit_free(pathname);
+
+       /* Scan the include directories looking for the name */
+       for(posn = 0; posn < num_include_dirs; ++posn)
+       {
+               pathname = (char *)jit_malloc(jit_strlen(include_dirs[posn]) +
+                                                                         jit_strlen(name) + 6);
+               if(!pathname)
+               {
+                       dpas_out_of_memory();
+               }
+               jit_strcpy(pathname, include_dirs[posn]);
+               jit_strcat(pathname, "/");
+               jit_strcat(pathname, name);
+               jit_strcat(pathname, ".pas");
+               if((file = fopen(pathname, "r")) != NULL)
+               {
+                       dpas_load_file(pathname, file);
+                       fclose(file);
+                       jit_free(pathname);
+                       return;
+               }
+               jit_free(pathname);
+       }
+
+       /* If we get here, then we could not find the specified module */
+       fprintf(stderr, "%s:%ld: could not locate the module `%s'\n",
+                       dpas_filename, dpas_linenum, name);
+       dpas_error_reported = 1;
+}
+
+/*
+ * Initialize the system.
+ */
+static void initialize(void)
+{
+       jit_init();
+       dpas_init_types();
+}
diff --git a/dpas/dpas-parser.y b/dpas/dpas-parser.y
new file mode 100644 (file)
index 0000000..2b3c513
--- /dev/null
@@ -0,0 +1,2247 @@
+%{
+/*
+ * dpas-parser.y - Bison grammar for the Dynamic Pascal language.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "dpas-internal.h"
+#include <jit/jit-dump.h>
+#include <config.h>
+#ifdef HAVE_STDLIB_H
+       #include <stdlib.h>
+#endif
+#ifdef HAVE_STDARG_H
+       #include <stdarg.h>
+#elif HAVE_VARARGS_H
+       #include <varargs.h>
+#endif
+
+/*
+ * Imports from the lexical analyser.
+ */
+extern int yylex(void);
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#else
+extern char yytext[];
+#endif
+
+/*
+ * Error reporting flag.
+ */
+int dpas_error_reported = 0;
+
+/*
+ * Report error messages from the parser.
+ */
+static void yyerror(char *msg)
+{
+       char *text = yytext;
+       char *newmsg;
+       int posn, outposn;
+       dpas_error_reported = 1;
+       if(!jit_strcmp(msg, "parse error") || !jit_strcmp(msg, "syntax error"))
+       {
+               /* This error is pretty much useless at telling the user
+                  what is happening.  Try to print a better message
+                  based on the current input token */
+       simpleError:
+               if(text && *text != '\0')
+               {
+                       fprintf(stderr, "%s:%ld: parse error at or near `%s'\n",
+                                       dpas_filename, dpas_linenum, text);
+               }
+               else
+               {
+                       fprintf(stderr, "%s:%ld: parse error\n",
+                                       dpas_filename, dpas_linenum);
+               }
+       }
+       else if(!jit_strncmp(msg, "parse error, expecting `", 24))
+       {
+               /* We have to quote the token names in the "%token" declarations
+                  within yacc grammars so that byacc doesn't mess up the output.
+                  But the quoting causes Bison to output quote characters in
+                  error messages which look awful.  This code attempts to fix
+                  things up */
+               newmsg = jit_strdup(msg);
+       expectingError:
+               if(newmsg)
+               {
+                       posn = 0;
+                       outposn = 0;
+                       while(newmsg[posn] != '\0')
+                       {
+                               if(newmsg[posn] == '`')
+                               {
+                                       if(newmsg[posn + 1] == '"' && newmsg[posn + 2] == '`')
+                                       {
+                                               /* Convert <`"`> into <`> */
+                                               posn += 2;
+                                               newmsg[outposn++] = '`';
+                                       }
+                                       else if(newmsg[posn + 1] == '"')
+                                       {
+                                               /* Convert <`"> into <> */
+                                               ++posn;
+                                       }
+                                       else if(newmsg[posn + 1] == '`' ||
+                                               newmsg[posn + 1] == '\'')
+                                       {
+                                               /* Convert <``> or <`'> into <`> */
+                                               ++posn;
+                                               newmsg[outposn++] = '`';
+                                       }
+                                       else
+                                       {
+                                               /* Ordinary <`> on its own */
+                                               newmsg[outposn++] = '`';
+                                       }
+                               }
+                               else if(newmsg[posn] == '\\')
+                               {
+                                       /* Ignore backslashes in the input */
+                               }
+                               else if(newmsg[posn] == '"' && newmsg[posn + 1] == '\'')
+                               {
+                                       /* Convert <"'> into <> */
+                                       ++posn;
+                               }
+                               else if(newmsg[posn] == '\'' && newmsg[posn + 1] == '"' &&
+                                       newmsg[posn + 2] == '\'')
+                               {
+                                       /* Convert <'"'> into <'> */
+                                       posn += 2;
+                                       newmsg[outposn++] = '\'';
+                               }
+                               else if(newmsg[posn] == '\'' && newmsg[posn + 1] == '\'')
+                               {
+                                       /* Convert <''> into <'> */
+                                       ++posn;
+                                       newmsg[outposn++] = '\'';
+                               }
+                               else if(newmsg[posn] == ' ' && newmsg[posn + 1] == '\'')
+                               {
+                                       /*  bison 1.75 - <'> following a space becomes <`> */
+                                       ++posn;
+                                       newmsg[outposn++] = ' ';
+                                       newmsg[outposn++] = '`';
+                               }
+                               else if(newmsg[posn] == '"')
+                               {
+                                       /* Ignore quotes - bison 1.75 */
+                               }
+                               else
+                               {
+                                       /* Ordinary character */
+                                       newmsg[outposn++] = newmsg[posn];
+                               }
+                               ++posn;
+                       }
+                       newmsg[outposn] = '\0';
+                       if(text && *text != '\0')
+                       {
+                               fprintf(stderr, "%s:%ld: %s, at or near `%s'\n",
+                                               dpas_filename, dpas_linenum, newmsg, text);
+                       }
+                       else
+                       {
+                               fprintf(stderr, "%s:%ld: %s\n",
+                                               dpas_filename, dpas_linenum, newmsg);
+                       }
+                       jit_free(newmsg);
+               }
+               else
+               {
+                       if(text && *text != '\0')
+                       {
+                               fprintf(stderr, "%s:%ld: %s at or near `%s'\n",
+                                               dpas_filename, dpas_linenum, msg, text);
+                       }
+                       else
+                       {
+                               fprintf(stderr, "%s:%ld: %s\n",
+                                               dpas_filename, dpas_linenum, msg);
+                       }
+               }
+       }
+       else if(!jit_strncmp(msg, "parse error, unexpected ", 24))
+       {
+               /* The error probably has the form "parse error, unexpected ...,
+                  expecting ..." - strip out the "unexpected" part */
+               posn = 24;
+               while(msg[posn] != '\0' &&
+                         jit_strncmp(msg + posn, ", expecting ", 12) != 0)
+               {
+                       ++posn;
+               }
+               if(msg[posn] == '\0')
+               {
+                       goto simpleError;
+               }
+               newmsg = (char *)jit_malloc(jit_strlen(msg) + 1);
+               if(!newmsg)
+               {
+                       goto defaultError;
+               }
+               jit_strcpy(newmsg, "parse error, expecting ");
+               jit_strcat(newmsg, msg + posn + 12);
+               goto expectingError;
+       }
+       else
+       {
+               /* The parser has probably included information as to what
+                  is expected in this context, so report that */
+       defaultError:
+               if(text && *text != '\0')
+               {
+                       fprintf(stderr, "%s:%ld: %s at or near `%s'\n",
+                                       dpas_filename, dpas_linenum, msg, text);
+               }
+               else
+               {
+                       fprintf(stderr, "%s:%ld: %s\n",
+                                       dpas_filename, dpas_linenum, msg);
+               }
+       }
+}
+
+void dpas_error(const char *format, ...)
+{
+       va_list va;
+#ifdef HAVE_STDARG_H
+       va_start(va, format);
+#else
+       va_start(va);
+#endif
+       fprintf(stderr, "%s:%ld: ", dpas_filename, dpas_linenum);
+       vfprintf(stderr, format, va);
+       putc('\n', stderr);
+       va_end(va);
+       dpas_error_reported = 1;
+}
+
+void dpas_warning(const char *format, ...)
+{
+       va_list va;
+#ifdef HAVE_STDARG_H
+       va_start(va, format);
+#else
+       va_start(va);
+#endif
+       fprintf(stderr, "%s:%ld: warning: ", dpas_filename, dpas_linenum);
+       vfprintf(stderr, format, va);
+       putc('\n', stderr);
+       va_end(va);
+}
+
+void dpas_error_on_line(const char *filename, long linenum,
+                        const char *format, ...)
+{
+       va_list va;
+#ifdef HAVE_STDARG_H
+       va_start(va, format);
+#else
+       va_start(va);
+#endif
+       fprintf(stderr, "%s:%ld: ", filename, linenum);
+       vfprintf(stderr, format, va);
+       putc('\n', stderr);
+       va_end(va);
+       dpas_error_reported = 1;
+}
+
+static void dpas_undeclared(const char *name)
+{
+       dpas_error("`%s' is not declared in the current scope", name);
+}
+
+static void dpas_redeclared(const char *name, dpas_scope_item_t item)
+{
+       dpas_error("`%s' is already declared in the current scope", name);
+       dpas_error_on_line(dpas_scope_item_filename(item),
+                                          dpas_scope_item_linenum(item),
+                                          "previous declaration of `%s' here", name);
+}
+
+/*
+ * Add an item to a list of identifiers.
+ */
+static void identifier_list_add(char ***list, int *len, char *name)
+{
+       char **new_list = (char **)jit_realloc(*list, sizeof(char *) * (*len + 1));
+       if(!new_list)
+       {
+               dpas_out_of_memory();
+       }
+       new_list[*len] = name;
+       ++(*len);
+       *list = new_list;
+}
+
+/*
+ * Free the contents of an identifier list.
+ */
+static void identifier_list_free(char **list, int len)
+{
+       int posn;
+       for(posn = 0; posn < len; ++posn)
+       {
+               jit_free(list[posn]);
+       }
+       jit_free(list);
+}
+
+/*
+ * Determine if an identifier list contains a specific item.
+ */
+static int identifier_list_contains(char **list, int len, const char *name)
+{
+       int posn;
+       for(posn = 0; posn < len; ++posn)
+       {
+               if(list[posn] && !jit_stricmp(list[posn], name))
+               {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Add an item to a list of types.
+ */
+static void type_list_add(jit_type_t **list, int *len, jit_type_t type)
+{
+       jit_type_t *new_list = (jit_type_t *)
+               jit_realloc(*list, sizeof(jit_type_t) * (*len + 1));
+       if(!new_list)
+       {
+               dpas_out_of_memory();
+       }
+       new_list[*len] = type;
+       ++(*len);
+       *list = new_list;
+}
+
+/*
+ * Initialize a parameter list.
+ */
+static void parameter_list_init(dpas_params *list)
+{
+       list->names = 0;
+       list->types = 0;
+       list->len = 0;
+       list->has_vararg = 0;
+}
+
+/*
+ * Add an item to a list of parameters.
+ */
+static void parameter_list_add(dpas_params *list, char *name, jit_type_t type)
+{
+       char **new_names = (char **)
+               jit_realloc(list->names, sizeof(char *) * (list->len + 1));
+       jit_type_t *new_types = (jit_type_t *)
+               jit_realloc(list->types, sizeof(jit_type_t) * (list->len + 1));
+       if(!new_names || !new_types)
+       {
+               dpas_out_of_memory();
+       }
+       new_names[list->len] = name;
+       new_types[list->len] = type;
+       ++(list->len);
+       list->names = new_names;
+       list->types = new_types;
+}
+
+/*
+ * Free the contents of a parameter list.
+ */
+static void parameter_list_free(dpas_params *list)
+{
+       int posn;
+       for(posn = 0; posn < list->len; ++posn)
+       {
+               jit_free(list->names[posn]);
+               jit_type_free(list->types[posn]);
+       }
+       jit_free(list->names);
+       jit_free(list->types);
+}
+
+/*
+ * Determine if a parameter list contains a specific item.
+ */
+static int parameter_list_contains(dpas_params *list, const char *name)
+{
+       int posn;
+       for(posn = 0; posn < list->len; ++posn)
+       {
+               if(list->names[posn] && !jit_stricmp(list->names[posn], name))
+               {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Create a new parameter list.
+ */
+static void parameter_list_create(dpas_params *list, char **names,
+                                                                 int num_names, jit_type_t type)
+{
+       char **temp = names;
+       parameter_list_init(list);
+       while(num_names > 0)
+       {
+               parameter_list_add(list, temp[0], jit_type_copy(type));
+               --num_names;
+               ++temp;
+       }
+       if(names)
+       {
+               jit_free(names);
+       }
+}
+
+/*
+ * Merge two parameter lists into one.
+ */
+static void parameter_list_merge(dpas_params *list1, dpas_params *list2)
+{
+       int posn;
+       char *name;
+       for(posn = 0; posn < list2->len; ++posn)
+       {
+               name = list2->names[posn];
+               if(name && parameter_list_contains(list1, name))
+               {
+                       dpas_error("`%s' used twice in a parameter or field list", name);
+                       jit_free(name);
+                       name = 0;
+               }
+               parameter_list_add(list1, name, list2->types[posn]);
+       }
+       jit_free(list2->names);
+       jit_free(list2->types);
+}
+
+/*
+ * Handle a numeric binary operator.
+ */
+#define        handle_binary(name,func,arg1,arg2)      \
+               do { \
+                       if(!dpas_sem_is_rvalue(arg1) || \
+                          !dpas_type_is_numeric(dpas_sem_get_type(arg2)) || \
+                          !dpas_sem_is_rvalue(arg1) || \
+                          !dpas_type_is_numeric(dpas_sem_get_type(arg2))) \
+                       { \
+                               if(!dpas_sem_is_error(arg1) && !dpas_sem_is_error(arg2)) \
+                               { \
+                                       dpas_error("invalid operands to binary `" name "'"); \
+                               } \
+                               dpas_sem_set_error(yyval.semvalue); \
+                       } \
+                       else \
+                       { \
+                               jit_value_t value; \
+                               value = func \
+                                       (dpas_current_function(), \
+                                        dpas_sem_get_value(arg1), \
+                                        dpas_sem_get_value(arg2)); \
+                               dpas_sem_set_rvalue \
+                                       (yyval.semvalue, jit_value_get_type(value), value); \
+                       } \
+               } while (0)
+
+/*
+ * Handle an integer binary operator.
+ */
+#define        handle_integer_binary(name,func,arg1,arg2)      \
+               do { \
+                       if(!dpas_sem_is_rvalue(arg1) || \
+                          !dpas_type_is_integer(dpas_sem_get_type(arg2)) || \
+                          !dpas_sem_is_rvalue(arg1) || \
+                          !dpas_type_is_integer(dpas_sem_get_type(arg2))) \
+                       { \
+                               if(!dpas_sem_is_error(arg1) && !dpas_sem_is_error(arg2)) \
+                               { \
+                                       dpas_error("invalid operands to binary `" name "'"); \
+                               } \
+                               dpas_sem_set_error(yyval.semvalue); \
+                       } \
+                       else \
+                       { \
+                               jit_value_t value; \
+                               value = func \
+                                       (dpas_current_function(), \
+                                        dpas_sem_get_value(arg1), \
+                                        dpas_sem_get_value(arg2)); \
+                               dpas_sem_set_rvalue \
+                                       (yyval.semvalue, jit_value_get_type(value), value); \
+                       } \
+               } while (0)
+
+/*
+ * Handle a comparison binary operator.
+ */
+#define        handle_compare_binary(name,func,arg1,arg2)      \
+               do { \
+                       if(dpas_sem_is_rvalue(arg1) && \
+                          jit_type_is_pointer(dpas_sem_get_type(arg1)) && \
+                          dpas_sem_is_rvalue(arg2) && \
+                          jit_type_is_pointer(dpas_sem_get_type(arg2))) \
+                       { \
+                               jit_value_t value; \
+                               value = func \
+                                       (dpas_current_function(), \
+                                        dpas_sem_get_value(arg1), \
+                                        dpas_sem_get_value(arg2)); \
+                               dpas_sem_set_rvalue \
+                                       (yyval.semvalue, jit_value_get_type(value), value); \
+                       } \
+                       else \
+                       { \
+                               handle_binary(name, func, arg1, arg2); \
+                       } \
+               } while (0)
+
+%}
+
+/*
+ * Define the structure of yylval.
+ */
+%union {
+       char               *name;
+       struct
+       {
+               jit_ulong       value;
+               jit_type_t      type;
+       }                               int_const;
+       jit_nfloat              real_const;
+       jit_constant_t  const_value;
+       jit_type_t              type;
+       struct
+       {
+               char      **list;
+               int                     len;
+       }                               id_list;
+       struct
+       {
+               jit_type_t *list;
+               int                     len;
+       }                               type_list;
+       dpas_params             parameters;
+       struct
+       {
+               char       *name;
+               jit_type_t      type;
+       }                               procedure;
+       struct
+       {
+               jit_type_t      type;
+               dpas_params     bounds;
+       }                               param_type;
+       dpas_semvalue   semvalue;
+}
+
+/*
+ * Primitive lexical tokens.
+ */
+%token IDENTIFIER                      "an identifier"
+%token INTEGER_CONSTANT                "an integer value"
+%token STRING_CONSTANT         "a string literal"
+%token REAL_CONSTANT           "a floating point value"
+
+/*
+ * Keywords.
+ */
+%token K_AND                           "`and'"
+%token K_ARRAY                         "`array'"
+%token K_BEGIN                         "`begin'"
+%token K_CASE                          "`case'"
+%token K_CATCH                         "`catch'"
+%token K_CONST                         "`const'"
+%token K_DIV                           "`div'"
+%token K_DO                                    "`do'"
+%token K_DOWNTO                                "`downto'"
+%token K_ELSE                          "`else'"
+%token K_END                           "`end'"
+%token K_EXIT                          "`exit'"
+%token K_FINALLY                       "`finally'"
+%token K_FOR                           "`for'"
+%token K_FORWARD                       "`forward'"
+%token K_FUNCTION                      "`function'"
+%token K_GOTO                          "`goto'"
+%token K_IF                                    "`if'"
+%token K_IN                                    "`in'"
+%token K_LABEL                         "`label'"
+%token K_IMPORT                                "`import'"
+%token K_MOD                           "`mod'"
+%token K_MODULE                                "`module'"
+%token K_NIL                           "`nil'"
+%token K_NOT                           "`not'"
+%token K_OF                                    "`of'"
+%token K_OR                                    "`or'"
+%token K_PACKED                                "`packed'"
+%token K_POW                           "`pow'"
+%token K_PROCEDURE                     "`procedure'"
+%token K_PROGRAM                       "`program'"
+%token K_RECORD                                "`record'"
+%token K_REPEAT                                "`repeat'"
+%token K_SET                           "`set'"
+%token K_SHL                           "`shl'"
+%token K_SHR                           "`shr'"
+%token K_SIZEOF                                "`sizeof'"
+%token K_THEN                          "`then'"
+%token K_THROW                         "`throw'"
+%token K_TO                                    "`to'"
+%token K_TRY                           "`try'"
+%token K_TYPE                          "`type'"
+%token K_UNTIL                         "`until'"
+%token K_VAR                           "`var'"
+%token K_VA_ARG                                "`va_arg'"
+%token K_WITH                          "`with'"
+%token K_WHILE                         "`while'"
+%token K_XOR                           "`xor'"
+
+/*
+ * Operators.
+ */
+%token K_NE                                    "`<>'"
+%token K_LE                                    "`<='"
+%token K_GE                                    "`>='"
+%token K_ASSIGN                                "`:='"
+%token K_DOT_DOT                       "`..'"
+
+/*
+ * Define the yylval types of the various non-terminals.
+ */
+%type <name>                           IDENTIFIER STRING_CONSTANT Identifier Directive
+%type <int_const>                      INTEGER_CONSTANT
+%type <real_const>                     REAL_CONSTANT
+%type <const_value>                    Constant ConstantValue BasicConstant
+%type <id_list>                                IdentifierList
+%type <type_list>                      ArrayBoundsList VariantCaseList
+
+%type <type>                           Type TypeIdentifier SimpleType StructuredType
+%type <type>                           BoundType Variant VariantList
+
+%type <param_type>                     ParameterType ConformantArray
+
+%type <parameters>                     FormalParameterList FormalParameterSection
+%type <parameters>                     FormalParameterSections FieldList FixedPart
+%type <parameters>                     RecordSection VariantPart BoundSpecificationList
+%type <parameters>                     BoundSpecification
+
+%type <procedure>                      ProcedureHeading FunctionHeading
+%type <procedure>                      ProcedureOrFunctionHeading
+
+%type <semvalue>                       Variable Expression SimpleExpression
+%type <semvalue>                       AdditionExpression Term Factor Power
+
+%expect 3
+
+%start Program
+%%
+
+/*
+ * Programs.
+ */
+
+Program
+       : ProgramHeading ImportDeclarationPart ProgramBlock '.'
+       ;
+
+ProgramHeading
+       : K_PROGRAM Identifier '(' IdentifierList ')' ';'       {
+                               jit_free($2);
+                               identifier_list_free($4.list, $4.len);
+                       }
+       | K_PROGRAM Identifier ';'      {
+                               jit_free($2);
+                       }
+       | K_MODULE Identifier '(' IdentifierList ')' ';'        {
+                               /* The "module" keyword is provided as an alternative
+                                  to "program" because it looks odd to put "program"
+                                  on code included via an "import" clause */
+                               jit_free($2);
+                               identifier_list_free($4.list, $4.len);
+                       }
+       | K_MODULE Identifier ';'       {
+                               jit_free($2);
+                       }
+       ;
+
+ImportDeclarationPart
+       : /* empty */
+       | K_IMPORT ImportDeclarations ';'
+       ;
+
+ImportDeclarations
+       : Identifier            {
+                               dpas_import($1);
+                               jit_free($1);
+                       }
+       | ImportDeclarations ',' Identifier     {
+                               dpas_import($3);
+                               jit_free($3);
+                       }
+       ;
+
+ProgramBlock
+       : ProgramBlock2         {
+                               /* Get the "main" function for this module */
+                               jit_function_t func = dpas_current_function();
+
+                               /* Make sure that the function is properly terminated */
+                               if(!jit_insn_default_return(func))
+                               {
+                                       dpas_out_of_memory();
+                               }
+
+                               /* Compile the function */
+                               /* TODO */
+                               jit_dump_function(stdout, func, "main");
+
+                               /* Pop the "main" function */
+                               dpas_pop_function();
+                       }
+       ;
+
+ProgramBlock2
+       : Block
+       | K_END
+       ;
+
+/*
+ * Identifiers and lists of identifiers.
+ */
+
+Identifier
+       : IDENTIFIER                    { $$ = $1; }
+       ;
+
+IdentifierList
+       : Identifier                                            {
+                               $$.list = 0;
+                               $$.len = 0;
+                               identifier_list_add(&($$.list), &($$.len), $1);
+                       }
+       | IdentifierList ',' Identifier         {
+                               $$ = $1;
+                               if(identifier_list_contains($$.list, $$.len, $3))
+                               {
+                                       dpas_error("`%s' declared twice in an identifier list", $3);
+                                       identifier_list_add(&($$.list), &($$.len), 0);
+                                       jit_free($3);
+                               }
+                               else
+                               {
+                                       identifier_list_add(&($$.list), &($$.len), $3);
+                               }
+                       }
+       ;
+
+/*
+ * Blocks.
+ */
+
+Block
+       : DeclarationPart StatementPart
+       ;
+
+DeclarationPart
+       : LabelDeclarationPart ConstantDefinitionPart TypeDefinitionPart
+         VariableDeclarationPart ProcedureAndFunctionDeclarationPart
+       ;
+
+LabelDeclarationPart
+       : /* empty */
+       | K_LABEL LabelList ';'
+       ;
+
+LabelList
+       : Label
+       | LabelList ',' Label
+       ;
+
+Label
+       : INTEGER_CONSTANT                      { /* label declarations are ignored */ }
+       ;
+
+ConstantDefinitionPart
+       : /* empty */
+       | K_CONST ConstantDefinitionList
+       ;
+
+ConstantDefinitionList
+       : ConstantDefinition
+       | ConstantDefinitionList ConstantDefinition
+       ;
+
+ConstantDefinition
+       : Identifier '=' Constant ';'           {
+                               dpas_scope_item_t item;
+                               item = dpas_scope_lookup(dpas_scope_current(), $1, 0);
+                               if(item)
+                               {
+                                       dpas_redeclared($1, item);
+                               }
+                               else
+                               {
+                                       dpas_scope_add_const(dpas_scope_current(), $1, &($3),
+                                                                                dpas_filename, dpas_linenum);
+                               }
+                               jit_free($1);
+                               jit_type_free($3.type);
+                       }
+       ;
+
+TypeDefinitionPart
+       : /* empty */
+       | K_TYPE TypeDefinitionList             {
+                               /* Check for undefined record types that were referred
+                                  to using a pointer reference of the form "^name" */
+                               dpas_scope_check_undefined(dpas_scope_current());
+                       }
+       ;
+
+TypeDefinitionList
+       : TypeDefinition
+       | TypeDefinitionList TypeDefinition
+       ;
+
+TypeDefinition
+       : Identifier '=' Type ';'                       {
+                               dpas_scope_item_t item;
+                               jit_type_t type;
+                               item = dpas_scope_lookup(dpas_scope_current(), $1, 0);
+                               type = (item ? dpas_scope_item_type(item) : 0);
+                               if(!item)
+                               {
+                                       dpas_type_set_name($3, $1);
+                                       dpas_scope_add(dpas_scope_current(), $1, $3,
+                                                                  DPAS_ITEM_TYPE, 0, 0,
+                                                                  dpas_filename, dpas_linenum);
+                               }
+                               else if(dpas_scope_item_kind(item) == DPAS_ITEM_TYPE &&
+                                           jit_type_get_tagged_kind(type) == DPAS_TAG_NAME &&
+                                           jit_type_get_tagged_type(type) == 0 &&
+                                               jit_type_get_tagged_kind($3) == DPAS_TAG_NAME)
+                               {
+                                       /* This is a defintion of a record type that was
+                                          previously encountered in a forward pointer
+                                          reference of the form "^name".  We need to
+                                          back-patch the previous type with the type info */
+                                       jit_type_set_tagged_type
+                                               (type, jit_type_get_tagged_type($3), 1);
+                               }
+                               else
+                               {
+                                       dpas_redeclared($1, item);
+                               }
+                               jit_free($1);
+                               jit_type_free($3);
+                       }
+       ;
+
+VariableDeclarationPart
+       : /* empty */
+       | K_VAR VariableDeclarationList
+       ;
+
+VariableDeclarationList
+       : VariableDeclaration
+       | VariableDeclarationList VariableDeclaration
+       ;
+
+VariableDeclaration
+       : IdentifierList ':' Type ';'           {
+                               /* Add each of the variables to the current scope */
+                               int posn;
+                               dpas_scope_item_t item;
+                               for(posn = 0; posn < $1.len; ++posn)
+                               {
+                                       item = dpas_scope_lookup(dpas_scope_current(),
+                                                                                    $1.list[posn], 0);
+                                       if(item)
+                                       {
+                                               dpas_redeclared($1.list[posn], item);
+                                       }
+                                       else
+                                       {
+                                               if(dpas_current_function())
+                                               {
+                                                       jit_value_t value;
+                                                       value = jit_value_create
+                                                               (dpas_current_function(), $3);
+                                                       if(!value)
+                                                       {
+                                                               dpas_out_of_memory();
+                                                       }
+                                                       dpas_scope_add(dpas_scope_current(),
+                                                                                  $1.list[posn], $3,
+                                                                                  DPAS_ITEM_VARIABLE, value, 0,
+                                                                                  dpas_filename, dpas_linenum);
+                                               }
+                                               else
+                                               {
+                                                       /* Allocate some memory to hold the global data */
+                                                       void *space = jit_calloc(1, jit_type_get_size($3));
+                                                       if(!space)
+                                                       {
+                                                               dpas_out_of_memory();
+                                                       }
+                                                       dpas_scope_add(dpas_scope_current(),
+                                                                                  $1.list[posn], $3,
+                                                                                  DPAS_ITEM_GLOBAL_VARIABLE, space, 0,
+                                                                                  dpas_filename, dpas_linenum);
+                                               }
+                                       }
+                               }
+
+                               /* Free the id list and type, which we don't need any more */
+                               identifier_list_free($1.list, $1.len);
+                               jit_type_free($3);
+                       }
+       ;
+
+ProcedureAndFunctionDeclarationPart
+       : /* empty */
+       | ProcedureOrFunctionList
+       ;
+
+ProcedureOrFunctionList
+       : ProcedureOrFunctionDeclaration ';'
+       | ProcedureOrFunctionList ProcedureOrFunctionDeclaration ';'
+       ;
+
+StatementPart
+       : K_BEGIN StatementSequence OptSemi K_END
+       | K_BEGIN OptSemi K_END
+       | K_BEGIN error K_END
+       ;
+
+OptSemi
+       : /* empty */
+       | ';'
+       ;
+
+/*
+ * Procedure and function declarations.
+ */
+
+ProcedureOrFunctionDeclaration
+       : ProcedureOrFunctionHeading ';'        {
+                               unsigned int num_params;
+                               unsigned int param;
+                               jit_type_t type;
+                               const char *name;
+                               dpas_scope_item_t item;
+                               jit_function_t func;
+
+                               /* Declare the procedure/function into the current scope */
+                               item = dpas_scope_lookup(dpas_scope_current(), $1.name, 0);
+                               if(item)
+                               {
+                                       dpas_redeclared($1.name, item);
+                               }
+                               else
+                               {
+                                       dpas_scope_add(dpas_scope_current(), $1.name, $1.type,
+                                                                  DPAS_ITEM_PROCEDURE, 0, 0,
+                                                                  dpas_filename, dpas_linenum);
+                               }
+
+                               /* Push into a new scope for the procedure/function body */
+                               dpas_scope_push();
+                               func = dpas_new_function($1.type);
+
+                               /* Declare the parameters into the scope.  If a name
+                                  is NULL, then it indicates that a duplicate parameter
+                                  name was detected, and replaced with no name */
+                               num_params = jit_type_num_params($1.type);
+                               for(param = 0; param < num_params; ++param)
+                               {
+                                       name = jit_type_get_name($1.type, param);
+                                       if(name)
+                                       {
+                                               jit_value_t value;
+                                               value = jit_value_get_param(func, param);
+                                               if(!value)
+                                               {
+                                                       dpas_out_of_memory();
+                                               }
+                                               dpas_scope_add(dpas_scope_current(), name,
+                                                                          jit_type_get_param($1.type, param),
+                                                                          DPAS_ITEM_VARIABLE, value, 0,
+                                                                          dpas_filename, dpas_linenum);
+                                       }
+                               }
+
+                               /* Declare the function return variable into the scope */
+                               type = jit_type_get_return($1.type);
+                               if(type != jit_type_void)
+                               {
+                                       if(dpas_scope_lookup(dpas_scope_current(), $1.name, 0))
+                                       {
+                                               dpas_error("`%s' is declared as both a parameter "
+                                                                  "and a function name", $1.name);
+                                       }
+                                       else
+                                       {
+                                               dpas_scope_add(dpas_scope_current(), $1.name, type,
+                                                                          DPAS_ITEM_FUNC_RETURN, 0, 0,
+                                                                          dpas_filename, dpas_linenum);
+                                       }
+                               }
+                       } Body {
+                               jit_function_t func = dpas_current_function();
+                               int result;
+
+                               /* Make sure that the function is properly terminated */
+                               result = jit_insn_default_return(func);
+                               if(!result)
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               else if(result == 1 &&
+                                       jit_type_get_return($1.type) != jit_type_void)
+                               {
+                                       dpas_error("control reached the end of a function");
+                               }
+
+                               /* Pop from the procedure/function scope */
+                               dpas_pop_function();
+                               dpas_scope_pop();
+
+                               /* TODO: compile the procedure/function */
+
+                               jit_dump_function(stdout, func, $1.name);
+
+                               /* Free values that we no longer require */
+                               jit_free($1.name);
+                               jit_type_free($1.type);
+                       }
+       ;
+
+ProcedureOrFunctionHeading
+       : ProcedureHeading                      { $$ = $1; }
+       | FunctionHeading                       { $$ = $1; }
+       ;
+
+Body
+       : Block                 {}
+       | Directive             {}
+       ;
+
+Directive
+       : K_FORWARD                                                             { $$ = 0; }
+       | K_IMPORT '(' STRING_CONSTANT ')'              { $$ = $3; }
+       ;
+
+ProcedureHeading
+       : K_PROCEDURE Identifier FormalParameterList    {
+                               $$.name = $2;
+                               $$.type = jit_type_create_signature
+                                       (($3.has_vararg ? jit_abi_vararg : jit_abi_cdecl),
+                                        jit_type_void, $3.types, (unsigned int)($3.len), 1);
+                               if(!($$.type))
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               if(!jit_type_set_names($$.type, $3.names,
+                                                                          (unsigned int)($3.len)))
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               parameter_list_free(&($3));
+                       }
+       ;
+
+FunctionHeading
+       : K_FUNCTION Identifier FormalParameterList ':' TypeIdentifier  {
+                               $$.name = $2;
+                               $$.type = jit_type_create_signature
+                                       (($3.has_vararg ? jit_abi_vararg : jit_abi_cdecl),
+                                        $5, $3.types, (unsigned int)($3.len), 1);
+                               if(!($$.type))
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               if(!jit_type_set_names($$.type, $3.names,
+                                                                          (unsigned int)($3.len)))
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               parameter_list_free(&($3));
+                               jit_type_free($5);
+                       }
+       ;
+
+FormalParameterList
+       : /* empty */           { parameter_list_init(&($$)); }
+       | '(' FormalParameterSections ')'                                       { $$ = $2; }
+       | '(' FormalParameterSections ';' K_DOT_DOT ')'         {
+                               $$ = $2;
+                               $$.has_vararg = 1;
+                       }
+       ;
+
+FormalParameterSections
+       : FormalParameterSection                { $$ = $1; }
+       | FormalParameterSections ';' FormalParameterSection    {
+                               $$ = $1;
+                               parameter_list_merge(&($$), &($3));
+                       }
+       ;
+
+FormalParameterSection
+       : IdentifierList ':' ParameterType                      {
+                               parameter_list_create(&($$), $1.list, $1.len, $3.type);
+                               if($3.bounds.len > 0)
+                               {
+                                       /* We should be using "var" with conformant array types */
+                                       dpas_warning("`%s' should be declared as `var'",
+                                                                $1.list[0]);
+                                       if($1.len > 1)
+                                       {
+                                               dpas_error("too many parameter names for "
+                                                                  "conformant array specification");
+                                       }
+                                       parameter_list_merge(&($$), &($3.bounds));
+                               }
+                               jit_type_free($3.type);
+                       }
+       | K_VAR IdentifierList ':' ParameterType        {
+                               jit_type_t type = jit_type_create_pointer($4.type, 0);
+                               if(!type)
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               if($4.bounds.len == 0)
+                               {
+                                       type = jit_type_create_tagged(type, DPAS_TAG_VAR, 0, 0, 0);
+                                       if(!type)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                               }
+                               parameter_list_create(&($$), $2.list, $2.len, type);
+                               if($4.bounds.len > 0)
+                               {
+                                       if($2.len > 1)
+                                       {
+                                               dpas_error("too many parameter names for "
+                                                                  "conformant array specification");
+                                       }
+                                       parameter_list_merge(&($$), &($4.bounds));
+                               }
+                               jit_type_free(type);
+                       }
+       | ProcedureHeading              {
+                               parameter_list_init(&($$));
+                               parameter_list_add(&($$), $1.name, $1.type);
+                       }
+       | FunctionHeading               {
+                               parameter_list_init(&($$));
+                               parameter_list_add(&($$), $1.name, $1.type);
+                       }
+       ;
+
+ParameterType
+       : TypeIdentifier                        {
+                               $$.type = $1;
+                               parameter_list_init(&($$.bounds));
+                       }
+       | ConformantArray                       { $$ = $1; }
+       ;
+
+ConformantArray
+       : K_PACKED K_ARRAY '[' BoundSpecification ']' K_OF TypeIdentifier       {
+                               $$.type = dpas_create_conformant_array($7, $4.len, 1);
+                               $$.bounds = $4;
+                       }
+       | K_ARRAY '[' BoundSpecificationList ']' K_OF ParameterType                     {
+                               $$.type = dpas_create_conformant_array($6.type, $3.len, 0);
+                               $$.bounds = $3;
+                               parameter_list_merge(&($$.bounds), &($6.bounds));
+                       }
+       ;
+
+BoundSpecificationList
+       : BoundSpecification            { $$ = $1; }
+       | BoundSpecificationList ';' BoundSpecification {
+                               $$ = $1;
+                               parameter_list_merge(&($$), &($3));
+                       }
+       ;
+
+BoundSpecification
+       : Identifier K_DOT_DOT Identifier ':' TypeIdentifier    {
+                               if($5 != jit_type_int)
+                               {
+                                       char *name = dpas_type_name($5);
+                                       dpas_error("`%s' cannot be used for array bounds; "
+                                                          "must be `Integer'", name);
+                                       jit_free(name);
+                               }
+                               jit_type_free($5);
+                               parameter_list_init(&($$));
+                               parameter_list_add(&($$), $1, jit_type_int);
+                               if(jit_strcmp($1, $3) != 0)
+                               {
+                                       parameter_list_add(&($$), $3, jit_type_int);
+                               }
+                               else
+                               {
+                                       dpas_error("`%s' used twice in a parameter or "
+                                                          "field list", $1);
+                                       parameter_list_add(&($$), 0, jit_type_int);
+                                       jit_free($3);
+                               }
+                       }
+       ;
+
+/*
+ * Statements.
+ */
+
+StatementSequence
+       : Statement
+       | StatementSequence ';' Statement
+       ;
+
+Statement
+       : Label ':' InnerStatement
+       | InnerStatement
+       ;
+
+InnerStatement
+       : Variable K_ASSIGN Expression                  {
+                               /* TODO: type checking and non-local variables */
+                               if(dpas_sem_is_lvalue($1) && dpas_sem_is_rvalue($3))
+                               {
+                                       if(!jit_insn_store(dpas_current_function(),
+                                                                          dpas_sem_get_value($1),
+                                                                          dpas_sem_get_value($3)))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                               }
+                               else
+                               {
+                                       dpas_error("invalid assignment");
+                               }
+                       }
+       | Identifier                                                    {}
+       | Identifier '(' ExpressionList ')'             {}
+       | K_GOTO Label
+       | CompoundStatement
+       | K_WHILE Expression K_DO Statement
+       | K_REPEAT StatementSequence OptSemi K_UNTIL Expression
+       | K_FOR Identifier K_ASSIGN Expression Direction Expression K_DO Statement
+       | K_IF Expression K_THEN Statement
+       | K_IF Expression K_THEN Statement K_ELSE Statement
+       | CaseStatement
+       | K_WITH VariableList K_DO Statement
+       | K_THROW Expression
+       | K_THROW
+       | TryStatement
+       | K_EXIT
+       ;
+
+CompoundStatement
+       : K_BEGIN StatementSequence OptSemi K_END
+       | K_BEGIN error K_END
+       ;
+
+Direction
+       : K_TO
+       | K_DOWNTO
+       ;
+
+CaseStatement
+       : K_CASE Expression K_OF CaseLimbList
+       ;
+
+CaseLimbList
+       : CaseLimb
+       | CaseLimbList ';' CaseLimb
+       ;
+
+CaseLimb
+       : CaseLabelList ':' Statement
+       ;
+
+CaseLabelList
+       : Constant                                              {}
+       | CaseLabelList ',' Constant    {}
+       ;
+
+VariableList
+       : Variable                                              {}
+       | VariableList ',' Variable             {}
+       ;
+
+TryStatement
+       : K_TRY StatementSequence OptSemi CatchClause FinallyClause K_END
+       ;
+
+CatchClause
+       : /* empty */
+       | K_CATCH Identifier ':' Type StatementSequence OptSemi
+       ;
+
+FinallyClause
+       : /* empty */
+       | K_FINALLY StatementSequence OptSemi
+       ;
+
+/*
+ * Expressions.
+ */
+
+Expression
+       : SimpleExpression                                                      { $$ = $1; }
+       | SimpleExpression '=' SimpleExpression         {
+                               handle_compare_binary("=", jit_insn_eq, $1, $3);
+                       }
+       | SimpleExpression K_NE SimpleExpression        {
+                               handle_compare_binary("<>", jit_insn_ne, $1, $3);
+                       }
+       | SimpleExpression '<' SimpleExpression         {
+                               handle_compare_binary("<", jit_insn_lt, $1, $3);
+                       }
+       | SimpleExpression '>' SimpleExpression         {
+                               handle_compare_binary(">", jit_insn_gt, $1, $3);
+                       }
+       | SimpleExpression K_LE SimpleExpression        {
+                               handle_compare_binary("<=", jit_insn_le, $1, $3);
+                       }
+       | SimpleExpression K_GE SimpleExpression        {
+                               handle_compare_binary(">=", jit_insn_ge, $1, $3);
+                       }
+       | SimpleExpression K_IN SimpleExpression        {
+                               /* TODO */
+                       }
+       ;
+
+ExpressionList
+       : Expression                                            { /* TODO */ }
+       | ExpressionList ',' Expression         { /* TODO */ }
+       ;
+
+SimpleExpression
+       : AdditionExpression                    { $$ = $1; }
+       | '+' AdditionExpression                {
+                               if(!dpas_sem_is_rvalue($2) ||
+                                  !dpas_type_is_numeric(dpas_sem_get_type($2)))
+                               {
+                                       if(!dpas_sem_is_error($2))
+                                       {
+                                               dpas_error("invalid operand to unary `+'");
+                                       }
+                                       dpas_sem_set_error($$);
+                               }
+                               else
+                               {
+                                       $$ = $2;
+                               }
+                       }
+       | '-' AdditionExpression                {
+                               if(!dpas_sem_is_rvalue($2) ||
+                                  !dpas_type_is_numeric(dpas_sem_get_type($2)))
+                               {
+                                       if(!dpas_sem_is_error($2))
+                                       {
+                                               dpas_error("invalid operand to unary `-'");
+                                       }
+                                       dpas_sem_set_error($$);
+                               }
+                               else
+                               {
+                                       jit_value_t value;
+                                       value = jit_insn_neg
+                                               (dpas_current_function(), dpas_sem_get_value($2));
+                                       dpas_sem_set_rvalue($$, jit_value_get_type(value), value);
+                               }
+                       }
+       ;
+
+AdditionExpression
+       : Term                                                  { $$ = $1; }
+       | AdditionExpression '+' Term   {
+                               handle_binary("+", jit_insn_add, $1, $3);
+                       }
+       | AdditionExpression '-' Term   {
+                               handle_binary("-", jit_insn_sub, $1, $3);
+                       }
+       | AdditionExpression K_OR Term  {
+                               if(dpas_sem_is_rvalue($1) &&
+                                  dpas_type_is_boolean(dpas_sem_get_type($1)) &&
+                                  dpas_sem_is_rvalue($3) &&
+                                  dpas_type_is_boolean(dpas_sem_get_type($3)))
+                               {
+                                       /* Output code to compute a short-circuited "or" */
+                                       jit_label_t label1 = jit_label_undefined;
+                                       jit_label_t label2 = jit_label_undefined;
+                                       jit_value_t value, const_value;
+                                       if(!jit_insn_branch_if
+                                                       (dpas_current_function(),
+                                                        dpas_sem_get_value($1), &label1))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_branch_if
+                                                       (dpas_current_function(),
+                                                        dpas_sem_get_value($3), &label1))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       value = jit_value_create
+                                               (dpas_current_function(), jit_type_int);
+                                       const_value = jit_value_create_nint_constant
+                                               (dpas_current_function(), jit_type_int, 0);
+                                       if(!value || !const_value)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_store(dpas_current_function(),
+                                                                          value, const_value))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_branch(dpas_current_function(), &label2))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_label(dpas_current_function(), &label1))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       const_value = jit_value_create_nint_constant
+                                               (dpas_current_function(), jit_type_int, 1);
+                                       if(!const_value)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_store(dpas_current_function(),
+                                                                          value, const_value))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_label(dpas_current_function(), &label2))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       dpas_sem_set_rvalue($$, dpas_type_boolean, value);
+                               }
+                               else
+                               {
+                                       handle_integer_binary("or", jit_insn_or, $1, $3);
+                               }
+                       }
+       ;
+
+Term
+       : Power                                                 { $$ = $1; }
+       | Term '*' Power                                {
+                               handle_binary("*", jit_insn_div, $1, $3);
+                       }
+       | Term '/' Power                                {
+                               /* Standard Pascal always returns a floating-point
+                                  result for '/', but we don't do that here yet */
+                               handle_binary("/", jit_insn_div, $1, $3);
+                       }
+       | Term K_DIV Power                              {
+                               handle_binary("div", jit_insn_div, $1, $3);
+                       }
+       | Term K_MOD Power                              {
+                               handle_binary("mod", jit_insn_rem, $1, $3);
+                       }
+       | Term K_AND Power                              {
+                               if(dpas_sem_is_rvalue($1) &&
+                                  dpas_type_is_boolean(dpas_sem_get_type($1)) &&
+                                  dpas_sem_is_rvalue($3) &&
+                                  dpas_type_is_boolean(dpas_sem_get_type($3)))
+                               {
+                                       /* Output code to compute a short-circuited "and" */
+                                       jit_label_t label1 = jit_label_undefined;
+                                       jit_label_t label2 = jit_label_undefined;
+                                       jit_value_t value, const_value;
+                                       if(!jit_insn_branch_if_not
+                                                       (dpas_current_function(),
+                                                        dpas_sem_get_value($1), &label1))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_branch_if_not
+                                                       (dpas_current_function(),
+                                                        dpas_sem_get_value($3), &label1))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       value = jit_value_create
+                                               (dpas_current_function(), jit_type_int);
+                                       const_value = jit_value_create_nint_constant
+                                               (dpas_current_function(), jit_type_int, 1);
+                                       if(!value || !const_value)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_store(dpas_current_function(),
+                                                                          value, const_value))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_branch(dpas_current_function(), &label2))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_label(dpas_current_function(), &label1))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       const_value = jit_value_create_nint_constant
+                                               (dpas_current_function(), jit_type_int, 0);
+                                       if(!const_value)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_store(dpas_current_function(),
+                                                                          value, const_value))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       if(!jit_insn_label(dpas_current_function(), &label2))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       dpas_sem_set_rvalue($$, dpas_type_boolean, value);
+                               }
+                               else
+                               {
+                                       handle_integer_binary("and", jit_insn_and, $1, $3);
+                               }
+                       }
+       | Term K_XOR Power                              {
+                               handle_integer_binary("xor", jit_insn_xor, $1, $3);
+                       }
+       | Term K_SHL Power                              {
+                               handle_integer_binary("shl", jit_insn_shl, $1, $3);
+                       }
+       | Term K_SHR Power                              {
+                               handle_integer_binary("shr", jit_insn_shr, $1, $3);
+                       }
+       ;
+
+Power
+       : Factor                                                { $$ = $1; }
+       | Power K_POW Factor                    {
+                               handle_binary("pow", jit_insn_pow, $1, $3);
+                       }
+       ;
+
+Factor
+       : Variable                                              { $$ = $1; }
+       | BasicConstant                                 {
+                               jit_value_t value = jit_value_create_constant
+                                       (dpas_current_function(), &($1));
+                               dpas_sem_set_rvalue($$, $1.type, value);
+                       }
+       | '[' ExpressionList ']'                { /* TODO */ }
+       | '[' ']'                                               { /* TODO */ }
+       | K_NOT Factor                                  {
+                               jit_value_t value;
+                               if(dpas_sem_is_rvalue($2) &&
+                                  dpas_type_is_boolean(dpas_sem_get_type($2)))
+                               {
+                                       value = jit_insn_to_not_bool
+                                               (dpas_current_function(), dpas_sem_get_value($2));
+                                       dpas_sem_set_rvalue($$, dpas_type_boolean, value);
+                               }
+                               else if(dpas_sem_is_rvalue($2) &&
+                                               dpas_type_is_integer(dpas_sem_get_type($2)))
+                               {
+                                       value = jit_insn_not
+                                               (dpas_current_function(), dpas_sem_get_value($2));
+                                       dpas_sem_set_rvalue($$, jit_value_get_type(value), value);
+                               }
+                               else
+                               {
+                                       if(!dpas_sem_is_error($2))
+                                       {
+                                               dpas_error("invalid operand to unary `not'");
+                                       }
+                                       dpas_sem_set_error($$);
+                               }
+                       }
+       | '&' Factor                                    {
+                               jit_type_t type;
+                               if(dpas_sem_is_lvalue($2))
+                               {
+                                       jit_value_t value;
+                                       value = jit_insn_address_of
+                                               (dpas_current_function(), dpas_sem_get_value($2));
+                                       type = jit_type_create_pointer(dpas_sem_get_type($2), 1);
+                                       if(!type)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       dpas_sem_set_rvalue($$, type, value);
+                               }
+                               else if(dpas_sem_is_lvalue_ea($2))
+                               {
+                                       /* Turn the effective address into an r-value */
+                                       type = jit_type_create_pointer(dpas_sem_get_type($2), 1);
+                                       if(!type)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       dpas_sem_set_rvalue($$, type, dpas_sem_get_value($2));
+                               }
+                               else
+                               {
+                                       if(!dpas_sem_is_error($2))
+                                       {
+                                               dpas_error("l-value required for address-of operator");
+                                       }
+                                       dpas_sem_set_error($$);
+                               }
+                       }
+       | '@' Factor                                    {
+                               jit_type_t type;
+                               if(dpas_sem_is_lvalue($2))
+                               {
+                                       jit_value_t value;
+                                       value = jit_insn_address_of
+                                               (dpas_current_function(), dpas_sem_get_value($2));
+                                       type = jit_type_create_pointer(dpas_sem_get_type($2), 1);
+                                       if(!type)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       dpas_sem_set_rvalue($$, jit_value_get_type(value), value);
+                               }
+                               else if(dpas_sem_is_lvalue_ea($2))
+                               {
+                                       /* Turn the effective address into an r-value */
+                                       type = jit_type_create_pointer(dpas_sem_get_type($2), 1);
+                                       if(!type)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       dpas_sem_set_rvalue($$, type, dpas_sem_get_value($2));
+                               }
+                               else
+                               {
+                                       if(!dpas_sem_is_error($2))
+                                       {
+                                               dpas_error("l-value required for address-of operator");
+                                       }
+                                       dpas_sem_set_error($$);
+                               }
+                       }
+       | '(' Expression ')'                    { $$ = $2; }
+       | Variable '(' ExpressionList ')'               { /* TODO */ }
+       | K_VA_ARG '(' TypeIdentifier ')'               { /* TODO */ }
+       | K_SIZEOF '(' Variable ')'                             { /* TODO */ }
+       | '(' K_IF Expression K_THEN Expression K_ELSE Expression ')'   {
+                               /* TODO */
+                       }
+       ;
+
+Variable
+       : Identifier                                            {
+                               dpas_scope_item_t item;
+                               item = dpas_scope_lookup(dpas_scope_current(), $1, 1);
+                               if(!item)
+                               {
+                                       dpas_error("`%s' is not declared in the current scope", $1);
+                                       dpas_sem_set_error($$);
+                               }
+                               else
+                               {
+                                       switch(dpas_scope_item_kind(item))
+                                       {
+                                               case DPAS_ITEM_TYPE:
+                                               {
+                                                       dpas_sem_set_type($$, dpas_scope_item_type(item));
+                                               }
+                                               break;
+
+                                               case DPAS_ITEM_VARIABLE:
+                                               {
+                                                       dpas_sem_set_lvalue
+                                                               ($$, dpas_scope_item_type(item),
+                                                                (jit_value_t)dpas_scope_item_info(item));
+                                               }
+                                               break;
+
+                                               case DPAS_ITEM_GLOBAL_VARIABLE:
+                                               {
+                                                       jit_value_t value;
+                                                       void *address = dpas_scope_item_info(item);
+                                                       value = jit_value_create_nint_constant
+                                                               (dpas_current_function(),
+                                                                jit_type_void_ptr, (jit_nint)address);
+                                                       if(!value)
+                                                       {
+                                                               dpas_out_of_memory();
+                                                       }
+                                                       dpas_sem_set_lvalue_ea
+                                                               ($$, dpas_scope_item_type(item), value);
+                                               }
+                                               break;
+
+                                               case DPAS_ITEM_CONSTANT:
+                                               {
+                                                       jit_value_t const_value;
+                                                       const_value = jit_value_create_constant
+                                                               (dpas_current_function(),
+                                                                (jit_constant_t *)dpas_scope_item_info(item));
+                                                       if(!const_value)
+                                                       {
+                                                               dpas_out_of_memory();
+                                                       }
+                                                       dpas_sem_set_rvalue
+                                                               ($$, dpas_scope_item_type(item), const_value);
+                                               }
+                                               break;
+
+                                               case DPAS_ITEM_PROCEDURE:
+                                               {
+                                                       dpas_sem_set_procedure
+                                                               ($$, dpas_scope_item_type(item), item);
+                                               }
+                                               break;
+
+                                               case DPAS_ITEM_WITH:
+                                               {
+                                                       /* TODO */
+                                                       dpas_sem_set_error($$);
+                                               }
+                                               break;
+
+                                               case DPAS_ITEM_FUNC_RETURN:
+                                               {
+                                                       dpas_sem_set_return
+                                                               ($$, dpas_scope_item_type(item));
+                                               }
+                                               break;
+
+                                               default:
+                                               {
+                                                       dpas_sem_set_error($$);
+                                               }
+                                               break;
+                                       }
+                               }
+                               jit_free($1);
+                       }
+       | Variable '[' ExpressionList ']'       {
+                               /* TODO */
+                       }
+       | Variable '.' Identifier                       {
+                               /* Fetch the effective address of a structure field */
+                               /* TODO */
+                       }
+       | Variable '^'                                          {
+                               /* Dereference a pointer value */
+                               jit_value_t value;
+                               if(!jit_type_is_pointer(dpas_sem_get_type($1)))
+                               {
+                                       if(!dpas_sem_is_error($1))
+                                       {
+                                               dpas_error("invalid operand to unary `^'");
+                                       }
+                                       dpas_sem_set_error($$);
+                               }
+                               else if(dpas_sem_is_lvalue($1) || dpas_sem_is_rvalue($1))
+                               {
+                                       /* Turn the pointer value into an effective address */
+                                       value = jit_insn_add_relative
+                                               (dpas_current_function(), dpas_sem_get_value($1), 0);
+                                       if(!value)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       dpas_sem_set_lvalue_ea
+                                               ($$, jit_type_get_ref(dpas_sem_get_type($1)), value);
+                               }
+                               else if(dpas_sem_is_lvalue_ea($1))
+                               {
+                                       /* Fetch the pointer value and construct a new adddress */
+                                       value = jit_insn_load_relative
+                                               (dpas_current_function(), dpas_sem_get_value($1),
+                                                0, jit_type_void_ptr);
+                                       if(!value)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       dpas_sem_set_lvalue_ea
+                                               ($$, jit_type_get_ref(dpas_sem_get_type($1)), value);
+                               }
+                               else
+                               {
+                                       if(!dpas_sem_is_error($1))
+                                       {
+                                               dpas_error("invalid operand to unary `^'");
+                                       }
+                                       dpas_sem_set_error($$);
+                               }
+                       }
+       ;
+
+/*
+ * Types.
+ */
+
+TypeIdentifier
+       : Identifier                    {
+                               dpas_scope_item_t item;
+                               item = dpas_scope_lookup(dpas_scope_current(), $1, 1);
+                               if(!item)
+                               {
+                                       dpas_undeclared($1);
+                                       $$ = jit_type_void;
+                               }
+                               else if(dpas_scope_item_kind(item) != DPAS_ITEM_TYPE)
+                               {
+                                       dpas_error("`%s' does not refer to a type in the "
+                                                          "current scope", $1);
+                                       $$ = jit_type_void;
+                               }
+                               else
+                               {
+                                       $$ = jit_type_copy(dpas_scope_item_type(item));
+                               }
+                               jit_free($1);
+                       }
+       ;
+
+Type
+       : SimpleType                            { $$ = $1; }
+       | StructuredType                        { $$ = $1; }
+       | K_PACKED StructuredType       { $$ = $2; }
+       ;
+
+SimpleType
+       : TypeIdentifier                                { $$ = $1; }
+       | '(' IdentifierList ')'                {
+                               jit_type_t type;
+                               int posn;
+                               dpas_scope_item_t item;
+                               jit_constant_t value;
+
+                               /* Create the enumerated type */
+                               type = dpas_create_enum(jit_type_int, $2.len);
+
+                               /* Declare all of the identifiers into the current scope
+                                  as constants whose values correspond to the positions */
+                               for(posn = 0; posn < $2.len; ++posn)
+                               {
+                                       if(!($2.list[posn]))
+                                       {
+                                               /* Placeholder for a duplicate identifier.  The error
+                                                  was already reported inside "IdentifierList" */
+                                               continue;
+                                       }
+                                       item = dpas_scope_lookup(dpas_scope_current(),
+                                                                                        $2.list[posn], 0);
+                                       if(item)
+                                       {
+                                               dpas_redeclared($2.list[posn], item);
+                                               continue;
+                                       }
+                                       value.type = type;
+                                       value.un.int_value = (jit_int)posn;
+                                       dpas_scope_add_const(dpas_scope_current(),
+                                                                               $2.list[posn], &value,
+                                                                               dpas_filename, dpas_linenum);
+                               }
+
+                               /* Free the identifier list, which we no longer need */
+                               identifier_list_free($2.list, $2.len);
+
+                               /* Return the type as our semantic value */
+                               $$ = type;
+                       }
+       | Constant K_DOT_DOT Constant   {
+                               /* Infer a common type for the subrange */
+                               jit_type_t type = dpas_common_type($1.type, $3.type, 1);
+                               if(type)
+                               {
+                                       /* TODO: check that value1 <= value2 */
+                                       dpas_subrange range;
+                                       dpas_convert_constant(&(range.first), &($1), type);
+                                       dpas_convert_constant(&(range.last), &($3), type);
+                                       $$ = dpas_create_subrange(type, &range);
+                                       jit_type_free($1.type);
+                                       jit_type_free($3.type);
+                               }
+                               else
+                               {
+                                       char *name1 = dpas_type_name($1.type);
+                                       char *name2 = dpas_type_name($3.type);
+                                       if(!jit_strcmp(name1, name2))
+                                       {
+                                               dpas_error("cannot declare a subrange within `%s'",
+                                                                  name1);
+                                       }
+                                       else
+                                       {
+                                               dpas_error("cannot declare a subrange within "
+                                                                  "`%s' or `%s'", name1, name2);
+                                       }
+                                       jit_free(name1);
+                                       jit_free(name2);
+                                       $$ = $1.type;
+                                       jit_type_free($3.type);
+                               }
+                       }
+       ;
+
+StructuredType
+       : K_ARRAY '[' ArrayBoundsList ']' K_OF Type     {
+                               $$ = dpas_create_array($3.list, $3.len, $6);
+                       }
+       | K_RECORD FieldList K_END              {
+                               jit_type_t type;
+                               type = jit_type_create_struct
+                                       ($2.types, (unsigned int)($2.len), 1);
+                               if(!type)
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               if(!jit_type_set_names
+                                               (type, $2.names, (unsigned int)($2.len)))
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               type = jit_type_create_tagged(type, DPAS_TAG_NAME, 0, 0, 0);
+                               parameter_list_free(&($2));
+                               $$ = type;
+                       }
+       | K_SET K_OF Type                               {
+                               if(!dpas_is_set_compatible($3))
+                               {
+                                       char *name = dpas_type_name($3);
+                                       dpas_error("`%s' cannot be used as the member type "
+                                                          "for a set", name);
+                                       jit_free(name);
+                               }
+                               $$ = jit_type_create_tagged
+                                               (jit_type_uint, DPAS_TAG_SET,
+                                                $3, (jit_meta_free_func)jit_type_free, 0);
+                       }
+       | '^' Identifier                        {
+                               dpas_scope_item_t item;
+                               item = dpas_scope_lookup(dpas_scope_current(), $2, 1);
+                               if(!item)
+                               {
+                                       /* The name is not declared yet, so it is probably a
+                                          forward reference to some later record type.  We need
+                                          to add a placeholder for the later definition */
+                                       char *name;
+                                       name = jit_strdup($2);
+                                       if(!name)
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       $$ = jit_type_create_tagged(0, DPAS_TAG_NAME,
+                                                                                               name, jit_free, 0);
+                                       if(!($$))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                                       dpas_scope_add(dpas_scope_current(), $2, $$,
+                                                                  DPAS_ITEM_TYPE, 0, 0,
+                                                                  dpas_filename, dpas_linenum);
+                               }
+                               else if(dpas_scope_item_kind(item) != DPAS_ITEM_TYPE)
+                               {
+                                       dpas_error("`%s' does not refer to a type in the "
+                                                          "current scope", $2);
+                                       $$ = jit_type_void;
+                               }
+                               else
+                               {
+                                       $$ = jit_type_copy(dpas_scope_item_type(item));
+                               }
+                               $$ = jit_type_create_pointer($$, 0);
+                               if(!($$))
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               jit_free($2);
+                       }
+       ;
+
+ArrayBoundsList
+       : BoundType                                             {
+                               $$.list = 0;
+                               $$.len = 0;
+                               type_list_add(&($$.list), &($$.len), $1);
+                       }
+       | ArrayBoundsList ',' BoundType {
+                               $$ = $1;
+                               type_list_add(&($$.list), &($$.len), $3);
+                       }
+       ;
+
+BoundType
+       : SimpleType            {
+                               /* The type must be an enumeration or integer subrange */
+                               if(jit_type_get_tagged_kind($1) == DPAS_TAG_ENUM)
+                               {
+                                       $$ = $1;
+                               }
+                               else if(jit_type_get_tagged_kind($1) == DPAS_TAG_SUBRANGE &&
+                                               jit_type_get_tagged_type($1) == jit_type_int)
+                               {
+                                       $$ = $1;
+                               }
+                               else
+                               {
+                                       char *name = dpas_type_name($1);
+                                       dpas_error("`%s' cannot be used as an array bound", name);
+                                       jit_free(name);
+                                       $$ = 0;
+                               }
+                       }
+       ;
+
+FieldList
+       : /* empty */                                   { parameter_list_init(&($$)); }
+       | FixedPart                                             { $$ = $1; }
+       | FixedPart ';'                                 { $$ = $1; }
+       | FixedPart ';' VariantPart             {
+                               $$ = $1;
+                               parameter_list_merge(&($$), &($3));
+                       }
+       | FixedPart ';' VariantPart ';' {
+                               $$ = $1;
+                               parameter_list_merge(&($$), &($3));
+                       }
+       | VariantPart                                   { $$ = $1; }
+       | VariantPart ';'                               { $$ = $1; }
+       ;
+
+FixedPart
+       : RecordSection                                 { $$ = $1; }
+       | FixedPart ';' RecordSection   {
+                               $$ = $1;
+                               parameter_list_merge(&($$), &($3));
+                       }
+       ;
+
+RecordSection
+       : IdentifierList ':' Type               {
+                               parameter_list_create(&($$), $1.list, $1.len, $3);
+                               jit_type_free($3);
+                       }
+       | ProcedureOrFunctionHeading    {
+                               parameter_list_init(&($$));
+                               parameter_list_add(&($$), $1.name, $1.type);
+                       }
+       ;
+
+VariantPart
+       : K_CASE Identifier ':' TypeIdentifier K_OF VariantList {
+                               parameter_list_init(&($$));
+                               parameter_list_add(&($$), $2, $4);
+                               parameter_list_add(&($$), 0, $6);
+                       }
+       | K_CASE ':' TypeIdentifier K_OF VariantList    {
+                               parameter_list_init(&($$));
+                               parameter_list_add(&($$), 0, $5);
+                               jit_type_free($3);
+                       }
+       ;
+
+VariantList
+       : VariantCaseList       {
+                               /* Create a union with all of the case limbs */
+                               $$ = jit_type_create_union
+                                       ($1.list, (unsigned int)($1.len), 0);
+                               jit_free($1.list);
+                       }
+       ;
+
+VariantCaseList
+       : Variant                       {
+                               $$.list = 0;
+                               $$.len = 0;
+                               type_list_add(&($$.list), &($$.len), $1);
+                       }
+       | VariantCaseList ';' Variant   {
+                               $$ = $1;
+                               type_list_add(&($$.list), &($$.len), $3);
+                       }
+       ;
+
+Variant
+       : VariantCaseLabelList ':' '(' FieldList ')'    {
+                               jit_type_t type;
+                               type = jit_type_create_struct
+                                       ($4.types, (unsigned int)($4.len), 1);
+                               if(!type)
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               if(!jit_type_set_names
+                                               (type, $4.names, (unsigned int)($4.len)))
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               parameter_list_free(&($4));
+                               $$ = type;
+                       }
+       ;
+
+/* We ignore the variant case labels, as we don't perform any
+   checks on the variant structure - we just use it as a union */
+VariantCaseLabelList
+       : Constant                                                      {}
+       | VariantCaseLabelList ',' Constant     {}
+       ;
+
+/*
+ * Constants.
+ */
+
+Constant
+       : ConstantValue                         { $$ = $1; }
+       | '+' ConstantValue                     {
+                               if($2.type != jit_type_int &&
+                                  $2.type != jit_type_uint &&
+                                  $2.type != jit_type_long &&
+                                  $2.type != jit_type_ulong &&
+                                  $2.type != jit_type_nfloat)
+                               {
+                                       char *name = dpas_type_name($2.type);
+                                       dpas_error("unary `+' cannot be applied to a constant "
+                                                          "of type `%s'", name);
+                                       jit_free(name);
+                               }
+                               $$ = $2;
+                       }
+       | '-' ConstantValue                     {
+                               if($2.type == jit_type_int)
+                               {
+                                       $$.type = $2.type;
+                                       $$.un.int_value = -($2.un.int_value);
+                               }
+                               else if($2.type == jit_type_uint)
+                               {
+                                       $$.type = jit_type_long;
+                                       $$.un.long_value = -((jit_long)($2.un.uint_value));
+                               }
+                               else if($2.type == jit_type_long)
+                               {
+                                       $$.type = jit_type_long;
+                                       $$.un.long_value = -($2.un.long_value);
+                               }
+                               else if($2.type == jit_type_ulong)
+                               {
+                                       $$.type = jit_type_long;
+                                       $$.un.long_value = -((jit_long)($2.un.ulong_value));
+                               }
+                               else if($2.type == jit_type_nfloat)
+                               {
+                                       $$.type = jit_type_nfloat;
+                                       $$.un.nfloat_value = -($2.un.nfloat_value);
+                               }
+                               else
+                               {
+                                       char *name = dpas_type_name($2.type);
+                                       dpas_error("unary `-' cannot be applied to a constant "
+                                                          "of type `%s'", name);
+                                       jit_free(name);
+                                       $$ = $2;
+                               }
+                       }
+       ;
+
+ConstantValue
+       : BasicConstant                         { $$ = $1; }
+       | Identifier                            {
+                               dpas_scope_item_t item;
+                               item = dpas_scope_lookup(dpas_scope_current(), $1, 1);
+                               if(!item)
+                               {
+                                       dpas_error("`%s' is not declared in the current scope", $1);
+                                       $$.type = jit_type_int;
+                                       $$.un.int_value = 0;
+                               }
+                               else if(dpas_scope_item_kind(item) != DPAS_ITEM_CONSTANT)
+                               {
+                                       dpas_error("`%s' is not declared as a constant "
+                                                          "in the current scope", $1);
+                                       $$.type = jit_type_int;
+                                       $$.un.int_value = 0;
+                               }
+                               else
+                               {
+                                       $$ = *((jit_constant_t *)(dpas_scope_item_info(item)));
+                               }
+                               jit_free($1);
+                       }
+       ;
+
+BasicConstant
+       : INTEGER_CONSTANT                      {
+                               $$.type = $1.type;
+                               if($1.type == jit_type_int)
+                               {
+                                       $$.un.int_value = (jit_int)($1.value);
+                               }
+                               else if($1.type == jit_type_uint)
+                               {
+                                       $$.un.uint_value = (jit_uint)($1.value);
+                               }
+                               else if($1.type == jit_type_long)
+                               {
+                                       $$.un.long_value = (jit_long)($1.value);
+                               }
+                               else
+                               {
+                                       $$.un.ulong_value = $1.value;
+                               }
+                       }
+       | REAL_CONSTANT                         {
+                               $$.type = jit_type_nfloat;
+                               $$.un.nfloat_value = $1;
+                       }
+       | STRING_CONSTANT                       {
+                               /* Note: the string pointer leaks from the parser,
+                                  but since we probably need it to hang around for
+                                  runtime, this shouldn't be serious */
+                               $$.type = dpas_type_string;
+                               $$.un.ptr_value = $1;
+                       }
+       | K_NIL                                         {
+                               $$.type = dpas_type_nil;
+                               $$.un.ptr_value = 0;
+                       }
+       ;
diff --git a/dpas/dpas-scanner.l b/dpas/dpas-scanner.l
new file mode 100644 (file)
index 0000000..399fcb8
--- /dev/null
@@ -0,0 +1,345 @@
+%{
+/*
+ * dpas-scanner.l - Input file for lex for the Dynamic Pascal token syntax.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "dpas-internal.h"
+#include "dpas-parser.h"
+
+extern YYSTYPE yylval;
+
+/*
+ * Current file and line number.
+ */
+char *dpas_filename = "";
+long dpas_linenum = 1;
+
+/*
+ * Return a token code from the lexical analyser.
+ */
+#define        RETURNTOK(x)            return (x)
+
+/*
+ * Parse a string value.
+ */
+static char *dpas_parse_string(const char *text)
+{
+       int quote = *text++;
+       char *str = (char *)jit_malloc(jit_strlen(text));
+       char *temp;
+       if(!str)
+       {
+               dpas_out_of_memory();
+       }
+       temp = str;
+       while(*text != '\0')
+       {
+               if(text[0] == quote && text[1] == quote)
+               {
+                       *temp++ = (char)quote;
+                       text += 2;
+               }
+               else
+               {
+                       *temp++ = *text++;
+               }
+       }
+       *temp = '\0';
+       return str;
+}
+
+/*
+ * Parse a floating-point value.
+ */
+static jit_nfloat dpas_parse_float(const char *text)
+{
+       double value = 0.0;
+       sscanf(text, "%lf", &value);
+       return (jit_nfloat)value;
+}
+
+/*
+ * Infer the best type for an integer constant.
+ */
+static void dpas_infer_type(YYSTYPE *lval)
+{
+       jit_ulong value = lval->int_const.value;
+       if(value <= (jit_ulong)(jit_long)jit_max_int)
+       {
+               lval->int_const.type = jit_type_int;
+       }
+       else if(value <= (jit_ulong)jit_max_uint)
+       {
+               lval->int_const.type = jit_type_uint;
+       }
+       else if(value <= (jit_ulong)jit_max_long)
+       {
+               lval->int_const.type = jit_type_long;
+       }
+       else
+       {
+               lval->int_const.type = jit_type_ulong;
+       }
+}
+
+/*
+ * Parse a decimal integer value.
+ */
+static void dpas_parse_decimal(const char *text, YYSTYPE *lval)
+{
+       jit_ulong value = 0;
+       while(*text != '\0')
+       {
+               value = value * 10 + (jit_ulong)(*text - '0');
+               ++text;
+       }
+       lval->int_const.value = value;
+       dpas_infer_type(lval);
+}
+
+/*
+ * Parse a hexadecimal integer value.
+ */
+static void dpas_parse_hex(const char *text, YYSTYPE *lval)
+{
+       jit_ulong value = 0;
+       while(*text != '\0')
+       {
+               if(*text >= '0' && *text <= '9')
+               {
+                       value = value * 16 + (jit_ulong)(*text - '0');
+               }
+               else if(*text >= 'A' && *text <= 'F')
+               {
+                       value = value * 16 + (jit_ulong)(*text - 'A' + 10);
+               }
+               else
+               {
+                       value = value * 16 + (jit_ulong)(*text - 'a' + 10);
+               }
+               ++text;
+       }
+       lval->int_const.value = value;
+       dpas_infer_type(lval);
+}
+
+/*
+ * Forward declaration.
+ */
+static void dpas_skip_comment(int star_style);
+
+%}
+
+%option outfile="lex.yy.c"
+%option noyywrap
+%option nounput
+%option case-insensitive
+
+DIGIT                                  [0-9]
+HEX                                            [0-9A-Fa-f]
+IDALPHA                                        [a-zA-Z_]
+EXPONENT                               [Ee][+-]?{DIGIT}+
+WHITE                                  [ \t\v\r\f]
+
+%%
+
+"<>"                                   { RETURNTOK(K_NE); }
+"<="                                   { RETURNTOK(K_LE); }
+">="                                   { RETURNTOK(K_GE); }
+":="                                   { RETURNTOK(K_ASSIGN); }
+".."                                   { RETURNTOK(K_DOT_DOT); }
+"**"                                   { RETURNTOK(K_POW); }
+
+"and"                                  { RETURNTOK(K_AND); }
+"array"                                        { RETURNTOK(K_ARRAY); }
+"begin"                                        { RETURNTOK(K_BEGIN); }
+"case"                                 { RETURNTOK(K_CASE); }
+"catch"                                        { RETURNTOK(K_CATCH); }
+"const"                                        { RETURNTOK(K_CONST); }
+"div"                                  { RETURNTOK(K_DIV); }
+"do"                                   { RETURNTOK(K_DO); }
+"downto"                               { RETURNTOK(K_DOWNTO); }
+"else"                                 { RETURNTOK(K_ELSE); }
+"end"                                  { RETURNTOK(K_END); }
+"exit"                                 { RETURNTOK(K_EXIT); }
+"finally"                              { RETURNTOK(K_FINALLY); }
+"for"                                  { RETURNTOK(K_FOR); }
+"forward"                              { RETURNTOK(K_FORWARD); }
+"function"                             { RETURNTOK(K_FUNCTION); }
+"goto"                                 { RETURNTOK(K_GOTO); }
+"if"                                   { RETURNTOK(K_IF); }
+"in"                                   { RETURNTOK(K_IN); }
+"label"                                        { RETURNTOK(K_LABEL); }
+"import"                               { RETURNTOK(K_IMPORT); }
+"mod"                                  { RETURNTOK(K_MOD); }
+"module"                               { RETURNTOK(K_MODULE); }
+"nil"                                  { RETURNTOK(K_NIL); }
+"not"                                  { RETURNTOK(K_NOT); }
+"of"                                   { RETURNTOK(K_OF); }
+"or"                                   { RETURNTOK(K_OR); }
+"packed"                               { RETURNTOK(K_PACKED); }
+"pow"                                  { RETURNTOK(K_POW); }
+"procedure"                            { RETURNTOK(K_PROCEDURE); }
+"program"                              { RETURNTOK(K_PROGRAM); }
+"record"                               { RETURNTOK(K_RECORD); }
+"repeat"                               { RETURNTOK(K_REPEAT); }
+"set"                                  { RETURNTOK(K_SET); }
+"shl"                                  { RETURNTOK(K_SHL); }
+"shr"                                  { RETURNTOK(K_SHR); }
+"sizeof"                               { RETURNTOK(K_SIZEOF); }
+"then"                                 { RETURNTOK(K_THEN); }
+"throw"                                        { RETURNTOK(K_THROW); }
+"to"                                   { RETURNTOK(K_TO); }
+"try"                                  { RETURNTOK(K_TRY); }
+"type"                                 { RETURNTOK(K_TYPE); }
+"until"                                        { RETURNTOK(K_UNTIL); }
+"var"                                  { RETURNTOK(K_VAR); }
+"va_arg"                               { RETURNTOK(K_VA_ARG); }
+"with"                                 { RETURNTOK(K_WITH); }
+"while"                                        { RETURNTOK(K_WHILE); }
+"xor"                                  { RETURNTOK(K_XOR); }
+
+'(''|[^'])*'                   { yylval.name = dpas_parse_string(yytext);
+                                                 RETURNTOK(STRING_CONSTANT); }
+
+\"(\"\"|[^"])*\"               { yylval.name = dpas_parse_string(yytext);
+                                                 RETURNTOK(STRING_CONSTANT); }
+
+{IDALPHA}({DIGIT}|{IDALPHA})*  {
+                       yylval.name = jit_strdup(yytext);
+                       if(!(yylval.name))
+                       {
+                               dpas_out_of_memory();
+                       }
+                       RETURNTOK(IDENTIFIER);
+               }
+
+{DIGIT}+{EXPONENT}                             { yylval.real_const = dpas_parse_float(yytext);
+                                                                 RETURNTOK(REAL_CONSTANT); }
+{DIGIT}+"."{DIGIT}*{EXPONENT}  { yylval.real_const = dpas_parse_float(yytext);
+                                                                 RETURNTOK(REAL_CONSTANT); }
+{DIGIT}+"."{DIGIT}+                            { yylval.real_const = dpas_parse_float(yytext);
+                                                                 RETURNTOK(REAL_CONSTANT); }
+{DIGIT}+"."[^.]                                        { yylval.real_const = dpas_parse_float(yytext);
+                                                                 RETURNTOK(REAL_CONSTANT); }
+
+{DIGIT}{HEX}*[hH]                              { dpas_parse_hex(yytext, &yylval);
+                                                                 RETURNTOK(INTEGER_CONSTANT); }
+
+{DIGIT}+                                               { dpas_parse_decimal(yytext, &yylval);
+                                                                 RETURNTOK(INTEGER_CONSTANT); }
+
+{WHITE}+                                               ;
+
+\n                                                             { ++dpas_linenum; }
+
+"{"                                                            { dpas_skip_comment(0); }
+"(*"                                                   { dpas_skip_comment(1); }
+
+.                                                              { RETURNTOK(((int)(yytext[0])) & 0xFF); }
+
+%%
+
+void dpas_load_file(char *filename, FILE *file)
+{
+       char *saved_filename;
+       long saved_linenum;
+       YY_BUFFER_STATE saved_buffer;
+       YY_BUFFER_STATE new_buffer;
+       extern int yyparse(void);
+
+       /* Save the current state */
+       saved_filename = dpas_filename;
+       saved_linenum = dpas_linenum;
+       saved_buffer = YY_CURRENT_BUFFER;
+
+       /* Create a buffer for the new file */
+       new_buffer = yy_create_buffer(file, BUFSIZ);
+       if(!new_buffer)
+       {
+               dpas_out_of_memory();
+       }
+
+       /* Switch to the new state */
+       dpas_filename = filename;
+       dpas_linenum = 1;
+       yy_switch_to_buffer(new_buffer);
+
+       /* Call the parser */
+       if(yyparse())
+       {
+               dpas_error_reported = 1;
+       }
+
+       /* Bail out if this was the top-most file in the parse process,
+          because flex cannot switch to a NULL buffer */
+       if(!saved_buffer)
+       {
+               return;
+       }
+
+       /* Switch back to the original file */
+       dpas_filename = saved_filename;
+       dpas_linenum = saved_linenum;
+       yy_switch_to_buffer(saved_buffer);
+
+       /* Delete the buffer that we used on the file we just parsed */
+       yy_delete_buffer(new_buffer);
+}
+
+/*
+ * Skip a comment in the input stream.
+ */
+static void dpas_skip_comment(int star_style)
+{
+       int ch;
+       for(;;)
+       {
+               ch = input();
+               if(ch == EOF)
+               {
+                       break;
+               }
+               else if(ch == '}' && !star_style)
+               {
+                       break;
+               }
+               else if(ch == '*' && star_style)
+               {
+                       ch = input();
+                       while(ch == '*')
+                       {
+                               ch = input();
+                       }
+                       if(ch == EOF || ch == ')')
+                       {
+                               break;
+                       }
+                       else if(ch == '\n')
+                       {
+                               ++dpas_linenum;
+                       }
+               }
+               else if(ch == '\n')
+               {
+                       ++dpas_linenum;
+               }
+       }
+}
+
diff --git a/dpas/dpas-scope.c b/dpas/dpas-scope.c
new file mode 100644 (file)
index 0000000..50b32d9
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * dpas-scope.c - Scope handling for Dynamic Pascal.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "dpas-internal.h"
+
+/*
+ * Internal structure of a scope item.
+ */
+struct dpas_scope_item
+{
+       int                                     kind;
+       char                       *name;
+       jit_type_t                      type;
+       void                       *info;
+       jit_meta_free_func      free_info;
+       char                       *filename;
+       long                            linenum;
+       dpas_scope_item_t       next;
+};
+
+/*
+ * Internal structure of a scope.
+ */
+struct dpas_scope
+{
+       dpas_scope_t            parent;
+       dpas_scope_item_t       first;
+       dpas_scope_item_t       last;
+       dpas_scope_item_t       first_with;
+       dpas_scope_item_t       last_with;
+       int                                     level;
+};
+
+dpas_scope_t dpas_scope_create(dpas_scope_t parent)
+{
+       dpas_scope_t scope;
+       scope = jit_new(struct dpas_scope);
+       if(!scope)
+       {
+               dpas_out_of_memory();
+       }
+       scope->parent = parent;
+       scope->first = 0;
+       scope->last = 0;
+       scope->first_with = 0;
+       scope->last_with = 0;
+       if(parent)
+       {
+               scope->level = parent->level + 1;
+       }
+       else
+       {
+               scope->level = 0;
+       }
+       return scope;
+}
+
+void dpas_scope_destroy(dpas_scope_t scope)
+{
+       if(scope)
+       {
+               dpas_scope_item_t item, next;
+               item = scope->first;
+               while(item != 0)
+               {
+                       next = item->next;
+                       if(item->name)
+                       {
+                               jit_free(item->name);
+                       }
+                       if(item->free_info)
+                       {
+                               (*(item->free_info))(item->info);
+                       }
+                       jit_type_free(item->type);
+                       jit_free(item);
+                       item = next;
+               }
+               item = scope->first_with;
+               while(item != 0)
+               {
+                       next = item->next;
+                       if(item->name)
+                       {
+                               jit_free(item->name);
+                       }
+                       if(item->free_info)
+                       {
+                               (*(item->free_info))(item->info);
+                       }
+                       jit_type_free(item->type);
+                       jit_free(item);
+                       item = next;
+               }
+               jit_free(scope);
+       }
+}
+
+dpas_scope_item_t dpas_scope_lookup(dpas_scope_t scope,
+                                                                       const char *name, int up)
+{
+       dpas_scope_item_t item;
+       int check_with = 1;
+       while(scope != 0)
+       {
+               /* Search through the "with" items for a field match */
+               if(check_with)
+               {
+                       item = scope->first_with;
+                       if(!item)
+                       {
+                               /* We are exiting from the top-most "with" scope
+                                  in the current procedure.  Ignore the rest of
+                                  the "with" scopes on the stack because we only
+                                  care about local/global variables from now on */
+                               check_with = 0;
+                       }
+                       while(item != 0)
+                       {
+                               if(dpas_type_find_name(item->type, name) != JIT_INVALID_NAME)
+                               {
+                                       return item;
+                               }
+                               item = item->next;
+                       }
+               }
+
+               /* Search the regular items for a match */
+               item = scope->first;
+               while(item != 0)
+               {
+                       if(!jit_stricmp(item->name, name))
+                       {
+                               return item;
+                       }
+                       item = item->next;
+               }
+
+               /* Move up to the parent scope if necessary */
+               if(!up)
+               {
+                       break;
+               }
+               scope = scope->parent;
+       }
+       return 0;
+}
+
+/*
+ * Add an item to a scope list.
+ */
+static void scope_add(dpas_scope_item_t *first, dpas_scope_item_t *last,
+                                         const char *name, jit_type_t type, int kind,
+                                         void *info, jit_meta_free_func free_info,
+                                         char *filename, long linenum)
+{
+       dpas_scope_item_t item;
+       item = jit_new(struct dpas_scope_item);
+       if(!item)
+       {
+               dpas_out_of_memory();
+       }
+       if(name)
+       {
+               item->name = jit_strdup(name);
+               if(!(item->name))
+               {
+                       dpas_out_of_memory();
+               }
+       }
+       else
+       {
+               item->name = 0;
+       }
+       item->type = jit_type_copy(type);
+       item->kind = kind;
+       item->info = info;
+       item->free_info = free_info;
+       if(filename)
+       {
+               item->filename = jit_strdup(filename);
+               if(!(item->filename))
+               {
+                       dpas_out_of_memory();
+               }
+       }
+       else
+       {
+               item->filename = 0;
+       }
+       item->linenum = linenum;
+       item->next = 0;
+       if(*last)
+       {
+               (*last)->next = item;
+       }
+       else
+       {
+               *first = item;
+       }
+       *last = item;
+}
+
+void dpas_scope_add(dpas_scope_t scope, const char *name, jit_type_t type,
+                                       int kind, void *info, jit_meta_free_func free_info,
+                                       char *filename, long linenum)
+{
+       scope_add(&(scope->first), &(scope->last),
+                         name, type, kind, info, free_info, filename, linenum);
+}
+
+void dpas_scope_add_with(dpas_scope_t scope, jit_type_t type,
+                                                void *with_info, jit_meta_free_func free_info)
+{
+       scope_add(&(scope->first_with), &(scope->last_with),
+                         0, type, DPAS_ITEM_WITH, with_info, free_info, 0, 0);
+}
+
+void dpas_scope_add_const(dpas_scope_t scope, const char *name,
+                                                 jit_constant_t *value, char *filename, long linenum)
+{
+       jit_constant_t *new_value;
+       new_value = jit_new(jit_constant_t);
+       if(!new_value)
+       {
+               dpas_out_of_memory();
+       }
+       *new_value = *value;
+       scope_add(&(scope->first), &(scope->last), name, value->type,
+                         DPAS_ITEM_CONSTANT, new_value, jit_free, filename, linenum);
+}
+
+void dpas_scope_check_undefined(dpas_scope_t scope)
+{
+       dpas_scope_item_t item = scope->first;
+       jit_type_t type, new_type;
+       while(item != 0)
+       {
+               if(item->kind == DPAS_ITEM_TYPE)
+               {
+                       type = item->type;
+                       if(jit_type_get_tagged_kind(type) == DPAS_TAG_NAME &&
+                          jit_type_get_tagged_type(type) == 0)
+                       {
+                               dpas_error_on_line
+                                       (item->filename, item->linenum,
+                                        "forward-referenced record type `%s' was not "
+                                        "declared", item->name);
+                               new_type = jit_type_create_struct(0, 0, 0);
+                               if(!new_type)
+                               {
+                                       dpas_out_of_memory();
+                               }
+                               jit_type_set_tagged_type(type, new_type, 0);
+                       }
+               }
+               item = item->next;
+       }
+}
+
+int dpas_scope_item_kind(dpas_scope_item_t item)
+{
+       return item->kind;
+}
+
+jit_type_t dpas_scope_item_type(dpas_scope_item_t item)
+{
+       return item->type;
+}
+
+void *dpas_scope_item_info(dpas_scope_item_t item)
+{
+       return item->info;
+}
+
+const char *dpas_scope_item_filename(dpas_scope_item_t item)
+{
+       return item->filename;
+}
+
+long dpas_scope_item_linenum(dpas_scope_item_t item)
+{
+       return item->linenum;
+}
+
+int dpas_scope_level(dpas_scope_t scope)
+{
+       return scope->level;
+}
+
+/*
+ * The global and current scopes.
+ */
+static dpas_scope_t global_scope = 0;
+static dpas_scope_t current_scope = 0;
+
+dpas_scope_t dpas_scope_current(void)
+{
+       if(!current_scope)
+       {
+               /* Create the global scope for the first time */
+               global_scope = dpas_scope_create(0);
+
+               /* Create a wrapper around the global scope to contain
+                  the program-private definitions.  This allows the
+                  program to override the global scope if it wants to */
+               current_scope = dpas_scope_create(global_scope);
+       }
+       return current_scope;
+}
+
+dpas_scope_t dpas_scope_global(void)
+{
+       if(!current_scope)
+       {
+               dpas_scope_current();
+       }
+       return global_scope;
+}
+
+dpas_scope_t dpas_scope_push(void)
+{
+       current_scope = dpas_scope_create(dpas_scope_current());
+       return current_scope;
+}
+
+void dpas_scope_pop(void)
+{
+       dpas_scope_t scope = dpas_scope_current();
+       if(scope->parent && scope->parent != global_scope)
+       {
+               current_scope = scope->parent;
+               dpas_scope_destroy(scope);
+       }
+}
diff --git a/dpas/dpas-scope.h b/dpas/dpas-scope.h
new file mode 100644 (file)
index 0000000..8d6633d
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * dpas-scope.h - Scope handling for Dynamic Pascal.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _DPAS_SCOPE_H
+#define        _DPAS_SCOPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Kinds of items that may be stored in a scope.
+ */
+#define        DPAS_ITEM_TYPE                          1
+#define        DPAS_ITEM_VARIABLE                      2
+#define        DPAS_ITEM_GLOBAL_VARIABLE       3
+#define        DPAS_ITEM_CONSTANT                      4
+#define        DPAS_ITEM_PROCEDURE                     5
+#define        DPAS_ITEM_WITH                          6
+#define        DPAS_ITEM_FUNC_RETURN           7
+
+/*
+ * Opaque type that represents a scope.
+ */
+typedef struct dpas_scope *dpas_scope_t;
+
+/*
+ * Opaque type that represents a scope item.
+ */
+typedef struct dpas_scope_item *dpas_scope_item_t;
+
+/*
+ * Create a new scope, with a specified parent scope.  If the parent
+ * scope is NULL, then this creates the global scope.
+ */
+dpas_scope_t dpas_scope_create(dpas_scope_t parent);
+
+/*
+ * Destroy a scope that is no longer required.
+ */
+void dpas_scope_destroy(dpas_scope_t scope);
+
+/*
+ * Look up a name within a scope.  If "up" is non-zero, then also
+ * check the parent scopes.
+ */
+dpas_scope_item_t dpas_scope_lookup(dpas_scope_t scope,
+                                                                       const char *name, int up);
+
+/*
+ * Add an entry to a scope.
+ */
+void dpas_scope_add(dpas_scope_t scope, const char *name, jit_type_t type,
+                                       int kind, void *info, jit_meta_free_func free_info,
+                                       char *filename, long linenum);
+
+/*
+ * Add a "with" field declaration to a scope.
+ */
+void dpas_scope_add_with(dpas_scope_t scope, jit_type_t type,
+                                                void *with_info, jit_meta_free_func free_info);
+
+/*
+ * Add a constant value to a scope.
+ */
+void dpas_scope_add_const(dpas_scope_t scope, const char *name,
+                                                 jit_constant_t *value, char *filename, long linenum);
+
+/*
+ * Search a scope to look for undefined record types that were
+ * referenced by a construct of the form "^name".
+ */
+void dpas_scope_check_undefined(dpas_scope_t scope);
+
+/*
+ * Get the kind associated with a scope item.
+ */
+int dpas_scope_item_kind(dpas_scope_item_t item);
+
+/*
+ * Get the type associated with a scope item.
+ */
+jit_type_t dpas_scope_item_type(dpas_scope_item_t item);
+
+/*
+ * Get the information block associated with a scope item.
+ */
+void *dpas_scope_item_info(dpas_scope_item_t item);
+
+/*
+ * Get the filename associated with a scope item.
+ */
+const char *dpas_scope_item_filename(dpas_scope_item_t item);
+
+/*
+ * Get the line number associated with a scope item.
+ */
+long dpas_scope_item_linenum(dpas_scope_item_t item);
+
+/*
+ * Get the level associated with the current scope (global is zero).
+ */
+int dpas_scope_level(dpas_scope_t scope);
+
+/*
+ * Get the current scope.
+ */
+dpas_scope_t dpas_scope_current(void);
+
+/*
+ * Get the global scope.
+ */
+dpas_scope_t dpas_scope_global(void);
+
+/*
+ * Create a new scope and push into it.
+ */
+dpas_scope_t dpas_scope_push(void);
+
+/*
+ * Pop the current scope level and destroy it.
+ */
+void dpas_scope_pop(void);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _DPAS_SCOPE_H */
diff --git a/dpas/dpas-semantics.h b/dpas/dpas-semantics.h
new file mode 100644 (file)
index 0000000..8d4dd95
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * dpas-semantics.h - Semantic value handling for Dynamic Pascal.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _DPAS_SEMANTICS_H
+#define        _DPAS_SEMANTICS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Structure of a semantic value.
+ */
+typedef struct
+{
+       int                     kind__;
+       jit_type_t      type__;
+       jit_value_t     value__;
+
+} dpas_semvalue;
+
+/*
+ * Semantic value kinds.
+ */
+#define        DPAS_SEM_LVALUE                 (1 << 0)
+#define        DPAS_SEM_RVALUE                 (1 << 1)
+#define        DPAS_SEM_TYPE                   (1 << 2)
+#define        DPAS_SEM_PROCEDURE              (1 << 3)
+#define        DPAS_SEM_ERROR                  (1 << 4)
+#define        DPAS_SEM_RETURN                 (1 << 5)
+#define        DPAS_SEM_LVALUE_EA              (1 << 6)
+
+/*
+ * Set a semantic value to an l-value.
+ */
+#define        dpas_sem_set_lvalue(sem,type,value)     \
+               do { \
+                       (sem).kind__ = DPAS_SEM_LVALUE | DPAS_SEM_RVALUE; \
+                       (sem).type__ = (type); \
+                       if(!(value)) \
+                       { \
+                               dpas_out_of_memory(); \
+                       } \
+                       (sem).value__ = (value); \
+               } while (0)
+
+/*
+ * Set a semantic value to an l-value that is actually an effective
+ * address that must be dereferenced to get the actual l-value.
+ */
+#define        dpas_sem_set_lvalue_ea(sem,type,value)  \
+               do { \
+                       (sem).kind__ = DPAS_SEM_LVALUE_EA | DPAS_SEM_RVALUE; \
+                       (sem).type__ = (type); \
+                       if(!(value)) \
+                       { \
+                               dpas_out_of_memory(); \
+                       } \
+                       (sem).value__ = (value); \
+               } while (0)
+
+/*
+ * Set a semantic value to an r-value.
+ */
+#define        dpas_sem_set_rvalue(sem,type,value)     \
+               do { \
+                       (sem).kind__ = DPAS_SEM_RVALUE; \
+                       (sem).type__ = (type); \
+                       if(!(value)) \
+                       { \
+                               dpas_out_of_memory(); \
+                       } \
+                       (sem).value__ = (value); \
+               } while (0)
+
+/*
+ * Set a semantic value to a type.
+ */
+#define        dpas_sem_set_type(sem,type)     \
+               do { \
+                       (sem).kind__ = DPAS_SEM_TYPE; \
+                       (sem).type__ = (type); \
+                       (sem).value__ = 0; \
+               } while (0)
+
+/*
+ * Set a semantic value to a procedure/function reference.
+ */
+#define        dpas_sem_set_procedure(sem,type,item)   \
+               do { \
+                       (sem).kind__ = DPAS_SEM_PROCEDURE; \
+                       (sem).type__ = (type); \
+                       (sem).value__ = (jit_value_t)(item); \
+               } while (0)
+
+/*
+ * Set a semantic value to an error.
+ */
+#define        dpas_sem_set_error(sem) \
+               do { \
+                       (sem).kind__ = DPAS_SEM_ERROR; \
+                       (sem).type__ = 0; \
+                       (sem).value__ = 0; \
+               } while (0)
+
+/*
+ * Set a semantic value to indicate the return slot.
+ */
+#define        dpas_sem_set_return(sem,type)   \
+               do { \
+                       (sem).kind__ = DPAS_SEM_RETURN; \
+                       (sem).type__ = (type); \
+                       (sem).value__ = 0; \
+               } while (0)
+
+/*
+ * Determine if a semantic value has a specific kind.
+ */
+#define        dpas_sem_is_lvalue(sem)         (((sem).kind__ & DPAS_SEM_LVALUE) != 0)
+#define        dpas_sem_is_lvalue_ea(sem)      (((sem).kind__ & DPAS_SEM_LVALUE_EA) != 0)
+#define        dpas_sem_is_rvalue(sem)         (((sem).kind__ & DPAS_SEM_RVALUE) != 0)
+#define        dpas_sem_is_type(sem)           (((sem).kind__ & DPAS_SEM_TYPE) != 0)
+#define        dpas_sem_is_procedure(sem)      (((sem).kind__ & DPAS_SEM_PROCEDURE) != 0)
+#define        dpas_sem_is_error(sem)          (((sem).kind__ & DPAS_SEM_ERROR) != 0)
+#define        dpas_sem_is_return(sem)         (((sem).kind__ & DPAS_SEM_RETURN) != 0)
+
+/*
+ * Extract the type information from a semantic value.
+ */
+#define        dpas_sem_get_type(sem)          ((sem).type__)
+
+/*
+ * Extract the value information from a semantic value.
+ */
+#define        dpas_sem_get_value(sem)         ((sem).value__)
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _DPAS_SEMANTICS_H */
diff --git a/dpas/dpas-types.c b/dpas/dpas-types.c
new file mode 100644 (file)
index 0000000..18f04a5
--- /dev/null
@@ -0,0 +1,1139 @@
+/*
+ * dpas-types.c - Special handling for Dynamic Pascal types.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "dpas-internal.h"
+#include <stddef.h>
+
+/*
+ * Define some special integer types that are distinguished from normal ones.
+ */
+jit_type_t dpas_type_boolean;
+jit_type_t dpas_type_cboolean;
+jit_type_t dpas_type_char;
+jit_type_t dpas_type_string;
+jit_type_t dpas_type_address;
+jit_type_t dpas_type_nil;
+
+/*
+ * Register a predefined type within the global scope.
+ */
+static void register_type(const char *name, jit_type_t type)
+{
+       dpas_scope_add(dpas_scope_global(), name, type, DPAS_ITEM_TYPE, 0, 0,
+                      "(builtin)", 1);
+}
+
+/*
+ * Get an integer type of a specific size.
+ */
+static jit_type_t get_int_type(unsigned int size)
+{
+       if(size == sizeof(jit_int))
+       {
+               return jit_type_int;
+       }
+       else if(size == sizeof(jit_long))
+       {
+               return jit_type_long;
+       }
+       else if(size == sizeof(jit_nint))
+       {
+               return jit_type_nint;
+       }
+       else if(size == sizeof(jit_short))
+       {
+               return jit_type_short;
+       }
+       else if(size == sizeof(jit_sbyte))
+       {
+               return jit_type_sbyte;
+       }
+       else
+       {
+               return jit_type_int;
+       }
+}
+
+/*
+ * Get an unsigned integer type of a specific size.
+ */
+static jit_type_t get_uint_type(unsigned int size)
+{
+       if(size == sizeof(jit_uint))
+       {
+               return jit_type_uint;
+       }
+       else if(size == sizeof(jit_ulong))
+       {
+               return jit_type_ulong;
+       }
+       else if(size == sizeof(jit_nuint))
+       {
+               return jit_type_nuint;
+       }
+       else if(size == sizeof(jit_ushort))
+       {
+               return jit_type_ushort;
+       }
+       else if(size == sizeof(jit_ubyte))
+       {
+               return jit_type_ubyte;
+       }
+       else
+       {
+               return jit_type_uint;
+       }
+}
+
+void dpas_init_types(void)
+{
+       jit_constant_t value;
+
+       /*
+        * Create the special types.
+        */
+       dpas_type_boolean = jit_type_create_tagged
+               (jit_type_sys_int, DPAS_TAG_BOOLEAN, 0, 0, 1);
+       dpas_type_cboolean = jit_type_create_tagged
+               (jit_type_sys_char, DPAS_TAG_CBOOLEAN, 0, 0, 1);
+       if(((char)0xFF) < 0)
+       {
+               dpas_type_char = jit_type_create_tagged
+                       (jit_type_sbyte, DPAS_TAG_CHAR, 0, 0, 1);
+       }
+       else
+       {
+               dpas_type_char = jit_type_create_tagged
+                       (jit_type_ubyte, DPAS_TAG_CHAR, 0, 0, 1);
+       }
+       dpas_type_string = jit_type_create_pointer(dpas_type_char, 1);
+       dpas_type_address = jit_type_void_ptr;
+       dpas_type_nil = jit_type_create_tagged
+               (jit_type_void_ptr, DPAS_TAG_NIL, 0, 0, 1);
+
+       /*
+        * Register all of the builtin types.
+        */
+       register_type("Boolean", dpas_type_boolean);
+       register_type("CBoolean", dpas_type_cboolean);
+       register_type("Char", dpas_type_char);
+       register_type("String", dpas_type_string);
+       register_type("Address", dpas_type_address);
+
+       register_type("Integer", jit_type_int);
+       register_type("Cardinal", jit_type_uint);
+       register_type("Word", jit_type_uint);
+
+       register_type("Byte", jit_type_ubyte);
+       register_type("ByteInt", jit_type_sbyte);
+       register_type("ByteWord", jit_type_ubyte);
+       register_type("ByteCard", jit_type_ubyte);
+
+       register_type("ShortInt", jit_type_short);
+       register_type("ShortWord", jit_type_ushort);
+       register_type("ShortCard", jit_type_ushort);
+
+       register_type("MedInt", jit_type_nint);
+       register_type("MedWord", jit_type_nuint);
+       register_type("MedCard", jit_type_nuint);
+
+       register_type("LongInt", jit_type_long);
+       register_type("LongWord", jit_type_ulong);
+       register_type("LongCard", jit_type_ulong);
+
+       register_type("LongestInt", jit_type_long);
+       register_type("LongestWord", jit_type_ulong);
+       register_type("LongestCard", jit_type_ulong);
+
+       register_type("PtrInt", jit_type_nint);
+       register_type("PtrWord", jit_type_nuint);
+       register_type("PtrCard", jit_type_nuint);
+
+       register_type("SmallInt", jit_type_short);
+       register_type("Comp", jit_type_long);
+
+       register_type("ShortReal", jit_type_float32);
+       register_type("Single", jit_type_float32);
+
+       register_type("Real", jit_type_float64);
+       register_type("Double", jit_type_float64);
+
+       register_type("LongReal", jit_type_nfloat);
+       register_type("Extended", jit_type_nfloat);
+
+       register_type("PtrDiffType", get_int_type(sizeof(ptrdiff_t)));
+       register_type("SizeType", get_uint_type(sizeof(size_t)));
+
+       register_type("SysInt", jit_type_sys_int);
+       register_type("SysCard", jit_type_sys_uint);
+       register_type("SysWord", jit_type_sys_uint);
+
+       register_type("SysLongInt", jit_type_sys_long);
+       register_type("SysLongCard", jit_type_sys_ulong);
+       register_type("SysLongWord", jit_type_sys_ulong);
+
+       register_type("SysLongestInt", jit_type_sys_longlong);
+       register_type("SysLongestCard", jit_type_sys_ulonglong);
+       register_type("SysLongestWord", jit_type_sys_ulonglong);
+
+       /*
+        * Register the "True" and "False" constants.
+        */
+       value.type = dpas_type_boolean;
+       value.un.int_value = 1;
+       dpas_scope_add_const(dpas_scope_global(), "True", &value, "(builtin)", 1);
+       value.type = dpas_type_boolean;
+       value.un.int_value = 0;
+       dpas_scope_add_const(dpas_scope_global(), "False", &value, "(builtin)", 1);
+}
+
+unsigned int dpas_type_find_name(jit_type_t type, const char *name)
+{
+       unsigned int field = jit_type_num_fields(type);
+       const char *fname;
+       while(field > 0)
+       {
+               --field;
+               fname = jit_type_get_name(type, field);
+               if(fname && !jit_stricmp(fname, name))
+               {
+                       return field;
+               }
+       }
+       return JIT_INVALID_NAME;
+}
+
+/*
+ * Concatenate two strings.
+ */
+static char *concat_strings(char *str1, char *str2)
+{
+       char *str;
+       if(!str1 || !str2)
+       {
+               dpas_out_of_memory();
+       }
+       str = (char *)jit_malloc(jit_strlen(str1) + jit_strlen(str2) + 1);
+       if(!str)
+       {
+               dpas_out_of_memory();
+       }
+       jit_strcpy(str, str1);
+       jit_strcat(str, str2);
+       jit_free(str1);
+       jit_free(str2);
+       return str;
+}
+
+static char *type_name(const char *embed_name, jit_type_t type)
+{
+       char *temp;
+       dpas_subrange *range;
+       char *name;
+       if(jit_type_is_primitive(type))
+       {
+               if(type == jit_type_void)
+               {
+                       temp = jit_strdup("void");
+               }
+               else if(type == jit_type_sbyte)
+               {
+                       temp = jit_strdup("ByteInt");
+               }
+               else if(type == jit_type_ubyte)
+               {
+                       temp = jit_strdup("Byte");
+               }
+               else if(type == jit_type_short)
+               {
+                       temp = jit_strdup("ShortInt");
+               }
+               else if(type == jit_type_ushort)
+               {
+                       temp = jit_strdup("ShortCard");
+               }
+               else if(type == jit_type_int)
+               {
+                       temp = jit_strdup("Integer");
+               }
+               else if(type == jit_type_uint)
+               {
+                       temp = jit_strdup("Cardinal");
+               }
+               else if(type == jit_type_long)
+               {
+                       temp = jit_strdup("LongInt");
+               }
+               else if(type == jit_type_ulong)
+               {
+                       temp = jit_strdup("LongCard");
+               }
+               else if(type == jit_type_float32)
+               {
+                       temp = jit_strdup("ShortReal");
+               }
+               else if(type == jit_type_float64)
+               {
+                       temp = jit_strdup("Real");
+               }
+               else if(type == jit_type_nfloat)
+               {
+                       temp = jit_strdup("LongReal");
+               }
+               else
+               {
+                       temp = jit_strdup("unknown-primitive-type");
+               }
+       }
+       else if(jit_type_is_struct(type) || jit_type_is_union(type))
+       {
+               /* Shouldn't happen: record types should be tagged with a name */
+               temp = jit_strdup("unknown-struct-or-union");
+       }
+       else if(jit_type_is_signature(type))
+       {
+               char *temp;
+               jit_type_t return_type, param_type;
+               unsigned int param, num_params;
+               const char *param_name;
+               return_type = jit_type_get_return(type);
+               if(return_type == jit_type_void)
+               {
+                       temp = jit_strdup("procedure");
+               }
+               else
+               {
+                       temp = jit_strdup("function");
+               }
+               if(embed_name)
+               {
+                       temp = concat_strings(temp, jit_strdup(" "));
+                       temp = concat_strings(temp, jit_strdup(embed_name));
+               }
+               num_params = jit_type_num_params(type);
+               if(num_params > 0)
+               {
+                       temp = concat_strings(temp, jit_strdup("("));
+                       for(param = 0; param < num_params; ++param)
+                       {
+                               if(param > 0)
+                               {
+                                       temp = concat_strings(temp, jit_strdup(", "));
+                               }
+                               param_type = jit_type_get_param(type, param);
+                               param_name = jit_type_get_name(type, param);
+                               temp = concat_strings
+                                       (temp, type_name(param_name, param_type));
+                       }
+                       temp = concat_strings(temp, jit_strdup(")"));
+               }
+               if(return_type != jit_type_void)
+               {
+                       temp = concat_strings(temp, jit_strdup(" : "));
+                       temp = concat_strings(temp, type_name(0, return_type));
+               }
+               return temp;
+       }
+       else if(jit_type_is_pointer(type))
+       {
+               if(jit_type_get_ref(type) == dpas_type_char)
+               {
+                       temp = jit_strdup("String");
+               }
+               else if(jit_type_get_ref(type) == jit_type_void)
+               {
+                       temp = jit_strdup("Address");
+               }
+               else
+               {
+                       temp = concat_strings
+                               (jit_strdup("^"), type_name(0, jit_type_get_ref(type)));
+               }
+       }
+       else if(jit_type_is_tagged(type))
+       {
+               switch(jit_type_get_tagged_kind(type))
+               {
+                       case DPAS_TAG_BOOLEAN:          temp = jit_strdup("Boolean"); break;
+                       case DPAS_TAG_CBOOLEAN:         temp = jit_strdup("CBoolean"); break;
+                       case DPAS_TAG_CHAR:                     temp = jit_strdup("Char"); break;
+                       case DPAS_TAG_NIL:                      temp = jit_strdup("nil"); break;
+
+                       case DPAS_TAG_NAME:
+                       {
+                               name = (char *)jit_type_get_tagged_data(type);
+                               if(name)
+                               {
+                                       temp = jit_strdup(name);
+                               }
+                               else
+                               {
+                                       temp = jit_strdup("anonymous_record");
+                               }
+                       }
+                       break;
+
+                       case DPAS_TAG_VAR:
+                       {
+                               return concat_strings
+                                       (jit_strdup("var "),
+                                        type_name(embed_name, jit_type_get_ref
+                                               (jit_type_get_tagged_type(type))));
+                       }
+                       /* Not reached */
+
+                       case DPAS_TAG_SUBRANGE:
+                       {
+                               range = (dpas_subrange *)jit_type_get_tagged_data(type);
+                               temp = concat_strings
+                                       (dpas_constant_name(&(range->first)),
+                                        concat_strings
+                                               (jit_strdup(".."),
+                                                dpas_constant_name(&(range->last))));
+                       }
+                       break;
+
+                       case DPAS_TAG_ENUM:
+                       {
+                               name = ((dpas_enum *)jit_type_get_tagged_data(type))->name;
+                               if(name)
+                               {
+                                       temp = jit_strdup(name);
+                               }
+                               else
+                               {
+                                       temp = jit_strdup("anonymous_enum");
+                               }
+                       }
+                       break;
+
+                       case DPAS_TAG_SET:
+                       {
+                               temp = concat_strings
+                                       (jit_strdup("set of "),
+                                        type_name(0, (jit_type_t)jit_type_get_tagged_data(type)));
+                       }
+                       break;
+
+                       case DPAS_TAG_ARRAY:
+                       {
+                               int dim;
+                               jit_type_t array_type;
+                               dpas_array *array_info = (dpas_array *)
+                                       jit_type_get_tagged_data(type);
+                               temp = jit_strdup("array [");
+                               for(dim = 0; dim < array_info->num_bounds; ++dim)
+                               {
+                                       if(dim != 0)
+                                       {
+                                               temp = concat_strings(temp, jit_strdup(", "));
+                                       }
+                                       if(array_info->bounds[dim])
+                                       {
+                                               temp = concat_strings
+                                                       (temp, type_name(0, array_info->bounds[dim]));
+                                       }
+                                       else
+                                       {
+                                               /* User-supplied type which can't be used as a bound */
+                                               temp = concat_strings(temp, jit_strdup("0 .. 0"));
+                                       }
+                               }
+                               temp = concat_strings(temp, jit_strdup("] of "));
+                               array_type = jit_type_get_tagged_type(type);
+                               temp = concat_strings
+                                       (temp, type_name(0, jit_type_get_field(array_type, 0)));
+                       }
+                       break;
+
+                       case DPAS_TAG_CONFORMANT_ARRAY:
+                       {
+                               int dim;
+                               jit_type_t array_type;
+                               dpas_conformant_array *array_info;
+                               array_info = (dpas_conformant_array *)
+                                       jit_type_get_tagged_data(type);
+                               if(array_info->is_packed)
+                               {
+                                       temp = jit_strdup("packed array [");
+                               }
+                               else
+                               {
+                                       temp = jit_strdup("array [");
+                               }
+                               for(dim = 1; dim < array_info->num_bounds; ++dim)
+                               {
+                                       temp = concat_strings(temp, jit_strdup(","));
+                               }
+                               temp = concat_strings(temp, jit_strdup("] of "));
+                               array_type = jit_type_get_ref(jit_type_get_tagged_type(type));
+                               temp = concat_strings(temp, type_name(0, array_type));
+                               if(embed_name)
+                               {
+                                       temp = concat_strings
+                                               (concat_strings(jit_strdup("var "),
+                                                                               jit_strdup(embed_name)),
+                                                concat_strings(jit_strdup(" : "), temp));
+                               }
+                               else
+                               {
+                                       temp = concat_strings(jit_strdup("var "), temp);
+                               }
+                               return temp;
+                       }
+                       /* Not reached */
+
+                       default: temp = jit_strdup("unknown-tagged-type"); break;
+               }
+       }
+       else
+       {
+               /* We shouldn't get here */
+               temp = jit_strdup("unknown-jit-type");
+       }
+       if(!temp)
+       {
+               dpas_out_of_memory();
+       }
+       if(embed_name)
+       {
+               temp = concat_strings(concat_strings
+                                       (jit_strdup(embed_name), jit_strdup(" : ")), temp);
+       }
+       return temp;
+}
+
+char *dpas_type_name(jit_type_t type)
+{
+       char *temp = type_name(0, type);
+       if(!temp)
+       {
+               dpas_out_of_memory();
+       }
+       return temp;
+}
+
+char *dpas_type_name_with_var(const char *name, jit_type_t type)
+{
+       char *temp = type_name(name, type);
+       if(!temp)
+       {
+               dpas_out_of_memory();
+       }
+       return temp;
+}
+
+jit_type_t dpas_promote_type(jit_type_t type)
+{
+       if(jit_type_get_tagged_kind(type) == DPAS_TAG_SUBRANGE)
+       {
+               /* Convert subrange types into their real integer counterparts */
+               type = jit_type_get_tagged_type(type);
+       }
+       if(type == jit_type_sbyte || type == jit_type_ubyte ||
+          type == jit_type_short || type == jit_type_ushort)
+       {
+               return jit_type_int;
+       }
+       else if(type == jit_type_nint)
+       {
+               if(sizeof(jit_nint) == sizeof(jit_int))
+               {
+                       return jit_type_int;
+               }
+               else
+               {
+                       return jit_type_long;
+               }
+       }
+       else if(type == jit_type_nuint)
+       {
+               if(sizeof(jit_nuint) == sizeof(jit_uint))
+               {
+                       return jit_type_uint;
+               }
+               else
+               {
+                       return jit_type_ulong;
+               }
+       }
+       else if(type == jit_type_float32 || type == jit_type_float64)
+       {
+               return jit_type_nfloat;
+       }
+       else
+       {
+               return type;
+       }
+}
+
+jit_type_t dpas_common_type(jit_type_t type1, jit_type_t type2, int int_only)
+{
+       type1 = dpas_promote_type(type1);
+       type2 = dpas_promote_type(type2);
+       if(type1 == type2)
+       {
+               if(int_only && type1 == jit_type_nfloat)
+               {
+                       return 0;
+               }
+               return type1;
+       }
+       if(type1 == jit_type_int)
+       {
+               if(type2 == jit_type_uint)
+               {
+                       return jit_type_int;
+               }
+               else if(type2 == jit_type_long || type2 == jit_type_ulong)
+               {
+                       return jit_type_long;
+               }
+               else if(type2 == jit_type_nfloat)
+               {
+                       if(!int_only)
+                       {
+                               return jit_type_nfloat;
+                       }
+               }
+       }
+       else if(type1 == jit_type_uint)
+       {
+               if(type2 == jit_type_int)
+               {
+                       return jit_type_int;
+               }
+               else if(type2 == jit_type_long)
+               {
+                       return jit_type_long;
+               }
+               else if(type2 == jit_type_ulong)
+               {
+                       return jit_type_ulong;
+               }
+               else if(type2 == jit_type_nfloat)
+               {
+                       if(!int_only)
+                       {
+                               return jit_type_nfloat;
+                       }
+               }
+       }
+       else if(type1 == jit_type_long)
+       {
+               if(type2 == jit_type_int || type2 == jit_type_uint ||
+                  type2 == jit_type_ulong)
+               {
+                       return jit_type_long;
+               }
+               else if(type2 == jit_type_nfloat)
+               {
+                       if(!int_only)
+                       {
+                               return jit_type_nfloat;
+                       }
+               }
+       }
+       else if(type1 == jit_type_ulong)
+       {
+               if(type2 == jit_type_int || type2 == jit_type_long)
+               {
+                       return jit_type_long;
+               }
+               else if(type2 == jit_type_uint)
+               {
+                       return jit_type_ulong;
+               }
+               else if(type2 == jit_type_nfloat)
+               {
+                       if(!int_only)
+                       {
+                               return jit_type_nfloat;
+                       }
+               }
+       }
+       else if(type1 == jit_type_nfloat)
+       {
+               if(type2 == jit_type_int || type2 == jit_type_uint ||
+                  type2 == jit_type_long || type2 == jit_type_ulong)
+               {
+                       if(!int_only)
+                       {
+                               return jit_type_nfloat;
+                       }
+               }
+       }
+       return 0;
+}
+
+jit_type_t dpas_create_subrange(jit_type_t underlying, dpas_subrange *values)
+{
+       dpas_subrange *copy;
+       jit_type_t type;
+       copy = jit_new(dpas_subrange);
+       if(!copy)
+       {
+               dpas_out_of_memory();
+       }
+       *copy = *values;
+       type = jit_type_create_tagged(underlying, DPAS_TAG_SUBRANGE,
+                                                                 copy, jit_free, 1);
+       if(!type)
+       {
+               dpas_out_of_memory();
+       }
+       return type;
+}
+
+/*
+ * Free the information block for an enumerated type.
+ */
+static void free_enum(void *info)
+{
+       jit_free(((dpas_enum *)info)->name);
+       jit_free(info);
+}
+
+jit_type_t dpas_create_enum(jit_type_t underlying, int num_elems)
+{
+       dpas_enum *enum_info;
+       jit_type_t type;
+       enum_info = jit_new(dpas_enum);
+       if(!enum_info)
+       {
+               dpas_out_of_memory();
+       }
+       enum_info->name = 0;
+       enum_info->num_elems = num_elems;
+       type = jit_type_create_tagged(underlying, DPAS_TAG_ENUM,
+                                                                 enum_info, free_enum, 1);
+       if(!type)
+       {
+               dpas_out_of_memory();
+       }
+       return type;
+}
+
+jit_nuint dpas_type_range_size(jit_type_t type)
+{
+       if(jit_type_get_tagged_kind(type) == DPAS_TAG_ENUM)
+       {
+               return (jit_nuint)(jit_nint)
+                       (((dpas_enum *)jit_type_get_tagged_data(type))->num_elems);
+       }
+       else if(jit_type_get_tagged_kind(type) == DPAS_TAG_SUBRANGE &&
+                       jit_type_get_tagged_type(type) == jit_type_int)
+       {
+               return (jit_nuint)(jit_nint)
+                       (((dpas_subrange *)jit_type_get_tagged_data(type))
+                                       ->last.un.int_value -
+                        ((dpas_subrange *)jit_type_get_tagged_data(type))
+                                       ->first.un.int_value + 1);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_type_t dpas_create_array(jit_type_t *bounds, int num_bounds,
+                                                        jit_type_t elem_type)
+{
+       jit_type_t type;
+       jit_type_t tagged;
+       dpas_array *info;
+       jit_nuint size;
+       int posn;
+
+       /* Create a struct type, with the element type in the first field */
+       type = jit_type_create_struct(&elem_type, 1, 0);
+       if(!type)
+       {
+               dpas_out_of_memory();
+       }
+
+       /* Tag the structure with the array bound information */
+       info = (dpas_array *)jit_malloc(sizeof(dpas_array));
+       if(!info)
+       {
+               dpas_out_of_memory();
+       }
+       info->bounds = bounds;
+       info->num_bounds = num_bounds;
+       tagged = jit_type_create_tagged(type, DPAS_TAG_ARRAY, info, jit_free, 0);
+
+       /* Infer the total size of the array */
+       size = jit_type_get_size(elem_type);
+       for(posn = 0; posn < num_bounds; ++posn)
+       {
+               size *= dpas_type_range_size(bounds[posn]);
+       }
+
+       /* If the array is empty, then allocate space for one element
+          so that the type's total size is non-zero */
+       if(!size)
+       {
+               size = jit_type_get_size(elem_type);
+       }
+
+       /* Set the array's final size and alignment */
+       jit_type_set_size_and_alignment
+               (type, size, jit_type_get_alignment(elem_type));
+
+       /* Return the tagged version of the array to the caller */
+       return tagged;
+}
+
+jit_type_t dpas_create_conformant_array(jit_type_t elem_type, int num_bounds,
+                                                                               int is_packed)
+{
+       jit_type_t type;
+       dpas_conformant_array *info;
+
+       /* A conformant array is actually a pointer to the first element */
+       type = jit_type_create_pointer(elem_type, 0);
+       if(!type)
+       {
+               dpas_out_of_memory();
+       }
+
+       /* Tag the pointer so that the rest of the system knows what it is */
+       info = jit_new(dpas_conformant_array);
+       if(!info)
+       {
+               dpas_out_of_memory();
+       }
+       info->num_bounds = num_bounds;
+       info->is_packed = is_packed;
+       type = jit_type_create_tagged(type, DPAS_TAG_CONFORMANT_ARRAY,
+                                                                 info, jit_free, 0);
+       if(!type)
+       {
+               dpas_out_of_memory();
+       }
+       return type;
+}
+
+void dpas_type_set_name(jit_type_t type, const char *name)
+{
+       char *copy;
+       dpas_enum *enum_info;
+       if(jit_type_get_tagged_kind(type) == DPAS_TAG_NAME)
+       {
+               if(!jit_type_get_tagged_data(type))
+               {
+                       copy = jit_strdup(name);
+                       if(!copy)
+                       {
+                               dpas_out_of_memory();
+                       }
+                       jit_type_set_tagged_data(type, copy, jit_free);
+               }
+       }
+       else if(jit_type_get_tagged_kind(type) == DPAS_TAG_ENUM)
+       {
+               enum_info = (dpas_enum *)jit_type_get_tagged_data(type);
+               if(!(enum_info->name))
+               {
+                       copy = jit_strdup(name);
+                       if(!copy)
+                       {
+                               dpas_out_of_memory();
+                       }
+                       enum_info->name = copy;
+               }
+       }
+}
+
+void dpas_convert_constant(jit_constant_t *result, jit_constant_t *from,
+                                                  jit_type_t to_type)
+{
+       jit_type_t from_type = dpas_promote_type(from->type);
+       to_type = dpas_promote_type(to_type);
+       result->type = to_type;
+       result->un = from->un;
+       if(to_type == jit_type_int)
+       {
+               if(from_type == jit_type_int)
+               {
+                       result->un.int_value = jit_int_to_int(from->un.int_value);
+               }
+               else if(from_type == jit_type_uint)
+               {
+                       result->un.int_value = jit_uint_to_int(from->un.uint_value);
+               }
+               else if(from_type == jit_type_long)
+               {
+                       result->un.int_value = jit_long_to_int(from->un.long_value);
+               }
+               else if(from_type == jit_type_ulong)
+               {
+                       result->un.int_value = jit_ulong_to_int(from->un.ulong_value);
+               }
+               else if(from_type == jit_type_nfloat)
+               {
+                       result->un.int_value = jit_nfloat_to_int(from->un.nfloat_value);
+               }
+       }
+       else if(to_type == jit_type_uint)
+       {
+               if(from_type == jit_type_int)
+               {
+                       result->un.uint_value = jit_int_to_uint(from->un.int_value);
+               }
+               else if(from_type == jit_type_uint)
+               {
+                       result->un.uint_value = jit_uint_to_uint(from->un.uint_value);
+               }
+               else if(from_type == jit_type_long)
+               {
+                       result->un.uint_value = jit_long_to_uint(from->un.long_value);
+               }
+               else if(from_type == jit_type_ulong)
+               {
+                       result->un.uint_value = jit_ulong_to_uint(from->un.ulong_value);
+               }
+               else if(from_type == jit_type_nfloat)
+               {
+                       result->un.uint_value = jit_nfloat_to_uint(from->un.nfloat_value);
+               }
+       }
+       else if(to_type == jit_type_long)
+       {
+               if(from_type == jit_type_int)
+               {
+                       result->un.long_value = jit_int_to_long(from->un.int_value);
+               }
+               else if(from_type == jit_type_uint)
+               {
+                       result->un.long_value = jit_uint_to_long(from->un.uint_value);
+               }
+               else if(from_type == jit_type_long)
+               {
+                       result->un.long_value = jit_long_to_long(from->un.long_value);
+               }
+               else if(from_type == jit_type_ulong)
+               {
+                       result->un.long_value = jit_ulong_to_long(from->un.ulong_value);
+               }
+               else if(from_type == jit_type_nfloat)
+               {
+                       result->un.long_value = jit_nfloat_to_long(from->un.nfloat_value);
+               }
+       }
+       else if(to_type == jit_type_ulong)
+       {
+               if(from_type == jit_type_int)
+               {
+                       result->un.ulong_value = jit_int_to_ulong(from->un.int_value);
+               }
+               else if(from_type == jit_type_uint)
+               {
+                       result->un.ulong_value = jit_uint_to_ulong(from->un.uint_value);
+               }
+               else if(from_type == jit_type_long)
+               {
+                       result->un.ulong_value = jit_long_to_ulong(from->un.long_value);
+               }
+               else if(from_type == jit_type_ulong)
+               {
+                       result->un.ulong_value = jit_ulong_to_ulong(from->un.ulong_value);
+               }
+               else if(from_type == jit_type_nfloat)
+               {
+                       result->un.ulong_value = jit_nfloat_to_ulong(from->un.nfloat_value);
+               }
+       }
+       else if(to_type == jit_type_nfloat)
+       {
+               if(from_type == jit_type_int)
+               {
+                       result->un.nfloat_value = jit_int_to_nfloat(from->un.int_value);
+               }
+               else if(from_type == jit_type_uint)
+               {
+                       result->un.nfloat_value = jit_uint_to_nfloat(from->un.uint_value);
+               }
+               else if(from_type == jit_type_long)
+               {
+                       result->un.nfloat_value = jit_long_to_nfloat(from->un.long_value);
+               }
+               else if(from_type == jit_type_ulong)
+               {
+                       result->un.nfloat_value =
+                               jit_ulong_to_nfloat(from->un.ulong_value);
+               }
+               else if(from_type == jit_type_nfloat)
+               {
+                       result->un.nfloat_value = from->un.nfloat_value;
+               }
+       }
+}
+
+static char *format_integer(char *buf, int is_neg, jit_ulong value)
+{
+       buf += 64;
+       *(--buf) = '\0';
+       if(value == 0)
+       {
+               *(--buf) = '0';
+       }
+       else
+       {
+               while(value != 0)
+               {
+                       *(--buf) = '0' + (int)(value % 10);
+                       value /= 10;
+               }
+       }
+       if(is_neg)
+       {
+               *(--buf) = '-';
+       }
+       return buf;
+}
+
+char *dpas_constant_name(jit_constant_t *value)
+{
+       jit_type_t type;
+       char buf[64];
+       char *result;
+       if(value->type == dpas_type_nil)
+       {
+               return jit_strdup("nil");
+       }
+       else if(jit_type_is_pointer(value->type) &&
+                       jit_type_get_ref(value->type) == dpas_type_char)
+       {
+               return concat_strings
+                       (concat_strings(jit_strdup("\""),
+                                                       jit_strdup((char *)(value->un.ptr_value))),
+                        jit_strdup("\""));
+       }
+       type = dpas_promote_type(value->type);
+       if(type == jit_type_int)
+       {
+               if(value->un.int_value < 0)
+               {
+                       result = format_integer
+                               (buf, 1, (jit_ulong)(-((jit_long)(value->un.int_value))));
+               }
+               else
+               {
+                       result = format_integer
+                               (buf, 0, (jit_ulong)(jit_long)(value->un.int_value));
+               }
+       }
+       else if(type == jit_type_uint)
+       {
+               result = format_integer
+                       (buf, 0, (jit_ulong)(value->un.uint_value));
+       }
+       else if(type == jit_type_long)
+       {
+               if(value->un.int_value < 0)
+               {
+                       result = format_integer
+                               (buf, 1, (jit_ulong)(-(value->un.long_value)));
+               }
+               else
+               {
+                       result = format_integer
+                               (buf, 0, (jit_ulong)(value->un.long_value));
+               }
+       }
+       else if(type == jit_type_ulong)
+       {
+               result = format_integer(buf, 0, value->un.ulong_value);
+       }
+       else if(type == jit_type_nfloat)
+       {
+               sprintf(buf, "%g", (double)(value->un.nfloat_value));
+               result = buf;
+       }
+       else
+       {
+               result = "unknown constant";
+       }
+       return jit_strdup(result);
+}
+
+int dpas_is_set_compatible(jit_type_t type)
+{
+       if(jit_type_get_tagged_kind(type) == DPAS_TAG_ENUM)
+       {
+               return (((dpas_enum *)jit_type_get_tagged_data(type))->num_elems <= 32);
+       }
+       else if(jit_type_get_tagged_kind(type) == DPAS_TAG_SUBRANGE)
+       {
+               dpas_subrange *range;
+               if(jit_type_get_tagged_type(type) != jit_type_int)
+               {
+                       return 0;
+               }
+               range = (dpas_subrange *)jit_type_get_tagged_data(type);
+               if(range->first.un.int_value < 0 || range->first.un.int_value > 31 ||
+                  range->last.un.int_value < 0 || range->last.un.int_value > 31)
+               {
+                       return 0;
+               }
+               return 1;
+       }
+       return 0;
+}
+
+int dpas_type_is_numeric(jit_type_t type)
+{
+       if(type == jit_type_sbyte || type == jit_type_ubyte ||
+          type == jit_type_short || type == jit_type_ushort ||
+          type == jit_type_int || type == jit_type_uint ||
+          type == jit_type_long || type == jit_type_ulong ||
+          type == jit_type_float32 || type == jit_type_float64 ||
+          type == jit_type_nfloat)
+       {
+               return 1;
+       }
+       if(jit_type_get_tagged_kind(type) == DPAS_TAG_SUBRANGE)
+       {
+               return 1;
+       }
+       return 0;
+}
+
+int dpas_type_is_integer(jit_type_t type)
+{
+       if(type == jit_type_sbyte || type == jit_type_ubyte ||
+          type == jit_type_short || type == jit_type_ushort ||
+          type == jit_type_int || type == jit_type_uint ||
+          type == jit_type_long || type == jit_type_ulong)
+       {
+               return 1;
+       }
+       if(jit_type_get_tagged_kind(type) == DPAS_TAG_SUBRANGE)
+       {
+               return 1;
+       }
+       return 0;
+}
+
+int dpas_type_is_boolean(jit_type_t type)
+{
+       return (type == dpas_type_boolean || type == dpas_type_cboolean);
+}
diff --git a/dpas/dpas-types.h b/dpas/dpas-types.h
new file mode 100644 (file)
index 0000000..ac5c4fe
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * dpas-types.h - Type handling for Dynamic Pascal.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _DPAS_TYPES_H
+#define        _DPAS_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Special type tags that are used in this language.
+ */
+#define        DPAS_TAG_BOOLEAN                        1
+#define        DPAS_TAG_CBOOLEAN                       2
+#define        DPAS_TAG_CHAR                           3
+#define        DPAS_TAG_NIL                            4
+#define        DPAS_TAG_NAME                           5
+#define        DPAS_TAG_VAR                            6
+#define        DPAS_TAG_SUBRANGE                       7
+#define        DPAS_TAG_ENUM                           8
+#define        DPAS_TAG_SET                            9
+#define        DPAS_TAG_ARRAY                          10
+#define        DPAS_TAG_CONFORMANT_ARRAY       11
+
+/*
+ * Define some special integer types that are distinguished from normal ones.
+ */
+extern jit_type_t dpas_type_boolean;
+extern jit_type_t dpas_type_cboolean;
+extern jit_type_t dpas_type_char;
+extern jit_type_t dpas_type_string;
+extern jit_type_t dpas_type_address;
+extern jit_type_t dpas_type_nil;
+
+/*
+ * Information block for a subrange.
+ */
+typedef struct
+{
+       jit_constant_t  first;
+       jit_constant_t  last;
+
+} dpas_subrange;
+
+/*
+ * Information block for an enumeration.
+ */
+typedef struct
+{
+       char               *name;
+       int                             num_elems;
+
+} dpas_enum;
+
+/*
+ * Information block for an array.
+ */
+typedef struct
+{
+       jit_type_t         *bounds;
+       int                             num_bounds;
+
+} dpas_array;
+
+/*
+ * Information block for a conformant array.
+ */
+typedef struct
+{
+       int                             num_bounds;
+       int                             is_packed;
+
+} dpas_conformant_array;
+
+/*
+ * Initialize the standard types.
+ */
+void dpas_init_types(void);
+
+/*
+ * Find a field within a record type.  This is similar to
+ * "jit_type_find_name", except that it ignores case.
+ */
+unsigned int dpas_type_find_name(jit_type_t type, const char *name);
+
+/*
+ * Get the name of a type, for printing in error messages.
+ */
+char *dpas_type_name(jit_type_t type);
+
+/*
+ * Get the name of a type, combined with a variable name.
+ */
+char *dpas_type_name_with_var(const char *name, jit_type_t type);
+
+/*
+ * Promote a numeric type to its best form for arithmetic.  e.g. byte -> int.
+ */
+jit_type_t dpas_promote_type(jit_type_t type);
+
+/*
+ * Infer a common type for a binary operation.  Returns NULL if not possible.
+ */
+jit_type_t dpas_common_type(jit_type_t type1, jit_type_t type2, int int_only);
+
+/*
+ * Create a subrange type.
+ */
+jit_type_t dpas_create_subrange(jit_type_t underlying, dpas_subrange *values);
+
+/*
+ * Create an enumerated type.
+ */
+jit_type_t dpas_create_enum(jit_type_t underlying, int num_elems);
+
+/*
+ * Get the size of a range type that is being used for an array bound.
+ */
+jit_nuint dpas_type_range_size(jit_type_t type);
+
+/*
+ * Create an array type.
+ */
+jit_type_t dpas_create_array(jit_type_t *bounds, int num_bounds,
+                                                        jit_type_t elem_type);
+
+/*
+ * Create a conformant array type.
+ */
+jit_type_t dpas_create_conformant_array(jit_type_t elem_type, int num_bounds,
+                                                                               int is_packed);
+
+/*
+ * Set the name of an enumerated or record type.  Ignored for other types,
+ * or types that already have a name.
+ */
+void dpas_type_set_name(jit_type_t type, const char *name);
+
+/*
+ * Convert a constant value into a new type.
+ */
+void dpas_convert_constant(jit_constant_t *result, jit_constant_t *from,
+                                                  jit_type_t to_type);
+
+/*
+ * Get the name form of a constant value.
+ */
+char *dpas_constant_name(jit_constant_t *value);
+
+/*
+ * Determine if a type is set-compatible.  It must be an enumerated
+ * or subrange type with 32 or less members.
+ */
+int dpas_is_set_compatible(jit_type_t type);
+
+/*
+ * Determine if a type is numeric, integer, or boolean.
+ */
+int dpas_type_is_numeric(jit_type_t type);
+int dpas_type_is_integer(jit_type_t type);
+int dpas_type_is_boolean(jit_type_t type);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _DPAS_TYPES_H */
diff --git a/include/.cvsignore b/include/.cvsignore
new file mode 100644 (file)
index 0000000..051d1bd
--- /dev/null
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+.deps
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644 (file)
index 0000000..2d98b59
--- /dev/null
@@ -0,0 +1,2 @@
+
+SUBDIRS = jit
diff --git a/include/jit/.cvsignore b/include/jit/.cvsignore
new file mode 100644 (file)
index 0000000..261801d
--- /dev/null
@@ -0,0 +1,4 @@
+Makefile
+Makefile.in
+.deps
+jit-defs.h
diff --git a/include/jit/Makefile.am b/include/jit/Makefile.am
new file mode 100644 (file)
index 0000000..b6e1a80
--- /dev/null
@@ -0,0 +1,24 @@
+
+libjitincludedir = $(includedir)/jit
+libjitinclude_HEADERS = jit.h \
+                                               jit-apply.h \
+                                               jit-block.h \
+                                               jit-common.h \
+                                               jit-context.h \
+                                               jit-defs.h \
+                                               jit-dump.h \
+                                               jit-elf.h \
+                                               jit-except.h \
+                                               jit-function.h \
+                                               jit-init.h \
+                                               jit-insn.h \
+                                               jit-intrinsic.h \
+                                               jit-meta.h \
+                                               jit-opcode.h \
+                                               jit-plus.h \
+                                               jit-type.h \
+                                               jit-util.h \
+                                               jit-value.h \
+                                               jit-walk.h
+
+DISTCLEANFILES = jit-defs.h
diff --git a/include/jit/jit-apply.h b/include/jit/jit-apply.h
new file mode 100644 (file)
index 0000000..342762e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * jit-apply.h - Dynamic invocation and closure support functions.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_APPLY_H
+#define        _JIT_APPLY_H
+
+#include <jit/jit-type.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Prototype for closure functions.
+ */
+typedef void (*jit_closure_func)(jit_type_t signature, void *result,
+                                 void **args, void *user_data);
+
+/*
+ * Opaque type for accessing vararg parameters on closures.
+ */
+typedef struct jit_closure_va_list *jit_closure_va_list_t;
+
+/*
+ * External function declarations.
+ */
+void jit_apply(jit_type_t signature, void *func,
+               void **args, unsigned int num_fixed_args,
+               void *return_value);
+void jit_apply_raw(jit_type_t signature, void *func,
+                   void *args, void *return_value);
+int jit_raw_supported(jit_type_t signature);
+void *jit_closure_create(jit_context_t context, jit_type_t signature,
+                                                jit_closure_func func, void *user_data);
+int jit_closures_supported(void);
+jit_nint jit_closure_va_get_nint(jit_closure_va_list_t va);
+jit_nuint jit_closure_va_get_nuint(jit_closure_va_list_t va);
+jit_long jit_closure_va_get_long(jit_closure_va_list_t va);
+jit_ulong jit_closure_va_get_ulong(jit_closure_va_list_t va);
+jit_float32 jit_closure_va_get_float32(jit_closure_va_list_t va);
+jit_float64 jit_closure_va_get_float64(jit_closure_va_list_t va);
+jit_nfloat jit_closure_va_get_nfloat(jit_closure_va_list_t va);
+void *jit_closure_va_get_ptr(jit_closure_va_list_t va);
+void jit_closure_va_get_struct
+       (jit_closure_va_list_t va, void *buf, jit_type_t type);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_APPLY_H */
diff --git a/include/jit/jit-block.h b/include/jit/jit-block.h
new file mode 100644 (file)
index 0000000..886ad52
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * jit-block.h - Functions for manipulating blocks.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_BLOCK_H
+#define        _JIT_BLOCK_H
+
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+jit_function_t jit_block_get_function(jit_block_t block);
+jit_context_t jit_block_get_context(jit_block_t block);
+jit_label_t jit_block_get_label(jit_block_t block);
+jit_block_t jit_block_next(jit_function_t func, jit_block_t previous);
+jit_block_t jit_block_previous(jit_function_t func, jit_block_t previous);
+jit_block_t jit_block_from_label(jit_function_t func, jit_label_t label);
+int jit_block_set_meta(jit_block_t block, int type, void *data,
+                                          jit_meta_free_func free_data);
+void *jit_block_get_meta(jit_block_t block, int type);
+void jit_block_free_meta(jit_block_t block, int type);
+int jit_block_is_reachable(jit_block_t block);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_BLOCK_H */
diff --git a/include/jit/jit-common.h b/include/jit/jit-common.h
new file mode 100644 (file)
index 0000000..2b182d6
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * jit-common.h - Common type definitions that are used by the JIT.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_COMMON_H
+#define        _JIT_COMMON_H
+
+#include <jit/jit-defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Opaque structure that represents a context.
+ */
+typedef struct _jit_context *jit_context_t;
+
+/*
+ * Opaque structure that represents a function.
+ */
+typedef struct _jit_function *jit_function_t;
+
+/*
+ * Opaque type that represents the compiled form of a function.
+ */
+typedef void *jit_function_compiled_t;
+
+/*
+ * Opaque structure that represents a block.
+ */
+typedef struct _jit_block *jit_block_t;
+
+/*
+ * Opaque structure that represents an instruction.
+ */
+typedef struct _jit_insn *jit_insn_t;
+
+/*
+ * Opaque structure that represents a value.
+ */
+typedef struct _jit_value *jit_value_t;
+
+/*
+ * Opaque structure that represents a type descriptor.
+ */
+typedef struct _jit_type *jit_type_t;
+
+/*
+ * Block label identifier.
+ */
+typedef jit_nuint jit_label_t;
+
+/*
+ * Value that represents an undefined label.
+ */
+#define        jit_label_undefined             ((jit_label_t)~((jit_uint)0))
+
+/*
+ * Function that is used to free user-supplied metadata.
+ */
+typedef void (*jit_meta_free_func)(void *data);
+
+/*
+ * Function that is used to compile a function on demand.
+ * Returns zero if the compilation process failed for some reason.
+ */
+typedef int (*jit_on_demand_func)(jit_function_t func);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_COMMON_H */
diff --git a/include/jit/jit-context.h b/include/jit/jit-context.h
new file mode 100644 (file)
index 0000000..6f52800
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * jit-context.h - Functions for manipulating JIT contexts.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_CONTEXT_H
+#define        _JIT_CONTEXT_H
+
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+jit_context_t jit_context_create(void);
+void jit_context_destroy(jit_context_t context);
+int jit_context_supports_threads(jit_context_t context);
+void jit_context_build_start(jit_context_t context);
+void jit_context_build_end(jit_context_t context);
+int jit_context_set_meta
+       (jit_context_t context, int type, void *data,
+        jit_meta_free_func free_data);
+int jit_context_set_meta_numeric
+       (jit_context_t context, int type, jit_nuint data);
+void *jit_context_get_meta(jit_context_t context, int type);
+jit_nuint jit_context_get_meta_numeric(jit_context_t context, int type);
+void jit_context_free_meta(jit_context_t context, int type);
+
+/*
+ * Standard meta values for builtin configurable options.
+ */
+#define        JIT_OPTION_CACHE_LIMIT          10000
+#define        JIT_OPTION_CACHE_PAGE_SIZE      10001
+#define        JIT_OPTION_PRE_COMPILE          10002
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_CONTEXT_H */
diff --git a/include/jit/jit-defs.h.in b/include/jit/jit-defs.h.in
new file mode 100644 (file)
index 0000000..57e3d4d
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * jit-defs.h - Define the primitive numeric types for use by the JIT.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_DEFS_H
+#define        _JIT_DEFS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+@JIT_INT64_INCLUDE@
+
+typedef @JITINT8@ jit_sbyte;
+typedef @JITUINT8@ jit_ubyte;
+typedef @JITINT16@ jit_short;
+typedef unsigned @JITINT16@ jit_ushort;
+typedef @JITINT32@ jit_int;
+typedef unsigned @JITINT32@ jit_uint;
+typedef @JITNATIVEINT@ jit_nint;
+typedef unsigned @JITNATIVEINT@ jit_nuint;
+#if defined(__cplusplus) && defined(__GNUC__)
+typedef @JITINT64CXX@ jit_long;
+typedef unsigned @JITINT64CXX@ jit_ulong;
+#else
+typedef @JITINT64@ jit_long;
+typedef unsigned @JITINT64@ jit_ulong;
+#endif
+typedef @JITFLOAT32@ jit_float32;
+typedef @JITFLOAT64@ jit_float64;
+typedef @JITNATIVEFLOAT@ jit_nfloat;
+typedef void *jit_ptr;
+
+#define        @JITNATIVEINTDEFINE@ 1
+@JITNFLOATISDOUBLE@
+
+#if defined(__cplusplus) && defined(__GNUC__)
+#define        JIT_NOTHROW             @JITTHROWIDIOM@
+#else
+#define        JIT_NOTHROW
+#endif
+
+#define        jit_min_int             (((jit_int)1) << (sizeof(jit_int) - 1))
+#define        jit_max_int             ((jit_int)(~jit_min_int))
+#define        jit_max_uint    ((jit_uint)(~((jit_uint)0)))
+#define        jit_min_long    (((jit_long)1) << (sizeof(jit_long) - 1))
+#define        jit_max_long    ((jit_long)(~jit_min_long))
+#define        jit_max_ulong   ((jit_ulong)(~((jit_ulong)0)))
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_DEFS_H */
diff --git a/include/jit/jit-dump.h b/include/jit/jit-dump.h
new file mode 100644 (file)
index 0000000..d036f32
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * jit-dump.h - Functions for dumping JIT structures, for debugging.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_DUMP_H
+#define        _JIT_DUMP_H
+
+#include <stdio.h>
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void jit_dump_type(FILE *stream, jit_type_t type);
+void jit_dump_value(FILE *stream, jit_function_t func,
+                                       jit_value_t value, const char *prefix);
+void jit_dump_insn(FILE *stream, jit_function_t func, jit_insn_t insn);
+void jit_dump_function(FILE *stream, jit_function_t func, const char *name);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_DUMP_H */
diff --git a/include/jit/jit-elf.h b/include/jit/jit-elf.h
new file mode 100644 (file)
index 0000000..eff30ed
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * <jit/jit-elf.h> - Routines to read and write ELF-format binaries.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_ELF_H
+#define        _JIT_ELF_H
+
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Opaque types that represent a loaded ELF binary in read or write mode.
+ */
+typedef struct jit_readelf *jit_readelf_t;
+typedef struct jit_writeelf *jit_writeelf_t;
+
+/*
+ * Flags for "jit_readelf_open".
+ */
+#define        JIT_READELF_FLAG_FORCE  (1 << 0)        /* Force file to load */
+#define        JIT_READELF_FLAG_DEBUG  (1 << 1)        /* Print debugging information */
+
+/*
+ * Result codes from "jit_readelf_open".
+ */
+#define        JIT_READELF_OK                  0       /* File was opened successfully */
+#define        JIT_READELF_CANNOT_OPEN 1       /* Could not open the file */
+#define        JIT_READELF_NOT_ELF             2       /* Not an ELF-format binary */
+#define        JIT_READELF_WRONG_ARCH  3       /* Wrong architecture for local system */
+#define        JIT_READELF_BAD_FORMAT  4       /* ELF file, but badly formatted */
+#define        JIT_READELF_MEMORY              5       /* Insufficient memory to load the file */
+
+/*
+ * External function declarations.
+ */
+int jit_readelf_open(jit_readelf_t *readelf, const char *filename, int flags);
+void jit_readelf_close(jit_readelf_t readelf);
+const char *jit_readelf_get_name(jit_readelf_t readelf);
+void *jit_readelf_get_symbol(jit_readelf_t readelf, const char *name);
+void *jit_readelf_get_section
+       (jit_readelf_t readelf, const char *name, jit_nuint *size);
+void *jit_readelf_get_section_by_type
+       (jit_readelf_t readelf, jit_int type, jit_nuint *size);
+void *jit_readelf_map_vaddr(jit_readelf_t readelf, jit_nuint vaddr);
+unsigned int jit_readelf_num_needed(jit_readelf_t readelf);
+const char *jit_readelf_get_needed(jit_readelf_t readelf, unsigned int index);
+void jit_readelf_add_to_context(jit_readelf_t readelf, jit_context_t context);
+int jit_readelf_resolve_all(jit_context_t context, int print_failures);
+
+jit_writeelf_t jit_writeelf_create(const char *library_name);
+void jit_writeelf_destroy(jit_writeelf_t writeelf);
+int jit_writeelf_write(jit_writeelf_t writeelf, const char *filename);
+int jit_writeelf_add_function
+       (jit_writeelf_t writeelf, jit_function_t func, const char *name);
+int jit_writeelf_add_needed
+       (jit_writeelf_t writeelf, const char *library_name);
+int jit_writeelf_write_section
+       (jit_writeelf_t writeelf, const char *name, jit_int type,
+        const void *buf, unsigned int len, int discardable);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_ELF_H */
diff --git a/include/jit/jit-except.h b/include/jit/jit-except.h
new file mode 100644 (file)
index 0000000..3afabc1
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * jit-except.h - Exception handling functions.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_EXCEPT_H
+#define        _JIT_EXCEPT_H
+
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Builtin exception type codes, and result values for intrinsic functions.
+ */
+#define        JIT_RESULT_OK                            1
+#define        JIT_RESULT_OVERFLOW                      0
+#define        JIT_RESULT_ARITHMETIC           -1
+#define        JIT_RESULT_DIVISION_BY_ZERO     -2
+#define        JIT_RESULT_COMPILE_ERROR        -3
+#define        JIT_RESULT_OUT_OF_MEMORY        -4
+#define        JIT_RESULT_NULL_REFERENCE       -5
+#define        JIT_RESULT_NULL_FUNCTION        -6
+#define        JIT_RESULT_CALLED_NESTED        -7
+
+/*
+ * Exception handling function for builtin exceptions.
+ */
+typedef void *(*jit_exception_func)(int exception_type);
+
+/*
+ * Opaque type that represents an exception stack trace.
+ */
+typedef struct jit_stack_trace *jit_stack_trace_t;
+
+/*
+ * External function declarations.
+ */
+void *jit_exception_get_last(void);
+void jit_exception_set_last(void *object);
+void jit_exception_clear_last(void);
+void jit_exception_throw(void *object);
+void jit_exception_builtin(int exception_type);
+jit_exception_func jit_exception_set_handler(jit_exception_func handler);
+jit_exception_func jit_exception_get_handler(void);
+jit_stack_trace_t jit_exception_get_stack_trace(void);
+unsigned int jit_stack_trace_get_size(jit_stack_trace_t trace);
+jit_function_t jit_stack_trace_get_function
+       (jit_context_t context, jit_stack_trace_t trace, unsigned int posn);
+void *jit_stack_trace_get_pc
+       (jit_stack_trace_t trace, unsigned int posn);
+#define        JIT_NO_OFFSET   (~((unsigned int)0))
+unsigned int jit_stack_trace_get_offset
+       (jit_context_t context, jit_stack_trace_t trace, unsigned int posn);
+void jit_stack_trace_free(jit_stack_trace_t trace);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_EXCEPT_H */
diff --git a/include/jit/jit-function.h b/include/jit/jit-function.h
new file mode 100644 (file)
index 0000000..cd5e5d6
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * jit-function.h - Functions for manipulating functions blocks.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_FUNCTION_H
+#define        _JIT_FUNCTION_H
+
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+jit_function_t jit_function_create
+       (jit_context_t context, jit_type_t signature) JIT_NOTHROW;
+jit_function_t jit_function_create_nested
+       (jit_context_t context, jit_type_t signature,
+        jit_function_t parent) JIT_NOTHROW;
+void jit_function_abandon(jit_function_t func) JIT_NOTHROW;
+jit_context_t jit_function_get_context(jit_function_t func) JIT_NOTHROW;
+jit_type_t jit_function_get_signature(jit_function_t func) JIT_NOTHROW;
+int jit_function_set_meta
+       (jit_function_t func, int type, void *data,
+        jit_meta_free_func free_data, int build_only) JIT_NOTHROW;
+void *jit_function_get_meta(jit_function_t func, int type) JIT_NOTHROW;
+void jit_function_free_meta(jit_function_t func, int type) JIT_NOTHROW;
+jit_function_t jit_function_next
+       (jit_context_t context, jit_function_t prev) JIT_NOTHROW;
+jit_function_t jit_function_previous
+       (jit_context_t context, jit_function_t prev) JIT_NOTHROW;
+jit_block_t jit_function_get_entry(jit_function_t func) JIT_NOTHROW;
+jit_block_t jit_function_get_current(jit_function_t func) JIT_NOTHROW;
+jit_function_t jit_function_get_nested_parent(jit_function_t func) JIT_NOTHROW;
+int jit_function_compile(jit_function_t func) JIT_NOTHROW;
+int jit_function_recompile(jit_function_t func) JIT_NOTHROW;
+int jit_function_is_compiled(jit_function_t func) JIT_NOTHROW;
+void jit_function_set_recompilable(jit_function_t func) JIT_NOTHROW;
+void jit_function_clear_recompilable(jit_function_t func) JIT_NOTHROW;
+int jit_function_is_recompilable(jit_function_t func) JIT_NOTHROW;
+void *jit_function_to_closure(jit_function_t func) JIT_NOTHROW;
+jit_function_t jit_function_from_closure
+       (jit_context_t context, void *closure) JIT_NOTHROW;
+jit_function_t jit_function_from_pc
+       (jit_context_t context, void *pc, void **handler) JIT_NOTHROW;
+void *jit_function_to_vtable_pointer(jit_function_t func) JIT_NOTHROW;
+void jit_function_set_on_demand_compiler
+               (jit_function_t func, jit_on_demand_func on_demand) JIT_NOTHROW;
+int jit_function_apply
+       (jit_function_t func, void **args, void *return_area);
+int jit_function_apply_vararg
+       (jit_function_t func, jit_type_t signature, void **args, void *return_area);
+void jit_function_set_optimization_level
+       (jit_function_t func, unsigned int level) JIT_NOTHROW;
+unsigned int jit_function_get_optimization_level
+       (jit_function_t func) JIT_NOTHROW;
+unsigned int jit_function_get_max_optimization_level(void) JIT_NOTHROW;
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_FUNCTION_H */
diff --git a/include/jit/jit-init.h b/include/jit/jit-init.h
new file mode 100644 (file)
index 0000000..e05215d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * jit-init.h - Initialization routines for the JIT.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_INIT_H
+#define        _JIT_INIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void jit_init(void);
+int jit_uses_interpreter(void);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_INIT_H */
diff --git a/include/jit/jit-insn.h b/include/jit/jit-insn.h
new file mode 100644 (file)
index 0000000..b0f9d35
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * jit-insn.h - Functions for manipulating instructions.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_INSN_H
+#define        _JIT_INSN_H
+
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Descriptor for an intrinsic function.
+ */
+typedef struct
+{
+       jit_type_t              return_type;
+       jit_type_t              ptr_result_type;
+       jit_type_t              arg1_type;
+       jit_type_t              arg2_type;
+
+} jit_intrinsic_descr_t;
+
+/*
+ * Structure for iterating over the instructions in a block.
+ * This should be treated as opaque.
+ */
+typedef struct
+{
+       jit_block_t             block;
+       int                             posn;
+
+} jit_insn_iter_t;
+
+/*
+ * Flags for "jit_insn_call" and friends.
+ */
+#define        JIT_CALL_NOTHROW                (1 << 0)
+#define        JIT_CALL_NORETURN               (1 << 1)
+#define        JIT_CALL_TAIL                   (1 << 2)
+
+int jit_insn_get_opcode(jit_insn_t insn) JIT_NOTHROW;
+jit_value_t jit_insn_get_dest(jit_insn_t insn) JIT_NOTHROW;
+jit_value_t jit_insn_get_value1(jit_insn_t insn) JIT_NOTHROW;
+jit_value_t jit_insn_get_value2(jit_insn_t insn) JIT_NOTHROW;
+jit_label_t jit_insn_get_label(jit_insn_t insn) JIT_NOTHROW;
+jit_function_t jit_insn_get_function(jit_insn_t insn) JIT_NOTHROW;
+void *jit_insn_get_native(jit_insn_t insn) JIT_NOTHROW;
+const char *jit_insn_get_name(jit_insn_t insn) JIT_NOTHROW;
+jit_type_t jit_insn_get_signature(jit_insn_t insn) JIT_NOTHROW;
+int jit_insn_dest_is_value(jit_insn_t insn) JIT_NOTHROW;
+
+int jit_insn_label(jit_function_t func, jit_label_t *label) JIT_NOTHROW;
+jit_value_t jit_insn_load(jit_function_t func, jit_value_t value) JIT_NOTHROW;
+jit_value_t jit_insn_dup(jit_function_t func, jit_value_t value) JIT_NOTHROW;
+jit_value_t jit_insn_load_small
+       (jit_function_t func, jit_value_t value) JIT_NOTHROW;
+int jit_insn_store
+       (jit_function_t func, jit_value_t dest, jit_value_t value) JIT_NOTHROW;
+jit_value_t jit_insn_load_relative
+       (jit_function_t func, jit_value_t value,
+        jit_nint offset, jit_type_t type) JIT_NOTHROW;
+int jit_insn_store_relative
+       (jit_function_t func, jit_value_t dest,
+        jit_nint offset, jit_value_t value) JIT_NOTHROW;
+jit_value_t jit_insn_add_relative
+       (jit_function_t func, jit_value_t value, jit_nint offset) JIT_NOTHROW;
+int jit_insn_check_null(jit_function_t func, jit_value_t value) JIT_NOTHROW;
+
+jit_value_t jit_insn_add
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_add_ovf
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_sub
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_sub_ovf
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_mul
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_mul_ovf
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_div
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_rem
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_rem_ieee
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_neg
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_and
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_or
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_xor
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_not
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_shl
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_shr
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_ushr
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_sshr
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_eq
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_ne
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_lt
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_le
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_gt
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_ge
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_cmpl
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_cmpg
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_to_bool
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_to_not_bool
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_acos
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_asin
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_atan
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_atan2
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_ceil
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_cos
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_cosh
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_exp
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_floor
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_log
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_log10
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_pow
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_rint
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_round
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_sin
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_sinh
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_sqrt
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_tan
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_tanh
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_is_nan
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_is_finite
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_is_inf
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_abs
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_min
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_max
+       (jit_function_t func, jit_value_t value1, jit_value_t value2) JIT_NOTHROW;
+jit_value_t jit_insn_sign
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+int jit_insn_branch
+       (jit_function_t func, jit_label_t *label) JIT_NOTHROW;
+int jit_insn_branch_if
+       (jit_function_t func, jit_value_t value, jit_label_t *label) JIT_NOTHROW;
+int jit_insn_branch_if_not
+       (jit_function_t func, jit_value_t value, jit_label_t *label) JIT_NOTHROW;
+jit_value_t jit_insn_address_of
+       (jit_function_t func, jit_value_t value1) JIT_NOTHROW;
+jit_value_t jit_insn_convert
+       (jit_function_t func, jit_value_t value,
+        jit_type_t type, int overflow_check) JIT_NOTHROW;
+
+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) JIT_NOTHROW;
+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) JIT_NOTHROW;
+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) JIT_NOTHROW;
+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 flags) JIT_NOTHROW;
+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) JIT_NOTHROW;
+int jit_insn_incoming_reg
+       (jit_function_t func, jit_value_t value, int reg) JIT_NOTHROW;
+int jit_insn_incoming_frame_posn
+       (jit_function_t func, jit_value_t value, jit_nint frame_offset) JIT_NOTHROW;
+int jit_insn_outgoing_reg
+       (jit_function_t func, jit_value_t value, int reg) JIT_NOTHROW;
+int jit_insn_return_reg
+       (jit_function_t func, jit_value_t value, int reg) JIT_NOTHROW;
+int jit_insn_setup_for_nested
+       (jit_function_t func, int nested_level, int reg) JIT_NOTHROW;
+int jit_insn_flush_struct(jit_function_t func, jit_value_t value) JIT_NOTHROW;
+jit_value_t jit_insn_import
+       (jit_function_t func, jit_value_t value) JIT_NOTHROW;
+int jit_insn_push(jit_function_t func, jit_value_t value) JIT_NOTHROW;
+int jit_insn_pop_stack(jit_function_t func, jit_nint num_items) JIT_NOTHROW;
+int jit_insn_return(jit_function_t func, jit_value_t value) JIT_NOTHROW;
+int jit_insn_default_return(jit_function_t func) JIT_NOTHROW;
+int jit_insn_throw(jit_function_t func, jit_value_t value) JIT_NOTHROW;
+jit_value_t jit_insn_get_call_stack(jit_function_t func) JIT_NOTHROW;
+int jit_insn_start_try
+       (jit_function_t func, jit_label_t *catch_label,
+        jit_label_t *finally_label, int finally_on_fault);
+jit_value_t jit_insn_start_catch
+       (jit_function_t func, jit_label_t *catch_label);
+int jit_insn_end_try(jit_function_t func);
+int jit_insn_start_finally(jit_function_t func, jit_label_t *finally_label);
+int jit_insn_return_from_finally(jit_function_t func);
+jit_value_t jit_insn_start_filter
+       (jit_function_t func, jit_label_t *label, jit_type_t type);
+int jit_insn_return_from_filter(jit_function_t func, jit_value_t value);
+jit_value_t jit_insn_call_filter
+       (jit_function_t func, jit_label_t *label,
+        jit_value_t value, jit_type_t type);
+
+void jit_insn_iter_init(jit_insn_iter_t *iter, jit_block_t block) JIT_NOTHROW;
+void jit_insn_iter_init_last
+       (jit_insn_iter_t *iter, jit_block_t block) JIT_NOTHROW;
+jit_insn_t jit_insn_iter_next(jit_insn_iter_t *iter) JIT_NOTHROW;
+jit_insn_t jit_insn_iter_previous(jit_insn_iter_t *iter) JIT_NOTHROW;
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_INSN_H */
diff --git a/include/jit/jit-intrinsic.h b/include/jit/jit-intrinsic.h
new file mode 100644 (file)
index 0000000..1e56425
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * jit-intrinsic.h - Support routines for JIT intrinsics.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_INTRINSIC_H
+#define        _JIT_INTRINSIC_H
+
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Perform operations on signed 32-bit integers.
+ */
+jit_int jit_int_add(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_sub(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_mul(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_div
+       (jit_int *result, jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_rem
+       (jit_int *result, jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_add_ovf
+       (jit_int *result, jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_sub_ovf
+       (jit_int *result, jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_mul_ovf
+       (jit_int *result, jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_neg(jit_int value1) JIT_NOTHROW;
+jit_int jit_int_and(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_or(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_xor(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_not(jit_int value1) JIT_NOTHROW;
+jit_int jit_int_shl(jit_int value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_int_shr(jit_int value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_int_eq(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_ne(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_lt(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_le(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_gt(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_ge(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_cmp(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_abs(jit_int value1) JIT_NOTHROW;
+jit_int jit_int_min(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_max(jit_int value1, jit_int value2) JIT_NOTHROW;
+jit_int jit_int_sign(jit_int value1) JIT_NOTHROW;
+
+/*
+ * Perform operations on unsigned 32-bit integers.
+ */
+jit_uint jit_uint_add(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_uint jit_uint_sub(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_uint jit_uint_mul(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_div
+       (jit_uint *result, jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_rem
+       (jit_uint *result, jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_add_ovf
+       (jit_uint *result, jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_sub_ovf
+       (jit_uint *result, jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_mul_ovf
+       (jit_uint *result, jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_uint jit_uint_neg(jit_uint value1) JIT_NOTHROW;
+jit_uint jit_uint_and(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_uint jit_uint_or(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_uint jit_uint_xor(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_uint jit_uint_not(jit_uint value1) JIT_NOTHROW;
+jit_uint jit_uint_shl(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_uint jit_uint_shr(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_eq(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_ne(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_lt(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_le(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_gt(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_ge(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_uint_cmp(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_uint jit_uint_min(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+jit_uint jit_uint_max(jit_uint value1, jit_uint value2) JIT_NOTHROW;
+
+/*
+ * Perform operations on signed 64-bit integers.
+ */
+jit_long jit_long_add(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_long jit_long_sub(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_long jit_long_mul(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_div
+       (jit_long *result, jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_rem
+       (jit_long *result, jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_add_ovf
+       (jit_long *result, jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_sub_ovf
+       (jit_long *result, jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_mul_ovf
+       (jit_long *result, jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_long jit_long_neg(jit_long value1) JIT_NOTHROW;
+jit_long jit_long_and(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_long jit_long_or(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_long jit_long_xor(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_long jit_long_not(jit_long value1) JIT_NOTHROW;
+jit_long jit_long_shl(jit_long value1, jit_uint value2) JIT_NOTHROW;
+jit_long jit_long_shr(jit_long value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_long_eq(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_ne(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_lt(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_le(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_gt(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_ge(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_cmp(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_long jit_long_abs(jit_long value1) JIT_NOTHROW;
+jit_long jit_long_min(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_long jit_long_max(jit_long value1, jit_long value2) JIT_NOTHROW;
+jit_int jit_long_sign(jit_long value1) JIT_NOTHROW;
+
+/*
+ * Perform operations on unsigned 64-bit integers.
+ */
+jit_ulong jit_ulong_add(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_ulong jit_ulong_sub(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_ulong jit_ulong_mul(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_int jit_ulong_div
+       (jit_ulong *result, jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_int jit_ulong_rem
+       (jit_ulong *result, jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_int jit_ulong_add_ovf
+       (jit_ulong *result, jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_int jit_ulong_sub_ovf
+       (jit_ulong *result, jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_int jit_ulong_mul_ovf
+       (jit_ulong *result, jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_ulong jit_ulong_neg(jit_ulong value1) JIT_NOTHROW;
+jit_ulong jit_ulong_and(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_ulong jit_ulong_or(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_ulong jit_ulong_xor(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_ulong jit_ulong_not(jit_ulong value1) JIT_NOTHROW;
+jit_ulong jit_ulong_shl(jit_ulong value1, jit_uint value2) JIT_NOTHROW;
+jit_ulong jit_ulong_shr(jit_ulong value1, jit_uint value2) JIT_NOTHROW;
+jit_int jit_ulong_eq(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_int jit_ulong_ne(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_int jit_ulong_lt(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_int jit_ulong_le(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_int jit_ulong_gt(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_int jit_ulong_ge(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_int jit_ulong_cmp(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_ulong jit_ulong_min(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+jit_ulong jit_ulong_max(jit_ulong value1, jit_ulong value2) JIT_NOTHROW;
+
+/*
+ * Perform operations on 32-bit floating-point values.
+ */
+jit_float32 jit_float32_add
+       (jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_float32 jit_float32_sub
+       (jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_float32 jit_float32_mul
+       (jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_float32 jit_float32_div
+       (jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_float32 jit_float32_rem
+       (jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_float32 jit_float32_ieee_rem
+       (jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_float32 jit_float32_neg(jit_float32 value1) JIT_NOTHROW;
+jit_int jit_float32_eq(jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_int jit_float32_ne(jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_int jit_float32_lt(jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_int jit_float32_le(jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_int jit_float32_gt(jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_int jit_float32_ge(jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_int jit_float32_cmpl(jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_int jit_float32_cmpg(jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_float32 jit_float32_acos(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_asin(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_atan(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_atan2
+       (jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_float32 jit_float32_ceil(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_cos(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_cosh(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_exp(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_floor(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_log(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_log10(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_pow
+       (jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_float32 jit_float32_rint(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_round(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_sin(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_sinh(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_sqrt(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_tan(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_tanh(jit_float32 value1) JIT_NOTHROW;
+jit_int jit_float32_is_finite(jit_float32 value) JIT_NOTHROW;
+jit_int jit_float32_is_nan(jit_float32 value) JIT_NOTHROW;
+jit_int jit_float32_is_inf(jit_float32 value) JIT_NOTHROW;
+jit_float32 jit_float32_abs(jit_float32 value1) JIT_NOTHROW;
+jit_float32 jit_float32_min
+       (jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_float32 jit_float32_max
+       (jit_float32 value1, jit_float32 value2) JIT_NOTHROW;
+jit_int jit_float32_sign(jit_float32 value1) JIT_NOTHROW;
+
+/*
+ * Perform operations on 64-bit floating-point values.
+ */
+jit_float64 jit_float64_add
+       (jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_float64 jit_float64_sub
+       (jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_float64 jit_float64_mul
+       (jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_float64 jit_float64_div
+       (jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_float64 jit_float64_rem
+       (jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_float64 jit_float64_ieee_rem
+       (jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_float64 jit_float64_neg(jit_float64 value1) JIT_NOTHROW;
+jit_int jit_float64_eq(jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_int jit_float64_ne(jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_int jit_float64_lt(jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_int jit_float64_le(jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_int jit_float64_gt(jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_int jit_float64_ge(jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_int jit_float64_cmpl(jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_int jit_float64_cmpg(jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_float64 jit_float64_acos(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_asin(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_atan(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_atan2
+       (jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_float64 jit_float64_ceil(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_cos(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_cosh(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_exp(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_floor(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_log(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_log10(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_pow
+       (jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_float64 jit_float64_rint(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_round(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_sin(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_sinh(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_sqrt(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_tan(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_tanh(jit_float64 value1) JIT_NOTHROW;
+jit_int jit_float64_is_finite(jit_float64 value) JIT_NOTHROW;
+jit_int jit_float64_is_nan(jit_float64 value) JIT_NOTHROW;
+jit_int jit_float64_is_inf(jit_float64 value) JIT_NOTHROW;
+jit_float64 jit_float64_abs(jit_float64 value1) JIT_NOTHROW;
+jit_float64 jit_float64_min
+       (jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_float64 jit_float64_max
+       (jit_float64 value1, jit_float64 value2) JIT_NOTHROW;
+jit_int jit_float64_sign(jit_float64 value1) JIT_NOTHROW;
+
+/*
+ * Perform operations on native floating-point values.
+ */
+jit_nfloat jit_nfloat_add(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_nfloat jit_nfloat_sub(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_nfloat jit_nfloat_mul(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_nfloat jit_nfloat_div(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_nfloat jit_nfloat_rem(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_nfloat jit_nfloat_ieee_rem
+       (jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_nfloat jit_nfloat_neg(jit_nfloat value1) JIT_NOTHROW;
+jit_int jit_nfloat_eq(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_int jit_nfloat_ne(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_int jit_nfloat_lt(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_int jit_nfloat_le(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_int jit_nfloat_gt(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_int jit_nfloat_ge(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_int jit_nfloat_cmpl(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_int jit_nfloat_cmpg(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_nfloat jit_nfloat_acos(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_asin(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_atan(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_atan2(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_nfloat jit_nfloat_ceil(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_cos(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_cosh(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_exp(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_floor(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_log(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_log10(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_pow(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_nfloat jit_nfloat_rint(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_round(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_sin(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_sinh(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_sqrt(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_tan(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_tanh(jit_nfloat value1) JIT_NOTHROW;
+jit_int jit_nfloat_is_finite(jit_nfloat value) JIT_NOTHROW;
+jit_int jit_nfloat_is_nan(jit_nfloat value) JIT_NOTHROW;
+jit_int jit_nfloat_is_inf(jit_nfloat value) JIT_NOTHROW;
+jit_nfloat jit_nfloat_abs(jit_nfloat value1) JIT_NOTHROW;
+jit_nfloat jit_nfloat_min(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_nfloat jit_nfloat_max(jit_nfloat value1, jit_nfloat value2) JIT_NOTHROW;
+jit_int jit_nfloat_sign(jit_nfloat value1) JIT_NOTHROW;
+
+/*
+ * Convert between integer types.
+ */
+jit_int jit_int_to_sbyte(jit_int value) JIT_NOTHROW;
+jit_int jit_int_to_ubyte(jit_int value) JIT_NOTHROW;
+jit_int jit_int_to_short(jit_int value) JIT_NOTHROW;
+jit_int jit_int_to_ushort(jit_int value) JIT_NOTHROW;
+jit_int jit_int_to_int(jit_int value) JIT_NOTHROW;
+jit_uint jit_int_to_uint(jit_int value) JIT_NOTHROW;
+jit_long jit_int_to_long(jit_int value) JIT_NOTHROW;
+jit_ulong jit_int_to_ulong(jit_int value) JIT_NOTHROW;
+jit_int jit_uint_to_int(jit_uint value) JIT_NOTHROW;
+jit_uint jit_uint_to_uint(jit_uint value) JIT_NOTHROW;
+jit_long jit_uint_to_long(jit_uint value) JIT_NOTHROW;
+jit_ulong jit_uint_to_ulong(jit_uint value) JIT_NOTHROW;
+jit_int jit_long_to_int(jit_long value) JIT_NOTHROW;
+jit_uint jit_long_to_uint(jit_long value) JIT_NOTHROW;
+jit_long jit_long_to_long(jit_long value) JIT_NOTHROW;
+jit_ulong jit_long_to_ulong(jit_long value) JIT_NOTHROW;
+jit_int jit_ulong_to_int(jit_ulong value) JIT_NOTHROW;
+jit_uint jit_ulong_to_uint(jit_ulong value) JIT_NOTHROW;
+jit_long jit_ulong_to_long(jit_ulong value) JIT_NOTHROW;
+jit_ulong jit_ulong_to_ulong(jit_ulong value) JIT_NOTHROW;
+
+/*
+ * Convert between integer types with overflow detection.
+ */
+jit_int jit_int_to_sbyte_ovf(jit_int *result, jit_int value) JIT_NOTHROW;
+jit_int jit_int_to_ubyte_ovf(jit_int *result, jit_int value) JIT_NOTHROW;
+jit_int jit_int_to_short_ovf(jit_int *result, jit_int value) JIT_NOTHROW;
+jit_int jit_int_to_ushort_ovf(jit_int *result, jit_int value) JIT_NOTHROW;
+jit_int jit_int_to_int_ovf(jit_int *result, jit_int value) JIT_NOTHROW;
+jit_int jit_int_to_uint_ovf(jit_uint *result, jit_int value) JIT_NOTHROW;
+jit_int jit_int_to_long_ovf(jit_long *result, jit_int value) JIT_NOTHROW;
+jit_int jit_int_to_ulong_ovf(jit_ulong *result, jit_int value) JIT_NOTHROW;
+jit_int jit_uint_to_int_ovf(jit_int *result, jit_uint value) JIT_NOTHROW;
+jit_int jit_uint_to_uint_ovf(jit_uint *result, jit_uint value) JIT_NOTHROW;
+jit_int jit_uint_to_long_ovf(jit_long *result, jit_uint value) JIT_NOTHROW;
+jit_int jit_uint_to_ulong_ovf(jit_ulong *result, jit_uint value) JIT_NOTHROW;
+jit_int jit_long_to_int_ovf(jit_int *result, jit_long value) JIT_NOTHROW;
+jit_int jit_long_to_uint_ovf(jit_uint *result, jit_long value) JIT_NOTHROW;
+jit_int jit_long_to_long_ovf(jit_long *result, jit_long value) JIT_NOTHROW;
+jit_int jit_long_to_ulong_ovf(jit_ulong *result, jit_long value) JIT_NOTHROW;
+jit_int jit_ulong_to_int_ovf(jit_int *result, jit_ulong value) JIT_NOTHROW;
+jit_int jit_ulong_to_uint_ovf(jit_uint *result, jit_ulong value) JIT_NOTHROW;
+jit_int jit_ulong_to_long_ovf(jit_long *result, jit_ulong value) JIT_NOTHROW;
+jit_int jit_ulong_to_ulong_ovf(jit_ulong *result, jit_ulong value) JIT_NOTHROW;
+
+/*
+ * Convert a native floating-point value into various integer types.
+ */
+jit_int jit_nfloat_to_int(jit_nfloat value) JIT_NOTHROW;
+jit_uint jit_nfloat_to_uint(jit_nfloat value) JIT_NOTHROW;
+jit_long jit_nfloat_to_long(jit_nfloat value) JIT_NOTHROW;
+jit_ulong jit_nfloat_to_ulong(jit_nfloat value) JIT_NOTHROW;
+
+/*
+ * Convert a native floating-point value into various integer types,
+ * with overflow detection.
+ */
+jit_int jit_nfloat_to_int_ovf(jit_int *result, jit_nfloat value) JIT_NOTHROW;
+jit_int jit_nfloat_to_uint_ovf(jit_uint *result, jit_nfloat value) JIT_NOTHROW;
+jit_int jit_nfloat_to_long_ovf(jit_long *result, jit_nfloat value) JIT_NOTHROW;
+jit_int jit_nfloat_to_ulong_ovf
+       (jit_ulong *result, jit_nfloat value) JIT_NOTHROW;
+
+/*
+ * Convert integer types into floating-point values.
+ */
+jit_nfloat jit_int_to_nfloat(jit_int value) JIT_NOTHROW;
+jit_nfloat jit_uint_to_nfloat(jit_uint value) JIT_NOTHROW;
+jit_nfloat jit_long_to_nfloat(jit_long value) JIT_NOTHROW;
+jit_nfloat jit_ulong_to_nfloat(jit_ulong value) JIT_NOTHROW;
+
+/*
+ * Convert between floating-point types.
+ */
+jit_nfloat jit_float32_to_nfloat(jit_float32 value) JIT_NOTHROW;
+jit_nfloat jit_float64_to_nfloat(jit_float64 value) JIT_NOTHROW;
+jit_float32 jit_nfloat_to_float32(jit_nfloat value) JIT_NOTHROW;
+jit_float64 jit_nfloat_to_float64(jit_nfloat value) JIT_NOTHROW;
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_INTRINSIC_H */
diff --git a/include/jit/jit-meta.h b/include/jit/jit-meta.h
new file mode 100644 (file)
index 0000000..b113a79
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * jit-meta.h - Manipulate lists of metadata values.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_META_H
+#define        _JIT_META_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _jit_meta *jit_meta_t;
+
+int jit_meta_set(jit_meta_t *list, int type, void *data,
+                                jit_meta_free_func free_data, jit_function_t pool_owner);
+void *jit_meta_get(jit_meta_t list, int type);
+void jit_meta_free(jit_meta_t *list, int type);
+void jit_meta_destroy(jit_meta_t *list);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_META_H */
diff --git a/include/jit/jit-opcode.h b/include/jit/jit-opcode.h
new file mode 100644 (file)
index 0000000..fc7e7d1
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * jit-opcode.h - List of primitive opcodes for JIT instructions.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_OPCODE_H
+#define        _JIT_OPCODE_H
+
+#include <jit/jit-defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Simple opcodes.
+ */
+#define        JIT_OP_NOP                                                      0x0000
+
+/*
+ * Conversion opcodes.
+ */
+#define        JIT_OP_TRUNC_SBYTE                                      0x0001
+#define        JIT_OP_TRUNC_UBYTE                                      0x0002
+#define        JIT_OP_TRUNC_SHORT                                      0x0003
+#define        JIT_OP_TRUNC_USHORT                                     0x0004
+#define        JIT_OP_TRUNC_INT                                        0x0005
+#define        JIT_OP_TRUNC_UINT                                       0x0006
+#define        JIT_OP_CHECK_SBYTE                                      0x0007
+#define        JIT_OP_CHECK_UBYTE                                      0x0008
+#define        JIT_OP_CHECK_SHORT                                      0x0009
+#define        JIT_OP_CHECK_USHORT                                     0x000A
+#define        JIT_OP_CHECK_INT                                        0x000B
+#define        JIT_OP_CHECK_UINT                                       0x000C
+#define        JIT_OP_LOW_WORD                                         0x000D
+#define        JIT_OP_EXPAND_INT                                       0x000E
+#define        JIT_OP_EXPAND_UINT                                      0x000F
+#define        JIT_OP_CHECK_LOW_WORD                           0x0010
+#define        JIT_OP_CHECK_SIGNED_LOW_WORD            0x0011
+#define        JIT_OP_CHECK_LONG                                       0x0012
+#define        JIT_OP_CHECK_ULONG                                      0x0013
+#define        JIT_OP_NFLOAT_TO_INT                            0x0014
+#define        JIT_OP_NFLOAT_TO_UINT                           0x0015
+#define        JIT_OP_NFLOAT_TO_LONG                           0x0016
+#define        JIT_OP_NFLOAT_TO_ULONG                          0x0017
+#define        JIT_OP_CHECK_NFLOAT_TO_INT                      0x0018
+#define        JIT_OP_CHECK_NFLOAT_TO_UINT                     0x0019
+#define        JIT_OP_CHECK_NFLOAT_TO_LONG                     0x001A
+#define        JIT_OP_CHECK_NFLOAT_TO_ULONG            0x001B
+#define        JIT_OP_INT_TO_NFLOAT                            0x001C
+#define        JIT_OP_UINT_TO_NFLOAT                           0x001D
+#define        JIT_OP_LONG_TO_NFLOAT                           0x001E
+#define        JIT_OP_ULONG_TO_NFLOAT                          0x001F
+#define        JIT_OP_NFLOAT_TO_FLOAT32                        0x0020
+#define        JIT_OP_NFLOAT_TO_FLOAT64                        0x0021
+#define        JIT_OP_FLOAT32_TO_NFLOAT                        0x0022
+#define        JIT_OP_FLOAT64_TO_NFLOAT                        0x0023
+
+/*
+ * Arithmetic opcodes.
+ */
+#define        JIT_OP_IADD                                                     0x0024
+#define        JIT_OP_IADD_OVF                                         0x0025
+#define        JIT_OP_IADD_OVF_UN                                      0x0026
+#define        JIT_OP_ISUB                                                     0x0027
+#define        JIT_OP_ISUB_OVF                                         0x0028
+#define        JIT_OP_ISUB_OVF_UN                                      0x0029
+#define        JIT_OP_IMUL                                                     0x002A
+#define        JIT_OP_IMUL_OVF                                         0x002B
+#define        JIT_OP_IMUL_OVF_UN                                      0x002C
+#define        JIT_OP_IDIV                                                     0x002D
+#define        JIT_OP_IDIV_UN                                          0x002E
+#define        JIT_OP_IREM                                                     0x002F
+#define        JIT_OP_IREM_UN                                          0x0030
+#define        JIT_OP_INEG                                                     0x0031
+#define        JIT_OP_LADD                                                     0x0032
+#define        JIT_OP_LADD_OVF                                         0x0033
+#define        JIT_OP_LADD_OVF_UN                                      0x0034
+#define        JIT_OP_LSUB                                                     0x0035
+#define        JIT_OP_LSUB_OVF                                         0x0036
+#define        JIT_OP_LSUB_OVF_UN                                      0x0037
+#define        JIT_OP_LMUL                                                     0x0038
+#define        JIT_OP_LMUL_OVF                                         0x0039
+#define        JIT_OP_LMUL_OVF_UN                                      0x003A
+#define        JIT_OP_LDIV                                                     0x003B
+#define        JIT_OP_LDIV_UN                                          0x003C
+#define        JIT_OP_LREM                                                     0x003D
+#define        JIT_OP_LREM_UN                                          0x003E
+#define        JIT_OP_LNEG                                                     0x003F
+#define        JIT_OP_FADD                                                     0x0040
+#define        JIT_OP_FSUB                                                     0x0041
+#define        JIT_OP_FMUL                                                     0x0042
+#define        JIT_OP_FDIV                                                     0x0043
+#define        JIT_OP_FREM                                                     0x0044
+#define        JIT_OP_FREM_IEEE                                        0x0045
+#define        JIT_OP_FNEG                                                     0x0046
+#define        JIT_OP_DADD                                                     0x0047
+#define        JIT_OP_DSUB                                                     0x0048
+#define        JIT_OP_DMUL                                                     0x0049
+#define        JIT_OP_DDIV                                                     0x004A
+#define        JIT_OP_DREM                                                     0x004B
+#define        JIT_OP_DREM_IEEE                                        0x004C
+#define        JIT_OP_DNEG                                                     0x004D
+#define        JIT_OP_NFADD                                            0x004E
+#define        JIT_OP_NFSUB                                            0x004F
+#define        JIT_OP_NFMUL                                            0x0050
+#define        JIT_OP_NFDIV                                            0x0051
+#define        JIT_OP_NFREM                                            0x0052
+#define        JIT_OP_NFREM_IEEE                                       0x0053
+#define        JIT_OP_NFNEG                                            0x0054
+
+/*
+ * Bitwise opcodes.
+ */
+#define        JIT_OP_IAND                                                     0x0055
+#define        JIT_OP_IOR                                                      0x0056
+#define        JIT_OP_IXOR                                                     0x0057
+#define        JIT_OP_INOT                                                     0x0058
+#define        JIT_OP_ISHL                                                     0x0059
+#define        JIT_OP_ISHR                                                     0x005A
+#define        JIT_OP_ISHR_UN                                          0x005B
+#define        JIT_OP_LAND                                                     0x005C
+#define        JIT_OP_LOR                                                      0x005D
+#define        JIT_OP_LXOR                                                     0x005E
+#define        JIT_OP_LNOT                                                     0x005F
+#define        JIT_OP_LSHL                                                     0x0060
+#define        JIT_OP_LSHR                                                     0x0061
+#define        JIT_OP_LSHR_UN                                          0x0062
+
+/*
+ * Branch opcodes.
+ */
+#define        JIT_OP_BR                                                       0x0063
+#define        JIT_OP_BR_IFALSE                                        0x0064
+#define        JIT_OP_BR_ITRUE                                         0x0065
+#define        JIT_OP_BR_IEQ                                           0x0066
+#define        JIT_OP_BR_INE                                           0x0067
+#define        JIT_OP_BR_ILT                                           0x0068
+#define        JIT_OP_BR_ILT_UN                                        0x0069
+#define        JIT_OP_BR_ILE                                           0x006A
+#define        JIT_OP_BR_ILE_UN                                        0x006B
+#define        JIT_OP_BR_IGT                                           0x006C
+#define        JIT_OP_BR_IGT_UN                                        0x006D
+#define        JIT_OP_BR_IGE                                           0x006E
+#define        JIT_OP_BR_IGE_UN                                        0x006F
+#define        JIT_OP_BR_LFALSE                                        0x0070
+#define        JIT_OP_BR_LTRUE                                         0x0071
+#define        JIT_OP_BR_LEQ                                           0x0072
+#define        JIT_OP_BR_LNE                                           0x0073
+#define        JIT_OP_BR_LLT                                           0x0074
+#define        JIT_OP_BR_LLT_UN                                        0x0075
+#define        JIT_OP_BR_LLE                                           0x0076
+#define        JIT_OP_BR_LLE_UN                                        0x0077
+#define        JIT_OP_BR_LGT                                           0x0078
+#define        JIT_OP_BR_LGT_UN                                        0x0079
+#define        JIT_OP_BR_LGE                                           0x007A
+#define        JIT_OP_BR_LGE_UN                                        0x007B
+#define        JIT_OP_BR_FEQ                                           0x007C
+#define        JIT_OP_BR_FNE                                           0x007D
+#define        JIT_OP_BR_FLT                                           0x007E
+#define        JIT_OP_BR_FLE                                           0x007F
+#define        JIT_OP_BR_FGT                                           0x0080
+#define        JIT_OP_BR_FGE                                           0x0081
+#define        JIT_OP_BR_FEQ_INV                                       0x0082
+#define        JIT_OP_BR_FNE_INV                                       0x0083
+#define        JIT_OP_BR_FLT_INV                                       0x0084
+#define        JIT_OP_BR_FLE_INV                                       0x0085
+#define        JIT_OP_BR_FGT_INV                                       0x0086
+#define        JIT_OP_BR_FGE_INV                                       0x0087
+#define        JIT_OP_BR_DEQ                                           0x0088
+#define        JIT_OP_BR_DNE                                           0x0089
+#define        JIT_OP_BR_DLT                                           0x008A
+#define        JIT_OP_BR_DLE                                           0x008B
+#define        JIT_OP_BR_DGT                                           0x008C
+#define        JIT_OP_BR_DGE                                           0x008D
+#define        JIT_OP_BR_DEQ_INV                                       0x008E
+#define        JIT_OP_BR_DNE_INV                                       0x008F
+#define        JIT_OP_BR_DLT_INV                                       0x0090
+#define        JIT_OP_BR_DLE_INV                                       0x0091
+#define        JIT_OP_BR_DGT_INV                                       0x0092
+#define        JIT_OP_BR_DGE_INV                                       0x0093
+#define        JIT_OP_BR_NFEQ                                          0x0094
+#define        JIT_OP_BR_NFNE                                          0x0095
+#define        JIT_OP_BR_NFLT                                          0x0096
+#define        JIT_OP_BR_NFLE                                          0x0097
+#define        JIT_OP_BR_NFGT                                          0x0098
+#define        JIT_OP_BR_NFGE                                          0x0099
+#define        JIT_OP_BR_NFEQ_INV                                      0x009A
+#define        JIT_OP_BR_NFNE_INV                                      0x009B
+#define        JIT_OP_BR_NFLT_INV                                      0x009C
+#define        JIT_OP_BR_NFLE_INV                                      0x009D
+#define        JIT_OP_BR_NFGT_INV                                      0x009E
+#define        JIT_OP_BR_NFGE_INV                                      0x009F
+
+/*
+ * Comparison opcodes.
+ */
+#define        JIT_OP_ICMP                                                     0x00A0
+#define        JIT_OP_ICMP_UN                                          0x00A1
+#define        JIT_OP_LCMP                                                     0x00A2
+#define        JIT_OP_LCMP_UN                                          0x00A3
+#define        JIT_OP_FCMPL                                            0x00A4
+#define        JIT_OP_FCMPG                                            0x00A5
+#define        JIT_OP_DCMPL                                            0x00A6
+#define        JIT_OP_DCMPG                                            0x00A7
+#define        JIT_OP_NFCMPL                                           0x00A8
+#define        JIT_OP_NFCMPG                                           0x00A9
+#define        JIT_OP_IEQ                                                      0x00AA
+#define        JIT_OP_INE                                                      0x00AB
+#define        JIT_OP_ILT                                                      0x00AC
+#define        JIT_OP_ILT_UN                                           0x00AD
+#define        JIT_OP_ILE                                                      0x00AE
+#define        JIT_OP_ILE_UN                                           0x00AF
+#define        JIT_OP_IGT                                                      0x00B0
+#define        JIT_OP_IGT_UN                                           0x00B1
+#define        JIT_OP_IGE                                                      0x00B2
+#define        JIT_OP_IGE_UN                                           0x00B3
+#define        JIT_OP_LEQ                                                      0x00B4
+#define        JIT_OP_LNE                                                      0x00B5
+#define        JIT_OP_LLT                                                      0x00B6
+#define        JIT_OP_LLT_UN                                           0x00B7
+#define        JIT_OP_LLE                                                      0x00B8
+#define        JIT_OP_LLE_UN                                           0x00B9
+#define        JIT_OP_LGT                                                      0x00BA
+#define        JIT_OP_LGT_UN                                           0x00BB
+#define        JIT_OP_LGE                                                      0x00BC
+#define        JIT_OP_LGE_UN                                           0x00BD
+#define        JIT_OP_FEQ                                                      0x00BE
+#define        JIT_OP_FNE                                                      0x00BF
+#define        JIT_OP_FLT                                                      0x00C0
+#define        JIT_OP_FLE                                                      0x00C1
+#define        JIT_OP_FGT                                                      0x00C2
+#define        JIT_OP_FGE                                                      0x00C3
+#define        JIT_OP_FEQ_INV                                          0x00C4
+#define        JIT_OP_FNE_INV                                          0x00C5
+#define        JIT_OP_FLT_INV                                          0x00C6
+#define        JIT_OP_FLE_INV                                          0x00C7
+#define        JIT_OP_FGT_INV                                          0x00C8
+#define        JIT_OP_FGE_INV                                          0x00C9
+#define        JIT_OP_DEQ                                                      0x00CA
+#define        JIT_OP_DNE                                                      0x00CB
+#define        JIT_OP_DLT                                                      0x00CC
+#define        JIT_OP_DLE                                                      0x00CD
+#define        JIT_OP_DGT                                                      0x00CE
+#define        JIT_OP_DGE                                                      0x00CF
+#define        JIT_OP_DEQ_INV                                          0x00D0
+#define        JIT_OP_DNE_INV                                          0x00D1
+#define        JIT_OP_DLT_INV                                          0x00D2
+#define        JIT_OP_DLE_INV                                          0x00D3
+#define        JIT_OP_DGT_INV                                          0x00D4
+#define        JIT_OP_DGE_INV                                          0x00D5
+#define        JIT_OP_NFEQ                                                     0x00D6
+#define        JIT_OP_NFNE                                                     0x00D7
+#define        JIT_OP_NFLT                                                     0x00D8
+#define        JIT_OP_NFLE                                                     0x00D9
+#define        JIT_OP_NFGT                                                     0x00DA
+#define        JIT_OP_NFGE                                                     0x00DB
+#define        JIT_OP_NFEQ_INV                                         0x00DC
+#define        JIT_OP_NFNE_INV                                         0x00DD
+#define        JIT_OP_NFLT_INV                                         0x00DE
+#define        JIT_OP_NFLE_INV                                         0x00DF
+#define        JIT_OP_NFGT_INV                                         0x00E0
+#define        JIT_OP_NFGE_INV                                         0x00E1
+#define        JIT_OP_IS_FNAN                                          0x00E2
+#define        JIT_OP_IS_FINF                                          0x00E3
+#define        JIT_OP_IS_FFINITE                                       0x00E4
+#define        JIT_OP_IS_DNAN                                          0x00E5
+#define        JIT_OP_IS_DINF                                          0x00E6
+#define        JIT_OP_IS_DFINITE                                       0x00E7
+#define        JIT_OP_IS_NFNAN                                         0x00E8
+#define        JIT_OP_IS_NFINF                                         0x00E9
+#define        JIT_OP_IS_NFFINITE                                      0x00EA
+
+/*
+ * Mathematical functions.
+ */
+#define        JIT_OP_FACOS                                            0x00EB
+#define        JIT_OP_FASIN                                            0x00EC
+#define        JIT_OP_FATAN                                            0x00ED
+#define        JIT_OP_FATAN2                                           0x00EE
+#define        JIT_OP_FCEIL                                            0x00EF
+#define        JIT_OP_FCOS                                                     0x00F0
+#define        JIT_OP_FCOSH                                            0x00F1
+#define        JIT_OP_FEXP                                                     0x00F2
+#define        JIT_OP_FFLOOR                                           0x00F3
+#define        JIT_OP_FLOG                                                     0x00F4
+#define        JIT_OP_FLOG10                                           0x00F5
+#define        JIT_OP_FPOW                                                     0x00F6
+#define        JIT_OP_FRINT                                            0x00F7
+#define        JIT_OP_FROUND                                           0x00F8
+#define        JIT_OP_FSIN                                                     0x00F9
+#define        JIT_OP_FSINH                                            0x00FA
+#define        JIT_OP_FSQRT                                            0x00FB
+#define        JIT_OP_FTAN                                                     0x00FC
+#define        JIT_OP_FTANH                                            0x00FD
+#define        JIT_OP_DACOS                                            0x00FE
+#define        JIT_OP_DASIN                                            0x00FF
+#define        JIT_OP_DATAN                                            0x0100
+#define        JIT_OP_DATAN2                                           0x0101
+#define        JIT_OP_DCEIL                                            0x0102
+#define        JIT_OP_DCOS                                                     0x0103
+#define        JIT_OP_DCOSH                                            0x0104
+#define        JIT_OP_DEXP                                                     0x0105
+#define        JIT_OP_DFLOOR                                           0x0106
+#define        JIT_OP_DLOG                                                     0x0107
+#define        JIT_OP_DLOG10                                           0x0108
+#define        JIT_OP_DPOW                                                     0x0109
+#define        JIT_OP_DRINT                                            0x010A
+#define        JIT_OP_DROUND                                           0x010B
+#define        JIT_OP_DSIN                                                     0x010C
+#define        JIT_OP_DSINH                                            0x010D
+#define        JIT_OP_DSQRT                                            0x010E
+#define        JIT_OP_DTAN                                                     0x010F
+#define        JIT_OP_DTANH                                            0x0110
+#define        JIT_OP_NFACOS                                           0x0111
+#define        JIT_OP_NFASIN                                           0x0112
+#define        JIT_OP_NFATAN                                           0x0113
+#define        JIT_OP_NFATAN2                                          0x0114
+#define        JIT_OP_NFCEIL                                           0x0115
+#define        JIT_OP_NFCOS                                            0x0116
+#define        JIT_OP_NFCOSH                                           0x0117
+#define        JIT_OP_NFEXP                                            0x0118
+#define        JIT_OP_NFFLOOR                                          0x0119
+#define        JIT_OP_NFLOG                                            0x011A
+#define        JIT_OP_NFLOG10                                          0x011B
+#define        JIT_OP_NFPOW                                            0x011C
+#define        JIT_OP_NFRINT                                           0x011D
+#define        JIT_OP_NFROUND                                          0x011E
+#define        JIT_OP_NFSIN                                            0x011F
+#define        JIT_OP_NFSINH                                           0x0120
+#define        JIT_OP_NFSQRT                                           0x0121
+#define        JIT_OP_NFTAN                                            0x0122
+#define        JIT_OP_NFTANH                                           0x0123
+
+/*
+ * Absolute, minimum, maximum, and sign.
+ */
+#define        JIT_OP_IABS                                                     0x0124
+#define        JIT_OP_LABS                                                     0x0125
+#define        JIT_OP_FABS                                                     0x0126
+#define        JIT_OP_DABS                                                     0x0127
+#define        JIT_OP_NFABS                                            0x0128
+#define        JIT_OP_IMIN                                                     0x0129
+#define        JIT_OP_IMIN_UN                                          0x012A
+#define        JIT_OP_LMIN                                                     0x012B
+#define        JIT_OP_LMIN_UN                                          0x012C
+#define        JIT_OP_FMIN                                                     0x012D
+#define        JIT_OP_DMIN                                                     0x012E
+#define        JIT_OP_NFMIN                                            0x012F
+#define        JIT_OP_IMAX                                                     0x0130
+#define        JIT_OP_IMAX_UN                                          0x0131
+#define        JIT_OP_LMAX                                                     0x0132
+#define        JIT_OP_LMAX_UN                                          0x0133
+#define        JIT_OP_FMAX                                                     0x0134
+#define        JIT_OP_DMAX                                                     0x0135
+#define        JIT_OP_NFMAX                                            0x0136
+#define        JIT_OP_ISIGN                                            0x0137
+#define        JIT_OP_LSIGN                                            0x0138
+#define        JIT_OP_FSIGN                                            0x0139
+#define        JIT_OP_DSIGN                                            0x013A
+#define        JIT_OP_NFSIGN                                           0x013B
+
+/*
+ * Pointer check opcodes.
+ */
+#define        JIT_OP_CHECK_NULL                                       0x013C
+
+/*
+ * Function calls.
+ */
+#define        JIT_OP_CALL                                                     0x013D
+#define        JIT_OP_CALL_TAIL                                        0x013E
+#define        JIT_OP_CALL_INDIRECT                            0x013F
+#define        JIT_OP_CALL_VTABLE_PTR                          0x0140
+#define        JIT_OP_CALL_EXTERNAL                            0x0141
+#define        JIT_OP_RETURN                                           0x0142
+#define        JIT_OP_RETURN_INT                                       0x0143
+#define        JIT_OP_RETURN_LONG                                      0x0144
+#define        JIT_OP_RETURN_FLOAT32                           0x0145
+#define        JIT_OP_RETURN_FLOAT64                           0x0146
+#define        JIT_OP_RETURN_NFLOAT                            0x0147
+#define        JIT_OP_RETURN_SMALL_STRUCT                      0x0148
+#define        JIT_OP_SETUP_FOR_NESTED                         0x0149
+#define        JIT_OP_SETUP_FOR_SIBLING                        0x014A
+#define        JIT_OP_IMPORT                                           0x014B
+
+/*
+ * Exception handling.
+ */
+#define        JIT_OP_THROW                                            0x014C
+#define        JIT_OP_LOAD_PC                                          0x014D
+#define        JIT_OP_ENTER_CATCH                                      0x014E
+#define        JIT_OP_ENTER_FINALLY                            0x014F
+#define        JIT_OP_LEAVE_FINALLY                            0x0150
+#define        JIT_OP_ENTER_FILTER                                     0x0151
+#define        JIT_OP_LEAVE_FILTER                                     0x0152
+#define        JIT_OP_CALL_FILTER                                      0x0153
+#define        JIT_OP_CALL_FILTER_RETURN                       0x0154
+#define        JIT_OP_PREPARE_FOR_LEAVE                        0x0155
+#define        JIT_OP_PREPARE_FOR_RETURN                       0x0156
+
+/*
+ * Data manipulation.
+ */
+#define        JIT_OP_COPY_LOAD_SBYTE                          0x0157
+#define        JIT_OP_COPY_LOAD_UBYTE                          0x0158
+#define        JIT_OP_COPY_LOAD_SHORT                          0x0159
+#define        JIT_OP_COPY_LOAD_USHORT                         0x015A
+#define        JIT_OP_COPY_INT                                         0x015B
+#define        JIT_OP_COPY_LONG                                        0x015C
+#define        JIT_OP_COPY_FLOAT32                                     0x015D
+#define        JIT_OP_COPY_FLOAT64                                     0x015E
+#define        JIT_OP_COPY_NFLOAT                                      0x015F
+#define        JIT_OP_COPY_STRUCT                                      0x0160
+#define        JIT_OP_COPY_STORE_BYTE                          0x0161
+#define        JIT_OP_COPY_STORE_SHORT                         0x0162
+#define        JIT_OP_ADDRESS_OF                                       0x0163
+
+/*
+ * Incoming registers, outgoing registers, and stack pushes.
+ */
+#define        JIT_OP_INCOMING_REG                                     0x0164
+#define        JIT_OP_INCOMING_FRAME_POSN                      0x0165
+#define        JIT_OP_OUTGOING_REG                                     0x0166
+#define        JIT_OP_RETURN_REG                                       0x0167
+#define        JIT_OP_PUSH_INT                                         0x0168
+#define        JIT_OP_PUSH_LONG                                        0x0169
+#define        JIT_OP_PUSH_FLOAT32                                     0x016A
+#define        JIT_OP_PUSH_FLOAT64                                     0x016B
+#define        JIT_OP_PUSH_NFLOAT                                      0x016C
+#define        JIT_OP_PUSH_STRUCT                                      0x016D
+#define        JIT_OP_POP_STACK                                        0x016E
+#define        JIT_OP_FLUSH_SMALL_STRUCT                       0x016F
+
+/*
+ * Pointer-relative loads and stores.
+ */
+#define        JIT_OP_LOAD_RELATIVE_SBYTE                      0x0170
+#define        JIT_OP_LOAD_RELATIVE_UBYTE                      0x0171
+#define        JIT_OP_LOAD_RELATIVE_SHORT                      0x0172
+#define        JIT_OP_LOAD_RELATIVE_USHORT                     0x0173
+#define        JIT_OP_LOAD_RELATIVE_INT                        0x0174
+#define        JIT_OP_LOAD_RELATIVE_LONG                       0x0175
+#define        JIT_OP_LOAD_RELATIVE_FLOAT32            0x0176
+#define        JIT_OP_LOAD_RELATIVE_FLOAT64            0x0177
+#define        JIT_OP_LOAD_RELATIVE_NFLOAT                     0x0178
+#define        JIT_OP_LOAD_RELATIVE_STRUCT                     0x0179
+#define        JIT_OP_STORE_RELATIVE_BYTE                      0x017A
+#define        JIT_OP_STORE_RELATIVE_SHORT                     0x017B
+#define        JIT_OP_STORE_RELATIVE_INT                       0x017C
+#define        JIT_OP_STORE_RELATIVE_LONG                      0x017D
+#define        JIT_OP_STORE_RELATIVE_FLOAT32           0x017E
+#define        JIT_OP_STORE_RELATIVE_FLOAT64           0x017F
+#define        JIT_OP_STORE_RELATIVE_NFLOAT            0x0180
+#define        JIT_OP_STORE_RELATIVE_STRUCT            0x0181
+#define        JIT_OP_ADD_RELATIVE                                     0x0182
+
+/*
+ * The number of opcodes in the above list.
+ */
+#define        JIT_OP_NUM_OPCODES                                      0x0183
+
+/*
+ * Opcode information.
+ */
+typedef struct jit_opcode_info jit_opcode_info_t;
+struct jit_opcode_info
+{
+       const char *name;
+       int                     flags;
+};
+#define        JIT_OPCODE_DEST_MASK                    0x0000000F
+#define        JIT_OPCODE_DEST_EMPTY                   0x00000000
+#define        JIT_OPCODE_DEST_INT                             0x00000001
+#define        JIT_OPCODE_DEST_LONG                    0x00000002
+#define        JIT_OPCODE_DEST_FLOAT32                 0x00000003
+#define        JIT_OPCODE_DEST_FLOAT64                 0x00000004
+#define        JIT_OPCODE_DEST_NFLOAT                  0x00000005
+#define        JIT_OPCODE_DEST_ANY                             0x00000006
+#define        JIT_OPCODE_SRC1_MASK                    0x000000F0
+#define        JIT_OPCODE_SRC1_EMPTY                   0x00000000
+#define        JIT_OPCODE_SRC1_INT                             0x00000010
+#define        JIT_OPCODE_SRC1_LONG                    0x00000020
+#define        JIT_OPCODE_SRC1_FLOAT32                 0x00000030
+#define        JIT_OPCODE_SRC1_FLOAT64                 0x00000040
+#define        JIT_OPCODE_SRC1_NFLOAT                  0x00000050
+#define        JIT_OPCODE_SRC1_ANY                             0x00000060
+#define        JIT_OPCODE_SRC2_MASK                    0x00000F00
+#define        JIT_OPCODE_SRC2_EMPTY                   0x00000000
+#define        JIT_OPCODE_SRC2_INT                             0x00000100
+#define        JIT_OPCODE_SRC2_LONG                    0x00000200
+#define        JIT_OPCODE_SRC2_FLOAT32                 0x00000300
+#define        JIT_OPCODE_SRC2_FLOAT64                 0x00000400
+#define        JIT_OPCODE_SRC2_NFLOAT                  0x00000500
+#define        JIT_OPCODE_SRC2_ANY                             0x00000600
+#define        JIT_OPCODE_IS_BRANCH                    0x00001000
+#define        JIT_OPCODE_IS_CALL                              0x00002000
+#define        JIT_OPCODE_IS_CALL_EXTERNAL             0x00004000
+#define        JIT_OPCODE_IS_REG                               0x00008000
+#define        JIT_OPCODE_OPER_MASK                    0x01F00000
+#define        JIT_OPCODE_OPER_NONE                    0x00000000
+#define        JIT_OPCODE_OPER_ADD                             0x00100000
+#define        JIT_OPCODE_OPER_SUB                             0x00200000
+#define        JIT_OPCODE_OPER_MUL                             0x00300000
+#define        JIT_OPCODE_OPER_DIV                             0x00400000
+#define        JIT_OPCODE_OPER_REM                             0x00500000
+#define        JIT_OPCODE_OPER_NEG                             0x00600000
+#define        JIT_OPCODE_OPER_AND                             0x00700000
+#define        JIT_OPCODE_OPER_OR                              0x00800000
+#define        JIT_OPCODE_OPER_XOR                             0x00900000
+#define        JIT_OPCODE_OPER_NOT                             0x00A00000
+#define        JIT_OPCODE_OPER_EQ                              0x00B00000
+#define        JIT_OPCODE_OPER_NE                              0x00C00000
+#define        JIT_OPCODE_OPER_LT                              0x00D00000
+#define        JIT_OPCODE_OPER_LE                              0x00E00000
+#define        JIT_OPCODE_OPER_GT                              0x00F00000
+#define        JIT_OPCODE_OPER_GE                              0x01000000
+#define        JIT_OPCODE_OPER_SHL                             0x01100000
+#define        JIT_OPCODE_OPER_SHR                             0x01200000
+#define        JIT_OPCODE_OPER_SHR_UN                  0x01300000
+#define        JIT_OPCODE_OPER_COPY                    0x01400000
+#define        JIT_OPCODE_OPER_ADDRESS_OF              0x01500000
+#ifdef JIT_NATIVE_INT32
+#define        JIT_OPCODE_DEST_PTR                             JIT_OPCODE_DEST_INT
+#define        JIT_OPCODE_SRC1_PTR                             JIT_OPCODE_SRC1_INT
+#define        JIT_OPCODE_SRC2_PTR                             JIT_OPCODE_SRC2_INT
+#else
+#define        JIT_OPCODE_DEST_PTR                             JIT_OPCODE_DEST_LONG
+#define        JIT_OPCODE_SRC1_PTR                             JIT_OPCODE_SRC1_LONG
+#define        JIT_OPCODE_SRC2_PTR                             JIT_OPCODE_SRC2_LONG
+#endif
+extern jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES];
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_OPCODE_H */
diff --git a/include/jit/jit-plus.h b/include/jit/jit-plus.h
new file mode 100644 (file)
index 0000000..920600e
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * jit-plus.h - C++ binding for the JIT library.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_PLUS_H
+#define        _JIT_PLUS_H
+
+#include <jit/jit.h>
+
+#ifdef __cplusplus
+
+class jit_value
+{
+public:
+       jit_value() { this->value = 0; }
+       jit_value(jit_value_t value) { this->value = value; }
+       jit_value(const jit_value& value) { this->value = value.value; }
+       ~jit_value() {}
+
+       jit_value& operator=(const jit_value& value)
+               { this->value = value.value; return *this; }
+
+       jit_value_t raw() const { return value; }
+       int is_valid() const { return (value != 0); }
+
+       int is_temporary() const { return jit_value_is_temporary(value); }
+       int is_local() const { return jit_value_is_local(value); }
+       int is_constant() const { return jit_value_is_constant(value); }
+
+       void set_volatile() { jit_value_set_volatile(value); }
+       int is_volatile() const { return jit_value_is_volatile(value); }
+
+       void set_addressable() { jit_value_set_addressable(value); }
+       int is_addressable() const { return jit_value_is_addressable(value); }
+
+       jit_type_t type() const { return jit_value_get_type(value); }
+       jit_function_t function() const { return jit_value_get_function(value); }
+       jit_block_t block() const { return jit_value_get_block(value); }
+       jit_context_t context() const { return jit_value_get_context(value); }
+
+       jit_constant_t constant() const
+               { return jit_value_get_constant(value); }
+       jit_nint nint_constant() const
+               { return jit_value_get_nint_constant(value); }
+       jit_long long_constant() const
+               { return jit_value_get_long_constant(value); }
+       jit_float32 float32_constant() const
+               { return jit_value_get_float32_constant(value); }
+       jit_float64 float64_constant() const
+               { return jit_value_get_float64_constant(value); }
+       jit_nfloat nfloat_constant() const
+               { return jit_value_get_nfloat_constant(value); }
+
+private:
+       jit_value_t value;
+};
+
+jit_value operator+(const jit_value& value1, const jit_value& value2);
+jit_value operator-(const jit_value& value1, const jit_value& value2);
+jit_value operator*(const jit_value& value1, const jit_value& value2);
+jit_value operator/(const jit_value& value1, const jit_value& value2);
+jit_value operator%(const jit_value& value1, const jit_value& value2);
+jit_value operator-(const jit_value& value1);
+jit_value operator&(const jit_value& value1, const jit_value& value2);
+jit_value operator|(const jit_value& value1, const jit_value& value2);
+jit_value operator^(const jit_value& value1, const jit_value& value2);
+jit_value operator~(const jit_value& value1);
+jit_value operator<<(const jit_value& value1, const jit_value& value2);
+jit_value operator>>(const jit_value& value1, const jit_value& value2);
+jit_value operator==(const jit_value& value1, const jit_value& value2);
+jit_value operator!=(const jit_value& value1, const jit_value& value2);
+jit_value operator<(const jit_value& value1, const jit_value& value2);
+jit_value operator<=(const jit_value& value1, const jit_value& value2);
+jit_value operator>(const jit_value& value1, const jit_value& value2);
+jit_value operator>=(const jit_value& value1, const jit_value& value2);
+
+class jit_label
+{
+public:
+       jit_label() { label = jit_label_undefined; }
+       jit_label(jit_label_t label) { this->label = label; }
+       jit_label(const jit_label& label) { this->label = label.label; }
+       ~jit_label() {}
+
+       jit_label_t raw() const { return label; }
+       jit_label_t *rawp() { return &label; }
+       int is_valid() const { return (label != jit_label_undefined); }
+
+       jit_label& operator=(const jit_label& value)
+               { this->label = value.label; return *this; }
+
+private:
+       jit_label_t label;
+};
+
+class jit_context
+{
+public:
+       jit_context();
+       jit_context(jit_context_t context);
+       ~jit_context();
+
+       jit_context_t raw() const { return context; }
+
+private:
+       jit_context_t context;
+       int copied;
+};
+
+class jit_function
+{
+public:
+       jit_function(jit_context& context, jit_type_t signature);
+       jit_function(jit_context& context);
+       jit_function(jit_function_t func);
+       virtual ~jit_function();
+
+       jit_function_t raw() const { return func; }
+       int is_valid() const { return (func != 0); }
+
+       static jit_function *from_raw(jit_function_t func);
+
+       jit_type_t signature() const { return jit_function_get_signature(func); }
+
+       void create(jit_type_t signature);
+       void create();
+
+       int compile();
+
+       int is_compiled() const { return jit_function_is_compiled(func); }
+
+       int recompile();
+
+       int is_recompilable() const { return jit_function_is_recompilable(func); }
+
+       void set_recompilable() { jit_function_set_recompilable(func); }
+       void clear_recompilable() { jit_function_set_recompilable(func); }
+       void set_recompilable(int flag)
+               { if(flag) set_recompilable(); else clear_recompilable(); }
+
+       void set_optimization_level(unsigned int level)
+               { jit_function_set_optimization_level(func, level); }
+       unsigned int optimization_level() const
+               { return jit_function_get_optimization_level(func); }
+       static unsigned int max_optimization_level()
+               { return jit_function_get_max_optimization_level(); }
+
+       void *closure() const { return jit_function_to_closure(func); }
+       void *vtable_pointer() const
+               { return jit_function_to_vtable_pointer(func); }
+
+       int apply(void **args, void *result)
+               { return jit_function_apply(func, args, result); }
+       int apply(jit_type_t signature, void **args, void *return_area)
+               { return jit_function_apply_vararg
+                       (func, signature, args, return_area); }
+
+       static jit_type_t const end_params;
+       static jit_type_t signature_helper(jit_type_t return_type, ...);
+
+protected:
+       virtual void build();
+       virtual jit_type_t create_signature();
+       void fail();
+       void out_of_memory();
+
+public:
+       void build_start()
+               { jit_context_build_start(jit_function_get_context(func)); }
+       void build_end()
+               { jit_context_build_end(jit_function_get_context(func)); }
+
+       jit_value new_value(jit_type_t type);
+       jit_value new_constant(jit_sbyte value, jit_type_t type=0);
+       jit_value new_constant(jit_ubyte value, jit_type_t type=0);
+       jit_value new_constant(jit_short value, jit_type_t type=0);
+       jit_value new_constant(jit_ushort value, jit_type_t type=0);
+       jit_value new_constant(jit_int value, jit_type_t type=0);
+       jit_value new_constant(jit_uint value, jit_type_t type=0);
+       jit_value new_constant(jit_long value, jit_type_t type=0);
+       jit_value new_constant(jit_ulong value, jit_type_t type=0);
+       jit_value new_constant(jit_float32 value, jit_type_t type=0);
+       jit_value new_constant(jit_float64 value, jit_type_t type=0);
+#ifndef JIT_NFLOAT_IS_DOUBLE
+       jit_value new_constant(jit_nfloat value, jit_type_t type=0);
+#endif
+       jit_value new_constant(void *value, jit_type_t type=0);
+       jit_value new_constant(const jit_constant_t& value);
+       jit_value get_param(unsigned int param);
+       jit_value get_struct_pointer();
+
+       void insn_label(jit_label& label);
+       jit_value insn_load(const jit_value& value);
+       jit_value insn_dup(const jit_value& value);
+       jit_value insn_load_small(const jit_value& value);
+       void store(const jit_value& dest, const jit_value& value);
+       jit_value insn_load_relative
+               (const jit_value& value, jit_nint offset, jit_type_t type);
+       void insn_store_relative
+               (const jit_value& dest, jit_nint offset, const jit_value& value);
+       jit_value insn_add_relative(const jit_value& value, jit_nint offset);
+       void insn_check_null(const jit_value& value);
+       jit_value insn_add(const jit_value& value1, const jit_value& value2);
+       jit_value insn_add_ovf(const jit_value& value1, const jit_value& value2);
+       jit_value insn_sub(const jit_value& value1, const jit_value& value2);
+       jit_value insn_sub_ovf(const jit_value& value1, const jit_value& value2);
+       jit_value insn_mul(const jit_value& value1, const jit_value& value2);
+       jit_value insn_mul_ovf(const jit_value& value1, const jit_value& value2);
+       jit_value insn_div(const jit_value& value1, const jit_value& value2);
+       jit_value insn_rem(const jit_value& value1, const jit_value& value2);
+       jit_value insn_rem_ieee(const jit_value& value1, const jit_value& value2);
+       jit_value insn_neg(const jit_value& value1);
+       jit_value insn_and(const jit_value& value1, const jit_value& value2);
+       jit_value insn_or(const jit_value& value1, const jit_value& value2);
+       jit_value insn_xor(const jit_value& value1, const jit_value& value2);
+       jit_value insn_not(const jit_value& value1);
+       jit_value insn_shl(const jit_value& value1, const jit_value& value2);
+       jit_value insn_shr(const jit_value& value1, const jit_value& value2);
+       jit_value insn_ushr(const jit_value& value1, const jit_value& value2);
+       jit_value insn_sshr(const jit_value& value1, const jit_value& value2);
+       jit_value insn_eq(const jit_value& value1, const jit_value& value2);
+       jit_value insn_ne(const jit_value& value1, const jit_value& value2);
+       jit_value insn_lt(const jit_value& value1, const jit_value& value2);
+       jit_value insn_le(const jit_value& value1, const jit_value& value2);
+       jit_value insn_gt(const jit_value& value1, const jit_value& value2);
+       jit_value insn_ge(const jit_value& value1, const jit_value& value2);
+       jit_value insn_cmpl(const jit_value& value1, const jit_value& value2);
+       jit_value insn_cmpg(const jit_value& value1, const jit_value& value2);
+       jit_value insn_to_bool(const jit_value& value1);
+       jit_value insn_to_not_bool(const jit_value& value1);
+       jit_value insn_acos(const jit_value& value1);
+       jit_value insn_asin(const jit_value& value1);
+       jit_value insn_atan(const jit_value& value1);
+       jit_value insn_atan2(const jit_value& value1, const jit_value& value2);
+       jit_value insn_ceil(const jit_value& value1);
+       jit_value insn_cos(const jit_value& value1);
+       jit_value insn_cosh(const jit_value& value1);
+       jit_value insn_exp(const jit_value& value1);
+       jit_value insn_floor(const jit_value& value1);
+       jit_value insn_log(const jit_value& value1);
+       jit_value insn_log10(const jit_value& value1);
+       jit_value insn_pow(const jit_value& value1, const jit_value& value2);
+       jit_value insn_rint(const jit_value& value1);
+       jit_value insn_round(const jit_value& value1);
+       jit_value insn_sin(const jit_value& value1);
+       jit_value insn_sinh(const jit_value& value1);
+       jit_value insn_sqrt(const jit_value& value1);
+       jit_value insn_tan(const jit_value& value1);
+       jit_value insn_tanh(const jit_value& value1);
+       jit_value insn_is_nan(const jit_value& value1);
+       jit_value insn_is_finite(const jit_value& value1);
+       jit_value insn_is_inf(const jit_value& value1);
+       jit_value insn_abs(const jit_value& value1);
+       jit_value insn_min(const jit_value& value1, const jit_value& value2);
+       jit_value insn_max(const jit_value& value1, const jit_value& value2);
+       jit_value insn_sign(const jit_value& value1);
+       void insn_branch(jit_label& label);
+       void insn_branch_if(const jit_value& value, jit_label& label);
+       void insn_branch_if_not(const jit_value& value, jit_label& label);
+       jit_value insn_address_of(const jit_value& value1);
+       jit_value insn_convert
+               (const jit_value& value, jit_type_t type, int overflow_check=0);
+       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=0);
+       jit_value insn_call_indirect
+               (const jit_value& value, jit_type_t signature,
+                jit_value_t *args, unsigned int num_args, int flags=0);
+       jit_value insn_call_indirect_vtable
+               (const jit_value& value, jit_type_t signature,
+                jit_value_t *args, unsigned int num_args, int flags=0);
+       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=0);
+       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);
+       jit_value insn_import(jit_value value);
+       void insn_return(const jit_value& value);
+       void insn_return();
+       void insn_default_return();
+       void insn_throw(const jit_value& value);
+       jit_value insn_get_call_stack();
+
+private:
+       jit_function_t func;
+       jit_context_t context;
+
+       void register_on_demand();
+       static int on_demand_compiler(jit_function_t func);
+       static void free_mapping(void *data);
+};
+
+#endif /* __cplusplus */
+
+#endif /* _JIT_PLUS_H */
diff --git a/include/jit/jit-type.h b/include/jit/jit-type.h
new file mode 100644 (file)
index 0000000..324f14c
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * jit-type.h - Functions for manipulating type descriptors.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_TYPE_H
+#define        _JIT_TYPE_H
+
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Pre-defined type descriptors.
+ */
+extern jit_type_t const jit_type_void;
+extern jit_type_t const jit_type_sbyte;
+extern jit_type_t const jit_type_ubyte;
+extern jit_type_t const jit_type_short;
+extern jit_type_t const jit_type_ushort;
+extern jit_type_t const jit_type_int;
+extern jit_type_t const jit_type_uint;
+extern jit_type_t const jit_type_nint;
+extern jit_type_t const jit_type_nuint;
+extern jit_type_t const jit_type_long;
+extern jit_type_t const jit_type_ulong;
+extern jit_type_t const jit_type_float32;
+extern jit_type_t const jit_type_float64;
+extern jit_type_t const jit_type_nfloat;
+extern jit_type_t const jit_type_void_ptr;
+
+/*
+ * Type descriptors for the system "char", "int", "long", etc types.
+ * These are defined to one of the above values.
+ */
+extern jit_type_t const jit_type_sys_char;
+extern jit_type_t const jit_type_sys_schar;
+extern jit_type_t const jit_type_sys_uchar;
+extern jit_type_t const jit_type_sys_short;
+extern jit_type_t const jit_type_sys_ushort;
+extern jit_type_t const jit_type_sys_int;
+extern jit_type_t const jit_type_sys_uint;
+extern jit_type_t const jit_type_sys_long;
+extern jit_type_t const jit_type_sys_ulong;
+extern jit_type_t const jit_type_sys_longlong;
+extern jit_type_t const jit_type_sys_ulonglong;
+extern jit_type_t const jit_type_sys_float;
+extern jit_type_t const jit_type_sys_double;
+extern jit_type_t const jit_type_sys_long_double;
+
+/*
+ * ABI types for function signatures.
+ */
+typedef enum
+{
+       jit_abi_cdecl,                  /* Native C calling conventions */
+       jit_abi_vararg,                 /* Native C with optional variable arguments */
+       jit_abi_stdcall,                /* Win32 STDCALL (same as cdecl if not Win32) */
+       jit_abi_fastcall                /* Win32 FASTCALL (same as cdecl if not Win32) */
+
+} jit_abi_t;
+
+/*
+ * External function declarations.
+ */
+jit_type_t jit_type_copy(jit_type_t type);
+void jit_type_free(jit_type_t type);
+jit_type_t jit_type_create_struct(jit_type_t *fields, unsigned int num_fields,
+                                  int incref);
+jit_type_t jit_type_create_union(jit_type_t *fields, unsigned int num_fields,
+                                  int incref);
+jit_type_t jit_type_create_signature(jit_abi_t abi, jit_type_t return_type,
+                                     jit_type_t *params,
+                                                                        unsigned int num_params, int incref);
+jit_type_t jit_type_create_pointer(jit_type_t type, int incref);
+jit_type_t jit_type_create_tagged(jit_type_t type, int kind, void *data,
+                                                                 jit_meta_free_func free_func, int incref);
+int jit_type_set_names(jit_type_t type, char **names, unsigned int num_names);
+void jit_type_set_size_and_alignment(jit_type_t type, jit_nint size,
+                                                                        jit_nint alignment);
+void jit_type_set_offset(jit_type_t type, unsigned int field_index,
+                                                jit_nuint offset);
+jit_nuint jit_type_get_size(jit_type_t type);
+jit_nuint jit_type_get_alignment(jit_type_t type);
+unsigned int jit_type_num_fields(jit_type_t type);
+jit_type_t jit_type_get_field(jit_type_t type, unsigned int field_index);
+jit_nuint jit_type_get_offset(jit_type_t type, unsigned int field_index);
+const char *jit_type_get_name(jit_type_t type, unsigned int index);
+#define        JIT_INVALID_NAME        (~((unsigned int)0))
+unsigned int jit_type_find_name(jit_type_t type, const char *name);
+unsigned int jit_type_num_params(jit_type_t type);
+jit_type_t jit_type_get_return(jit_type_t type);
+jit_type_t jit_type_get_param(jit_type_t type, unsigned int param_index);
+jit_abi_t jit_type_get_abi(jit_type_t type);
+jit_type_t jit_type_get_ref(jit_type_t type);
+jit_type_t jit_type_get_tagged_type(jit_type_t type);
+void jit_type_set_tagged_type(jit_type_t type, jit_type_t underlying,
+                              int incref);
+int jit_type_get_tagged_kind(jit_type_t type);
+void *jit_type_get_tagged_data(jit_type_t type);
+void jit_type_set_tagged_data(jit_type_t type, void *data,
+                              jit_meta_free_func free_func);
+int jit_type_is_primitive(jit_type_t type);
+int jit_type_is_struct(jit_type_t type);
+int jit_type_is_union(jit_type_t type);
+int jit_type_is_signature(jit_type_t type);
+int jit_type_is_pointer(jit_type_t type);
+int jit_type_is_tagged(jit_type_t type);
+jit_nuint jit_type_best_alignment(void);
+jit_type_t jit_type_normalize(jit_type_t type);
+jit_type_t jit_type_remove_tags(jit_type_t type);
+jit_type_t jit_type_promote_int(jit_type_t type);
+int jit_type_return_via_pointer(jit_type_t type);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_TYPE_H */
diff --git a/include/jit/jit-util.h b/include/jit/jit-util.h
new file mode 100644 (file)
index 0000000..ea9a056
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * jit-util.h - Utility functions.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_UTIL_H
+#define        _JIT_UTIL_H
+
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Memory allocation routines.
+ */
+void *jit_malloc(unsigned int size);
+void *jit_calloc(unsigned int num, unsigned int size);
+void *jit_realloc(void *ptr, unsigned int size);
+void jit_free(void *ptr);
+void *jit_malloc_exec(unsigned int size);
+void jit_free_exec(void *ptr, unsigned int size);
+void jit_flush_exec(void *ptr, unsigned int size);
+unsigned int jit_exec_page_size(void);
+#define        jit_new(type)           ((type *)jit_malloc(sizeof(type)))
+#define        jit_cnew(type)          ((type *)jit_calloc(1, sizeof(type)))
+
+/*
+ * Memory set/copy/compare routines.
+ */
+void *jit_memset(void *dest, int ch, unsigned int len);
+void *jit_memcpy(void *dest, const void *src, unsigned int len);
+void *jit_memmove(void *dest, const void *src, unsigned int len);
+int   jit_memcmp(const void *s1, const void *s2, unsigned int len);
+void *jit_memchr(const void *str, int ch, unsigned int len);
+
+/*
+ * String routines.  Note: jit_stricmp uses fixed ASCII rules for case
+ * comparison, whereas jit_stricoll uses localized rules.
+ */
+unsigned int jit_strlen(const char *str);
+char *jit_strcpy(char *dest, const char *src);
+char *jit_strcat(char *dest, const char *src);
+char *jit_strncpy(char *dest, const char *src, unsigned int len);
+char *jit_strdup(const char *str);
+char *jit_strndup(const char *str, unsigned int len);
+int jit_strcmp(const char *str1, const char *str2);
+int jit_strncmp(const char *str1, const char *str2, unsigned int len);
+int jit_stricmp(const char *str1, const char *str2);
+int jit_strnicmp(const char *str1, const char *str2, unsigned int len);
+int jit_strcoll(const char *str1, const char *str2);
+int jit_strncoll(const char *str1, const char *str2, unsigned int len);
+int jit_stricoll(const char *str1, const char *str2);
+int jit_strnicoll(const char *str1, const char *str2, unsigned int len);
+char *jit_strchr(const char *str, int ch);
+char *jit_strrchr(const char *str, int ch);
+int jit_sprintf(char *str, const char *format, ...);
+int jit_snprintf(char *str, unsigned int len, const char *format, ...);
+
+/*
+ * Dynamic library routines.
+ */
+typedef void *jit_dynlib_handle_t;
+jit_dynlib_handle_t jit_dynlib_open(const char *name);
+void jit_dynlib_close(jit_dynlib_handle_t handle);
+void *jit_dynlib_get_symbol(jit_dynlib_handle_t handle, const char *symbol);
+const char *jit_dynlib_get_suffix(void);
+void jit_dynlib_set_debug(int flag);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_UTIL_H */
diff --git a/include/jit/jit-value.h b/include/jit/jit-value.h
new file mode 100644 (file)
index 0000000..c72f0f2
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * jit-value.h - Functions for manipulating temporary values.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_VALUE_H
+#define        _JIT_VALUE_H
+
+#include <jit/jit-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Full struction that can hold a constant of any type.
+ */
+typedef struct
+{
+       jit_type_t                      type;
+       union
+       {
+               void               *ptr_value;
+               jit_int                 int_value;
+               jit_uint                uint_value;
+               jit_nint                nint_value;
+               jit_nuint               nuint_value;
+               jit_long                long_value;
+               jit_ulong               ulong_value;
+               jit_float32             float32_value;
+               jit_float64             float64_value;
+               jit_nfloat              nfloat_value;
+
+       } un;
+
+} jit_constant_t;
+
+/*
+ * External function declarations.
+ */
+jit_value_t jit_value_create(jit_function_t func, jit_type_t type) JIT_NOTHROW;
+jit_value_t jit_value_create_nint_constant
+       (jit_function_t func, jit_type_t type, jit_nint const_value) JIT_NOTHROW;
+jit_value_t jit_value_create_long_constant
+       (jit_function_t func, jit_type_t type, jit_long const_value) JIT_NOTHROW;
+jit_value_t jit_value_create_float32_constant
+       (jit_function_t func, jit_type_t type,
+        jit_float32 const_value) JIT_NOTHROW;
+jit_value_t jit_value_create_float64_constant
+       (jit_function_t func, jit_type_t type,
+        jit_float64 const_value) JIT_NOTHROW;
+jit_value_t jit_value_create_nfloat_constant
+       (jit_function_t func, jit_type_t type,
+        jit_nfloat const_value) JIT_NOTHROW;
+jit_value_t jit_value_create_constant
+       (jit_function_t func, const jit_constant_t *const_value) JIT_NOTHROW;
+jit_value_t jit_value_get_param
+       (jit_function_t func, unsigned int param) JIT_NOTHROW;
+jit_value_t jit_value_get_struct_pointer(jit_function_t func) JIT_NOTHROW;
+int jit_value_is_temporary(jit_value_t value) JIT_NOTHROW;
+int jit_value_is_local(jit_value_t value) JIT_NOTHROW;
+int jit_value_is_constant(jit_value_t value) JIT_NOTHROW;
+void jit_value_ref(jit_function_t func, jit_value_t value) JIT_NOTHROW;
+void jit_value_set_volatile(jit_value_t value) JIT_NOTHROW;
+int jit_value_is_volatile(jit_value_t value) JIT_NOTHROW;
+void jit_value_set_addressable(jit_value_t value) JIT_NOTHROW;
+int jit_value_is_addressable(jit_value_t value) JIT_NOTHROW;
+jit_type_t jit_value_get_type(jit_value_t value) JIT_NOTHROW;
+jit_function_t jit_value_get_function(jit_value_t value) JIT_NOTHROW;
+jit_block_t jit_value_get_block(jit_value_t value) JIT_NOTHROW;
+jit_context_t jit_value_get_context(jit_value_t value) JIT_NOTHROW;
+jit_constant_t jit_value_get_constant(jit_value_t value) JIT_NOTHROW;
+jit_nint jit_value_get_nint_constant(jit_value_t value) JIT_NOTHROW;
+jit_long jit_value_get_long_constant(jit_value_t value) JIT_NOTHROW;
+jit_float32 jit_value_get_float32_constant(jit_value_t value) JIT_NOTHROW;
+jit_float64 jit_value_get_float64_constant(jit_value_t value) JIT_NOTHROW;
+jit_nfloat jit_value_get_nfloat_constant(jit_value_t value) JIT_NOTHROW;
+int jit_constant_convert
+       (jit_constant_t *result, const jit_constant_t *value,
+        jit_type_t type, int overflow_check) JIT_NOTHROW;
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_VALUE_H */
diff --git a/include/jit/jit-walk.h b/include/jit/jit-walk.h
new file mode 100644 (file)
index 0000000..0c2df9c
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * jit-walk.h - Functions for walking stack frames.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_WALK_H
+#define        _JIT_WALK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Get the frame address for a frame which is "n" levels up the stack.
+ * A level value of zero indicates the current frame.
+ */
+void *_jit_get_frame_address(void *start, unsigned int n);
+#if defined(__GNUC__)
+#define        jit_get_frame_address(n)        \
+               (_jit_get_frame_address(__builtin_frame_address(0), (n)))
+#else
+#define        jit_get_frame_address(n)        (_jit_get_frame_address(0, (n)))
+#endif
+
+/*
+ * Get the frame address for the current frame.  May be more efficient
+ * than using "jit_get_frame_address(0)".
+ */
+#if defined(__GNUC__)
+#define        jit_get_current_frame()         (__builtin_frame_address(0))
+#else
+#define        jit_get_current_frame()         (jit_get_frame_address(0))
+#endif
+
+/*
+ * Get the next frame up the stack from a specified frame.
+ * Returns NULL if it isn't possible to retrieve the next frame.
+ */
+void *jit_get_next_frame_address(void *frame);
+
+/*
+ * Get the return address for a specific frame.
+ */
+void *_jit_get_return_address(void *frame, void *frame0, void *return0);
+#if defined(__GNUC__)
+#define        jit_get_return_address(frame)   \
+               (_jit_get_return_address        \
+                       ((frame), __builtin_frame_address(0), __builtin_return_address(0)))
+#else
+#define        jit_get_return_address(frame)   \
+               (_jit_get_return_address((frame), 0, 0))
+#endif
+
+/*
+ * Get the return address for the current frame.  May be more efficient
+ * than using "jit_get_return_address(0)".
+ */
+#if defined(__GNUC__)
+#define        jit_get_current_return()        (__builtin_return_address(0))
+#else
+#define        jit_get_current_return()        \
+                       (jit_get_return_address(jit_get_current_frame()))
+#endif
+
+/*
+ * Declare a stack crawl mark variable.  The address of this variable
+ * can be passed to "jit_frame_contains_crawl_mark" to determine
+ * if a frame contains the mark.
+ */
+typedef struct { void * volatile mark; } jit_crawl_mark_t;
+#define        jit_declare_crawl_mark(name)    jit_crawl_mark_t name = {0}
+
+/*
+ * Determine if the stack frame just above "frame" contains a
+ * particular crawl mark.
+ */
+int jit_frame_contains_crawl_mark(void *frame, jit_crawl_mark_t *mark);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_WALK_H */
diff --git a/include/jit/jit.h b/include/jit/jit.h
new file mode 100644 (file)
index 0000000..60c3769
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * jit.h - General definitions for JIT back-ends.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_H
+#define        _JIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <jit/jit-defs.h>
+#include <jit/jit-common.h>
+#include <jit/jit-context.h>
+#include <jit/jit-apply.h>
+#include <jit/jit-block.h>
+#include <jit/jit-elf.h>
+#include <jit/jit-except.h>
+#include <jit/jit-function.h>
+#include <jit/jit-init.h>
+#include <jit/jit-insn.h>
+#include <jit/jit-meta.h>
+#include <jit/jit-opcode.h>
+#include <jit/jit-type.h>
+#include <jit/jit-intrinsic.h>
+#include <jit/jit-util.h>
+#include <jit/jit-value.h>
+#include <jit/jit-walk.h>
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_H */
diff --git a/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..e9de238
--- /dev/null
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       true
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+               chmodcmd=""
+       else
+               instcmd=mkdir
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               true
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               true
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               true
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='   
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               true
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               true
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/jit/.cvsignore b/jit/.cvsignore
new file mode 100644 (file)
index 0000000..3bfe1a5
--- /dev/null
@@ -0,0 +1,4 @@
+Makefile
+Makefile.in
+.deps
+jit-apply-rules.h
diff --git a/jit/Makefile.am b/jit/Makefile.am
new file mode 100644 (file)
index 0000000..1002134
--- /dev/null
@@ -0,0 +1,52 @@
+
+lib_LIBRARIES = libjit.a
+
+libjit_a_SOURCES = \
+               jit-alloc.c \
+               jit-apply.c \
+               jit-apply-func.h \
+               jit-apply-arm.h \
+               jit-apply-arm.c \
+               jit-apply-x86.h \
+               jit-apply-x86.c \
+               jit-block.c \
+               jit-cache.c \
+               jit-context.c \
+               jit-dump.c \
+               jit-dynlib.c \
+               jit-elf-defs.h \
+               jit-elf-read.c \
+               jit-elf-write.c \
+               jit-except.cpp \
+               jit-function.c \
+               jit-gen-arm.h \
+               jit-gen-arm.c \
+               jit-gen-x86.h \
+               jit-insn.c \
+               jit-init.c \
+               jit-internal.h \
+               jit-interp.cpp \
+               jit-intrinsic.c \
+               jit-live.c \
+               jit-memory.c \
+               jit-memory.h \
+               jit-meta.c \
+               jit-opcode.c \
+               jit-pool.c \
+               jit-reg-alloc.h \
+               jit-reg-alloc.c \
+               jit-rules.h \
+               jit-rules.c \
+               jit-rules-interp.c \
+               jit-rules-arm.h \
+               jit-rules-arm.c \
+               jit-rules-x86.h \
+               jit-rules-x86.c \
+               jit-string.c \
+               jit-thread.c \
+               jit-type.c \
+               jit-value.c \
+               jit-walk.c
+
+AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I. -I$(srcdir)
+AM_CXXFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I. -I$(srcdir)
diff --git a/jit/jit-alloc.c b/jit/jit-alloc.c
new file mode 100644 (file)
index 0000000..730944b
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * jit-alloc.c - Memory allocation routines.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include <config.h>
+#ifdef HAVE_STDLIB_H
+       #include <stdlib.h>
+#endif
+#ifndef JIT_WIN32_PLATFORM
+#ifdef HAVE_SYS_TYPES_H
+       #include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+       #include <unistd.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+       #include <sys/mman.h>
+#endif
+#ifdef HAVE_FCNTL_H
+       #include <fcntl.h>
+#endif
+#else /* JIT_WIN32_PLATFORM */
+       #include <windows.h>
+       #include <io.h>
+#endif
+
+/*@
+ * @section Memory allocation
+ *
+ * The @code{libjit} library provides an interface to the traditional
+ * system @code{malloc} routines.  All heap allocation in @code{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.
+@*/
+
+/*@
+ * @deftypefun {void *} jit_malloc ({unsigned int} size)
+ * Allocate @code{size} bytes of memory from the heap.
+ * @end deftypefun
+ *
+ * @deftypefun {type *} jit_new (type)
+ * Allocate @code{sizeof(type)} bytes of memory from the heap and
+ * cast the return pointer to @code{type *}.  This is a macro that
+ * wraps up the underlying @code{jit_malloc} function and is less
+ * error-prone when allocating structures.
+ * @end deftypefun
+@*/
+void *jit_malloc(unsigned int size)
+{
+       return malloc(size);
+}
+
+/*@
+ * @deftypefun {void *} jit_calloc ({unsigned int} num, {unsigned int} size)
+ * Allocate @code{num * size} bytes of memory from the heap and clear
+ * them to zero.
+ * @end deftypefun
+ *
+ * @deftypefun {type *} jit_cnew (type)
+ * Allocate @code{sizeof(type)} bytes of memory from the heap and
+ * cast the return pointer to @code{type *}.  The memory is cleared
+ * to zero.
+ * @end deftypefun
+@*/
+void *jit_calloc(unsigned int num, unsigned int size)
+{
+       return calloc(num, size);
+}
+
+/*@
+ * @deftypefun {void *} jit_realloc ({void *} ptr, {unsigned int} size)
+ * Re-allocate the memory at @code{ptr} to be @code{size} bytes in size.
+ * The memory block at @code{ptr} must have been allocated by a previous
+ * call to @code{jit_malloc}, @code{jit_calloc}, or @code{jit_realloc}.
+ * @end deftypefun
+@*/
+void *jit_realloc(void *ptr, unsigned int size)
+{
+       return realloc(ptr, size);
+}
+
+/*@
+ * @deftypefun void jit_free ({void *} ptr)
+ * Free the memory at @code{ptr}.  It is safe to pass a NULL pointer.
+ * @end deftypefun
+@*/
+void jit_free(void *ptr)
+{
+       if(ptr)
+       {
+               free(ptr);
+       }
+}
+
+/*@
+ * @deftypefun {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 @code{jit_exec_page_size()}.
+ *
+ * This will usually be identical to @code{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 @code{jit_free} to free the result of @code{jit_malloc_exec}.
+ * @end deftypefun
+@*/
+void *jit_malloc_exec(unsigned int size)
+{
+       return malloc(size);
+}
+
+/*@
+ * @deftypefun void jit_free_exec ({void *} ptr, {unsigned int} size)
+ * Free a block of memory that was previously allocated by
+ * @code{jit_malloc_exec}.  The @code{size} must be identical to the
+ * original allocated size, as some systems need to know this information
+ * to be able to free the block.
+ * @end deftypefun
+@*/
+void jit_free_exec(void *ptr, unsigned int size)
+{
+       if(ptr)
+       {
+               free(ptr);
+       }
+}
+
+/*@
+ * @deftypefun void jit_flush_exec ({void *} ptr, {unsigned int} size)
+ * Flush the contents of the block at @code{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.
+ * @end deftypefun
+@*/
+void jit_flush_exec(void *ptr, unsigned int size)
+{
+#if defined(__GNUC__)
+#if defined(PPC)
+
+       /* Flush the CPU cache on PPC platforms */
+       register unsigned char *p;
+
+       /* Flush the data out of the data cache */
+       p = (unsigned char *)ptr;
+       while(size > 0)
+       {
+               __asm__ __volatile__ ("dcbst 0,%0" :: "r"(p));
+               p += 4;
+               size -= 4;
+       }
+       __asm__ __volatile__ ("sync");
+
+       /* Invalidate the cache lines in the instruction cache */
+       p = (unsigned char *)ptr;
+       while(size > 0)
+       {
+               __asm__ __volatile__ ("icbi 0,%0; isync" :: "r"(p));
+               p += 4;
+               size -= 4;
+       }
+       __asm__ __volatile__ ("isync");
+
+#elif defined(__sparc)
+
+       /* Flush the CPU cache on sparc platforms */
+       register unsigned char *p = (unsigned char *)ptr;
+       __asm__ __volatile__ ("stbar");
+       while(size > 0)
+       {
+               __asm__ __volatile__ ("flush %0" :: "r"(p));
+               p += 4;
+               size -= 4;
+       }
+       __asm__ __volatile__ ("nop; nop; nop; nop; nop");
+
+#elif (defined(__arm__) || defined(__arm)) && defined(linux)
+
+       /* ARM Linux has a "cacheflush" system call */
+       /* R0 = start of range, R1 = end of range, R3 = flags */
+       /* flags = 0 indicates data cache, flags = 1 indicates both caches */
+       __asm __volatile ("mov r0, %0\n"
+                         "mov r1, %1\n"
+                                         "mov r2, %2\n"
+                                         "swi 0x9f0002       @ sys_cacheflush"
+                                         : /* no outputs */
+                                         : "r" (ptr),
+                                           "r" (((int)ptr) + (int)size),
+                                               "r" (0)
+                                         : "r0", "r1", "r3" );
+
+#elif (defined(__ia64) || defined(__ia64__)) && defined(linux)
+       void *end = (char*)ptr + size;
+       while(ptr < end)
+       {
+               asm volatile("fc %0" :: "r"(ptr));
+               ptr = (char*)ptr + 32;
+       }
+       asm volatile(";;sync.i;;srlz.i;;");
+#endif
+#endif /* __GNUC__ */
+}
+
+/*@
+ * @deftypefun {unsigned int} jit_exec_page_size (void)
+ * Get the page allocation size for the system.  This is the preferred
+ * unit when making calls to @code{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.
+ * @end deftypefun
+@*/
+unsigned int jit_exec_page_size(void)
+{
+#ifndef JIT_WIN32_PLATFORM
+       /* Get the page size using a Unix-like sequence */
+       #ifdef HAVE_GETPAGESIZE
+               return (unsigned long)getpagesize();
+       #else
+               #ifdef NBPG
+                       return NBPG;
+               #else
+                       #ifdef PAGE_SIZE
+                               return PAGE_SIZE;
+                       #else
+                               return 4096;
+                       #endif
+               #endif
+       #endif
+#else
+       /* Get the page size from a Windows-specific API */
+       SYSTEM_INFO sysInfo;
+       GetSystemInfo(&sysInfo);
+       return (unsigned long)(sysInfo.dwPageSize);
+#endif
+}
diff --git a/jit/jit-apply-arm.c b/jit/jit-apply-arm.c
new file mode 100644 (file)
index 0000000..dd16e23
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * jit-apply-arm.c - Apply support routines for ARM.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+
+#if defined(__arm) || defined(__arm__)
+
+#include "jit-gen-arm.h"
+
+void _jit_create_closure(unsigned char *buf, void *func,
+                         void *closure, void *_type)
+{
+       arm_inst_ptr inst = (arm_inst_ptr)buf;
+
+       /* Set up the local stack frame */
+       arm_setup_frame(inst, 0);
+       arm_alu_reg_imm8(inst, ARM_SUB, ARM_SP, ARM_SP, 24);
+
+       /* Create the apply argument block on the stack */
+       arm_store_membase(inst, ARM_R0, ARM_FP, -28);
+       arm_store_membase(inst, ARM_R1, ARM_FP, -24);
+       arm_store_membase(inst, ARM_R2, ARM_FP, -20);
+       arm_store_membase(inst, ARM_R3, ARM_FP, -16);
+       arm_alu_reg_imm(inst, ARM_ADD, ARM_R3, ARM_FP, 4);
+       arm_store_membase(inst, ARM_R3, ARM_FP, -36);
+       arm_store_membase(inst, ARM_R0, ARM_FP, -32);
+
+       /* Set up the arguments for calling "func" */
+       arm_mov_reg_imm(inst, ARM_R0, (int)(jit_nint)closure);
+       arm_mov_reg_reg(inst, ARM_R1, ARM_SP);
+
+       /* Call the closure handling function */
+       arm_call(inst, func);
+
+       /* Pop the current stack frame and return */
+       arm_pop_frame(inst, 0);
+}
+
+void *_jit_create_redirector(unsigned char *buf, void *func,
+                                                        void *user_data, int abi)
+{
+       arm_inst_ptr inst;
+
+       /* Align "buf" on an appropriate boundary */
+       if((((jit_nint)buf) % jit_closure_align) != 0)
+       {
+               buf += jit_closure_align - (((jit_nint)buf) % jit_closure_align);
+       }
+
+       /* Set up the instruction output pointer */
+       inst = (arm_inst_ptr)buf;
+
+       /* Set up the local stack frame, and save R0-R3 */
+       arm_setup_frame(inst, 0x000F);
+
+       /* Set up the arguments for calling "func" */
+       arm_mov_reg_imm(inst, ARM_R0, (int)(jit_nint)user_data);
+
+       /* Call the redirector handling function */
+       arm_call(inst, func);
+
+       /* Shift the result into R12, because we are about to restore R0 */
+       arm_mov_reg_reg(inst, ARM_R12, ARM_R0);
+
+       /* Pop the current stack frame, but don't change PC yet */
+       arm_pop_frame_tail(inst, 0x000F);
+
+       /* Jump to the function that the redirector indicated */
+       arm_mov_reg_reg(inst, ARM_PC, ARM_R12);
+
+       /* Flush the cache lines that we just wrote */
+       jit_flush_exec(buf, ((unsigned char *)inst) - buf);
+
+       /* Return the aligned start of the buffer as the entry point */
+       return (void *)buf;
+}
+
+#endif /* arm */
diff --git a/jit/jit-apply-arm.h b/jit/jit-apply-arm.h
new file mode 100644 (file)
index 0000000..ce0fbc4
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * jit-apply-arm.h - Special definitions for ARM function application.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_APPLY_ARM_H
+#define        _JIT_APPLY_ARM_H
+
+/*
+ * The maximum number of bytes that are needed to represent a closure,
+ * and the alignment to use for the closure.
+ */
+#define        jit_closure_size                128
+#define        jit_closure_align               16
+
+/*
+ * The number of bytes that are needed for a redirector stub.
+ * This includes any extra bytes that are needed for alignment.
+ */
+#define        jit_redirector_size             128
+
+#endif /* _JIT_APPLY_ARM_H */
diff --git a/jit/jit-apply-func.h b/jit/jit-apply-func.h
new file mode 100644 (file)
index 0000000..54424d5
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * jit-apply-func.h - Definition of "__builtin_apply" and friends.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_APPLY_FUNC_H
+#define        _JIT_APPLY_FUNC_H
+
+#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
+
+#include "jit-apply-x86.h"
+
+#elif defined(__arm) || defined(__arm__)
+
+#include "jit-apply-arm.h"
+
+#endif
+
+#if !defined(jit_builtin_apply)
+
+#define        jit_builtin_apply(func,args,size,return_float,return_buf)       \
+               do { \
+                       (return_buf) = __builtin_apply \
+                                       ((void (*)())(func), (args), (size)); \
+               } while (0)
+
+#define        jit_builtin_apply_args(type,args)       \
+               do { \
+                       (args) = (type)__builtin_apply_args(); \
+               } while (0)
+
+#define        jit_builtin_return_int(return_buf)      \
+               do { \
+                       __builtin_return((return_buf)); \
+               } while (0)
+
+#define        jit_builtin_return_float(return_buf)    \
+               do { \
+                       __builtin_return((return_buf)); \
+               } while (0)
+
+#endif
+
+/*
+ * Create a closure for the underlying platform in the given buffer.
+ * The closure must arrange to call "func" with two arguments:
+ * "closure" and a pointer to an apply structure.
+ */
+void _jit_create_closure(unsigned char *buf, void *func,
+                         void *closure, void *type);
+
+/*
+ * Create a redirector stub for the underlying platform in the given buffer.
+ * The redirector arranges to call "func" with the "user_data" argument.
+ * It is assumed that "func" returns a pointer to the actual function.
+ * Returns a pointer to the position in "buf" where the redirector starts,
+ * which may be different than "buf" if alignment occurred.
+ */
+void *_jit_create_redirector(unsigned char *buf, void *func,
+                                                        void *user_data, int abi);
+
+/*
+ * Pad a buffer with NOP instructions.  Used to align code.
+ * This will only be called if "jit_should_pad" is defined.
+ */
+void _jit_pad_buffer(unsigned char *buf, int len);
+
+#endif /* _JIT_APPLY_FUNC_H */
diff --git a/jit/jit-apply-x86.c b/jit/jit-apply-x86.c
new file mode 100644 (file)
index 0000000..04d20c8
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * jit-apply-x86.c - Apply support routines for x86.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-apply-rules.h"
+#include "jit-apply-func.h"
+
+#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
+
+#include "jit-gen-x86.h"
+
+void _jit_create_closure(unsigned char *buf, void *func,
+                         void *closure, void *_type)
+{
+       jit_type_t signature = (jit_type_t)_type;
+       jit_type_t type;
+#if JIT_APPLY_X86_FASTCALL == 1
+       jit_abi_t abi = jit_type_get_abi(signature);
+#endif
+       unsigned int num_bytes = 0;
+       int struct_return_offset = 0;
+
+       /* Set up the local stack frame */
+       x86_push_reg(buf, X86_EBP);
+       x86_mov_reg_reg(buf, X86_EBP, X86_ESP, 4);
+
+       /* Create the apply argument block on the stack */
+#if JIT_APPLY_X86_FASTCALL == 1
+       if(abi == jit_abi_fastcall)
+       {
+               x86_push_reg(buf, X86_EDX);
+               x86_push_reg(buf, X86_ECX);
+       }
+#endif
+       x86_lea_membase(buf, X86_EAX, X86_EBP, 8);
+       x86_push_reg(buf, X86_EAX);
+
+       /* Push the arguments for calling "func" */
+       x86_mov_reg_reg(buf, X86_EAX, X86_ESP, 4);
+       x86_push_reg(buf, X86_EAX);
+       x86_push_imm(buf, (int)closure);
+
+       /* Call the closure handling function */
+       x86_call_code(buf, func);
+
+       /* Determine the number of bytes to pop when we return */
+#if JIT_APPLY_X86_FASTCALL == 1
+       if(abi == jit_abi_stdcall || abi == jit_abi_fastcall)
+       {
+               unsigned int word_regs;
+               unsigned int size;
+               unsigned int num_params;
+               unsigned int param;
+               if(abi == jit_abi_stdcall)
+               {
+                       word_regs = 0;
+               }
+               else
+               {
+                       word_regs = 2;
+               }
+               type = jit_type_normalize(jit_type_get_return(signature));
+               if(jit_type_return_via_pointer(type))
+               {
+                       if(word_regs > 0)
+                       {
+                               --word_regs;
+                       }
+                       else
+                       {
+                               num_bytes += sizeof(void *);
+                               struct_return_offset = 2 * sizeof(void *);
+                       }
+               }
+               num_params = jit_type_num_params(signature);
+               for(param = 0; param < num_params; ++param)
+               {
+                       type = jit_type_normalize(jit_type_get_param(signature, param));
+                       size = jit_type_get_size(type);
+                       if(word_regs > 0)
+                       {
+                               switch(type->kind)
+                               {
+                                       case JIT_TYPE_SBYTE:
+                                       case JIT_TYPE_UBYTE:
+                                       case JIT_TYPE_SHORT:
+                                       case JIT_TYPE_USHORT:
+                                       case JIT_TYPE_INT:
+                                       case JIT_TYPE_UINT:
+                                       case JIT_TYPE_NINT:
+                                       case JIT_TYPE_NUINT:
+                                       case JIT_TYPE_SIGNATURE:
+                                       case JIT_TYPE_PTR:
+                                       {
+                                               --word_regs;
+                                       }
+                                       continue;
+
+                                       case JIT_TYPE_LONG:
+                                       case JIT_TYPE_ULONG:
+                                       {
+                                               if(word_regs == 1)
+                                               {
+                                                       num_bytes += sizeof(void *);
+                                               }
+                                               word_regs = 0;
+                                       }
+                                       continue;
+                               }
+                               word_regs = 0;
+                       }
+                       num_bytes += (size + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
+               }
+       }
+       else
+#endif
+       {
+               type = jit_type_normalize(jit_type_get_return(signature));
+               if(jit_type_return_via_pointer(type))
+               {
+#if JIT_APPLY_X86_POP_STRUCT_RETURN == 1
+                       /* Pop the structure return pointer as we return back */
+                       num_bytes += sizeof(void *);
+#endif
+                       struct_return_offset = 2 * sizeof(void *);
+               }
+       }
+
+       /* If we are returning a structure via a pointer, then load
+          the address of the structure into the EAX register */
+       if(struct_return_offset != 0)
+       {
+               x86_mov_reg_membase(buf, X86_EAX, X86_EBP, struct_return_offset, 4);
+       }
+
+       /* Pop the current stack frame */
+       x86_mov_reg_reg(buf, X86_ESP, X86_EBP, 4);
+       x86_pop_reg(buf, X86_EBP);
+
+       /* Return from the closure */
+       if(num_bytes > 0)
+       {
+               x86_ret_imm(buf, num_bytes);
+       }
+       else
+       {
+               x86_ret(buf);
+       }
+}
+
+void *_jit_create_redirector(unsigned char *buf, void *func,
+                                                        void *user_data, int abi)
+{
+       void *start = (void *)buf;
+
+       /* Set up a new stack frame */
+       x86_push_reg(buf, X86_EBP);
+       x86_mov_reg_reg(buf, X86_EBP, X86_ESP, 4);
+
+       /* Save the fastcall registers, if necessary */
+#if JIT_APPLY_X86_FASTCALL == 1
+       if(abi == (int)jit_abi_fastcall)
+       {
+               x86_push_reg(buf, X86_EDX);
+               x86_push_reg(buf, X86_ECX);
+       }
+#endif
+
+       /* Push the user data onto the stack */
+       x86_push_imm(buf, (int)user_data);
+
+       /* Call "func" (the pointer result will be in EAX) */
+       x86_call_code(buf, func);
+
+       /* Remove the user data from the stack */
+       x86_pop_reg(buf, X86_ECX);
+
+       /* Restore the fastcall registers, if necessary */
+#if JIT_APPLY_X86_FASTCALL == 1
+       if(abi == (int)jit_abi_fastcall)
+       {
+               x86_pop_reg(buf, X86_ECX);
+               x86_pop_reg(buf, X86_EDX);
+       }
+#endif
+
+       /* Restore the value of EBP */
+       x86_pop_reg(buf, X86_EBP);
+
+       /* Jump to the function that the redirector indicated */
+       x86_jump_reg(buf, X86_EAX);
+
+       /* Return the start of the buffer as the redirector entry point */
+       return start;
+}
+
+void _jit_pad_buffer(unsigned char *buf, int len)
+{
+       while(len >= 6)
+       {
+               /* "leal 0(%esi), %esi" with 32-bit displacement */
+               *buf++ = (unsigned char)0x8D;
+               x86_address_byte(buf, 2, X86_ESI, X86_ESI);
+               x86_imm_emit32(buf, 0);
+               len -= 6;
+       }
+       if(len >= 3)
+       {
+               /* "leal 0(%esi), %esi" with 8-bit displacement */
+               *buf++ = (unsigned char)0x8D;
+               x86_address_byte(buf, 1, X86_ESI, X86_ESI);
+               x86_imm_emit8(buf, 0);
+               len -= 3;
+       }
+       if(len == 1)
+       {
+               /* Traditional x86 NOP */
+               x86_nop(buf);
+       }
+       else if(len == 2)
+       {
+               /* movl %esi, %esi */
+               x86_mov_reg_reg(buf, X86_ESI, X86_ESI, 4);
+       }
+}
+
+#endif /* x86 */
diff --git a/jit/jit-apply-x86.h b/jit/jit-apply-x86.h
new file mode 100644 (file)
index 0000000..1467e1d
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * jit-apply-x86.h - Special definitions for x86 function application.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_APPLY_X86_H
+#define        _JIT_APPLY_X86_H
+
+/*
+ * The "__builtin_apply" functionality in gcc has some problems
+ * dealing with floating-point values, and it also doesn't handle
+ * STDCALL and FASTCALL functions well.  Therefore, we use assembly
+ * code instead.
+ *
+ * There are three versions here: gcc/non-Win32, gcc/Win32, and msvc/Win32.
+ */
+
+#if defined(__GNUC__)
+
+#if !defined(__CYGWIN__) && !defined(__CYGWIN32__) && \
+       !defined(_WIN32) && !defined(WIN32)
+
+#define        jit_builtin_apply(func,args,size,return_float,return_buf)       \
+               do { \
+                       void *__func = (void *)(func); \
+                       void *__args = (void *)(args); \
+                       void *__size = (void *)(size); \
+                       void *__return_buf = alloca(20); \
+                       (return_buf) = __return_buf; \
+                       __asm__ ( \
+                               "pushl %%esi\n\t" \
+                               "movl %%esp, %%esi\n\t" \
+                               "subl %2, %%esp\n\t" \
+                               "movl %%esp, %%eax\n\t" \
+                               "movl %1, %%ecx\n\t" \
+                               "movl (%%ecx), %%ecx\n\t" \
+                               "pushl %2\n\t" \
+                               "pushl %%ecx\n\t" \
+                               "pushl %%eax\n\t" \
+                               "call memcpy\n\t" \
+                               "addl $12, %%esp\n\t" \
+                               "movl %1, %%ecx\n\t" \
+                               "movl %0, %%eax\n\t" \
+                               "call *%%eax\n\t" \
+                               "movl %3, %%ecx\n\t" \
+                               "movl %%eax, (%%ecx)\n\t" \
+                               "movl %%edx, 4(%%ecx)\n\t" \
+                               "movl %%esi, %%esp\n\t" \
+                               "popl %%esi\n\t" \
+                               : : "m"(__func), "m"(__args), "m"(__size), "m"(__return_buf) \
+                               : "eax", "ecx", "edx" \
+                       ); \
+                       if((return_float)) \
+                       { \
+                               __asm__ ( \
+                                       "movl %0, %%ecx\n\t" \
+                                       "fstpt 8(%%ecx)\n\t" \
+                                       : : "m"(__return_buf) \
+                                       : "ecx", "st" \
+                               ); \
+                       } \
+               } while (0)
+
+#define        jit_builtin_apply_args(type,args)       \
+               do { \
+                       void *__args = alloca(4); \
+                       __asm__ ( \
+                               "leal 8(%%ebp), %%eax\n\t" \
+                               "movl %0, %%ecx\n\t" \
+                               "movl %%eax, (%%ecx)\n\t" \
+                               : : "m"(__args) \
+                               : "eax", "ecx" \
+                       ); \
+                       (args) = (type)__args; \
+               } while (0)
+
+#define        jit_builtin_return_int(return_buf)      \
+               do { \
+                       __asm__ ( \
+                               "movl %0, %%ecx\n\t" \
+                               "movl (%%ecx), %%eax\n\t" \
+                               "movl 4(%%ecx), %%edx\n\t" \
+                               : : "m"((return_buf)) \
+                               : "eax", "ecx", "edx" \
+                       ); \
+                       return; \
+               } while (0)
+
+#define        jit_builtin_return_float(return_buf)    \
+               do { \
+                       jit_nfloat __value = \
+                               ((jit_apply_return *)(return_buf))-> \
+                                       f_value.inner_value.nfloat_value; \
+                       if(sizeof(jit_nfloat) == sizeof(double)) \
+                       { \
+                               __asm__ ( \
+                                       "leal %0, %%ecx\n\t" \
+                                       "fldl (%%ecx)\n\t" \
+                                       : : "m"(__value) \
+                                       : "ecx", "st" \
+                               ); \
+                       } \
+                       else \
+                       { \
+                               __asm__ ( \
+                                       "leal %0, %%ecx\n\t" \
+                                       "fldt (%%ecx)\n\t" \
+                                       : : "m"(__value) \
+                                       : "ecx", "st" \
+                               ); \
+                       } \
+                       return; \
+               } while (0)
+
+#else /* Win32 */
+
+#define        jit_builtin_apply(func,args,size,return_float,return_buf)       \
+               do { \
+                       void *__func = (void *)(func); \
+                       void *__args = (void *)(args); \
+                       void *__size = (void *)(size); \
+                       void *__return_buf = alloca(20); \
+                       (return_buf) = __return_buf; \
+                       __asm__ ( \
+                               "pushl %%esi\n\t" \
+                               "movl %%esp, %%esi\n\t" \
+                               "subl %2, %%esp\n\t" \
+                               "movl %%esp, %%eax\n\t" \
+                               "movl %1, %%ecx\n\t" \
+                               "movl (%%ecx), %%ecx\n\t" \
+                               "pushl %2\n\t" \
+                               "pushl %%ecx\n\t" \
+                               "pushl %%eax\n\t" \
+                               "call _memcpy\n\t" \
+                               "addl $12, %%esp\n\t" \
+                               "movl %1, %%ecx\n\t" \
+                               "movl 8(%%ecx), %%edx\n\t" \
+                               "movl 4(%%ecx), %%ecx\n\t" \
+                               "movl %0, %%eax\n\t" \
+                               "call *%%eax\n\t" \
+                               "movl %3, %%ecx\n\t" \
+                               "movl %%eax, (%%ecx)\n\t" \
+                               "movl %%edx, 4(%%ecx)\n\t" \
+                               "movl %%esi, %%esp\n\t" \
+                               "popl %%esi\n\t" \
+                               : : "m"(__func), "m"(__args), "m"(__size), "m"(__return_buf) \
+                               : "eax", "ecx", "edx" \
+                       ); \
+                       if((return_float)) \
+                       { \
+                               __asm__ ( \
+                                       "movl %0, %%ecx\n\t" \
+                                       "fstpt 8(%%ecx)\n\t" \
+                                       : : "m"(__return_buf) \
+                                       : "ecx", "st" \
+                               ); \
+                       } \
+               } while (0)
+
+#define        jit_builtin_apply_args(type,args)       \
+               do { \
+                       void *__args = alloca(12); \
+                       __asm__ ( \
+                               "movl %0, %%eax\n\t" \
+                               "movl %%ecx, 4(%%eax)\n\t" \
+                               "movl %%edx, 8(%%eax)\n\t" \
+                               "leal 8(%%ebp), %%ecx\n\t" \
+                               "movl %%ecx, (%%eax)\n\t" \
+                               : : "m"(__args) \
+                               : "eax", "ecx", "edx" \
+                       ); \
+                       (args) = (type)__args; \
+               } while (0)
+
+#define        jit_builtin_return_int(return_buf)      \
+               do { \
+                       __asm__ ( \
+                               "movl %0, %%ecx\n\t" \
+                               "movl (%%ecx), %%eax\n\t" \
+                               "movl 4(%%ecx), %%edx\n\t" \
+                               : : "m"((return_buf)) \
+                               : "eax", "ecx", "edx" \
+                       ); \
+                       return; \
+               } while (0)
+
+#define        jit_builtin_return_float(return_buf)    \
+               do { \
+                       double __value = \
+                               ((jit_apply_return *)(return_buf))-> \
+                                       f_value.inner_value.nfloat_value; \
+                       __asm__ ( \
+                               "leal %0, %%ecx\n\t" \
+                               "fldl (%%ecx)\n\t" \
+                               : : "m"(__value) \
+                               : "ecx", "st" \
+                       ); \
+                       return; \
+               } while (0)
+
+#endif /* Win32 */
+
+#elif defined(_MSC_VER)
+
+#define        jit_builtin_apply(func,args,size,return_float,return_buf)       \
+               do { \
+                       void *__func = (void *)(func); \
+                       void *__args = (void *)(args); \
+                       void *__size = (void *)(size); \
+                       void *__return_buf = alloca(20); \
+                       (return_buf) = __return_buf; \
+                       __asm { \
+                               __asm push esi \
+                               __asm mov esi, esp \
+                               __asm sub esp, dword ptr __size \
+                               __asm mov eax, esp \
+                               __asm mov ecx, dword ptr __args \
+                               __asm mov ecx, [ecx] \
+                               __asm push dword ptr __size \
+                               __asm push ecx \
+                               __asm push eax \
+                               __asm call jit_memcpy \
+                               __asm add esp, 12 \
+                               __asm mov ecx, dword ptr __args \
+                               __asm mov edx, [ecx + 8] \
+                               __asm mov ecx, [ecx + 4] \
+                               __asm mov eax, dword ptr __func \
+                               __asm call eax \
+                               __asm mov ecx, dword ptr __return_buf \
+                               __asm mov [ecx], eax \
+                               __asm mov [ecx + 4], edx \
+                               __asm mov esp, esi \
+                               __asm pop esi \
+                       } \
+                       if((return_float)) \
+                       { \
+                               __asm { \
+                                       __asm mov ecx, dword ptr __return_buf \
+                                       /*__asm fstpt [ecx + 8]*/ \
+                                       __asm _emit 0xDB \
+                                       __asm _emit 0x79 \
+                                       __asm _emit 0x08 \
+                               } \
+                       } \
+               } while (0)
+
+#define        jit_builtin_apply_args(type,args)       \
+               do { \
+                       void *__args = alloca(12); \
+                       __asm { \
+                               __asm mov eax, dword ptr __args \
+                               __asm mov [eax + 4], ecx \
+                               __asm mov [eax + 8], edx \
+                               __asm lea ecx, [ebp + 8] \
+                               __asm mov [eax], ecx \
+                       } \
+                       (args) = (type)(__args); \
+               } while (0)
+
+#define        jit_builtin_return_int(return_buf)      \
+               do { \
+                       void *__return_buf = (void *)(return_buf); \
+                       __asm { \
+                               __asm mov ecx, dword ptr __return_buf \
+                               __asm mov eax, [ecx] \
+                               __asm mov edx, [ecx + 4] \
+                       } \
+                       return; \
+               } while (0)
+
+#define        jit_builtin_return_float(return_buf)    \
+               do { \
+                       double __value = \
+                               ((jit_apply_return *)(return_buf))-> \
+                                       f_value.inner_value.nfloat_value; \
+                       __asm { \
+                               __asm lea ecx, dword ptr __value \
+                               /* __asm fldl [ecx] */ \
+                               __asm _emit 0xDD \
+                               __asm _emit 0x01 \
+                       } \
+                       return; \
+               } while (0)
+
+#endif /* MSC_VER */
+
+/*
+ * The maximum number of bytes that are needed to represent a closure,
+ * and the alignment to use for the closure.
+ */
+#define        jit_closure_size                64
+#define        jit_closure_align               32
+
+/*
+ * The number of bytes that are needed for a redirector stub.
+ * This includes any extra bytes that are needed for alignment.
+ */
+#define        jit_redirector_size             32
+
+/*
+ * We should pad unused code space with NOP's.
+ */
+#define        jit_should_pad                  1
+
+#endif /* _JIT_APPLY_X86_H */
diff --git a/jit/jit-apply.c b/jit/jit-apply.c
new file mode 100644 (file)
index 0000000..3876f22
--- /dev/null
@@ -0,0 +1,980 @@
+/*
+ * jit-apply.c - Dynamic invocation and closure support functions.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-memory.h"
+#include "jit-apply-rules.h"
+#include "jit-apply-func.h"
+#include "jit-cache.h"
+#if HAVE_ALLOCA_H
+       #include <alloca.h>
+#endif
+#ifdef JIT_WIN32_PLATFORM
+       #include <malloc.h>
+       #ifndef alloca
+               #define alloca  _alloca
+       #endif
+#endif
+
+/*
+
+If you need to tweak the way that this code behaves for a specific
+platform, then you would normally do it in "tools/gen-apply.c" or
+the CPU-specific "jit-apply-XXX.h" file, not here.
+
+*/
+
+/*@
+
+@section Function application and closures
+@cindex Function application
+@cindex Closures
+@cindex jit-apply.h
+
+Sometimes all you have for a function is a pointer to it and a dynamic
+description of its arguments.  Calling such a function can be extremely
+difficult in standard C.  The routines in this section, particularly
+@code{jit_apply}, provide a convenient interface for doing this.
+
+At other times, you may wish to wrap up one of your own dynamic functions
+in such a way that it appears to be a regular C function.  This is
+performed with @code{jit_closure_create}.
+
+@*/
+
+/*
+ * Flags that indicate which structure sizes are returned in registers.
+ */
+unsigned char const _jit_apply_return_in_reg[] =
+               JIT_APPLY_STRUCT_RETURN_IN_REG_INIT;
+
+/*
+ * Get the maximum argument stack size of a signature type.
+ */
+static unsigned int jit_type_get_max_arg_size(jit_type_t signature)
+{
+       unsigned int size;
+       unsigned int typeSize;
+       unsigned int param;
+       jit_type_t type;
+       if(signature->size)
+       {
+               /* We have a cached argument size from last time */
+               return signature->size;
+       }
+       size = 0;
+       param = jit_type_num_params(signature);
+       while(param > 0)
+       {
+               --param;
+               type = jit_type_normalize(jit_type_get_param(signature, param));
+               switch(type->kind)
+               {
+                       case JIT_TYPE_SBYTE:
+                       case JIT_TYPE_UBYTE:
+                       case JIT_TYPE_SHORT:
+                       case JIT_TYPE_USHORT:
+                       case JIT_TYPE_INT:
+                       case JIT_TYPE_UINT:
+                       case JIT_TYPE_NINT:
+                       case JIT_TYPE_NUINT:
+                       case JIT_TYPE_PTR:
+                       case JIT_TYPE_SIGNATURE:
+                       {
+                               size += sizeof(jit_nint);
+                       }
+                       break;
+
+                       case JIT_TYPE_LONG:
+                       case JIT_TYPE_ULONG:
+                       {
+                       #ifdef JIT_NATIVE_INT32
+                               /* Add one extra word for possible alignment padding */
+                               size += sizeof(jit_long) + sizeof(jit_nint);
+                       #else
+                               size += sizeof(jit_nint);
+                       #endif
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT32:
+                       case JIT_TYPE_FLOAT64:
+                       case JIT_TYPE_NFLOAT:
+                       {
+                               /* Allocate space for an "nfloat" and an alignment word */
+                               size += (sizeof(jit_nfloat) + sizeof(jit_nint) * 2 - 1) &
+                                                       ~(sizeof(jit_nint) - 1);
+                       }
+                       break;
+
+                       case JIT_TYPE_STRUCT:
+                       case JIT_TYPE_UNION:
+                       {
+                               /* Allocate space for the structure and an alignment word */
+                               typeSize = jit_type_get_size(type);
+                               size += (typeSize + sizeof(jit_nint) * 2 - 1) &
+                                                       ~(sizeof(jit_nint) - 1);
+                       }
+                       break;
+               }
+       }
+       type = jit_type_get_return(signature);
+       if(jit_type_is_struct(type) || jit_type_is_union(type))
+       {
+               /* Add one extra word for the possibility of a structure pointer */
+               size += sizeof(jit_nint);
+       }
+       signature->size = size;
+       return size;
+}
+
+/*
+ * Copy apply arguments into position.
+ */
+static void jit_apply_builder_add_arguments
+               (jit_apply_builder *builder, jit_type_t signature,
+                void **args, unsigned int index, unsigned int num_args)
+{
+       unsigned int param;
+       jit_type_t type;
+       for(param = 0; param < num_args; ++param)
+       {
+               type = jit_type_normalize
+                       (jit_type_get_param(signature, index + param));
+               switch(type->kind)
+               {
+                       case JIT_TYPE_SBYTE:
+                       {
+                               jit_apply_builder_add_sbyte
+                                       (builder, *((jit_sbyte *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_UBYTE:
+                       {
+                               jit_apply_builder_add_ubyte
+                                       (builder, *((jit_ubyte *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_SHORT:
+                       {
+                               jit_apply_builder_add_short
+                                       (builder, *((jit_short *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_USHORT:
+                       {
+                               jit_apply_builder_add_ushort
+                                       (builder, *((jit_ushort *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_INT:
+                       {
+                               jit_apply_builder_add_int
+                                       (builder, *((jit_int *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_UINT:
+                       {
+                               jit_apply_builder_add_uint
+                                       (builder, *((jit_uint *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_NINT:
+                       case JIT_TYPE_PTR:
+                       case JIT_TYPE_SIGNATURE:
+                       {
+                               jit_apply_builder_add_nint
+                                       (builder, *((jit_nint *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_NUINT:
+                       {
+                               jit_apply_builder_add_nuint
+                                       (builder, *((jit_nuint *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_LONG:
+                       {
+                               jit_apply_builder_add_long
+                                       (builder, *((jit_long *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_ULONG:
+                       {
+                               jit_apply_builder_add_ulong
+                                       (builder, *((jit_ulong *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT32:
+                       {
+                               jit_apply_builder_add_float32
+                                       (builder, *((jit_float32 *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT64:
+                       {
+                               jit_apply_builder_add_float64
+                                       (builder, *((jit_float64 *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_NFLOAT:
+                       {
+                               jit_apply_builder_add_nfloat
+                                       (builder, *((jit_nfloat *)(args[param])));
+                       }
+                       break;
+
+                       case JIT_TYPE_STRUCT:
+                       case JIT_TYPE_UNION:
+                       {
+                               jit_apply_builder_add_struct
+                                       (builder, args[param], jit_type_get_size(type),
+                                        jit_type_get_alignment(type));
+                       }
+                       break;
+               }
+       }
+}
+
+/*
+ * Get the return value after calling a function using "__builtin_apply".
+ */
+static void jit_apply_builder_get_return
+               (jit_apply_builder *builder, void *return_value,
+                jit_type_t type, jit_apply_return *result)
+{
+       switch(type->kind)
+       {
+               case JIT_TYPE_SBYTE:
+               {
+                       *((jit_sbyte *)return_value) =
+                               jit_apply_return_get_sbyte(result);
+               }
+               break;
+
+               case JIT_TYPE_UBYTE:
+               {
+                       *((jit_ubyte *)return_value) =
+                               jit_apply_return_get_ubyte(result);
+               }
+               break;
+
+               case JIT_TYPE_SHORT:
+               {
+                       *((jit_short *)return_value) =
+                               jit_apply_return_get_short(result);
+               }
+               break;
+
+               case JIT_TYPE_USHORT:
+               {
+                       *((jit_ushort *)return_value) =
+                               jit_apply_return_get_ushort(result);
+               }
+               break;
+
+               case JIT_TYPE_INT:
+               {
+                       *((jit_int *)return_value) =
+                               jit_apply_return_get_int(result);
+               }
+               break;
+
+               case JIT_TYPE_UINT:
+               {
+                       *((jit_uint *)return_value) =
+                               jit_apply_return_get_uint(result);
+               }
+               break;
+
+               case JIT_TYPE_NINT:
+               case JIT_TYPE_PTR:
+               case JIT_TYPE_SIGNATURE:
+               {
+                       *((jit_nint *)return_value) =
+                               jit_apply_return_get_nint(result);
+               }
+               break;
+
+               case JIT_TYPE_NUINT:
+               {
+                       *((jit_nuint *)return_value) =
+                               jit_apply_return_get_nuint(result);
+               }
+               break;
+
+               case JIT_TYPE_LONG:
+               {
+                       *((jit_long *)return_value) =
+                               jit_apply_return_get_long(result);
+               }
+               break;
+
+               case JIT_TYPE_ULONG:
+               {
+                       *((jit_ulong *)return_value) =
+                               jit_apply_return_get_ulong(result);
+               }
+               break;
+
+               case JIT_TYPE_FLOAT32:
+               {
+                       *((jit_float32 *)return_value) =
+                               jit_apply_return_get_float32(result);
+               }
+               break;
+
+               case JIT_TYPE_FLOAT64:
+               {
+                       *((jit_float64 *)return_value) =
+                               jit_apply_return_get_float64(result);
+               }
+               break;
+
+               case JIT_TYPE_NFLOAT:
+               {
+                       *((jit_nfloat *)return_value) =
+                               jit_apply_return_get_nfloat(result);
+               }
+               break;
+
+               case JIT_TYPE_STRUCT:
+               case JIT_TYPE_UNION:
+               {
+                       unsigned int size = jit_type_get_size(type);
+                       jit_apply_builder_get_struct_return
+                               (builder, size, return_value, result);
+               }
+               break;
+       }
+}
+
+/*@
+ * @deftypefun void jit_apply (jit_type_t signature, {void *} func, {void **} args, {unsigned int} num_fixed_args, {void *} return_value)
+ * Call a function that has a particular function signature.
+ * If the signature has more than @code{num_fixed_args} arguments,
+ * then it is assumed to be a vararg call, with the additional
+ * arguments passed in the vararg argument area on the stack.
+ * The @code{signature} must specify the type of all arguments,
+ * including those in the vararg argument area.
+ * @end deftypefun
+@*/
+void jit_apply(jit_type_t signature, void *func,
+               void **args, unsigned int num_fixed_args,
+                          void *return_value)
+{
+       jit_apply_builder builder;
+       unsigned int size;
+       jit_apply_return *apply_return;
+       jit_type_t type;
+
+       /* Initialize the argument builder */
+       jit_apply_builder_init(&builder, signature);
+
+       /* Handle the structure return argument */
+       type = jit_type_normalize(jit_type_get_return(signature));
+       if(jit_type_is_struct(type) || jit_type_is_union(type))
+       {
+               size = jit_type_get_size(type);
+               jit_apply_builder_add_struct_return(&builder, size, return_value);
+       }
+
+       /* Copy the arguments into position */
+       jit_apply_builder_add_arguments
+               (&builder, signature, args, 0, num_fixed_args);
+       jit_apply_builder_start_varargs(&builder);
+       jit_apply_builder_add_arguments
+               (&builder, signature, args + num_fixed_args, num_fixed_args,
+                jit_type_num_params(signature) - num_fixed_args);
+
+       /* Call the function using "__builtin_apply" or something similar */
+       if(type->kind < JIT_TYPE_FLOAT32 || type->kind > JIT_TYPE_NFLOAT)
+       {
+               jit_builtin_apply(func, builder.apply_args,
+                                                 builder.stack_used, 0, apply_return);
+       }
+       else
+       {
+               jit_builtin_apply(func, builder.apply_args,
+                                                 builder.stack_used, 1, apply_return);
+       }
+
+       /* Copy the return value into position */
+       if(return_value != 0 && type != jit_type_void)
+       {
+               jit_apply_builder_get_return
+                       (&builder, return_value, type, apply_return);
+       }
+}
+
+/*@
+ * @deftypefun void jit_apply_raw (jit_type_t signature, {void *} func, {void *} args, {void *} return_value)
+ * Call a function, passing a set of raw arguments.  This can only
+ * be used if @code{jit_raw_supported} returns non-zero for the signature.
+ * The @code{args} value is assumed to be an array of @code{jit_nint} values
+ * that correspond to each of the arguments.  Raw function calls
+ * are slightly faster than their non-raw counterparts, but can
+ * only be used in certain circumstances.
+ * @end deftypefun
+@*/
+void jit_apply_raw(jit_type_t signature, void *func,
+                   void *args, void *return_value)
+{
+       jit_apply_return *apply_return;
+       unsigned int size;
+       jit_type_t type;
+
+       /* Call the function using "__builtin_apply" or something similar */
+       type = jit_type_normalize(jit_type_get_return(signature));
+       size = jit_type_num_params(signature) * sizeof(jit_nint);
+       if(type->kind < JIT_TYPE_FLOAT32 || type->kind > JIT_TYPE_NFLOAT)
+       {
+               jit_builtin_apply(func, args, size, 0, apply_return);
+       }
+       else
+       {
+               jit_builtin_apply(func, args, size, 1, apply_return);
+       }
+
+       /* Copy the return value into position */
+       if(return_value != 0 && type != jit_type_void)
+       {
+               jit_apply_builder_get_return
+                       (0, return_value, type, apply_return);
+       }
+}
+
+/*@
+ * @deftypefun int jit_raw_supported (jit_type_t signature)
+ * Determine if @code{jit_apply_raw} can be used to call functions
+ * with a particular signature.  Returns zero if not.
+ * @end deftypefun
+@*/
+int jit_raw_supported(jit_type_t signature)
+{
+#if JIT_APPLY_NUM_WORD_REGS == 0 && JIT_APPLY_NUM_FLOAT_REGS == 0 && \
+       JIT_APPLY_STRUCT_RETURN_SPECIAL_REG == 0
+
+       unsigned int param;
+       jit_type_t type;
+
+#if JIT_APPLY_X86_FASTCALL != 0
+       /* Cannot use raw calls with fastcall functions */
+       if(jit_type_get_abi(signature) == jit_abi_fastcall)
+       {
+               return 0;
+       }
+#endif
+
+       /* Check that all of the arguments are word-sized */
+       param = jit_type_num_params(signature);
+       while(param > 0)
+       {
+               --param;
+               type = jit_type_normalize(jit_type_get_param(signature, param));
+               if(type->kind < JIT_TYPE_SBYTE || type->kind > JIT_TYPE_NUINT)
+               {
+                       return 0;
+               }
+       }
+
+       /* Check that the return value does not involve structures */
+       type = jit_type_get_return(signature);
+       if(jit_type_is_struct(type) || jit_type_is_union(type))
+       {
+               return 0;
+       }
+
+       /* The signature is suitable for use with "jit_apply_raw" */
+       return 1;
+
+#else
+       /* We cannot use raw calls if we need to use registers in applys */
+       return 0;
+#endif
+}
+
+/*
+ * Define the structure of a vararg list for closures.
+ */
+struct jit_closure_va_list
+{
+       jit_apply_builder builder;
+};
+
+#ifdef jit_closure_size
+
+/*
+ * Define the closure structure.
+ */
+typedef struct jit_closure *jit_closure_t;
+struct jit_closure
+{
+       unsigned char           buf[jit_closure_size];
+       jit_type_t              signature;
+       jit_closure_func        func;
+       void                   *user_data;
+};
+
+/*
+ * Handler that is called when a closure is invoked.
+ */
+static void closure_handler(jit_closure_t closure, void *apply_args)
+{
+       jit_type_t signature = closure->signature;
+       jit_type_t type;
+       jit_apply_builder parser;
+       void *return_buffer;
+       void **args;
+       void *temp_arg;
+       unsigned int num_params;
+       unsigned int param;
+       jit_apply_return apply_return;
+       int is_float_return;
+
+       /* Initialize the argument parser */
+       jit_apply_parser_init(&parser, closure->signature, apply_args);
+
+       /* Allocate space for the return value */
+       type = jit_type_normalize(jit_type_get_return(signature));
+       if(!type || type == jit_type_void)
+       {
+               return_buffer = 0;
+       }
+       else if(jit_type_return_via_pointer(type))
+       {
+               jit_apply_parser_get_struct_return(&parser, return_buffer);
+       }
+       else
+       {
+               return_buffer = alloca(jit_type_get_size(type));
+       }
+
+       /* Allocate space for the argument buffer.  We allow for one
+          extra argument to hold the "va" list */
+       num_params = jit_type_num_params(signature);
+       args = (void **)alloca((num_params + 1) * sizeof(void *));
+
+       /* Extract the fixed arguments */
+       for(param = 0; param < num_params; ++param)
+       {
+               type = jit_type_normalize(jit_type_get_param(signature, param));
+               if(!type)
+               {
+                       args[param] = 0;
+                       continue;
+               }
+               temp_arg = alloca(jit_type_get_size(type));
+               args[param] = temp_arg;
+               switch(type->kind)
+               {
+                       case JIT_TYPE_SBYTE:
+                       {
+                               jit_apply_parser_get_sbyte
+                                       (&parser, *((jit_sbyte *)temp_arg));
+                       }
+                       break;
+
+                       case JIT_TYPE_UBYTE:
+                       {
+                               jit_apply_parser_get_ubyte
+                                       (&parser, *((jit_ubyte *)temp_arg));
+                       }
+                       break;
+
+                       case JIT_TYPE_SHORT:
+                       {
+                               jit_apply_parser_get_short
+                                       (&parser, *((jit_short *)temp_arg));
+                       }
+                       break;
+
+                       case JIT_TYPE_USHORT:
+                       {
+                               jit_apply_parser_get_ushort
+                                       (&parser, *((jit_ushort *)temp_arg));
+                       }
+                       break;
+
+                       case JIT_TYPE_INT:
+                       {
+                               jit_apply_parser_get_int
+                                       (&parser, *((jit_int *)temp_arg));
+                       }
+                       break;
+
+                       case JIT_TYPE_UINT:
+                       {
+                               jit_apply_parser_get_uint
+                                       (&parser, *((jit_uint *)temp_arg));
+                       }
+                       break;
+
+                       case JIT_TYPE_LONG:
+                       {
+                               jit_apply_parser_get_long
+                                       (&parser, *((jit_long *)temp_arg));
+                       }
+                       break;
+
+                       case JIT_TYPE_ULONG:
+                       {
+                               jit_apply_parser_get_ulong
+                                       (&parser, *((jit_ulong *)temp_arg));
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT32:
+                       {
+                               jit_apply_parser_get_float32
+                                       (&parser, *((jit_float32 *)temp_arg));
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT64:
+                       {
+                               jit_apply_parser_get_float64
+                                       (&parser, *((jit_float64 *)temp_arg));
+                       }
+                       break;
+
+                       case JIT_TYPE_NFLOAT:
+                       {
+                               jit_apply_parser_get_nfloat
+                                       (&parser, *((jit_nfloat *)temp_arg));
+                       }
+                       break;
+
+                       case JIT_TYPE_STRUCT:
+                       case JIT_TYPE_UNION:
+                       {
+                               jit_apply_parser_get_struct
+                                       (&parser, jit_type_get_size(type),
+                                        jit_type_get_alignment(type), temp_arg);
+                       }
+                       break;
+               }
+       }
+
+       /* Adjust the argument parser for the start of the va arguments */
+       jit_apply_parser_start_varargs(&parser);
+
+       /* Record the address of the va handler in the last argument slot.
+          Not all functions will need this, but it doesn't hurt to include it */
+       args[num_params] = &parser;
+
+       /* Call the user's closure handling function */
+       (*(closure->func))(signature, return_buffer, args, closure->user_data);
+
+       /* Set up the "apply return" buffer */
+       jit_memzero(&apply_return, sizeof(apply_return));
+       type = jit_type_normalize(jit_type_get_return(signature));
+       is_float_return = 0;
+       if(type)
+       {
+               switch(type->kind)
+               {
+                       case JIT_TYPE_SBYTE:
+                       {
+                               jit_apply_return_set_sbyte
+                                       (&apply_return, *((jit_sbyte *)return_buffer));
+                       }
+                       break;
+
+                       case JIT_TYPE_UBYTE:
+                       {
+                               jit_apply_return_set_ubyte
+                                       (&apply_return, *((jit_ubyte *)return_buffer));
+                       }
+                       break;
+
+                       case JIT_TYPE_SHORT:
+                       {
+                               jit_apply_return_set_short
+                                       (&apply_return, *((jit_short *)return_buffer));
+                       }
+                       break;
+
+                       case JIT_TYPE_USHORT:
+                       {
+                               jit_apply_return_set_ushort
+                                       (&apply_return, *((jit_ushort *)return_buffer));
+                       }
+                       break;
+
+                       case JIT_TYPE_INT:
+                       {
+                               jit_apply_return_set_int
+                                       (&apply_return, *((jit_int *)return_buffer));
+                       }
+                       break;
+
+                       case JIT_TYPE_UINT:
+                       {
+                               jit_apply_return_set_uint
+                                       (&apply_return, *((jit_uint *)return_buffer));
+                       }
+                       break;
+
+                       case JIT_TYPE_LONG:
+                       {
+                               jit_apply_return_set_long
+                                       (&apply_return, *((jit_long *)return_buffer));
+                       }
+                       break;
+
+                       case JIT_TYPE_ULONG:
+                       {
+                               jit_apply_return_set_ulong
+                                       (&apply_return, *((jit_ulong *)return_buffer));
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT32:
+                       {
+                               jit_apply_return_set_float32
+                                       (&apply_return, *((jit_float32 *)return_buffer));
+                               is_float_return = 1;
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT64:
+                       {
+                               jit_apply_return_set_float64
+                                       (&apply_return, *((jit_float64 *)return_buffer));
+                               is_float_return = 1;
+                       }
+                       break;
+
+                       case JIT_TYPE_NFLOAT:
+                       {
+                               jit_apply_return_set_nfloat
+                                       (&apply_return, *((jit_nfloat *)return_buffer));
+                               is_float_return = 1;
+                       }
+                       break;
+
+                       case JIT_TYPE_STRUCT:
+                       case JIT_TYPE_UNION:
+                       {
+                               if(!jit_type_return_via_pointer(type))
+                               {
+                                       jit_memcpy(&apply_return, return_buffer,
+                                                          jit_type_get_size(type));
+                               }
+                       }
+                       break;
+               }
+       }
+
+       /* Return the result to the caller */
+       if(!is_float_return)
+       {
+               jit_builtin_return_int(&apply_return);
+       }
+       else
+       {
+               jit_builtin_return_float(&apply_return);
+       }
+}
+
+#endif /* jit_closure_size */
+
+/*@
+ * @deftypefun {void *} jit_closure_create (jit_context_t context, jit_type_t signature, {jit_closure_func} func, {void *} user_data)
+ * Create a closure from a function signature, a closure handling function,
+ * and a user data value.  Returns NULL if out of memory, or if closures are
+ * not supported.  The @code{func} argument should have the following
+ * prototype:
+ *
+ * @example
+ * void func (jit_type_t signature, void *result,
+ *            void **args, void *user_data);
+ * @end example
+ *
+ * If the closure signature includes variable arguments, then @code{args}
+ * will contain pointers to the fixed arguments, followed by a
+ * @code{jit_closure_va_list_t} value for accessing the remainder of
+ * the arguments.
+ *
+ * The memory for the closure will be reclaimed when the @code{context}
+ * is destroyed.
+ * @end deftypefun
+@*/
+void *jit_closure_create(jit_context_t context, jit_type_t signature,
+                                                jit_closure_func func, void *user_data)
+{
+#ifdef jit_closure_size
+       jit_cache_t cache;
+       jit_closure_t closure;
+
+       /* Validate the parameters */
+       if(!context || !signature || !func)
+       {
+               return 0;
+       }
+
+       /* Acquire the cache lock while we do this */
+       jit_mutex_lock(&(context->cache_lock));
+       
+       /* Allocate space for the closure within the context's function cache */
+       cache = _jit_context_get_cache(context);
+       if(!cache)
+       {
+               jit_mutex_unlock(&(context->cache_lock));
+               return 0;
+       }
+       closure = (jit_closure_t)_jit_cache_alloc_no_method
+               (cache, sizeof(struct jit_closure), jit_closure_align);
+       if(!closure)
+       {
+               jit_mutex_unlock(&(context->cache_lock));
+               return 0;
+       }
+
+       /* Fill in the closure fields */
+       _jit_create_closure
+               (closure->buf, (void *)closure_handler, closure, signature);
+       closure->signature = signature;
+       closure->func = func;
+       closure->user_data = user_data;
+
+       /* Perform a cache flush on the closure's code */
+       jit_flush_exec(closure->buf, sizeof(closure->buf));
+
+       /* Unlock the cache, as we are finished with it */
+       jit_mutex_unlock(&(context->cache_lock));
+
+       /* Return the completed closure to the caller */
+       return closure;
+
+#else
+       /* Closures are not supported on this platform */
+       return 0;
+#endif
+}
+
+/*@
+ * @deftypefun int jit_closures_supported (void)
+ * Determine if this platform has support for closures.
+ * @end deftypefun
+@*/
+int jit_closures_supported(void)
+{
+#ifdef jit_closure_size
+       return 1;
+#else
+       return 0;
+#endif
+}
+
+/*@
+ * @deftypefun jit_nint jit_closure_va_get_nint (jit_closure_va_list_t va)
+ * @deftypefunx jit_nuint jit_closure_va_get_nuint (jit_closure_va_list_t va)
+ * @deftypefunx jit_long jit_closure_va_get_long (jit_closure_va_list_t va)
+ * @deftypefunx jit_ulong jit_closure_va_get_ulong (jit_closure_va_list_t va)
+ * @deftypefunx jit_float32 jit_closure_va_get_float32 (jit_closure_va_list_t va)
+ * @deftypefunx jit_float64 jit_closure_va_get_float64 (jit_closure_va_list_t va)
+ * @deftypefunx jit_nfloat jit_closure_va_get_nfloat (jit_closure_va_list_t va)
+ * @deftypefunx {void *} jit_closure_va_get_ptr (jit_closure_va_list_t va)
+ * Get the next value of a specific type from a closure's variable arguments.
+ * @end deftypefun
+@*/
+jit_nint jit_closure_va_get_nint(jit_closure_va_list_t va)
+{
+       jit_nint value;
+       jit_apply_parser_get_nint(&(va->builder), value);
+       return value;
+}
+
+jit_nuint jit_closure_va_get_nuint(jit_closure_va_list_t va)
+{
+       jit_nuint value;
+       jit_apply_parser_get_nuint(&(va->builder), value);
+       return value;
+}
+
+jit_long jit_closure_va_get_long(jit_closure_va_list_t va)
+{
+       jit_long value;
+       jit_apply_parser_get_long(&(va->builder), value);
+       return value;
+}
+
+jit_ulong jit_closure_va_get_ulong(jit_closure_va_list_t va)
+{
+       jit_ulong value;
+       jit_apply_parser_get_ulong(&(va->builder), value);
+       return value;
+}
+
+jit_float32 jit_closure_va_get_float32(jit_closure_va_list_t va)
+{
+       jit_float32 value;
+       jit_apply_parser_get_float32(&(va->builder), value);
+       return value;
+}
+
+jit_float64 jit_closure_va_get_float64(jit_closure_va_list_t va)
+{
+       jit_float64 value;
+       jit_apply_parser_get_float64(&(va->builder), value);
+       return value;
+}
+
+jit_nfloat jit_closure_va_get_nfloat(jit_closure_va_list_t va)
+{
+       jit_nfloat value;
+       jit_apply_parser_get_nfloat(&(va->builder), value);
+       return value;
+}
+
+void *jit_closure_va_get_ptr(jit_closure_va_list_t va)
+{
+       jit_nint value;
+       jit_apply_parser_get_nint(&(va->builder), value);
+       return (void *)value;
+}
+
+/*@
+ * @deftypefun void jit_closure_va_get_struct (jit_closure_va_list_t va, void *buf, jit_type_t type)
+ * Get a structure or union value of a specific @code{type} from a closure's
+ * variable arguments, and copy it into @code{buf}.
+ * @end deftypefun
+@*/
+void jit_closure_va_get_struct
+       (jit_closure_va_list_t va, void *buf, jit_type_t type)
+{
+       jit_apply_parser_get_struct
+               (&(va->builder), jit_type_get_size(type),
+                jit_type_get_alignment(type), buf);
+}
diff --git a/jit/jit-block.c b/jit/jit-block.c
new file mode 100644 (file)
index 0000000..d6f6960
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * jit-block.c - Functions for manipulating blocks.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-memory.h"
+
+/*@
+
+@cindex jit-block.h
+
+@*/
+
+int _jit_block_init(jit_function_t func)
+{
+       func->builder->entry = _jit_block_create(func, 0);
+       if(!(func->builder->entry))
+       {
+               return 0;
+       }
+       func->builder->entry->entered_via_top = 1;
+       func->builder->current_block = func->builder->entry;
+       return 1;
+}
+
+void _jit_block_free(jit_function_t func)
+{
+       jit_block_t current = func->builder->first_block;
+       jit_block_t next;
+       jit_block_eh_t current_eh;
+       jit_block_eh_t next_eh;
+       while(current != 0)
+       {
+               next = current->next;
+               jit_meta_destroy(&(current->meta));
+               jit_free(current);
+               current = next;
+       }
+       current_eh = func->builder->exception_handlers;
+       while(current_eh != 0)
+       {
+               next_eh = current_eh->next;
+               jit_free(current_eh);
+               current_eh = next_eh;
+       }
+       func->builder->first_block = 0;
+       func->builder->last_block = 0;
+       func->builder->entry = 0;
+       func->builder->current_block = 0;
+       func->builder->exception_handlers = 0;
+       func->builder->current_handler = 0;
+}
+
+jit_block_t _jit_block_create(jit_function_t func, jit_label_t *label)
+{
+       jit_block_t block;
+
+       /* Allocate memory for the block */
+       block = jit_cnew(struct _jit_block);
+       if(!block)
+       {
+               return 0;
+       }
+
+       /* Initialize the block and set its label */
+       block->func = func;
+       block->first_insn = func->builder->num_insns;
+       block->last_insn = block->first_insn - 1;
+       if(label)
+       {
+               if(*label == jit_label_undefined)
+               {
+                       *label = (func->builder->next_label)++;
+               }
+               block->label = *label;
+               if(!_jit_block_record_label(block))
+               {
+                       jit_free(block);
+                       return 0;
+               }
+       }
+       else
+       {
+               block->label = jit_label_undefined;
+       }
+
+       /* Set the exception handling context for this block */
+       block->block_eh = func->builder->current_handler;
+
+       /* Add the block to the end of the function's list */
+       block->next = 0;
+       block->prev = func->builder->last_block;
+       if(func->builder->last_block)
+       {
+               func->builder->last_block->next = block;
+       }
+       else
+       {
+               func->builder->first_block = block;
+       }
+       func->builder->last_block = block;
+       return block;
+}
+
+int _jit_block_record_label(jit_block_t block)
+{
+       jit_builder_t builder = block->func->builder;
+       jit_label_t num;
+       jit_block_t *blocks;
+       if(block->label >= builder->max_label_blocks)
+       {
+               num = builder->max_label_blocks;
+               if(num < 64)
+               {
+                       num = 64;
+               }
+               while(num <= block->label)
+               {
+                       num *= 2;
+               }
+               blocks = (jit_block_t *)jit_realloc
+                       (builder->label_blocks, num * sizeof(jit_block_t));
+               if(!blocks)
+               {
+                       return 0;
+               }
+               jit_memzero(blocks + builder->max_label_blocks,
+                                       sizeof(jit_block_t) * (num - builder->max_label_blocks));
+               builder->label_blocks = blocks;
+               builder->max_label_blocks = num;
+       }
+       builder->label_blocks[block->label] = block;
+       return 1;
+}
+
+/*@
+ * @deftypefun jit_function_t jit_block_get_function (jit_block_t block)
+ * Get the function that a particular @code{block} belongs to.
+ * @end deftypefun
+@*/
+jit_function_t jit_block_get_function(jit_block_t block)
+{
+       if(block)
+       {
+               return block->func;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_context_t jit_block_get_context (jit_block_t block)
+ * Get the context that a particular @code{block} belongs to.
+ * @end deftypefun
+@*/
+jit_context_t jit_block_get_context(jit_block_t block)
+{
+       if(block)
+       {
+               return block->func->context;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_label_t jit_block_get_label (jit_block_t block)
+ * Get the label associated with a block.
+ * @end deftypefun
+@*/
+jit_label_t jit_block_get_label(jit_block_t block)
+{
+       if(block)
+       {
+               return block->label;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{previous} argument should be NULL on the first call.
+ * This function will return NULL if there are no further blocks to iterate.
+ * @end deftypefun
+@*/
+jit_block_t jit_block_next(jit_function_t func, jit_block_t previous)
+{
+       if(previous)
+       {
+               return previous->next;
+       }
+       else if(func && func->builder)
+       {
+               return func->builder->first_block;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{previous} argument should be NULL on the first call.
+ * This function will return NULL if there are no further blocks to iterate.
+ * @end deftypefun
+@*/
+jit_block_t jit_block_previous(jit_function_t func, jit_block_t previous)
+{
+       if(previous)
+       {
+               return previous->prev;
+       }
+       else if(func && func->builder)
+       {
+               return func->builder->last_block;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_block_t jit_block_from_label (jit_function_t func, jit_label_t label)
+ * Get the block that corresponds to a particular @code{label}.
+ * Returns NULL if there is no block associated with the label.
+ * @end deftypefun
+@*/
+jit_block_t jit_block_from_label(jit_function_t func, jit_label_t label)
+{
+       if(func && func->builder && label < func->builder->max_label_blocks)
+       {
+               return func->builder->label_blocks[label];
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_insn_t _jit_block_add_insn(jit_block_t block)
+{
+       jit_builder_t builder = block->func->builder;
+       jit_insn_t insn;
+       int num;
+       jit_insn_t *insns;
+
+       /* Allocate the instruction from the builder's memory pool */
+       insn = jit_memory_pool_alloc(&(builder->insn_pool), struct _jit_insn);
+       if(!insn)
+       {
+               return 0;
+       }
+
+       /* Make space for the instruction in the function's instruction list */
+       if(builder->num_insns >= builder->max_insns)
+       {
+               num = builder->max_insns * 2;
+               if(num < 64)
+               {
+                       num = 64;
+               }
+               insns = (jit_insn_t *)jit_realloc
+                       (builder->insns, num * sizeof(jit_insn_t));
+               if(!insns)
+               {
+                       return 0;
+               }
+               builder->insns = insns;
+               builder->max_insns = num;
+       }
+       else
+       {
+               insns = builder->insns;
+       }
+       insns[builder->num_insns] = insn;
+       block->last_insn = (builder->num_insns)++;
+
+       /* Return the instruction, which is now ready to fill in */
+       return insn;
+}
+
+jit_insn_t _jit_block_get_last(jit_block_t block)
+{
+       if(block->first_insn <= block->last_insn)
+       {
+               return block->func->builder->insns[block->last_insn];
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{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.
+ * @end deftypefun
+@*/
+int jit_block_set_meta(jit_block_t block, int type, void *data,
+                                          jit_meta_free_func free_data)
+{
+       return jit_meta_set(&(block->meta), type, data, free_data, block->func);
+}
+
+/*@
+ * @deftypefun {void *} jit_block_get_meta (jit_block_t block, int type)
+ * Get the metadata associated with a particular tag.  Returns NULL
+ * if @code{type} does not have any metadata associated with it.
+ * @end deftypefun
+@*/
+void *jit_block_get_meta(jit_block_t block, int type)
+{
+       return jit_meta_get(block->meta, type);
+}
+
+/*@
+ * @deftypefun void jit_block_free_meta (jit_block_t block, int type)
+ * Free metadata of a specific type on a block.  Does nothing if
+ * the @code{type} does not have any metadata associated with it.
+ * @end deftypefun
+@*/
+void jit_block_free_meta(jit_block_t block, int type)
+{
+       jit_meta_free(&(block->meta), type);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+int jit_block_is_reachable(jit_block_t block)
+{
+       return (block->entered_via_top || block->entered_via_branch);
+}
diff --git a/jit/jit-cache.c b/jit/jit-cache.c
new file mode 100644 (file)
index 0000000..e27debc
--- /dev/null
@@ -0,0 +1,1351 @@
+/*
+ * jit-cache.c - Translated function cache implementation.
+ *
+ * Copyright (C) 2002, 2003  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+See the bottom of this file for documentation on the cache system.
+*/
+
+#include "jit-internal.h"
+#include "jit-cache.h"
+#include "jit-apply-func.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Tune the default size of a cache page.  Memory is allocated from
+ * the system in chunks of this size.  This will also determine
+ * the maximum method size that can be translated.
+ */
+#ifndef        JIT_CACHE_PAGE_SIZE
+#define        JIT_CACHE_PAGE_SIZE             (128 * 1024)
+#endif
+
+/*
+ * Structure of a debug information header for a method.
+ * This header is followed by the debug data, which is
+ * stored as compressed metadata integers.
+ */
+typedef struct jit_cache_debug *jit_cache_debug_t;
+struct jit_cache_debug
+{
+       jit_cache_debug_t next;                 /* Next block for the method */
+
+};
+
+/*
+ * Method information block, organised as a red-black tree node.
+ * There may be more than one such block associated with a method
+ * if the method contains exception regions.
+ */
+typedef struct jit_cache_method *jit_cache_method_t;
+struct jit_cache_method
+{
+       void                  *method;          /* Method containing the region */
+       void                  *cookie;          /* Cookie value for the region */
+       unsigned char     *start;               /* Start of the region */
+       unsigned char     *end;                 /* End of the region */
+       jit_cache_debug_t  debug;               /* Debug information for method */
+       jit_cache_method_t left;                /* Left sub-tree and red/black bit */
+       jit_cache_method_t right;               /* Right sub-tree */
+
+};
+
+/*
+ * Structure of the method cache.
+ */
+#define        JIT_CACHE_DEBUG_SIZE            64
+struct jit_cache
+{
+       void                **pages;            /* List of pages currently in the cache */
+       unsigned long     numPages;             /* Number of pages currently in the cache */
+       unsigned long     pageSize;             /* Size of a page for allocation */
+       unsigned char    *freeStart;    /* Start of the current free region */
+       unsigned char    *freeEnd;              /* End of the current free region */
+       int                               outOfMemory;  /* True when cache is out of memory */
+       int                               needRestart;  /* True when page restart is required */
+       long                      pagesLeft;    /* Number of pages left to allocate */
+       jit_cache_method_t method;              /* Information for the current method */
+       struct jit_cache_method head;   /* Head of the lookup tree */
+       struct jit_cache_method nil;    /* Nil pointer for the lookup tree */
+       unsigned char    *start;                /* Start of the current method */
+       unsigned char     debugData[JIT_CACHE_DEBUG_SIZE];
+       int                               debugLen;             /* Length of temporary debug data */
+       jit_cache_debug_t firstDebug;   /* First debug block for method */
+       jit_cache_debug_t lastDebug;    /* Last debug block for method */
+
+};
+
+/*
+ * Compress a "long" value so that it takes up less bytes.
+ * This is used to store offsets within functions and
+ * debug line numbers, which are usually small integers.
+ */
+static int CompressInt(unsigned char *buf, long data)
+{
+       if(data >= 0)
+       {
+               if(data < (long)0x40)
+               {
+                       buf[0] = (unsigned char)(data << 1);
+                       return 1;
+               }
+               else if(data < (long)(1 << 13))
+               {
+                       buf[0] = (unsigned char)(((data >> 7) & 0x3F) | 0x80);
+                       buf[1] = (unsigned char)(data << 1);
+                       return 2;
+               }
+               else if(data < (unsigned long)(1L << 28))
+               {
+                       buf[0] = (unsigned char)((data >> 23) | 0xC0);
+                       buf[1] = (unsigned char)(data >> 15);
+                       buf[2] = (unsigned char)(data >> 7);
+                       buf[3] = (unsigned char)(data << 1);
+                       return 4;
+               }
+               else
+               {
+                       buf[0] = (unsigned char)0xE0;
+                       buf[1] = (unsigned char)(data >> 23);
+                       buf[2] = (unsigned char)(data >> 15);
+                       buf[3] = (unsigned char)(data >> 7);
+                       buf[4] = (unsigned char)(data << 1);
+                       return 5;
+               }
+       }
+       else
+       {
+               if(data >= ((long)-0x40))
+               {
+                       buf[0] = ((((unsigned char)(data << 1)) & 0x7E) | 0x01);
+                       return 1;
+               }
+               else if(data >= ((long)-(1 << 13)))
+               {
+                       buf[0] = (unsigned char)(((data >> 7) & 0x3F) | 0x80);
+                       buf[1] = (unsigned char)((data << 1) | 0x01);
+                       return 2;
+               }
+               else if(data >= ((long)-(1L << 29)))
+               {
+                       buf[0] = (unsigned char)(((data >> 23) & 0x1F) | 0xC0);
+                       buf[1] = (unsigned char)(data >> 15);
+                       buf[2] = (unsigned char)(data >> 7);
+                       buf[3] = (unsigned char)((data << 1) | 0x01);
+                       return 4;
+               }
+               else
+               {
+                       buf[0] = (unsigned char)0xE1;
+                       buf[1] = (unsigned char)(data >> 23);
+                       buf[2] = (unsigned char)(data >> 15);
+                       buf[3] = (unsigned char)(data >> 7);
+                       buf[4] = (unsigned char)((data << 1) | 0x01);
+                       return 5;
+               }
+       }
+}
+
+/*
+ * Control data structure that is used by "UncompressInt".
+ */
+typedef struct
+{
+       const unsigned char *data;              /* Current data position */
+       unsigned long            len;           /* Length remaining to read */
+       int                                      error;         /* Set to non-zero if error encountered */
+
+} UncompressReader;
+
+/*
+ * Uncompress a value that was compressed by "CompressInt".
+ */
+static long UncompressInt(UncompressReader *meta)
+{
+       unsigned char ch;
+       unsigned char ch2;
+       unsigned char ch3;
+       unsigned char ch4;
+       unsigned long value;
+
+       if(meta->len > 0)
+       {
+               ch = *((meta->data)++);
+               --(meta->len);
+               if((ch & 0x80) == 0x00)
+               {
+                       /* One-byte form of the item */
+                       if((ch & 0x01) == 0x00)
+                               return (long)(ch >> 1);
+                       else
+                               return (long)(signed char)((ch >> 1) | 0xC0);
+               }
+               else if((ch & 0xC0) == 0x80)
+               {
+                       /* Two-byte form of the item */
+                       if(meta->len > 0)
+                       {
+                               --(meta->len);
+                               value = (((unsigned long)(ch & 0x3F)) << 8) |
+                                            ((unsigned long)(*((meta->data)++)));
+                               if((value & 0x01) == 0x00)
+                                       return (long)(value >> 1);
+                               else
+                                       return (long)(jit_int)((value >> 1) | 0xFFFFE000);
+                       }
+                       else
+                       {
+                               meta->error = 1;
+                               return 0;
+                       }
+               }
+               else if((ch & 0xE0) == 0xC0)
+               {
+                       /* Four-byte form of the item */
+                       if(meta->len >= 3)
+                       {
+                               ch2 = meta->data[0];
+                               ch3 = meta->data[1];
+                               ch4 = meta->data[2];
+                               meta->len -= 3;
+                               meta->data += 3;
+                               value = (((unsigned long)(ch & 0x1F)) << 24) |
+                                           (((unsigned long)ch2) << 16) |
+                                           (((unsigned long)ch3) << 8) |
+                                            ((unsigned long)ch4);
+                               if((value & 0x01) == 0x00)
+                                       return (long)(value >> 1);
+                               else
+                                       return (long)(jit_int)((value >> 1) | 0xF0000000);
+                       }
+                       else
+                       {
+                               meta->len = 0;
+                               meta->error = 1;
+                               return 0;
+                       }
+               }
+               else
+               {
+                       /* Five-byte form of the item */
+                       if(meta->len >= 4)
+                       {
+                               ch  = meta->data[0];
+                               ch2 = meta->data[1];
+                               ch3 = meta->data[2];
+                               ch4 = meta->data[3];
+                               meta->len -= 4;
+                               meta->data += 4;
+                               value = (((unsigned long)ch) << 24) |
+                                           (((unsigned long)ch2) << 16) |
+                                           (((unsigned long)ch3) << 8) |
+                                            ((unsigned long)ch4);
+                               return (long)(jit_int)value;
+                       }
+                       else
+                       {
+                               meta->len = 0;
+                               meta->error = 1;
+                               return 0;
+                       }
+               }
+       }
+       else
+       {
+               meta->error = 1;
+               return 0;
+       }
+}
+
+/*
+ * Allocate a cache page and add it to the cache.
+ */
+static void AllocCachePage(jit_cache_t cache)
+{
+       void *ptr;
+       void **list;
+
+       /* If we are already out of memory, then bail out */
+       if(cache->outOfMemory || !(cache->pagesLeft))
+       {
+               goto failAlloc;
+       }
+
+       /* Try to allocate a physical page */
+       ptr = jit_malloc_exec((unsigned int)(cache->pageSize));
+       if(!ptr)
+       {
+               goto failAlloc;
+       }
+
+       /* Add the page to the page list.  We keep this in an array
+          that is separate from the pages themselves so that we don't
+          have to "touch" the pages to free them.  Touching the pages
+          may cause them to be swapped in if they are currently out.
+          There's no point doing that if we are trying to free them */
+       list = (void **)jit_realloc
+               (cache->pages, sizeof(void *) * (cache->numPages + 1));
+       if(!list)
+       {
+               jit_free_exec(ptr, cache->pageSize);
+       failAlloc:
+               cache->outOfMemory = 1;
+               cache->freeStart = 0;
+               cache->freeEnd = 0;
+               return;
+       }
+       cache->pages = list;
+       list[(cache->numPages)++] = ptr;
+
+       /* One less page before we hit the limit */
+       if(cache->pagesLeft > 0)
+       {
+               --(cache->pagesLeft);
+       }
+
+       /* Set up the working region within the new page */
+       cache->freeStart = ptr;
+       cache->freeEnd = (void *)(((char *)ptr) + (int)(cache->pageSize));
+}
+
+/*
+ * Get or set the sub-trees of a node.
+ */
+#define        GetLeft(node)   \
+       ((jit_cache_method_t)(((jit_nuint)((node)->left)) & ~((jit_nuint)1)))
+#define        GetRight(node)  ((node)->right)
+#define        SetLeft(node,value)     \
+       ((node)->left = (jit_cache_method_t)(((jit_nuint)(value)) | \
+                                               (((jit_nuint)((node)->left)) & ((jit_nuint)1))))
+#define        SetRight(node,value)    \
+                       ((node)->right = (value))
+
+/*
+ * Get or set the red/black state of a node.
+ */
+#define        GetRed(node)    \
+       ((((jit_nuint)((node)->left)) & ((jit_nuint)1)) != 0)
+#define        SetRed(node)    \
+       ((node)->left = (jit_cache_method_t)(((jit_nuint)((node)->left)) | \
+                                                                            ((jit_nuint)1)))
+#define        SetBlack(node)  \
+       ((node)->left = (jit_cache_method_t)(((jit_nuint)((node)->left)) & \
+                                                                           ~((jit_nuint)1)))
+
+/*
+ * Compare a key against a node, being careful of sentinel nodes.
+ */
+static int CacheCompare(jit_cache_t cache, unsigned char *key,
+                                               jit_cache_method_t node)
+{
+       if(node == &(cache->nil) || node == &(cache->head))
+       {
+               /* Every key is greater than the sentinel nodes */
+               return 1;
+       }
+       else
+       {
+               /* Compare a regular node */
+               if(key < node->start)
+               {
+                       return -1;
+               }
+               else if(key > node->start)
+               {
+                       return 1;
+               }
+               else
+               {
+                       return 0;
+               }
+       }
+}
+
+/*
+ * Rotate a sub-tree around a specific node.
+ */
+static jit_cache_method_t CacheRotate(jit_cache_t cache, unsigned char *key,
+                                                                     jit_cache_method_t around)
+{
+       jit_cache_method_t child, grandChild;
+       int setOnLeft;
+       if(CacheCompare(cache, key, around) < 0)
+       {
+               child = GetLeft(around);
+               setOnLeft = 1;
+       }
+       else
+       {
+               child = GetRight(around);
+               setOnLeft = 0;
+       }
+       if(CacheCompare(cache, key, child) < 0)
+       {
+               grandChild = GetLeft(child);
+               SetLeft(child, GetRight(grandChild));
+               SetRight(grandChild, child);
+       }
+       else
+       {
+               grandChild = GetRight(child);
+               SetRight(child, GetLeft(grandChild));
+               SetLeft(grandChild, child);
+       }
+       if(setOnLeft)
+       {
+               SetLeft(around, grandChild);
+       }
+       else
+       {
+               SetRight(around, grandChild);
+       }
+       return grandChild;
+}
+
+/*
+ * Split a red-black tree at the current position.
+ */
+#define        Split()         \
+                       do { \
+                               SetRed(temp); \
+                               SetBlack(GetLeft(temp)); \
+                               SetBlack(GetRight(temp)); \
+                               if(GetRed(parent)) \
+                               { \
+                                       SetRed(grandParent); \
+                                       if((CacheCompare(cache, key, grandParent) < 0) != \
+                                                       (CacheCompare(cache, key, parent) < 0)) \
+                                       { \
+                                               parent = CacheRotate(cache, key, grandParent); \
+                                       } \
+                                       temp = CacheRotate(cache, key, greatGrandParent); \
+                                       SetBlack(temp); \
+                               } \
+                       } while (0)
+
+/*
+ * Add a method region block to the red-black lookup tree
+ * that is associated with a method cache.
+ */
+static void AddToLookupTree(jit_cache_t cache, jit_cache_method_t method)
+{
+       unsigned char *key = method->start;
+       jit_cache_method_t temp;
+       jit_cache_method_t greatGrandParent;
+       jit_cache_method_t grandParent;
+       jit_cache_method_t parent;
+       jit_cache_method_t nil = &(cache->nil);
+       int cmp;
+
+       /* Search for the insert position */
+       temp = &(cache->head);
+       greatGrandParent = temp;
+       grandParent = temp;
+       parent = temp;
+       while(temp != nil)
+       {
+               /* Adjust our ancestor pointers */
+               greatGrandParent = grandParent;
+               grandParent = parent;
+               parent = temp;
+
+               /* Compare the key against the current node */
+               cmp = CacheCompare(cache, key, temp);
+               if(cmp == 0)
+               {
+                       /* This is a duplicate, which normally shouldn't happen.
+                          If it does happen, then ignore the node and bail out */
+                       return;
+               }
+               else if(cmp < 0)
+               {
+                       temp = GetLeft(temp);
+               }
+               else
+               {
+                       temp = GetRight(temp);
+               }
+
+               /* Do we need to split this node? */
+               if(GetRed(GetLeft(temp)) && GetRed(GetRight(temp)))
+               {
+                       Split();
+               }
+       }
+
+       /* Insert the new node into the current position */
+       method->left = (jit_cache_method_t)(((jit_nuint)nil) | ((jit_nuint)1));
+       method->right = nil;
+       if(CacheCompare(cache, key, parent) < 0)
+       {
+               SetLeft(parent, method);
+       }
+       else
+       {
+               SetRight(parent, method);
+       }
+       Split();
+       SetBlack(cache->head.right);
+}
+
+/*
+ * Flush the current debug buffer.
+ */
+static void FlushCacheDebug(jit_cache_posn *posn)
+{
+       jit_cache_t cache = posn->cache;
+       jit_cache_debug_t debug;
+
+       /* Allocate a new jit_cache_debug structure to hold the data */
+       debug = _jit_cache_alloc(posn,
+               (unsigned long)(sizeof(struct jit_cache_debug) + cache->debugLen));
+       if(!debug)
+       {
+               cache->debugLen = 0;
+               return;
+       }
+
+       /* Copy the temporary debug data into the new structure */
+       jit_memcpy(debug + 1, cache->debugData, cache->debugLen);
+
+       /* Link the structure into the debug list */
+       debug->next = 0;
+       if(cache->lastDebug)
+       {
+               cache->lastDebug->next = debug;
+       }
+       else
+       {
+               cache->firstDebug = debug;
+       }
+       cache->lastDebug = debug;
+
+       /* Reset the temporary debug buffer */
+       cache->debugLen = 0;
+}
+
+/*
+ * Write a debug pair to the cache.  The pair (-1, -1)
+ * terminates the debug information for a method.
+ */
+static void WriteCacheDebug(jit_cache_posn *posn, long offset, long nativeOffset)
+{
+       jit_cache_t cache = posn->cache;
+
+       /* Write the two values to the temporary debug buffer */
+       cache->debugLen += CompressInt
+               (cache->debugData + cache->debugLen, offset);
+       cache->debugLen += CompressInt
+               (cache->debugData + cache->debugLen, nativeOffset);
+       if((cache->debugLen + 5 * 2 + 1) > (int)(sizeof(cache->debugData)))
+       {
+               /* Overflow occurred: write -2 to mark the end of this buffer */
+               cache->debugLen += CompressInt
+                               (cache->debugData + cache->debugLen, -2);
+
+               /* Flush the debug data that we have collected so far */
+               FlushCacheDebug(posn);
+       }
+}
+
+jit_cache_t _jit_cache_create(long limit, long cache_page_size)
+{
+       jit_cache_t cache;
+       unsigned long size;
+
+       /* Allocate space for the cache control structure */
+       if((cache = (jit_cache_t )jit_malloc(sizeof(struct jit_cache))) == 0)
+       {
+               return 0;
+       }
+
+       /* Initialize the rest of the cache fields */
+       cache->pages = 0;
+       cache->numPages = 0;
+       size = jit_exec_page_size();
+       if(!cache_page_size)
+       {
+               cache_page_size = JIT_CACHE_PAGE_SIZE;
+       }
+       size = (cache_page_size / size) * size;
+       if(!size)
+       {
+               size = jit_exec_page_size();
+       }
+       cache->pageSize = size;
+       cache->freeStart = 0;
+       cache->freeEnd = 0;
+       cache->outOfMemory = 0;
+       cache->needRestart = 0;
+       if(limit > 0)
+       {
+               cache->pagesLeft = limit / size;
+               if(cache->pagesLeft < 1)
+               {
+                       cache->pagesLeft = 1;
+               }
+       }
+       else
+       {
+               cache->pagesLeft = -1;
+       }
+       cache->method = 0;
+       cache->nil.method = 0;
+       cache->nil.cookie = 0;
+       cache->nil.start = 0;
+       cache->nil.end = 0;
+       cache->nil.debug = 0;
+       cache->nil.left = &(cache->nil);
+       cache->nil.right = &(cache->nil);
+       cache->head.method = 0;
+       cache->head.cookie = 0;
+       cache->head.start = 0;
+       cache->head.end = 0;
+       cache->head.debug = 0;
+       cache->head.left = 0;
+       cache->head.right = &(cache->nil);
+       cache->start = 0;
+       cache->debugLen = 0;
+       cache->firstDebug = 0;
+       cache->lastDebug = 0;
+
+       /* Allocate the initial cache page */
+       AllocCachePage(cache);
+       if(cache->outOfMemory)
+       {
+               _jit_cache_destroy(cache);
+               return 0;
+       }
+
+       /* Ready to go */
+       return cache;
+}
+
+void _jit_cache_destroy(jit_cache_t cache)
+{
+       unsigned long page;
+
+       /* Free all of the cache pages */
+       for(page = 0; page < cache->numPages; ++page)
+       {
+               jit_free_exec(cache->pages[page], cache->pageSize);
+       }
+       if(cache->pages)
+       {
+               jit_free(cache->pages);
+       }
+
+       /* Free the cache object itself */
+       jit_free(cache);
+}
+
+int _jit_cache_is_full(jit_cache_t cache, jit_cache_posn *posn)
+{
+       return (cache->outOfMemory || (posn && posn->ptr >= posn->limit));
+}
+
+void *_jit_cache_start_method(jit_cache_t cache, jit_cache_posn *posn,
+                                                 int align, void *method)
+{
+       jit_nuint temp;
+
+       /* Do we need to allocate a new cache page? */
+       if(cache->needRestart)
+       {
+               cache->needRestart = 0;
+               AllocCachePage(cache);
+       }
+
+       /* Bail out if the cache is already full */
+       if(cache->outOfMemory)
+       {
+               return 0;
+       }
+
+       /* Set up the initial cache position */
+       posn->cache = cache;
+       posn->ptr = cache->freeStart;
+       posn->limit = cache->freeEnd;
+
+       /* Align the method start */
+       if(align <= 1)
+       {
+               align = 1;
+       }
+       temp = (((jit_nuint)(posn->ptr)) + ((jit_nuint)align) - 1) &
+                  ~(((jit_nuint)align) - 1);
+       if(((unsigned char *)temp) >= posn->limit)
+       {
+               /* There is insufficient space in this page, so create a new one */
+               AllocCachePage(cache);
+               if(cache->outOfMemory)
+               {
+                       return 0;
+               }
+
+               /* Set up the cache position again and align it */
+               posn->ptr = cache->freeStart;
+               posn->limit = cache->freeEnd;
+               temp = (((jit_nuint)(posn->ptr)) + ((jit_nuint)align) - 1) &
+                          ~(((jit_nuint)align) - 1);
+       }
+#ifdef jit_should_pad
+       if(temp > (jit_nuint)(posn->ptr))
+       {
+               _jit_pad_buffer(posn->ptr, (int)(((jit_nuint)(posn->ptr)) - temp));
+       }
+#endif
+       posn->ptr = (unsigned char *)temp;
+
+       /* Allocate memory for the method information block */
+       cache->method = (jit_cache_method_t)
+               _jit_cache_alloc(posn, sizeof(struct jit_cache_method));
+       if(cache->method)
+       {
+               cache->method->method = method;
+               cache->method->cookie = 0;
+               cache->method->start = posn->ptr;
+               cache->method->end = posn->ptr;
+               cache->method->debug = 0;
+               cache->method->left = 0;
+               cache->method->right = 0;
+       }
+       cache->start = posn->ptr;
+
+       /* Clear the debug data */
+       cache->debugLen = 0;
+       cache->firstDebug = 0;
+       cache->lastDebug = 0;
+
+       /* Return the method entry point to the caller */
+       return (void *)(posn->ptr);
+}
+
+int _jit_cache_end_method(jit_cache_posn *posn)
+{
+       jit_cache_t cache = posn->cache;
+       jit_cache_method_t method;
+       jit_cache_method_t next;
+
+       /* Determine if we ran out of space while writing the method */
+       if(posn->ptr >= posn->limit)
+       {
+               /* Determine if the method was too big, or we need a restart.
+                  The method is judged to be too big if we had a new page and
+                  yet it was insufficent to hold the method */
+               if(cache->freeStart ==
+                               ((unsigned char *)(cache->pages[cache->numPages - 1])) &&
+                  cache->freeEnd == (cache->freeStart + cache->pageSize))
+               {
+                       return JIT_CACHE_END_TOO_BIG;
+               }
+               else
+               {
+                       cache->needRestart = 1;
+                       return JIT_CACHE_END_RESTART;
+               }
+       }
+
+       /* Terminate the debug information and flush it */
+       if(cache->firstDebug || cache->debugLen)
+       {
+               WriteCacheDebug(posn, -1, -1);
+               if(cache->debugLen)
+               {
+                       FlushCacheDebug(posn);
+               }
+       }
+
+       /* Flush the position information back to the cache */
+       cache->freeStart = posn->ptr;
+       cache->freeEnd = posn->limit;
+
+       /* Update the last method region block and then
+          add all method regions to the lookup tree */
+       method = cache->method;
+       if(method)
+       {
+               method->end = posn->ptr;
+               do
+               {
+                       method->debug = cache->firstDebug;
+                       next = method->right;
+                       AddToLookupTree(cache, method);
+                       method = next;
+               }
+               while(method != 0);
+               cache->method = 0;
+       }
+
+       /* The method is ready to go */
+       return JIT_CACHE_END_OK;
+}
+
+void *_jit_cache_alloc(jit_cache_posn *posn, unsigned long size)
+{
+       unsigned char *ptr;
+
+       /* Bail out if the request is too big to ever be satisfiable */
+       if(size > (unsigned long)(posn->limit - posn->ptr))
+       {
+               posn->ptr = posn->limit;
+               return 0;
+       }
+
+       /* Allocate memory from the top of the free region, so that it
+          does not overlap with the method code being written at the
+          bottom of the free region */
+       ptr = (unsigned char *)(((jit_nuint)(posn->limit - size)) &
+                                   ~(((jit_nuint)JIT_BEST_ALIGNMENT) - 1));
+       if(ptr < posn->ptr)
+       {
+               /* When we aligned the block, it caused an overflow */
+               posn->ptr = posn->limit;
+               return 0;
+       }
+
+       /* Allocate the block and return it */
+       posn->limit = ptr;
+       return (void *)ptr;
+}
+
+void *_jit_cache_alloc_no_method
+       (jit_cache_t cache, unsigned long size, unsigned long align)
+{
+       unsigned char *ptr;
+
+       /* Bail out if the request is too big to ever be satisfiable */
+       if(size > (unsigned long)(cache->freeEnd - cache->freeStart))
+       {
+               AllocCachePage(cache);
+               if(size > (unsigned long)(cache->freeEnd - cache->freeStart))
+               {
+                       return 0;
+               }
+       }
+
+       /* Allocate memory from the top of the free region, so that it
+          does not overlap with the method code being written at the
+          bottom of the free region */
+       ptr = (unsigned char *)(((jit_nuint)(cache->freeEnd - size)) &
+                                   ~(((jit_nuint)align) - 1));
+       if(ptr < cache->freeStart)
+       {
+               /* When we aligned the block, it caused an overflow */
+               return 0;
+       }
+
+       /* Allocate the block and return it */
+       cache->freeEnd = ptr;
+       return (void *)ptr;
+}
+
+void _jit_cache_align(jit_cache_posn *posn, int align, int diff, int nop)
+{
+       jit_nuint current;
+       jit_nuint next;
+
+       /* Determine the location of the next alignment boundary */
+       if(align <= 1)
+       {
+               align = 1;
+       }
+       current = (jit_nuint)(posn->ptr);
+       next = (current + ((jit_nuint)align) - 1) &
+                  ~(((jit_nuint)align) - 1);
+       if(current == next || (next - current) >= (jit_nuint)diff)
+       {
+               return;
+       }
+
+       /* Detect overflow of the free memory region */
+       if(next > ((jit_nuint)(posn->limit)))
+       {
+               posn->ptr = posn->limit;
+               return;
+       }
+
+#ifndef jit_should_pad
+       /* Fill from "current" to "next" with nop bytes */
+       while(current < next)
+       {
+               *((posn->ptr)++) = (unsigned char)nop;
+               ++current;
+       }
+#else
+       /* Use CPU-specific padding, because it may be more efficient */
+       _jit_pad_buffer((unsigned char *)current, (int)(next - current));
+#endif
+}
+
+void _jit_cache_mark_bytecode(jit_cache_posn *posn, unsigned long offset)
+{
+       WriteCacheDebug(posn, (long)offset,
+                                   (long)(posn->ptr - posn->cache->start));
+}
+
+void _jit_cache_new_region(jit_cache_posn *posn, void *cookie)
+{
+       jit_cache_method_t method;
+       jit_cache_method_t newMethod;
+
+       /* Fetch the current method information block */
+       method = posn->cache->method;
+       if(!method)
+       {
+               return;
+       }
+
+       /* If the current region starts here, then simply update it */
+       if(method->start == posn->ptr)
+       {
+               method->cookie = cookie;
+               return;
+       }
+
+       /* Close off the current method region */
+       method->end = posn->ptr;
+
+       /* Allocate a new method region block and initialise it */
+       newMethod = (jit_cache_method_t)
+               _jit_cache_alloc(posn, sizeof(struct jit_cache_method));
+       if(!newMethod)
+       {
+               return;
+       }
+       newMethod->method = method->method;
+       newMethod->cookie = cookie;
+       newMethod->start = posn->ptr;
+       newMethod->end = posn->ptr;
+
+       /* Attach the new region to the cache */
+       newMethod->left = 0;
+       newMethod->right = method;
+       posn->cache->method = newMethod;
+}
+
+void _jit_cache_set_cookie(jit_cache_posn *posn, void *cookie)
+{
+       if(posn->cache->method)
+       {
+               posn->cache->method->cookie = cookie;
+       }
+}
+
+void *_jit_cache_get_method(jit_cache_t cache, void *pc, void **cookie)
+{
+       jit_cache_method_t node = cache->head.right;
+       while(node != &(cache->nil))
+       {
+               if(((unsigned char *)pc) < node->start)
+               {
+                       node = GetLeft(node);
+               }
+               else if(((unsigned char *)pc) >= node->end)
+               {
+                       node = GetRight(node);
+               }
+               else
+               {
+                       if(cookie)
+                       {
+                               *cookie = node->cookie;
+                       }
+                       return node->method;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Count the number of methods in a sub-tree.
+ */
+static unsigned long CountMethods(jit_cache_method_t node,
+                                                                 jit_cache_method_t nil,
+                                                                 void **prev)
+{
+       unsigned long num;
+
+       /* Bail out if we've reached a leaf */
+       if(node == nil)
+       {
+               return 0;
+       }
+
+       /* Count the number of methods in the left sub-tree */
+       num = CountMethods(GetLeft(node), nil, prev);
+
+       /* Process the current node */
+       if(node->method != 0 && node->method != *prev)
+       {
+               ++num;
+               *prev = node->method;
+       }
+
+       /* Count the number of methods in the right sub-tree */
+       return num + CountMethods(GetRight(node), nil, prev);
+}
+
+/*
+ * Fill a list with methods.
+ */
+static unsigned long FillMethodList(void **list,
+                                                                       jit_cache_method_t node,
+                                                                   jit_cache_method_t nil,
+                                                                   void **prev)
+{
+       unsigned long num;
+
+       /* Bail out if we've reached a leaf */
+       if(node == nil)
+       {
+               return 0;
+       }
+
+       /* Process the methods in the left sub-tree */
+       num = FillMethodList(list, GetLeft(node), nil, prev);
+
+       /* Process the current node */
+       if(node->method != 0 && node->method != *prev)
+       {
+               list[num] = node->method;
+               ++num;
+               *prev = node->method;
+       }
+
+       /* Process the methods in the right sub-tree */
+       return num + FillMethodList(list + num, GetRight(node), nil, prev);
+}
+
+void **_jit_cache_get_method_list(jit_cache_t cache)
+{
+       void *prev;
+       unsigned long num;
+       void **list;
+
+       /* Count the number of distinct methods in the tree */
+       prev = 0;
+       num = CountMethods(cache->head.right, &(cache->nil), &prev);
+
+       /* Allocate a list to hold all of the method descriptors */
+       list = (void **)jit_malloc((num + 1) * sizeof(void *));
+       if(!list)
+       {
+               return 0;
+       }
+
+       /* Fill the list with methods and then return it */
+       prev = 0;
+       FillMethodList(list, cache->head.right, &(cache->nil), &prev);
+       list[num] = 0;
+       return list;
+}
+
+/*
+ * Temporary structure for iterating over a method's debug list.
+ */
+typedef struct
+{
+       jit_cache_debug_t       list;
+       UncompressReader        reader;
+
+} jit_cache_debug_iter;
+
+/*
+ * Initialize a debug information list iterator for a method.
+ */
+static void InitDebugIter(jit_cache_debug_iter *iter,
+                                                 jit_cache_t cache, void *start)
+{
+       jit_cache_method_t node = cache->head.right;
+       while(node != &(cache->nil))
+       {
+               if(((unsigned char *)start) < node->start)
+               {
+                       node = GetLeft(node);
+               }
+               else if(((unsigned char *)start) >= node->end)
+               {
+                       node = GetRight(node);
+               }
+               else
+               {
+                       iter->list = node->debug;
+                       if(iter->list)
+                       {
+                               iter->reader.data = (unsigned char *)(iter->list + 1);
+                               iter->reader.len = JIT_CACHE_DEBUG_SIZE;
+                               iter->reader.error = 0;
+                       }
+                       return;
+               }
+       }
+       iter->list = 0;
+}
+
+/*
+ * Get the next debug offset pair from a debug information list.
+ * Returns non-zero if OK, or zero at the end of the list.
+ */
+static int GetNextDebug(jit_cache_debug_iter *iter, unsigned long *offset,
+                                               unsigned long *nativeOffset)
+{
+       long value;
+       while(iter->list)
+       {
+               value = UncompressInt(&(iter->reader));
+               if(value == -1)
+               {
+                       return 0;
+               }
+               else if(value != -2)
+               {
+                       *offset = (unsigned long)value;
+                       *nativeOffset = (unsigned long)(UncompressInt(&(iter->reader)));
+                       return 1;
+               }
+               iter->list = iter->list->next;
+               if(iter->list)
+               {
+                       iter->reader.data = (unsigned char *)(iter->list + 1);
+                       iter->reader.len = JIT_CACHE_DEBUG_SIZE;
+                       iter->reader.error = 0;
+               }
+       }
+       return 0;
+}
+
+unsigned long _jit_cache_get_native(jit_cache_t cache, void *start,
+                                                                       unsigned long offset, int exact)
+{
+       jit_cache_debug_iter iter;
+       unsigned long ofs, nativeOfs;
+       unsigned long prevNativeOfs = JIT_CACHE_NO_OFFSET;
+
+       /* Search for the bytecode offset */
+       InitDebugIter(&iter, cache, start);
+       while(GetNextDebug(&iter, &ofs, &nativeOfs))
+       {
+               if(exact)
+               {
+                       if(ofs == offset)
+                       {
+                               return nativeOfs;
+                       }
+               }
+               else if(ofs > offset)
+               {
+                       return prevNativeOfs;
+               }
+               prevNativeOfs = nativeOfs;
+       }
+       return JIT_CACHE_NO_OFFSET;
+}
+
+unsigned long _jit_cache_get_bytecode(jit_cache_t cache, void *start,
+                                                                         unsigned long offset, int exact)
+{
+       jit_cache_debug_iter iter;
+       unsigned long ofs, nativeOfs;
+       unsigned long prevOfs = JIT_CACHE_NO_OFFSET;
+
+       /* Search for the native offset */
+       InitDebugIter(&iter, cache, start);
+       while(GetNextDebug(&iter, &ofs, &nativeOfs))
+       {
+               if(exact)
+               {
+                       if(nativeOfs == offset)
+                       {
+                               return ofs;
+                       }
+               }
+               else if(nativeOfs > offset)
+               {
+                       return prevOfs;
+               }
+               prevOfs = ofs;
+       }
+       return JIT_CACHE_NO_OFFSET;
+}
+
+unsigned long _jit_cache_get_size(jit_cache_t cache)
+{
+       return (cache->numPages * cache->pageSize) -
+                  (cache->freeEnd - cache->freeStart);
+}
+
+/*
+
+Using the cache
+---------------
+
+To output the code for a method, first call _jit_cache_start_method:
+
+       jit_cache_posn posn;
+       void *start;
+
+       start = _jit_cache_start_method(cache, &posn, METHOD_ALIGNMENT, method);
+
+"METHOD_ALIGNMENT" is used to align the start of the method on an
+appropriate boundary for the target CPU.  Use the value 1 if no
+special alignment is required.  Note: this value is a hint to the
+cache - it may alter the alignment value.
+
+"method" is a value that uniquely identifies the method that is being
+translated.  Usually this is the "jit_function_t" pointer.
+
+The function initializes the "posn" structure, and returns the starting
+address for the method.  If the function returns NULL, then it indicates
+that the cache is full and further method translation is not possible.
+
+To write code to the method, use the following:
+
+       jit_cache_byte(&posn, value);
+       jit_cache_word16(&posn, value);
+       jit_cache_word32(&posn, value);
+       jit_cache_native(&posn, value);
+       jit_cache_word64(&posn, value);
+
+These macros write the value to cache and then update the current
+position.  If the macros detect the end of the current cache page,
+they will flag overflow, but otherwise do nothing (overflow is
+flagged when posn->ptr == posn->limit).  The current position
+in the method can be obtained using "jit_cache_get_posn".
+
+Some CPU optimization guides recommend that labels should be aligned.
+This can be achieved using _jit_cache_align.
+
+Once the method code has been output, call _jit_cache_end_method to finalize
+the process.  This function returns one of three result codes:
+
+       JIT_CACHE_END_OK       The translation process was successful.
+       JIT_CACHE_END_RESTART  The cache page overflowed.  It is necessary
+                              to restart the translation process from
+                              the beginning (_jit_cache_start_method).
+       JIT_CACHE_END_TOO_BIG  The cache page overflowed, but the method
+                              is too big to fit and a restart won't help.
+
+The caller should repeatedly translate the method while _jit_cache_end_method
+continues to return JIT_CACHE_END_RESTART.  Normally there will be no
+more than a single request to restart, but the caller should not rely
+upon this.  The cache algorithm guarantees that the restart loop will
+eventually terminate.
+
+Cache data structure
+--------------------
+
+The cache consists of one or more "cache pages", which contain method
+code and auxillary data.  The default size for a cache page is 128k
+(JIT_CACHE_PAGE_SIZE).  The size is adjusted to be a multiple
+of the system page size (usually 4k), and then stored in "pageSize".
+
+Method code is written into a cache page starting at the bottom of the
+page, and growing upwards.  Auxillary data is written into a cache page
+starting at the top of the page, and growing downwards.  When the two
+regions meet, a new cache page is allocated and the process restarts.
+
+No method, plus its auxillary data, can be greater in size than one
+cache page.  The default should be sufficient for normal applications,
+but is easy to increase should the need arise.
+
+Each method has one or more jit_cache_method auxillary data blocks associated
+with it.  These blocks indicate the start and end of regions within the
+method.  Normally these regions correspond to exception "try" blocks, or
+regular code between "try" blocks.
+
+The jit_cache_method blocks are organised into a red-black tree, which
+is used to perform fast lookups by address (_jit_cache_get_method).  These
+lookups are used when walking the stack during exceptions or security
+processing.
+
+Each method can also have offset information associated with it, to map
+between native code addresses and offsets within the original bytecode.
+This is typically used to support debugging.  Offset information is stored
+as auxillary data, attached to the jit_cache_method block.
+
+Threading issues
+----------------
+
+Writing a method to the cache, querying a method by address, or querying
+offset information for a method, are not thread-safe.  The caller should
+arrange for a cache lock to be acquired prior to performing these
+operations.
+
+Executing methods from the cache is thread-safe, as the method code is
+fixed in place once it has been written.
+
+Note: some CPU's require that a special cache flush instruction be
+performed before executing method code that has just been written.
+This is especially important in SMP environments.  It is the caller's
+responsibility to perform this flush operation.
+
+We do not provide locking or CPU flush capabilities in the cache
+implementation itself, because the caller may need to perform other
+duties before flushing the CPU cache or releasing the lock.
+
+The following is the recommended way to map an "jit_function_t" pointer
+to a starting address for execution:
+
+       Look in "jit_function_t" to see if we already have a starting address.
+               If so, then bail out.
+       Acquire the cache lock.
+       Check again to see if we already have a starting address, just
+               in case another thread got here first.  If so, then release
+               the cache lock and bail out.
+       Translate the method.
+       Update the "jit_function_t" structure to contain the starting address.
+       Force a CPU cache line flush.
+       Release the cache lock.
+
+Why aren't methods flushed when the cache fills up?
+---------------------------------------------------
+
+In this cache implementation, methods are never "flushed" when the
+cache becomes full.  Instead, all translation stops.  This is not a bug.
+It is a feature.
+
+In a multi-threaded environment, it is impossible to know if some
+other thread is executing the code of a method that may be a candidate
+for flushing.  Impossible that is unless one introduces a huge number
+of read-write locks, one per method, to prevent a method from being
+flushed.  The read locks must be acquired on entry to a method, and
+released on exit.  The write locks are acquired prior to translation.
+
+The overhead of introducing all of these locks and the associated cache
+data structures is very high.  The only safe thing to do is to assume
+that once a method has been translated, its code must be fixed in place
+for all time.
+
+We've looked at the code for other Free Software and Open Source JIT's,
+and they all use a constantly-growing method cache.  No one has found
+a solution to this problem, it seems.  Suggestions are welcome.
+
+To prevent the cache from chewing up all of system memory, it is possible
+to set a limit on how far it will grow.  Once the limit is reached, out
+of memory will be reported and there is no way to recover.
+
+*/
+
+#ifdef __cplusplus
+};
+#endif
diff --git a/jit/jit-cache.h b/jit/jit-cache.h
new file mode 100644 (file)
index 0000000..03b339b
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * jit-cache.h - Translated method cache implementation.
+ *
+ * Copyright (C) 2002, 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_CACHE_H
+#define        _JIT_CACHE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Opaque method cache type.
+ */
+typedef struct jit_cache *jit_cache_t;
+
+/*
+ * Writing position within a cache.
+ */
+typedef struct
+{
+       jit_cache_t         cache;                      /* Cache this position is attached to */
+       unsigned char  *ptr;                    /* Current code pointer */
+       unsigned char  *limit;                  /* Limit of the current page */
+
+} jit_cache_posn;
+
+/*
+ * Create a method cache.  Returns NULL if out of memory.
+ * If "limit" is non-zero, then it specifies the maximum
+ * size of the cache in bytes.  If "cache_page_size" is
+ * non-zero, then it indicates the size of each cache page.
+ */
+jit_cache_t _jit_cache_create(long limit, long cache_page_size);
+
+/*
+ * Destroy a method cache.
+ */
+void _jit_cache_destroy(jit_cache_t cache);
+
+/*
+ * Determine if the cache is full.  The "posn" value should
+ * be supplied while translating a method, or be NULL otherwise.
+ */
+int _jit_cache_is_full(jit_cache_t cache, jit_cache_posn *posn);
+
+/*
+ * Start output of a method, returning a cache position.
+ * The "align" value indicates the default alignment for
+ * the start of the method.  The "cookie" value is a
+ * cookie for referring to the method.  Returns the
+ * method entry point, or NULL if the cache is full.
+ */
+void *_jit_cache_start_method(jit_cache_t cache, jit_cache_posn *posn,
+                                                 int align, void *cookie);
+
+/*
+ * Return values for "_jit_cache_end_method".
+ */
+#define        JIT_CACHE_END_OK                0               /* Function is OK */
+#define        JIT_CACHE_END_RESTART   1               /* Restart is required */
+#define        JIT_CACHE_END_TOO_BIG   2               /* Function is too big for the cache */
+
+/*
+ * End output of a method.  Returns zero if a restart.
+ */
+int _jit_cache_end_method(jit_cache_posn *posn);
+
+/*
+ * Allocate "size" bytes of storage in the method cache's
+ * auxillary data area.  Returns NULL if insufficient space
+ * to satisfy the request.  It may be possible to satisfy
+ * the request after a restart.
+ */
+void *_jit_cache_alloc(jit_cache_posn *posn, unsigned long size);
+
+/*
+ * Allocate "size" bytes of storage when we aren't currently
+ * translating a method.
+ */
+void *_jit_cache_alloc_no_method
+       (jit_cache_t cache, unsigned long size, unsigned long align);
+
+/*
+ * Align the method code on a particular boundary if the
+ * difference between the current position and the aligned
+ * boundary is less than "diff".  The "nop" value is used
+ * to pad unused bytes.
+ */
+void _jit_cache_align(jit_cache_posn *posn, int align, int diff, int nop);
+
+/*
+ * Mark the current position with a bytecode offset value.
+ */
+void _jit_cache_mark_bytecode(jit_cache_posn *posn, unsigned long offset);
+
+/*
+ * Change to a new exception region within the current method.
+ * The cookie will typically be NULL if no exception region.
+ */
+void _jit_cache_new_region(jit_cache_posn *posn, void *cookie);
+
+/*
+ * Set the exception region cookie for the current region.
+ */
+void _jit_cache_set_cookie(jit_cache_posn *posn, void *cookie);
+
+/*
+ * Find the method that is associated with a particular
+ * program counter.  Returns NULL if the PC is not associated
+ * with a method within the cache.  The exception region
+ * cookie is returned in "*cookie", if "cookie" is not NULL.
+ */
+void *_jit_cache_get_method(jit_cache_t cache, void *pc, void **cookie);
+
+/*
+ * Get a list of all method that are presently in the cache.
+ * The list is terminated by a NULL, and must be free'd with
+ * "ILFree".  Returns NULL if out of memory.
+ */
+void **_jit_cache_get_method_list(jit_cache_t cache);
+
+/*
+ * Get the native offset that is associated with a bytecode
+ * offset within a method.  The value "start" indicates the
+ * entry point for the method.  Returns JIT_CACHE_NO_OFFSET
+ * if the native offset could not be determined.
+ */
+#define        JIT_CACHE_NO_OFFSET             (~((unsigned long)0))
+unsigned long _jit_cache_get_native(jit_cache_t cache, void *start,
+                                                                       unsigned long offset, int exact);
+
+/*
+ * Get the bytecode offset that is associated with a native
+ * offset within a method.  The value "start" indicates the
+ * entry point for the method.  Returns JIT_CACHE_NO_OFFSET
+ * if the bytecode offset could not be determined.
+ */
+unsigned long _jit_cache_get_bytecode(jit_cache_t cache, void *start,
+                                                                         unsigned long offset, int exact);
+
+/*
+ * Get the number of bytes currently in use in the method cache.
+ */
+unsigned long _jit_cache_get_size(jit_cache_t cache);
+
+/*
+ * Convert a return address into a program counter value
+ * that can be used with "_jit_cache_get_method".  Normally
+ * return addresses point to the next instruction after
+ * an instruction that falls within a method region.  This
+ * macro corrects for the "off by 1" address.
+ */
+#define        jit_cache_return_to_pc(addr)    \
+                       ((void *)(((unsigned char *)(addr)) - 1))
+
+/*
+ * Output a single byte to the current method.
+ */
+#define        jit_cache_byte(posn,value)      \
+                       do { \
+                               if((posn)->ptr < (posn)->limit) \
+                               { \
+                                       *(((posn)->ptr)++) = (unsigned char)(value); \
+                               } \
+                       } while (0)
+
+/*
+ * Output a 16-bit word to the current method.
+ */
+#define        jit_cache_word16(posn,value)    \
+                       do { \
+                               if(((posn)->ptr + 1) < (posn)->limit) \
+                               { \
+                                       *((jit_ushort *)((posn)->ptr)) = (jit_ushort)(value); \
+                                       (posn)->ptr += 2; \
+                               } \
+                               else \
+                               { \
+                                       (posn)->ptr = (posn)->limit; \
+                               } \
+                       } while (0)
+
+/*
+ * Output a 32-bit word to the current method.
+ */
+#define        jit_cache_word32(posn,value)    \
+                       do { \
+                               if(((posn)->ptr + 3) < (posn)->limit) \
+                               { \
+                                       *((jit_uint *)((posn)->ptr)) = (jit_uint)(value); \
+                                       (posn)->ptr += 4; \
+                               } \
+                               else \
+                               { \
+                                       (posn)->ptr = (posn)->limit; \
+                               } \
+                       } while (0)
+
+/*
+ * Output a native word to the current method.
+ */
+#define        jit_cache_native(posn,value)    \
+                       do { \
+                               if(((posn)->ptr + sizeof(jit_nuint) - 1) < (posn)->limit) \
+                               { \
+                                       *((jit_nuint *)((posn)->ptr)) = (jit_nuint)(value); \
+                                       (posn)->ptr += sizeof(jit_nuint); \
+                               } \
+                               else \
+                               { \
+                                       (posn)->ptr = (posn)->limit; \
+                               } \
+                       } while (0)
+
+/*
+ * Output a 64-bit word to the current method.
+ */
+#define        jit_cache_word64(posn,value)    \
+                       do { \
+                               if(((posn)->ptr + 7) < (posn)->limit) \
+                               { \
+                                       *((jit_ulong *)((posn)->ptr)) = (jit_ulong)(value); \
+                                       (posn)->ptr += 8; \
+                               } \
+                               else \
+                               { \
+                                       (posn)->ptr = (posn)->limit; \
+                               } \
+                       } while (0)
+
+/*
+ * Get the output position within the current method.
+ */
+#define        jit_cache_get_posn(posn)        ((posn)->ptr)
+
+/*
+ * Determine if there is sufficient space for N bytes in the current method.
+ */
+#define        jit_cache_check_for_n(posn,n)   \
+                               (((posn)->ptr + (n)) <= (posn)->limit)
+
+/*
+ * Mark the cache as full.
+ */
+#define        jit_cache_mark_full(posn)       \
+                       do { \
+                               (posn)->ptr = (posn)->limit; \
+                       } while (0)
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_CACHE_H */
diff --git a/jit/jit-context.c b/jit/jit-context.c
new file mode 100644 (file)
index 0000000..5c8abbc
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * jit-context.c - Functions for manipulating JIT contexts.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-cache.h"
+
+/*@
+
+Everything that is done with @code{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
+@code{jit_function_create}, and then populate its body with
+calls to the value and instruction functions.  See @xref{Values}, and
+@ref{Instructions} for more information on how to do this.
+
+@section 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 @code{jit_context_build_start} before
+creating the function.  And then call @code{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.
+
+@section Context functions
+@cindex jit-context.h
+
+The following functions are available to create, manage, and
+ultimately destroy JIT contexts:
+
+@*/
+
+/*@
+ * @deftypefun jit_context_t jit_context_create (void)
+ * Create a new context block for the JIT.  Returns NULL
+ * if out of memory.
+ * @end deftypefun
+@*/
+jit_context_t jit_context_create(void)
+{
+       jit_context_t context;
+
+       /* Make sure that the JIT is initialized */
+       jit_init();
+
+       /* Allocate memory for the context */
+       context = jit_cnew(struct _jit_context);
+       if(!context)
+       {
+               return 0;
+       }
+
+       /* Initialize the context and return it */
+       jit_mutex_create(&(context->builder_lock));
+       jit_mutex_create(&(context->cache_lock));
+       context->functions = 0;
+       context->last_function = 0;
+       return context;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+void jit_context_destroy(jit_context_t context)
+{
+       if(context)
+       {
+               while(context->functions != 0)
+               {
+                       _jit_function_destroy(context->functions);
+               }
+               if(context->cache)
+               {
+                       _jit_cache_destroy(context->cache);
+               }
+               jit_mutex_destroy(&(context->cache_lock));
+               jit_mutex_destroy(&(context->builder_lock));
+               jit_free(context);
+       }
+}
+
+/*@
+ * @deftypefun int jit_context_supports_threads (jit_context_t context)
+ * Determine if the JIT supports threads.
+ * @end deftypefun
+@*/
+int jit_context_supports_threads(jit_context_t context)
+{
+       return JIT_THREADS_SUPPORTED;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+void jit_context_build_start(jit_context_t context)
+{
+       jit_mutex_lock(&(context->builder_lock));
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+void jit_context_build_end(jit_context_t context)
+{
+       jit_mutex_unlock(&(context->builder_lock));
+}
+
+/*@
+ * @deftypefun 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 @code{type} already has some metadata associated with it, then
+ * the previous value will be freed.
+ * @end deftypefun
+@*/
+int jit_context_set_meta
+       (jit_context_t context, int type, void *data,
+        jit_meta_free_func free_data)
+{
+       return jit_meta_set(&(context->meta), type, data, free_data, 0);
+}
+
+/*@
+ * @deftypefun 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:
+ *
+ * @table @code
+ * @vindex JIT_OPTION_CACHE_LIMIT
+ * @item 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.
+ *
+ * @vindex JIT_OPTION_CACHE_PAGE_SIZE
+ * @item 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.
+ *
+ * @vindex JIT_OPTION_PRE_COMPILE
+ * @item 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.
+ * @end table
+ *
+ * Metadata type values of 10000 or greater are reserved for internal use.
+ * @end deftypefun
+@*/
+int jit_context_set_meta_numeric
+       (jit_context_t context, int type, jit_nuint data)
+{
+       return jit_meta_set(&(context->meta), type, (void *)data, 0, 0);
+}
+
+/*@
+ * @deftypefun {void *} jit_context_get_meta (jit_context_t context, int type)
+ * Get the metadata associated with a particular tag.  Returns NULL
+ * if @code{type} does not have any metadata associated with it.
+ * @end deftypefun
+@*/
+void *jit_context_get_meta(jit_context_t context, int type)
+{
+       return jit_meta_get(context->meta, type);
+}
+
+/*@
+ * @deftypefun jit_nuint jit_context_get_meta_numeric (jit_context_t context, int type)
+ * Get the metadata associated with a particular tag.  Returns zero
+ * if @code{type} does not have any metadata associated with it.
+ * This version is more convenient for the pre-defined numeric option values.
+ * @end deftypefun
+@*/
+jit_nuint jit_context_get_meta_numeric(jit_context_t context, int type)
+{
+       return (jit_nuint)jit_meta_get(context->meta, type);
+}
+
+/*@
+ * @deftypefun void jit_context_free_meta (jit_context_t context, int type)
+ * Free metadata of a specific type on a context.  Does nothing if
+ * the @code{type} does not have any metadata associated with it.
+ * @end deftypefun
+@*/
+void jit_context_free_meta(jit_context_t context, int type)
+{
+       jit_meta_free(&(context->meta), type);
+}
+
+struct jit_cache *_jit_context_get_cache(jit_context_t context)
+{
+       if(!(context->cache))
+       {
+               context->cache = _jit_cache_create
+                       ((long)jit_context_get_meta_numeric
+                               (context, JIT_OPTION_CACHE_LIMIT),
+                        (long)jit_context_get_meta_numeric
+                               (context, JIT_OPTION_CACHE_PAGE_SIZE));
+       }
+       return context->cache;
+}
diff --git a/jit/jit-dump.c b/jit/jit-dump.c
new file mode 100644 (file)
index 0000000..7d66792
--- /dev/null
@@ -0,0 +1,759 @@
+/*
+ * jit-dump.c - Functions for dumping JIT structures, for debugging.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-rules.h"
+#include <jit/jit-dump.h>
+
+#if defined(JIT_BACKEND_INTERP)
+       #include "jit-interp.h"
+#endif
+
+/*@
+ * @deftypefun void jit_dump_type ({FILE *} stream, jit_type_t type)
+ * Dump the name of a type to a stdio stream.
+ * @end deftypefun
+@*/
+void jit_dump_type(FILE *stream, jit_type_t type)
+{
+       const char *name;
+       type = jit_type_remove_tags(type);
+       if(!type || !stream)
+       {
+               return;
+       }
+       switch(type->kind)
+       {
+               case JIT_TYPE_VOID:                     name = "void"; break;
+               case JIT_TYPE_SBYTE:            name = "sbyte"; break;
+               case JIT_TYPE_UBYTE:            name = "ubyte"; break;
+               case JIT_TYPE_SHORT:            name = "short"; break;
+               case JIT_TYPE_USHORT:           name = "ushort"; break;
+               case JIT_TYPE_INT:                      name = "int"; break;
+               case JIT_TYPE_UINT:                     name = "uint"; break;
+               case JIT_TYPE_NINT:                     name = "nint"; break;
+               case JIT_TYPE_NUINT:            name = "nuint"; break;
+               case JIT_TYPE_LONG:                     name = "long"; break;
+               case JIT_TYPE_ULONG:            name = "ulong"; break;
+               case JIT_TYPE_FLOAT32:          name = "float32"; break;
+               case JIT_TYPE_FLOAT64:          name = "float64"; break;
+               case JIT_TYPE_NFLOAT:           name = "nfloat"; break;
+
+               case JIT_TYPE_STRUCT:
+               {
+                       fprintf(stream, "struct<%u>",
+                                       (unsigned int)(jit_type_get_size(type)));
+                       return;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_UNION:
+               {
+                       fprintf(stream, "union<%u>",
+                                       (unsigned int)(jit_type_get_size(type)));
+                       return;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_SIGNATURE:        name = "signature"; break;
+               case JIT_TYPE_PTR:                      name = "ptr"; break;
+               default:                                        name = "<unknown-type>"; break;
+       }
+       fputs(name, stream);
+}
+
+/*
+ * Format an integer value of arbitrary precision.
+ */
+static char *format_integer(char *buf, int is_neg, jit_ulong value)
+{
+       buf += 64;
+       *(--buf) = '\0';
+       if(value == 0)
+       {
+               *(--buf) = '0';
+       }
+       else
+       {
+               while(value != 0)
+               {
+                       *(--buf) = '0' + (int)(value % 10);
+                       value /= 10;
+               }
+       }
+       if(is_neg)
+       {
+               *(--buf) = '-';
+       }
+       return buf;
+}
+
+/*@
+ * @deftypefun 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 @code{prefix} is not
+ * NULL, then it indicates a type prefix to add to the value name.
+ * If @code{prefix} is NULL, then this function intuits the type prefix.
+ * @end deftypefun
+@*/
+void jit_dump_value(FILE *stream, jit_function_t func, jit_value_t value, const char *prefix)
+{
+       jit_pool_block_t block;
+       unsigned int block_size;
+       unsigned int posn;
+
+       /* Bail out if we have insufficient informaition for the dump */
+       if(!stream || !func || !(func->builder) || !value)
+       {
+               return;
+       }
+
+       /* Handle constants and non-local variables */
+       if(value->is_constant)
+       {
+               jit_constant_t const_value;
+               char buf[64];
+               char *name;
+               const_value = jit_value_get_constant(value);
+               switch((jit_type_promote_int
+                                       (jit_type_normalize(const_value.type)))->kind)
+               {
+                       case JIT_TYPE_INT:
+                       {
+                               if(const_value.un.int_value < 0)
+                               {
+                                       name = format_integer
+                                               (buf, 1, (jit_ulong)(jit_uint)
+                                                       (-(const_value.un.int_value)));
+                               }
+                               else
+                               {
+                                       name = format_integer
+                                               (buf, 0, (jit_ulong)(jit_uint)
+                                                       (const_value.un.int_value));
+                               }
+                       }
+                       break;
+
+                       case JIT_TYPE_UINT:
+                       {
+                               name = format_integer
+                                       (buf, 0, (jit_ulong)(const_value.un.uint_value));
+                       }
+                       break;
+
+                       case JIT_TYPE_LONG:
+                       {
+                               if(const_value.un.long_value < 0)
+                               {
+                                       name = format_integer
+                                               (buf, 1, (jit_ulong)(-(const_value.un.long_value)));
+                               }
+                               else
+                               {
+                                       name = format_integer
+                                               (buf, 0, (jit_ulong)(const_value.un.long_value));
+                               }
+                       }
+                       break;
+
+                       case JIT_TYPE_ULONG:
+                       {
+                               name = format_integer(buf, 0, const_value.un.ulong_value);
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT32:
+                       {
+                               jit_snprintf(buf, sizeof(buf), "%g",
+                                                        (double)(const_value.un.float32_value));
+                               name = buf;
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT64:
+                       {
+                               jit_snprintf(buf, sizeof(buf), "%g",
+                                                        (double)(const_value.un.float64_value));
+                               name = buf;
+                       }
+                       break;
+
+                       case JIT_TYPE_NFLOAT:
+                       {
+                               jit_snprintf(buf, sizeof(buf), "%g",
+                                                        (double)(const_value.un.nfloat_value));
+                               name = buf;
+                       }
+                       break;
+
+                       default:
+                       {
+                               name = "<unknown-constant>";
+                       }
+                       break;
+               }
+               fputs(name, stream);
+               return;
+       }
+       else if(value->is_local && value->block->func != func)
+       {
+               /* Accessing a local variable in an outer function frame */
+               int scope = 0;
+               while(func && func->builder && func != value->block->func)
+               {
+                       ++scope;
+                       func = func->nested_parent;
+               }
+               fprintf(stream, "{%d}", scope);
+               if(!func || !(func->builder))
+               {
+                       return;
+               }
+       }
+
+       /* Intuit the prefix if one was not supplied */
+       if(!prefix)
+       {
+               switch(jit_type_normalize(jit_value_get_type(value))->kind)
+               {
+                       case JIT_TYPE_VOID:                     prefix = "v"; break;
+                       case JIT_TYPE_SBYTE:            prefix = "i"; break;
+                       case JIT_TYPE_UBYTE:            prefix = "i"; break;
+                       case JIT_TYPE_SHORT:            prefix = "i"; break;
+                       case JIT_TYPE_USHORT:           prefix = "i"; break;
+                       case JIT_TYPE_INT:                      prefix = "i"; break;
+                       case JIT_TYPE_UINT:                     prefix = "i"; break;
+                       case JIT_TYPE_LONG:                     prefix = "l"; break;
+                       case JIT_TYPE_ULONG:            prefix = "l"; break;
+                       case JIT_TYPE_FLOAT32:          prefix = "f"; break;
+                       case JIT_TYPE_FLOAT64:          prefix = "d"; break;
+                       case JIT_TYPE_NFLOAT:           prefix = "D"; break;
+                       case JIT_TYPE_STRUCT:           prefix = "s"; break;
+                       case JIT_TYPE_UNION:            prefix = "u"; break;
+                       default:                                        prefix = "?"; break;
+               }
+       }
+
+       /* Get the position of the value within the function's value pool */
+       block = func->builder->value_pool.blocks;
+       block_size = func->builder->value_pool.elem_size *
+                                func->builder->value_pool.elems_per_block;
+       posn = 1;
+       while(block != 0)
+       {
+               if(((char *)value) >= block->data &&
+                  ((char *)value) < (block->data + block_size))
+               {
+                       posn += (((char *)value) - block->data) /
+                                       func->builder->value_pool.elem_size;
+                       break;
+               }
+               posn += func->builder->value_pool.elems_per_block;
+               block = block->next;
+       }
+
+       /* Dump the prefix and the position, as the value's final name */
+       fprintf(stream, "%s%u", prefix, posn);
+}
+
+/*
+ * Dump a temporary value, prefixed by its type.
+ */
+static void dump_value(FILE *stream, jit_function_t func,
+                                          jit_value_t value, int type)
+{
+       /* Normalize the type, so that it reflects JIT_OPCODE_DEST_xxx values */
+       if((type & JIT_OPCODE_SRC1_MASK) != 0)
+       {
+               type >>= 4;
+       }
+       if((type & JIT_OPCODE_SRC2_MASK) != 0)
+       {
+               type >>= 8;
+       }
+
+       /* Dump the value, prefixed appropriately */
+       switch(type)
+       {
+               case JIT_OPCODE_DEST_INT:
+               {
+                       jit_dump_value(stream, func, value, "i");
+               }
+               break;
+
+               case JIT_OPCODE_DEST_LONG:
+               {
+                       jit_dump_value(stream, func, value, "l");
+               }
+               break;
+
+               case JIT_OPCODE_DEST_FLOAT32:
+               {
+                       jit_dump_value(stream, func, value, "f");
+               }
+               break;
+
+               case JIT_OPCODE_DEST_FLOAT64:
+               {
+                       jit_dump_value(stream, func, value, "d");
+               }
+               break;
+
+               case JIT_OPCODE_DEST_NFLOAT:
+               {
+                       jit_dump_value(stream, func, value, "D");
+               }
+               break;
+
+               case JIT_OPCODE_DEST_ANY:
+               {
+                       /* Intuit the prefix from the value if the type is "any" */
+                       jit_dump_value(stream, func, value, 0);
+               }
+               break;
+       }
+}
+
+/*@
+ * @deftypefun void jit_dump_insn ({FILE *} stream, jit_function_t func, jit_value_t value)
+ * Dump the contents of an instruction to a stdio stream.
+ * @end deftypefun
+@*/
+void jit_dump_insn(FILE *stream, jit_function_t func, jit_insn_t insn)
+{
+       const char *name;
+       const char *infix_name;
+       int opcode, flags;
+       jit_nint reg;
+
+       /* Bail out if we have insufficient information for the dump */
+       if(!stream || !func || !insn)
+       {
+               return;
+       }
+
+       /* Get the opcode details */
+       opcode = insn->opcode;
+       if(opcode < JIT_OP_NOP || opcode >= JIT_OP_NUM_OPCODES)
+       {
+               fprintf(stream, "unknown opcode %d\n", opcode);
+               return;
+       }
+       name = jit_opcodes[opcode].name;
+       flags = jit_opcodes[opcode].flags;
+       infix_name = 0;
+
+       /* Dump branch, call, or register information */
+       if((flags & JIT_OPCODE_IS_BRANCH) != 0)
+       {
+               if(opcode == JIT_OP_BR)
+               {
+                       fprintf(stream, "goto .L%ld", (long)(jit_insn_get_label(insn)));
+                       return;
+               }
+               fprintf(stream, "if ");
+       }
+       else if((flags & JIT_OPCODE_IS_CALL) != 0)
+       {
+               if(insn->value1)
+                       fprintf(stream, "call %s", (const char *)(insn->value1));
+               else
+                       fprintf(stream, "call 0x08%lx", (long)(jit_nuint)(insn->dest));
+               return;
+       }
+       else if((flags & JIT_OPCODE_IS_CALL_EXTERNAL) != 0)
+       {
+               if(insn->value1)
+                       fprintf(stream, "call_external %s",
+                                       (const char *)(insn->value1));
+               else
+                       fprintf(stream, "call_external 0x08%lx",
+                                       (long)(jit_nuint)(insn->dest));
+               return;
+       }
+       else if((flags & JIT_OPCODE_IS_REG) != 0)
+       {
+               reg = jit_value_get_nint_constant(jit_insn_get_value2(insn));
+               fputs(name, stream);
+               putc('(', stream);
+               jit_dump_value(stream, func, jit_insn_get_value1(insn), 0);
+               fputs(", ", stream);
+               fputs(_jit_reg_info[(int)reg].name, stream);
+               putc(')', stream);
+               return;
+       }
+
+       /* Output the destination information */
+       if((flags & JIT_OPCODE_DEST_MASK) != JIT_OPCODE_DEST_EMPTY &&
+          !jit_insn_dest_is_value(insn))
+       {
+               dump_value(stream, func, jit_insn_get_dest(insn),
+                                  flags & JIT_OPCODE_DEST_MASK);
+               fprintf(stream, " = ");
+       }
+
+       /* Dump the details of the operation */
+       switch(flags & JIT_OPCODE_OPER_MASK)
+       {
+               case JIT_OPCODE_OPER_ADD:                       infix_name = " + ";   break;
+               case JIT_OPCODE_OPER_SUB:                       infix_name = " - ";   break;
+               case JIT_OPCODE_OPER_MUL:                       infix_name = " * ";   break;
+               case JIT_OPCODE_OPER_DIV:                       infix_name = " / ";   break;
+               case JIT_OPCODE_OPER_REM:                       infix_name = " % ";   break;
+               case JIT_OPCODE_OPER_NEG:                       infix_name = "-";    break;
+               case JIT_OPCODE_OPER_AND:                       infix_name = " & ";   break;
+               case JIT_OPCODE_OPER_OR:                        infix_name = " | ";   break;
+               case JIT_OPCODE_OPER_XOR:                       infix_name = " ^ ";   break;
+               case JIT_OPCODE_OPER_NOT:                       infix_name = "~";    break;
+               case JIT_OPCODE_OPER_EQ:                        infix_name = " == ";  break;
+               case JIT_OPCODE_OPER_NE:                        infix_name = " != ";  break;
+               case JIT_OPCODE_OPER_LT:                        infix_name = " < ";   break;
+               case JIT_OPCODE_OPER_LE:                        infix_name = " <= ";  break;
+               case JIT_OPCODE_OPER_GT:                        infix_name = " > ";   break;
+               case JIT_OPCODE_OPER_GE:                        infix_name = " >= ";  break;
+               case JIT_OPCODE_OPER_SHL:                       infix_name = " << ";  break;
+               case JIT_OPCODE_OPER_SHR:                       infix_name = " >> ";  break;
+               case JIT_OPCODE_OPER_SHR_UN:            infix_name = " >>> "; break;
+               case JIT_OPCODE_OPER_COPY:                      infix_name = "";      break;
+               case JIT_OPCODE_OPER_ADDRESS_OF:        infix_name = "&";    break;
+       }
+       if(infix_name)
+       {
+               if((flags & JIT_OPCODE_SRC2_MASK) != 0)
+               {
+                       /* Binary operation with a special operator name */
+                       dump_value(stream, func, jit_insn_get_value1(insn),
+                                          flags & JIT_OPCODE_SRC1_MASK);
+                       fputs(infix_name, stream);
+                       dump_value(stream, func, jit_insn_get_value2(insn),
+                                          flags & JIT_OPCODE_SRC2_MASK);
+               }
+               else
+               {
+                       /* Unary operation with a special operator name */
+                       fputs(infix_name, stream);
+                       dump_value(stream, func, jit_insn_get_value1(insn),
+                                          flags & JIT_OPCODE_SRC1_MASK);
+               }
+       }
+       else
+       {
+               /* Not a special operator, so use the opcode name */
+               if(!jit_strncmp(name, "br_", 3))
+               {
+                       name += 3;
+               }
+               fputs(name, stream);
+               if((flags & (JIT_OPCODE_SRC1_MASK | JIT_OPCODE_SRC2_MASK)) != 0)
+               {
+                       putc('(', stream);
+                       if(jit_insn_dest_is_value(insn))
+                       {
+                               dump_value(stream, func, jit_insn_get_dest(insn),
+                                                  flags & JIT_OPCODE_DEST_MASK);
+                               fputs(", ", stream);
+                       }
+                       dump_value(stream, func, jit_insn_get_value1(insn),
+                                          flags & JIT_OPCODE_SRC1_MASK);
+                       if((flags & JIT_OPCODE_SRC2_MASK) != 0)
+                       {
+                               fputs(", ", stream);
+                               dump_value(stream, func, jit_insn_get_value2(insn),
+                                                  flags & JIT_OPCODE_SRC2_MASK);
+                       }
+                       putc(')', stream);
+               }
+       }
+
+       /* Dump the "then" information on a conditional branch */
+       if((flags & JIT_OPCODE_IS_BRANCH) != 0)
+       {
+               fprintf(stream, " then goto .L%ld", (long)(jit_insn_get_label(insn)));
+       }
+}
+
+#if defined(JIT_BACKEND_INTERP)
+
+extern jit_opcode_info_t const _jit_interp_opcodes[JIT_OP_NUM_INTERP_OPCODES];
+
+/*
+ * Dump the interpreted bytecode representation of a function.
+ */
+static void dump_interp_code(FILE *stream, void **pc)
+{
+       int opcode;
+       const jit_opcode_info_t *info;
+       for(;;)
+       {
+               /* Fetch the next opcode */
+               opcode = (int)(jit_nint)(*pc);
+               if(opcode == JIT_OP_END_MARKER)
+               {
+                       break;
+               }
+
+               /* Dump the address of the opcode */
+               fprintf(stream, "\t%08lX: ", (long)(jit_nint)pc);
+               ++pc;
+
+               /* Get information about this opcode */
+               if(opcode < JIT_OP_NUM_OPCODES)
+               {
+                       info = &(jit_opcodes[opcode]);
+               }
+               else
+               {
+                       info = &(_jit_interp_opcodes[opcode - JIT_OP_NUM_OPCODES]);
+               }
+
+               /* Dump the name of the opcode */
+               fputs(info->name, stream);
+
+               /* Dump additional parameters from the opcode stream */
+               switch(info->flags & JIT_OPCODE_INTERP_ARGS_MASK)
+               {
+                       case JIT_OPCODE_NINT_ARG:
+                       {
+                               fprintf(stream, " %ld", (long)(jit_nint)(*pc));
+                               ++pc;
+                       }
+                       break;
+
+                       case JIT_OPCODE_NINT_ARG_TWO:
+                       {
+                               fprintf(stream, " %ld, %ld",
+                                               (long)(jit_nint)(pc[0]), (long)(jit_nint)(pc[1]));
+                               pc += 2;
+                       }
+                       break;
+
+                       case JIT_OPCODE_CONST_LONG:
+                       {
+                               /* TODO */
+                       }
+                       break;
+
+                       case JIT_OPCODE_CONST_FLOAT32:
+                       {
+                               /* TODO */
+                       }
+                       break;
+
+                       case JIT_OPCODE_CONST_FLOAT64:
+                       {
+                               /* TODO */
+                       }
+                       break;
+
+                       case JIT_OPCODE_CONST_NFLOAT:
+                       {
+                               /* TODO */
+                       }
+                       break;
+
+                       case JIT_OPCODE_CALL_INDIRECT_ARGS:
+                       {
+                               /* TODO */
+                       }
+                       break;
+
+                       default:
+                       {
+                               if((info->flags & JIT_OPCODE_IS_BRANCH) != 0)
+                               {
+                                       fprintf(stream, " %08lX",
+                                                       (long)(jit_nint)((pc - 1) + (jit_nint)(*pc)));
+                                       ++pc;
+                               }
+                               else if((info->flags & JIT_OPCODE_IS_CALL) != 0)
+                               {
+                                       fprintf(stream, " 0x%lX", (long)(jit_nint)(*pc));
+                                       ++pc;
+                               }
+                               else if((info->flags & JIT_OPCODE_IS_CALL_EXTERNAL) != 0)
+                               {
+                                       putc(' ', stream);
+                                       jit_dump_type(stream, (jit_type_t)(pc[0]));
+                                       fprintf(stream, ", 0x%lX, %ld",
+                                                       (long)(jit_nint)(pc[1]), (long)(jit_nint)(pc[2]));
+                                       pc += 3;
+                               }
+                       }
+                       break;
+               }
+
+               /* Terminate the current disassembly line */
+               putc('\n', stream);
+       }
+}
+
+#endif /* JIT_BACKEND_INTERP */
+
+/*@
+ * @deftypefun void jit_dump_function ({FILE *} stream, jit_function_t func, {const char *} name)
+ * Dump the three-address instructions within a function to a stdio stream.
+ * The @code{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.
+ * @end deftypefun
+@*/
+void jit_dump_function(FILE *stream, jit_function_t func, const char *name)
+{
+       jit_block_t block;
+       jit_insn_iter_t iter;
+       jit_insn_t insn;
+       int prev_block;
+       jit_type_t signature;
+       unsigned int param;
+       unsigned int num_params;
+       jit_value_t value;
+
+       /* Bail out if we don't have sufficient information to dump */
+       if(!stream || !func)
+       {
+               return;
+       }
+
+       /* Output the function header */
+       if(name)
+               fprintf(stream, "function %s(", name);
+       else
+               fprintf(stream, "function 0x%08lX(", (long)(jit_nuint)func);
+       signature = func->signature;
+       num_params = jit_type_num_params(signature);
+       if(func->builder)
+       {
+               value = jit_value_get_struct_pointer(func);
+               if(value || func->nested_parent)
+               {
+                       /* We have extra hidden parameters */
+                       putc('[', stream);
+                       if(func->nested_parent)
+                       {
+                               fputs("parent_frame", stream);
+                               if(value)
+                               {
+                                       fputs(", ", stream);
+                               }
+                       }
+                       if(value)
+                       {
+                               jit_dump_value(stream, func, value, 0);
+                               fputs(" : struct_ptr", stream);
+                       }
+                       putc(']', stream);
+                       if(num_params > 0)
+                       {
+                               fputs(", ", stream);
+                       }
+               }
+               for(param = 0; param < num_params; ++param)
+               {
+                       if(param != 0)
+                       {
+                               fputs(", ", stream);
+                       }
+                       value = jit_value_get_param(func, param);
+                       if(value)
+                       {
+                               jit_dump_value(stream, func, value, 0);
+                       }
+                       else
+                       {
+                               fputs("???", stream);
+                       }
+                       fputs(" : ", stream);
+                       jit_dump_type(stream, jit_type_get_param(signature, param));
+               }
+       }
+       else
+       {
+               for(param = 0; param < num_params; ++param)
+               {
+                       if(param != 0)
+                       {
+                               fputs(", ", stream);
+                       }
+                       jit_dump_type(stream, jit_type_get_param(signature, param));
+               }
+       }
+       fprintf(stream, ") : ");
+       jit_dump_type(stream, jit_type_get_return(signature));
+       putc('\n', stream);
+
+       /* Should we dump the three address code or the native code? */
+       if(func->builder)
+       {
+               /* Output each of the three address blocks in turn */
+               block = 0;
+               prev_block = 0;
+               while((block = jit_block_next(func, block)) != 0)
+               {
+                       /* Output the block's label, if it has one */
+                       if(prev_block && block->label == jit_label_undefined)
+                       {
+                               /* A new block was started, but it doesn't have a label yet */
+                               if(_jit_block_get_last(block) != 0)
+                               {
+                                       block->label = (func->builder->next_label)++;
+                               }
+                       }
+                       if(block->label != jit_label_undefined)
+                       {
+                               fprintf(stream, ".L%ld:\n", (long)(block->label));
+                       }
+                       prev_block = 1;
+
+                       /* Dump the instructions in the block */
+                       jit_insn_iter_init(&iter, block);
+                       while((insn = jit_insn_iter_next(&iter)) != 0)
+                       {
+                               putc('\t', stream);
+                               jit_dump_insn(stream, func, insn);
+                               putc('\n', stream);
+                       }
+                       if(block->ends_in_dead)
+                       {
+                               fputs("\tends_in_dead\n", stream);
+                       }
+               }
+       }
+       else if(func->is_compiled)
+       {
+#if defined(JIT_BACKEND_INTERP)
+               /* Dump the interpreter's bytecode representation */
+               jit_function_interp_t interp;
+               interp = (jit_function_interp_t)(func->entry_point);
+               fprintf(stream, "\t%08lX: prolog(0x%lX, %d, %d, %d)\n",
+                               (long)(jit_nint)interp, (long)(jit_nint)func,
+                               (int)(interp->args_size), (int)(interp->frame_size),
+                               (int)(interp->working_area));
+               dump_interp_code(stream, (void **)(interp + 1));
+#else
+               /* TODO: use objdump to dump native code */
+#endif
+       }
+
+       /* Output the function footer */
+       fprintf(stream, "end\n\n");
+}
diff --git a/jit/jit-dynlib.c b/jit/jit-dynlib.c
new file mode 100644 (file)
index 0000000..b0ea6d4
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * jit-dynlib.c - Dynamic library support routines.
+ *
+ * Copyright (C) 2001-2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include "jit-internal.h"
+#ifdef JIT_WIN32_PLATFORM
+       #include <windows.h>
+       #ifndef JIT_WIN32_NATIVE
+               #ifdef HAVE_SYS_CYGWIN_H
+                       #include <sys/cygwin.h>
+               #endif
+       #endif
+#else
+#ifdef HAVE_DLFCN_H
+       #include <dlfcn.h>
+#endif
+#endif
+
+/*@
+
+@section Dynamic libraries
+@cindex Dynamic libraries
+
+The following routines are supplied to help load and inspect dynamic
+libraries.  They should be used in place of the traditional
+@code{dlopen}, @code{dlclose}, and @code{dlsym} functions, which
+are not portable across operating systems.
+
+@deftypefun jit_dynlib_handle_t jit_dynlib_open ({const char *} name)
+Opens the dynamic library called @code{name}, returning a handle for it.
+@end deftypefun
+
+@deftypefun void jit_dynlib_close (jit_dynlib_handle_t handle)
+Close a dynamic library.
+@end deftypefun
+
+@deftypefun {void *} jit_dynlib_get_symbol (jit_dynlib_handle_t handle, {const char *} symbol)
+Retrieve the symbol @code{name} 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 @code{name} on platforms
+where it makes sense to do so, so there is no need for the caller
+to perform prefixing.
+@end deftypefun
+
+@deftypefun 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.
+@end deftypefun
+
+@deftypefun {const char *} jit_dynlib_get_suffix (void)
+Get the preferred dynamic library suffix for this platform.
+Usually something like @code{so}, @code{dll}, or @code{dylib}.
+@end deftypefun
+
+@*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static int dynlib_debug = 0;
+
+void jit_dynlib_set_debug(int flag)
+{
+       dynlib_debug = flag;
+}
+
+#if defined(__APPLE__) && defined(__MACH__)    /* MacOS X */
+
+#include <mach-o/dyld.h>
+
+jit_dynlib_handle_t jit_dynlib_open(const char *name)
+{
+       NSObjectFileImage file;
+       NSObjectFileImageReturnCode result;
+       NSModule module;
+       void *image;
+       const char *msg;
+
+       /* Attempt to open the dylib file */
+       result = NSCreateObjectFileImageFromFile(name, &file);
+       if(result == NSObjectFileImageInappropriateFile)
+       {
+               /* May be an image, and not a bundle */
+               image = (void *)NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
+               if(image)
+               {
+                       return image;
+               }
+       }
+       if(result != NSObjectFileImageSuccess)
+       {
+               switch(result)
+               {
+                       case NSObjectFileImageFailure:
+                               msg = " (NSObjectFileImageFailure)"; break;
+                       case NSObjectFileImageInappropriateFile:
+                               msg = " (NSObjectFileImageInappropriateFile)"; break;
+                       case NSObjectFileImageArch:
+                               msg = " (NSObjectFileImageArch)"; break;
+                       case NSObjectFileImageFormat:
+                               msg = " (NSObjectFileImageFormat)"; break;
+                       case NSObjectFileImageAccess:
+                               msg = " (NSObjectFileImageAccess)"; break;
+                       default:
+                               msg = ""; break;
+               }
+               if(dynlib_debug)
+               {
+                       fprintf(stderr, "%s: could not load dynamic library%s\n",
+                                       name, msg);
+               }
+               return 0;
+       }
+
+       /* Link the module dependencies */
+       module = NSLinkModule(file, name,
+                                                 NSLINKMODULE_OPTION_BINDNOW |
+                                                 NSLINKMODULE_OPTION_PRIVATE |
+                                                 NSLINKMODULE_OPTION_RETURN_ON_ERROR);
+       return (void *)module;
+}
+
+void jit_dynlib_close(jit_dynlib_handle_t handle)
+{
+       if((((struct mach_header *)handle)->magic == MH_MAGIC) ||
+          (((struct mach_header *)handle)->magic == MH_CIGAM))
+       {
+               /* Cannot remove dynamic images once they've been loaded */
+               return;
+       }
+       NSUnLinkModule((NSModule)handle, NSUNLINKMODULE_OPTION_NONE);
+}
+
+static void *GetSymbol(jit_dynlib_handle_t handle, const char *symbol)
+{
+       NSSymbol sym;
+
+       /* We have to use a different lookup approach for images and modules */
+       if((((struct mach_header *)handle)->magic == MH_MAGIC) ||
+          (((struct mach_header *)handle)->magic == MH_CIGAM))
+       {
+               if(NSIsSymbolNameDefinedInImage((struct mach_header *)handle, symbol))
+               {
+                       sym = NSLookupSymbolInImage((struct mach_header *)handle, symbol,
+                                               NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
+                                               NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
+               }
+               else
+               {
+                       sym = 0;
+               }
+       }
+       else
+       {
+               sym = NSLookupSymbolInModule((NSModule)handle, symbol);
+       }
+
+       /* Did we find the symbol? */
+       if(sym == 0)
+       {
+               return 0;
+       }
+
+       /* Convert the symbol into the address that we require */
+       return (void *)NSAddressOfSymbol(sym);
+}
+
+void *jit_dynlib_get_symbol(jit_dynlib_handle_t handle, const char *symbol)
+{
+       void *value = GetSymbol(handle, (char *)symbol);
+       char *newName;
+       if(value)
+       {
+               return value;
+       }
+       newName = (char *)jit_malloc(jit_strlen(symbol) + 2);
+       if(newName)
+       {
+               /* Try again with '_' prepended to the name */
+               newName[0] = '_';
+               jit_strcpy(newName + 1, symbol);
+               value = GetSymbol(handle, newName);
+               if(value)
+               {
+                       jit_free(newName);
+                       return value;
+               }
+               jit_free(newName);
+       }
+       if(dynlib_debug)
+       {
+               fprintf(stderr, "%s: could not find the specified symbol\n", symbol);
+       }
+       return 0;
+}
+
+const char *jit_dynlib_get_suffix(void)
+{
+       return "dylib";
+}
+
+#elif defined(JIT_WIN32_PLATFORM)      /* Native Win32 or Cygwin */
+
+jit_dynlib_handle_t jit_dynlib_open(const char *name)
+{
+       void *libHandle;
+       char *newName = 0;
+
+#if defined(JIT_WIN32_CYGWIN) && defined(HAVE_SYS_CYGWIN_H) && \
+    defined(HAVE_CYGWIN_CONV_TO_WIN32_PATH)
+
+       /* Use Cygwin to expand the path */
+       {
+               char buf[4096];
+               if(cygwin_conv_to_win32_path(name, buf) == 0)
+               {
+                       newName = jit_strdup(buf);
+                       if(!newName)
+                       {
+                               return 0;
+                       }
+               }
+       }
+
+#endif
+
+       /* Attempt to load the library */
+       libHandle = (void *)LoadLibrary((newName ? newName : name));
+       if(libHandle == 0)
+       {
+               if(dynlib_debug)
+               {
+                       fprintf(stderr, "%s: could not load dynamic library\n",
+                                       (newName ? newName : name));
+               }
+               if(newName)
+               {
+                       jit_free(newName);
+               }
+               return 0;
+       }
+       if(newName)
+       {
+               jit_free(newName);
+       }
+       return libHandle;
+}
+
+void jit_dynlib_close(jit_dynlib_handle_t handle)
+{
+       FreeLibrary((HINSTANCE)handle);
+}
+
+void *jit_dynlib_get_symbol(jit_dynlib_handle_t handle, const char *symbol)
+{
+       void *procAddr;
+       procAddr = (void *)GetProcAddress((HINSTANCE)handle, symbol);
+       if(procAddr == 0)
+       {
+               if(dynlib_debug)
+               {
+                       fprintf(stderr, "%s: could not resolve symbol", symbol);
+               }
+               return 0;
+       }
+       return procAddr;
+}
+
+const char *jit_dynlib_get_suffix(void)
+{
+       return "dll";
+}
+
+#elif defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN)
+
+jit_dynlib_handle_t jit_dynlib_open(const char *name)
+{
+       jit_dynlib_handle_t handle;
+       const char *error;
+       handle = (jit_dynlib_handle_t)dlopen(name, RTLD_LAZY | RTLD_GLOBAL);
+       if(!handle)
+       {
+               /* If the name does not start with "lib" and does not
+                  contain a path, then prepend "lib" and try again */
+               if(jit_strncmp(name, "lib", 3) != 0)
+               {
+                       error = name;
+                       while(*error != '\0' && *error != '/' && *error != '\\')
+                       {
+                               ++error;
+                       }
+                       if(*error == '\0')
+                       {
+                               /* Try adding "lib" to the start */
+                               char *temp = (char *)jit_malloc(jit_strlen(name) + 4);
+                               if(temp)
+                               {
+                                       jit_strcpy(temp, "lib");
+                                       jit_strcat(temp, name);
+                                       handle = dlopen(temp, RTLD_LAZY | RTLD_GLOBAL);
+                                       jit_free(temp);
+                                       if(handle)
+                                       {
+                                               return handle;
+                                       }
+                               }
+
+                               /* Reload the original error state */
+                               handle = dlopen(name, RTLD_LAZY | RTLD_GLOBAL);
+                       }
+               }
+
+               /* Report the error, or just clear the error state */
+               if(dynlib_debug)
+               {
+                       error = dlerror();
+                       fprintf(stderr, "%s: %s\n", name,
+                                       (error ? error : "could not load dynamic library"));
+               }
+               else
+               {
+                       dlerror();
+               }
+               return 0;
+       }
+       else
+       {
+               return handle;
+       }
+}
+
+void jit_dynlib_close(jit_dynlib_handle_t handle)
+{
+       dlclose(handle);
+}
+
+void *jit_dynlib_get_symbol(jit_dynlib_handle_t handle, const char *symbol)
+{
+       void *value = dlsym(handle, (char *)symbol);
+       const char *error = dlerror();
+       char *newName;
+       if(error == 0)
+       {
+               return value;
+       }
+       newName = (char *)jit_malloc(jit_strlen(symbol) + 2);
+       if(newName)
+       {
+               /* Try again with '_' prepended to the name in case
+                  we are running on a system with a busted "dlsym" */
+               newName[0] = '_';
+               jit_strcpy(newName + 1, symbol);
+               value = dlsym(handle, newName);
+               error = dlerror();
+               if(error == 0)
+               {
+                       jit_free(newName);
+                       return value;
+               }
+               jit_free(newName);
+       }
+       if(dynlib_debug)
+       {
+               fprintf(stderr, "%s: %s\n", symbol, error);
+       }
+       return 0;
+}
+
+const char *jit_dynlib_get_suffix(void)
+{
+       return "so";
+}
+
+#else  /* No dynamic library support */
+
+jit_dynlib_handle_t jit_dynlib_open(const char *name)
+{
+       if(dynlib_debug)
+       {
+               fprintf(stderr, "%s: dynamic libraries are not available\n", name);
+       }
+       return 0;
+}
+
+void jit_dynlib_close(jit_dynlib_handle_t handle)
+{
+}
+
+void *jit_dynlib_get_symbol(jit_dynlib_handle_t handle, const char *symbol)
+{
+       return 0;
+}
+
+const char *jit_dynlib_get_suffix(void)
+{
+       return "so";
+}
+
+#endif /* No dynamic library support */
+
+#ifdef __cplusplus
+};
+#endif
diff --git a/jit/jit-elf-defs.h b/jit/jit-elf-defs.h
new file mode 100644 (file)
index 0000000..11cb6be
--- /dev/null
@@ -0,0 +1,2134 @@
+/* This file defines standard ELF types, structures, and macros.
+   Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _JIT_ELF_DEFS_H
+#define        _JIT_ELF_DEFS_H 1
+
+/* This is the GNU/Linux <elf.h> file, with slight modifications
+   to compile within the libjit environment */
+#include <jit/jit-defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Standard ELF types.  */
+
+/* Type for a 16-bit quantity.  */
+typedef jit_ushort Elf32_Half;
+typedef jit_ushort Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities.  */
+typedef jit_uint Elf32_Word;
+typedef        jit_int  Elf32_Sword;
+typedef jit_uint Elf64_Word;
+typedef        jit_int  Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities.  */
+typedef jit_ulong Elf32_Xword;
+typedef        jit_long  Elf32_Sxword;
+typedef jit_ulong Elf64_Xword;
+typedef        jit_long  Elf64_Sxword;
+
+/* Type of addresses.  */
+typedef jit_uint Elf32_Addr;
+typedef jit_ulong Elf64_Addr;
+
+/* Type of file offsets.  */
+typedef jit_uint Elf32_Off;
+typedef jit_ulong Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities.  */
+typedef jit_ushort Elf32_Section;
+typedef jit_ushort Elf64_Section;
+
+/* Type for version symbol information.  */
+typedef Elf32_Half Elf32_Versym;
+typedef Elf64_Half Elf64_Versym;
+
+
+/* The ELF file header.  This appears at the start of every ELF file.  */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+  unsigned char        e_ident[EI_NIDENT];     /* Magic number and other info */
+  Elf32_Half   e_type;                 /* Object file type */
+  Elf32_Half   e_machine;              /* Architecture */
+  Elf32_Word   e_version;              /* Object file version */
+  Elf32_Addr   e_entry;                /* Entry point virtual address */
+  Elf32_Off    e_phoff;                /* Program header table file offset */
+  Elf32_Off    e_shoff;                /* Section header table file offset */
+  Elf32_Word   e_flags;                /* Processor-specific flags */
+  Elf32_Half   e_ehsize;               /* ELF header size in bytes */
+  Elf32_Half   e_phentsize;            /* Program header table entry size */
+  Elf32_Half   e_phnum;                /* Program header table entry count */
+  Elf32_Half   e_shentsize;            /* Section header table entry size */
+  Elf32_Half   e_shnum;                /* Section header table entry count */
+  Elf32_Half   e_shstrndx;             /* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+  unsigned char        e_ident[EI_NIDENT];     /* Magic number and other info */
+  Elf64_Half   e_type;                 /* Object file type */
+  Elf64_Half   e_machine;              /* Architecture */
+  Elf64_Word   e_version;              /* Object file version */
+  Elf64_Addr   e_entry;                /* Entry point virtual address */
+  Elf64_Off    e_phoff;                /* Program header table file offset */
+  Elf64_Off    e_shoff;                /* Section header table file offset */
+  Elf64_Word   e_flags;                /* Processor-specific flags */
+  Elf64_Half   e_ehsize;               /* ELF header size in bytes */
+  Elf64_Half   e_phentsize;            /* Program header table entry size */
+  Elf64_Half   e_phnum;                /* Program header table entry count */
+  Elf64_Half   e_shentsize;            /* Section header table entry size */
+  Elf64_Half   e_shnum;                /* Section header table entry count */
+  Elf64_Half   e_shstrndx;             /* Section header string table index */
+} Elf64_Ehdr;
+
+/* Fields in the e_ident array.  The EI_* macros are indices into the
+   array.  The macros under each EI_* macro are the values the byte
+   may have.  */
+
+#define EI_MAG0                0               /* File identification byte 0 index */
+#define ELFMAG0                0x7f            /* Magic number byte 0 */
+
+#define EI_MAG1                1               /* File identification byte 1 index */
+#define ELFMAG1                'E'             /* Magic number byte 1 */
+
+#define EI_MAG2                2               /* File identification byte 2 index */
+#define ELFMAG2                'L'             /* Magic number byte 2 */
+
+#define EI_MAG3                3               /* File identification byte 3 index */
+#define ELFMAG3                'F'             /* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word.  */
+#define        ELFMAG          "\177ELF"
+#define        SELFMAG         4
+
+#define EI_CLASS       4               /* File class byte index */
+#define ELFCLASSNONE   0               /* Invalid class */
+#define ELFCLASS32     1               /* 32-bit objects */
+#define ELFCLASS64     2               /* 64-bit objects */
+#define ELFCLASSNUM    3
+
+#define EI_DATA                5               /* Data encoding byte index */
+#define ELFDATANONE    0               /* Invalid data encoding */
+#define ELFDATA2LSB    1               /* 2's complement, little endian */
+#define ELFDATA2MSB    2               /* 2's complement, big endian */
+#define ELFDATANUM     3
+
+#define EI_VERSION     6               /* File version byte index */
+                                       /* Value must be EV_CURRENT */
+
+#define EI_OSABI       7               /* OS ABI identification */
+#define ELFOSABI_NONE          0       /* UNIX System V ABI */
+#define ELFOSABI_SYSV          0       /* Alias.  */
+#define ELFOSABI_HPUX          1       /* HP-UX */
+#define ELFOSABI_NETBSD                2       /* NetBSD.  */
+#define ELFOSABI_LINUX         3       /* Linux.  */
+#define ELFOSABI_SOLARIS       6       /* Sun Solaris.  */
+#define ELFOSABI_AIX           7       /* IBM AIX.  */
+#define ELFOSABI_IRIX          8       /* SGI Irix.  */
+#define ELFOSABI_FREEBSD       9       /* FreeBSD.  */
+#define ELFOSABI_TRU64         10      /* Compaq TRU64 UNIX.  */
+#define ELFOSABI_MODESTO       11      /* Novell Modesto.  */
+#define ELFOSABI_OPENBSD       12      /* OpenBSD.  */
+#define ELFOSABI_ARM           97      /* ARM */
+#define ELFOSABI_STANDALONE    255     /* Standalone (embedded) application */
+
+#define EI_ABIVERSION  8               /* ABI version */
+
+#define EI_PAD         9               /* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type).  */
+
+#define ET_NONE                0               /* No file type */
+#define ET_REL         1               /* Relocatable file */
+#define ET_EXEC                2               /* Executable file */
+#define ET_DYN         3               /* Shared object file */
+#define ET_CORE                4               /* Core file */
+#define        ET_NUM          5               /* Number of defined types */
+#define ET_LOOS                0xfe00          /* OS-specific range start */
+#define ET_HIOS                0xfeff          /* OS-specific range end */
+#define ET_LOPROC      0xff00          /* Processor-specific range start */
+#define ET_HIPROC      0xffff          /* Processor-specific range end */
+
+/* Legal values for e_machine (architecture).  */
+
+#define EM_NONE                 0              /* No machine */
+#define EM_M32          1              /* AT&T WE 32100 */
+#define EM_SPARC        2              /* SUN SPARC */
+#define EM_386          3              /* Intel 80386 */
+#define EM_68K          4              /* Motorola m68k family */
+#define EM_88K          5              /* Motorola m88k family */
+#define EM_860          7              /* Intel 80860 */
+#define EM_MIPS                 8              /* MIPS R3000 big-endian */
+#define EM_S370                 9              /* IBM System/370 */
+#define EM_MIPS_RS3_LE 10              /* MIPS R3000 little-endian */
+
+#define EM_PARISC      15              /* HPPA */
+#define EM_VPP500      17              /* Fujitsu VPP500 */
+#define EM_SPARC32PLUS 18              /* Sun's "v8plus" */
+#define EM_960         19              /* Intel 80960 */
+#define EM_PPC         20              /* PowerPC */
+#define EM_PPC64       21              /* PowerPC 64-bit */
+#define EM_S390                22              /* IBM S390 */
+
+#define EM_V800                36              /* NEC V800 series */
+#define EM_FR20                37              /* Fujitsu FR20 */
+#define EM_RH32                38              /* TRW RH-32 */
+#define EM_RCE         39              /* Motorola RCE */
+#define EM_ARM         40              /* ARM */
+#define EM_FAKE_ALPHA  41              /* Digital Alpha */
+#define EM_SH          42              /* Hitachi SH */
+#define EM_SPARCV9     43              /* SPARC v9 64-bit */
+#define EM_TRICORE     44              /* Siemens Tricore */
+#define EM_ARC         45              /* Argonaut RISC Core */
+#define EM_H8_300      46              /* Hitachi H8/300 */
+#define EM_H8_300H     47              /* Hitachi H8/300H */
+#define EM_H8S         48              /* Hitachi H8S */
+#define EM_H8_500      49              /* Hitachi H8/500 */
+#define EM_IA_64       50              /* Intel Merced */
+#define EM_MIPS_X      51              /* Stanford MIPS-X */
+#define EM_COLDFIRE    52              /* Motorola Coldfire */
+#define EM_68HC12      53              /* Motorola M68HC12 */
+#define EM_MMA         54              /* Fujitsu MMA Multimedia Accelerator*/
+#define EM_PCP         55              /* Siemens PCP */
+#define EM_NCPU                56              /* Sony nCPU embeeded RISC */
+#define EM_NDR1                57              /* Denso NDR1 microprocessor */
+#define EM_STARCORE    58              /* Motorola Start*Core processor */
+#define EM_ME16                59              /* Toyota ME16 processor */
+#define EM_ST100       60              /* STMicroelectronic ST100 processor */
+#define EM_TINYJ       61              /* Advanced Logic Corp. Tinyj emb.fam*/
+#define EM_X86_64      62              /* AMD x86-64 architecture */
+#define EM_PDSP                63              /* Sony DSP Processor */
+
+#define EM_FX66                66              /* Siemens FX66 microcontroller */
+#define EM_ST9PLUS     67              /* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7         68              /* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16      69              /* Motorola MC68HC16 microcontroller */
+#define EM_68HC11      70              /* Motorola MC68HC11 microcontroller */
+#define EM_68HC08      71              /* Motorola MC68HC08 microcontroller */
+#define EM_68HC05      72              /* Motorola MC68HC05 microcontroller */
+#define EM_SVX         73              /* Silicon Graphics SVx */
+#define EM_AT19                74              /* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX         75              /* Digital VAX */
+#define EM_CRIS                76              /* Axis Communications 32-bit embedded processor */
+#define EM_JAVELIN     77              /* Infineon Technologies 32-bit embedded processor */
+#define EM_FIREPATH    78              /* Element 14 64-bit DSP Processor */
+#define EM_ZSP         79              /* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX                80              /* Donald Knuth's educational 64-bit processor */
+#define EM_HUANY       81              /* Harvard University machine-independent object files */
+#define EM_PRISM       82              /* SiTera Prism */
+#define EM_AVR         83              /* Atmel AVR 8-bit microcontroller */
+#define EM_FR30                84              /* Fujitsu FR30 */
+#define EM_D10V                85              /* Mitsubishi D10V */
+#define EM_D30V                86              /* Mitsubishi D30V */
+#define EM_V850                87              /* NEC v850 */
+#define EM_M32R                88              /* Mitsubishi M32R */
+#define EM_MN10300     89              /* Matsushita MN10300 */
+#define EM_MN10200     90              /* Matsushita MN10200 */
+#define EM_PJ          91              /* picoJava */
+#define EM_OPENRISC    92              /* OpenRISC 32-bit embedded processor */
+#define EM_ARC_A5      93              /* ARC Cores Tangent-A5 */
+#define EM_XTENSA      94              /* Tensilica Xtensa Architecture */
+#define EM_NUM         95
+
+/* If it is necessary to assign new unofficial EM_* values, please
+   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+   chances of collision with official or non-GNU unofficial values.  */
+
+#define EM_ALPHA       0x9026
+
+/* Legal values for e_version (version).  */
+
+#define EV_NONE                0               /* Invalid ELF version */
+#define EV_CURRENT     1               /* Current version */
+#define EV_NUM         2
+
+/* Section header.  */
+
+typedef struct
+{
+  Elf32_Word   sh_name;                /* Section name (string tbl index) */
+  Elf32_Word   sh_type;                /* Section type */
+  Elf32_Word   sh_flags;               /* Section flags */
+  Elf32_Addr   sh_addr;                /* Section virtual addr at execution */
+  Elf32_Off    sh_offset;              /* Section file offset */
+  Elf32_Word   sh_size;                /* Section size in bytes */
+  Elf32_Word   sh_link;                /* Link to another section */
+  Elf32_Word   sh_info;                /* Additional section information */
+  Elf32_Word   sh_addralign;           /* Section alignment */
+  Elf32_Word   sh_entsize;             /* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+  Elf64_Word   sh_name;                /* Section name (string tbl index) */
+  Elf64_Word   sh_type;                /* Section type */
+  Elf64_Xword  sh_flags;               /* Section flags */
+  Elf64_Addr   sh_addr;                /* Section virtual addr at execution */
+  Elf64_Off    sh_offset;              /* Section file offset */
+  Elf64_Xword  sh_size;                /* Section size in bytes */
+  Elf64_Word   sh_link;                /* Link to another section */
+  Elf64_Word   sh_info;                /* Additional section information */
+  Elf64_Xword  sh_addralign;           /* Section alignment */
+  Elf64_Xword  sh_entsize;             /* Entry size if section holds table */
+} Elf64_Shdr;
+
+/* Special section indices.  */
+
+#define SHN_UNDEF      0               /* Undefined section */
+#define SHN_LORESERVE  0xff00          /* Start of reserved indices */
+#define SHN_LOPROC     0xff00          /* Start of processor-specific */
+#define SHN_HIPROC     0xff1f          /* End of processor-specific */
+#define SHN_LOOS       0xff20          /* Start of OS-specific */
+#define SHN_HIOS       0xff3f          /* End of OS-specific */
+#define SHN_ABS                0xfff1          /* Associated symbol is absolute */
+#define SHN_COMMON     0xfff2          /* Associated symbol is common */
+#define SHN_XINDEX     0xffff          /* Index is in extra table.  */
+#define SHN_HIRESERVE  0xffff          /* End of reserved indices */
+
+/* Legal values for sh_type (section type).  */
+
+#define SHT_NULL         0             /* Section header table entry unused */
+#define SHT_PROGBITS     1             /* Program data */
+#define SHT_SYMTAB       2             /* Symbol table */
+#define SHT_STRTAB       3             /* String table */
+#define SHT_RELA         4             /* Relocation entries with addends */
+#define SHT_HASH         5             /* Symbol hash table */
+#define SHT_DYNAMIC      6             /* Dynamic linking information */
+#define SHT_NOTE         7             /* Notes */
+#define SHT_NOBITS       8             /* Program space with no data (bss) */
+#define SHT_REL                  9             /* Relocation entries, no addends */
+#define SHT_SHLIB        10            /* Reserved */
+#define SHT_DYNSYM       11            /* Dynamic linker symbol table */
+#define SHT_INIT_ARRAY   14            /* Array of constructors */
+#define SHT_FINI_ARRAY   15            /* Array of destructors */
+#define SHT_PREINIT_ARRAY 16           /* Array of pre-constructors */
+#define SHT_GROUP        17            /* Section group */
+#define SHT_SYMTAB_SHNDX  18           /* Extended section indeces */
+#define        SHT_NUM           19            /* Number of defined types.  */
+#define SHT_LOOS         0x60000000    /* Start OS-specific */
+#define SHT_GNU_LIBLIST          0x6ffffff7    /* Prelink library list */
+#define SHT_CHECKSUM     0x6ffffff8    /* Checksum for DSO content.  */
+#define SHT_LOSUNW       0x6ffffffa    /* Sun-specific low bound.  */
+#define SHT_SUNW_move    0x6ffffffa
+#define SHT_SUNW_COMDAT   0x6ffffffb
+#define SHT_SUNW_syminfo  0x6ffffffc
+#define SHT_GNU_verdef   0x6ffffffd    /* Version definition section.  */
+#define SHT_GNU_verneed          0x6ffffffe    /* Version needs section.  */
+#define SHT_GNU_versym   0x6fffffff    /* Version symbol table.  */
+#define SHT_HISUNW       0x6fffffff    /* Sun-specific high bound.  */
+#define SHT_HIOS         0x6fffffff    /* End OS-specific type */
+#define SHT_LOPROC       0x70000000    /* Start of processor-specific */
+#define SHT_HIPROC       0x7fffffff    /* End of processor-specific */
+#define SHT_LOUSER       0x80000000    /* Start of application-specific */
+#define SHT_HIUSER       0x8fffffff    /* End of application-specific */
+
+/* Legal values for sh_flags (section flags).  */
+
+#define SHF_WRITE           (1 << 0)   /* Writable */
+#define SHF_ALLOC           (1 << 1)   /* Occupies memory during execution */
+#define SHF_EXECINSTR       (1 << 2)   /* Executable */
+#define SHF_MERGE           (1 << 4)   /* Might be merged */
+#define SHF_STRINGS         (1 << 5)   /* Contains nul-terminated strings */
+#define SHF_INFO_LINK       (1 << 6)   /* `sh_info' contains SHT index */
+#define SHF_LINK_ORDER      (1 << 7)   /* Preserve order after combining */
+#define SHF_OS_NONCONFORMING (1 << 8)  /* Non-standard OS specific handling
+                                          required */
+#define SHF_GROUP           (1 << 9)   /* Section is member of a group.  */
+#define SHF_TLS                     (1 << 10)  /* Section hold thread-local data.  */
+#define SHF_MASKOS          0x0ff00000 /* OS-specific.  */
+#define SHF_MASKPROC        0xf0000000 /* Processor-specific */
+
+/* Section group handling.  */
+#define GRP_COMDAT     0x1             /* Mark group as COMDAT.  */
+
+/* Symbol table entry.  */
+
+typedef struct
+{
+  Elf32_Word   st_name;                /* Symbol name (string tbl index) */
+  Elf32_Addr   st_value;               /* Symbol value */
+  Elf32_Word   st_size;                /* Symbol size */
+  unsigned char        st_info;                /* Symbol type and binding */
+  unsigned char        st_other;               /* Symbol visibility */
+  Elf32_Section        st_shndx;               /* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+  Elf64_Word   st_name;                /* Symbol name (string tbl index) */
+  unsigned char        st_info;                /* Symbol type and binding */
+  unsigned char st_other;              /* Symbol visibility */
+  Elf64_Section        st_shndx;               /* Section index */
+  Elf64_Addr   st_value;               /* Symbol value */
+  Elf64_Xword  st_size;                /* Symbol size */
+} Elf64_Sym;
+
+/* The syminfo section if available contains additional information about
+   every dynamic symbol.  */
+
+typedef struct
+{
+  Elf32_Half si_boundto;               /* Direct bindings, symbol bound to */
+  Elf32_Half si_flags;                 /* Per symbol flags */
+} Elf32_Syminfo;
+
+typedef struct
+{
+  Elf64_Half si_boundto;               /* Direct bindings, symbol bound to */
+  Elf64_Half si_flags;                 /* Per symbol flags */
+} Elf64_Syminfo;
+
+/* Possible values for si_boundto.  */
+#define SYMINFO_BT_SELF                0xffff  /* Symbol bound to self */
+#define SYMINFO_BT_PARENT      0xfffe  /* Symbol bound to parent */
+#define SYMINFO_BT_LOWRESERVE  0xff00  /* Beginning of reserved entries */
+
+/* Possible bitmasks for si_flags.  */
+#define SYMINFO_FLG_DIRECT     0x0001  /* Direct bound symbol */
+#define SYMINFO_FLG_PASSTHRU   0x0002  /* Pass-thru symbol for translator */
+#define SYMINFO_FLG_COPY       0x0004  /* Symbol is a copy-reloc */
+#define SYMINFO_FLG_LAZYLOAD   0x0008  /* Symbol bound to object to be lazy
+                                          loaded */
+/* Syminfo version values.  */
+#define SYMINFO_NONE           0
+#define SYMINFO_CURRENT                1
+#define SYMINFO_NUM            2
+
+
+/* Special section index.  */
+
+#define SHN_UNDEF      0               /* No section, undefined symbol.  */
+
+/* How to extract and insert information held in the st_info field.  */
+
+#define ELF32_ST_BIND(val)             (((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val)             ((val) & 0xf)
+#define ELF32_ST_INFO(bind, type)      (((bind) << 4) + ((type) & 0xf))
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.  */
+#define ELF64_ST_BIND(val)             ELF32_ST_BIND (val)
+#define ELF64_ST_TYPE(val)             ELF32_ST_TYPE (val)
+#define ELF64_ST_INFO(bind, type)      ELF32_ST_INFO ((bind), (type))
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
+
+#define STB_LOCAL      0               /* Local symbol */
+#define STB_GLOBAL     1               /* Global symbol */
+#define STB_WEAK       2               /* Weak symbol */
+#define        STB_NUM         3               /* Number of defined types.  */
+#define STB_LOOS       10              /* Start of OS-specific */
+#define STB_HIOS       12              /* End of OS-specific */
+#define STB_LOPROC     13              /* Start of processor-specific */
+#define STB_HIPROC     15              /* End of processor-specific */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_NOTYPE     0               /* Symbol type is unspecified */
+#define STT_OBJECT     1               /* Symbol is a data object */
+#define STT_FUNC       2               /* Symbol is a code object */
+#define STT_SECTION    3               /* Symbol associated with a section */
+#define STT_FILE       4               /* Symbol's name is file name */
+#define STT_COMMON     5               /* Symbol is a common data object */
+#define        STT_NUM         6               /* Number of defined types.  */
+#define STT_LOOS       10              /* Start of OS-specific */
+#define STT_HIOS       12              /* End of OS-specific */
+#define STT_LOPROC     13              /* Start of processor-specific */
+#define STT_HIPROC     15              /* End of processor-specific */
+
+
+/* Symbol table indices are found in the hash buckets and chain table
+   of a symbol hash table section.  This special index value indicates
+   the end of a chain, meaning no further symbols are found in that bucket.  */
+
+#define STN_UNDEF      0               /* End of a chain.  */
+
+
+/* How to extract and insert information held in the st_other field.  */
+
+#define ELF32_ST_VISIBILITY(o) ((o) & 0x03)
+
+/* For ELF64 the definitions are the same.  */
+#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o)
+
+/* Symbol visibility specification encoded in the st_other field.  */
+#define STV_DEFAULT    0               /* Default symbol visibility rules */
+#define STV_INTERNAL   1               /* Processor specific hidden class */
+#define STV_HIDDEN     2               /* Sym unavailable in other modules */
+#define STV_PROTECTED  3               /* Not preemptible, not exported */
+
+
+/* Relocation table entry without addend (in section of type SHT_REL).  */
+
+typedef struct
+{
+  Elf32_Addr   r_offset;               /* Address */
+  Elf32_Word   r_info;                 /* Relocation type and symbol index */
+} Elf32_Rel;
+
+/* I have seen two different definitions of the Elf64_Rel and
+   Elf64_Rela structures, so we'll leave them out until Novell (or
+   whoever) gets their act together.  */
+/* The following, at least, is used on Sparc v9, MIPS, and Alpha.  */
+
+typedef struct
+{
+  Elf64_Addr   r_offset;               /* Address */
+  Elf64_Xword  r_info;                 /* Relocation type and symbol index */
+} Elf64_Rel;
+
+/* Relocation table entry with addend (in section of type SHT_RELA).  */
+
+typedef struct
+{
+  Elf32_Addr   r_offset;               /* Address */
+  Elf32_Word   r_info;                 /* Relocation type and symbol index */
+  Elf32_Sword  r_addend;               /* Addend */
+} Elf32_Rela;
+
+typedef struct
+{
+  Elf64_Addr   r_offset;               /* Address */
+  Elf64_Xword  r_info;                 /* Relocation type and symbol index */
+  Elf64_Sxword r_addend;               /* Addend */
+} Elf64_Rela;
+
+/* How to extract and insert information held in the r_info field.  */
+
+#define ELF32_R_SYM(val)               ((val) >> 8)
+#define ELF32_R_TYPE(val)              ((val) & 0xff)
+#define ELF32_R_INFO(sym, type)                (((sym) << 8) + ((type) & 0xff))
+
+#define ELF64_R_SYM(i)                 ((i) >> 32)
+#define ELF64_R_TYPE(i)                        ((i) & 0xffffffff)
+#define ELF64_R_INFO(sym,type)         ((((Elf64_Xword) (sym)) << 32) + (type))
+
+/* Program segment header.  */
+
+typedef struct
+{
+  Elf32_Word   p_type;                 /* Segment type */
+  Elf32_Off    p_offset;               /* Segment file offset */
+  Elf32_Addr   p_vaddr;                /* Segment virtual address */
+  Elf32_Addr   p_paddr;                /* Segment physical address */
+  Elf32_Word   p_filesz;               /* Segment size in file */
+  Elf32_Word   p_memsz;                /* Segment size in memory */
+  Elf32_Word   p_flags;                /* Segment flags */
+  Elf32_Word   p_align;                /* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+  Elf64_Word   p_type;                 /* Segment type */
+  Elf64_Word   p_flags;                /* Segment flags */
+  Elf64_Off    p_offset;               /* Segment file offset */
+  Elf64_Addr   p_vaddr;                /* Segment virtual address */
+  Elf64_Addr   p_paddr;                /* Segment physical address */
+  Elf64_Xword  p_filesz;               /* Segment size in file */
+  Elf64_Xword  p_memsz;                /* Segment size in memory */
+  Elf64_Xword  p_align;                /* Segment alignment */
+} Elf64_Phdr;
+
+/* Legal values for p_type (segment type).  */
+
+#define        PT_NULL         0               /* Program header table entry unused */
+#define PT_LOAD                1               /* Loadable program segment */
+#define PT_DYNAMIC     2               /* Dynamic linking information */
+#define PT_INTERP      3               /* Program interpreter */
+#define PT_NOTE                4               /* Auxiliary information */
+#define PT_SHLIB       5               /* Reserved */
+#define PT_PHDR                6               /* Entry for header table itself */
+#define PT_TLS         7               /* Thread-local storage segment */
+#define        PT_NUM          8               /* Number of defined types */
+#define PT_LOOS                0x60000000      /* Start of OS-specific */
+#define PT_GNU_EH_FRAME 0x6474e550     /* GCC .eh_frame_hdr segment */
+#define PT_HIOS                0x6fffffff      /* End of OS-specific */
+#define PT_LOPROC      0x70000000      /* Start of processor-specific */
+#define PT_HIPROC      0x7fffffff      /* End of processor-specific */
+
+/* Legal values for p_flags (segment flags).  */
+
+#define PF_X           (1 << 0)        /* Segment is executable */
+#define PF_W           (1 << 1)        /* Segment is writable */
+#define PF_R           (1 << 2)        /* Segment is readable */
+#define PF_MASKOS      0x0ff00000      /* OS-specific */
+#define PF_MASKPROC    0xf0000000      /* Processor-specific */
+
+/* Legal values for note segment descriptor types for core files. */
+
+#define NT_PRSTATUS    1               /* Contains copy of prstatus struct */
+#define NT_FPREGSET    2               /* Contains copy of fpregset struct */
+#define NT_PRPSINFO    3               /* Contains copy of prpsinfo struct */
+#define NT_PRXREG      4               /* Contains copy of prxregset struct */
+#define NT_PLATFORM    5               /* String from sysinfo(SI_PLATFORM) */
+#define NT_AUXV                6               /* Contains copy of auxv array */
+#define NT_GWINDOWS    7               /* Contains copy of gwindows struct */
+#define NT_PSTATUS     10              /* Contains copy of pstatus struct */
+#define NT_PSINFO      13              /* Contains copy of psinfo struct */
+#define NT_PRCRED      14              /* Contains copy of prcred struct */
+#define NT_UTSNAME     15              /* Contains copy of utsname struct */
+#define NT_LWPSTATUS   16              /* Contains copy of lwpstatus struct */
+#define NT_LWPSINFO    17              /* Contains copy of lwpinfo struct */
+#define NT_PRFPXREG    20              /* Contains copy of fprxregset struct*/
+
+/* Legal values for the note segment descriptor types for object files.  */
+
+#define NT_VERSION     1               /* Contains a version string.  */
+
+
+/* Dynamic section entry.  */
+
+typedef struct
+{
+  Elf32_Sword  d_tag;                  /* Dynamic entry type */
+  union
+    {
+      Elf32_Word d_val;                        /* Integer value */
+      Elf32_Addr d_ptr;                        /* Address value */
+    } d_un;
+} Elf32_Dyn;
+
+typedef struct
+{
+  Elf64_Sxword d_tag;                  /* Dynamic entry type */
+  union
+    {
+      Elf64_Xword d_val;               /* Integer value */
+      Elf64_Addr d_ptr;                        /* Address value */
+    } d_un;
+} Elf64_Dyn;
+
+/* Legal values for d_tag (dynamic entry type).  */
+
+#define DT_NULL                0               /* Marks end of dynamic section */
+#define DT_NEEDED      1               /* Name of needed library */
+#define DT_PLTRELSZ    2               /* Size in bytes of PLT relocs */
+#define DT_PLTGOT      3               /* Processor defined value */
+#define DT_HASH                4               /* Address of symbol hash table */
+#define DT_STRTAB      5               /* Address of string table */
+#define DT_SYMTAB      6               /* Address of symbol table */
+#define DT_RELA                7               /* Address of Rela relocs */
+#define DT_RELASZ      8               /* Total size of Rela relocs */
+#define DT_RELAENT     9               /* Size of one Rela reloc */
+#define DT_STRSZ       10              /* Size of string table */
+#define DT_SYMENT      11              /* Size of one symbol table entry */
+#define DT_INIT                12              /* Address of init function */
+#define DT_FINI                13              /* Address of termination function */
+#define DT_SONAME      14              /* Name of shared object */
+#define DT_RPATH       15              /* Library search path (deprecated) */
+#define DT_SYMBOLIC    16              /* Start symbol search here */
+#define DT_REL         17              /* Address of Rel relocs */
+#define DT_RELSZ       18              /* Total size of Rel relocs */
+#define DT_RELENT      19              /* Size of one Rel reloc */
+#define DT_PLTREL      20              /* Type of reloc in PLT */
+#define DT_DEBUG       21              /* For debugging; unspecified */
+#define DT_TEXTREL     22              /* Reloc might modify .text */
+#define DT_JMPREL      23              /* Address of PLT relocs */
+#define        DT_BIND_NOW     24              /* Process relocations of object */
+#define        DT_INIT_ARRAY   25              /* Array with addresses of init fct */
+#define        DT_FINI_ARRAY   26              /* Array with addresses of fini fct */
+#define        DT_INIT_ARRAYSZ 27              /* Size in bytes of DT_INIT_ARRAY */
+#define        DT_FINI_ARRAYSZ 28              /* Size in bytes of DT_FINI_ARRAY */
+#define DT_RUNPATH     29              /* Library search path */
+#define DT_FLAGS       30              /* Flags for the object being loaded */
+#define DT_ENCODING    32              /* Start of encoded range */
+#define DT_PREINIT_ARRAY 32            /* Array with addresses of preinit fct*/
+#define DT_PREINIT_ARRAYSZ 33          /* size in bytes of DT_PREINIT_ARRAY */
+#define        DT_NUM          34              /* Number used */
+#define DT_LOOS                0x60000000      /* Start of OS-specific */
+#define DT_HIOS                0x6fffffff      /* End of OS-specific */
+#define DT_LOPROC      0x70000000      /* Start of processor-specific */
+#define DT_HIPROC      0x7fffffff      /* End of processor-specific */
+#define        DT_PROCNUM      DT_MIPS_NUM     /* Most used by any processor */
+
+/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
+   Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
+   approach.  */
+#define DT_VALRNGLO    0x6ffffd00
+#define DT_GNU_PRELINKED 0x6ffffdf5    /* Prelinking timestamp */
+#define DT_GNU_CONFLICTSZ 0x6ffffdf6   /* Size of conflict section */
+#define DT_GNU_LIBLISTSZ 0x6ffffdf7    /* Size of library list */
+#define DT_CHECKSUM    0x6ffffdf8
+#define DT_PLTPADSZ    0x6ffffdf9
+#define DT_MOVEENT     0x6ffffdfa
+#define DT_MOVESZ      0x6ffffdfb
+#define DT_FEATURE_1   0x6ffffdfc      /* Feature selection (DTF_*).  */
+#define DT_POSFLAG_1   0x6ffffdfd      /* Flags for DT_* entries, effecting
+                                          the following DT_* entry.  */
+#define DT_SYMINSZ     0x6ffffdfe      /* Size of syminfo table (in bytes) */
+#define DT_SYMINENT    0x6ffffdff      /* Entry size of syminfo */
+#define DT_VALRNGHI    0x6ffffdff
+
+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+   Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+
+   If any adjustment is made to the ELF object after it has been
+   built these entries will need to be adjusted.  */
+#define DT_ADDRRNGLO   0x6ffffe00
+#define DT_GNU_CONFLICT        0x6ffffef8      /* Start of conflict section */
+#define DT_GNU_LIBLIST 0x6ffffef9      /* Library list */
+#define DT_CONFIG      0x6ffffefa      /* Configuration information.  */
+#define DT_DEPAUDIT    0x6ffffefb      /* Dependency auditing.  */
+#define DT_AUDIT       0x6ffffefc      /* Object auditing.  */
+#define        DT_PLTPAD       0x6ffffefd      /* PLT padding.  */
+#define        DT_MOVETAB      0x6ffffefe      /* Move table.  */
+#define DT_SYMINFO     0x6ffffeff      /* Syminfo table.  */
+#define DT_ADDRRNGHI   0x6ffffeff
+
+/* The versioning entry types.  The next are defined as part of the
+   GNU extension.  */
+#define DT_VERSYM      0x6ffffff0
+
+#define DT_RELACOUNT   0x6ffffff9
+#define DT_RELCOUNT    0x6ffffffa
+
+/* These were chosen by Sun.  */
+#define DT_FLAGS_1     0x6ffffffb      /* State flags, see DF_1_* below.  */
+#define        DT_VERDEF       0x6ffffffc      /* Address of version definition
+                                          table */
+#define        DT_VERDEFNUM    0x6ffffffd      /* Number of version definitions */
+#define        DT_VERNEED      0x6ffffffe      /* Address of table with needed
+                                          versions */
+#define        DT_VERNEEDNUM   0x6fffffff      /* Number of needed versions */
+#define DT_VERSIONTAGIDX(tag)  (DT_VERNEEDNUM - (tag)) /* Reverse order! */
+#define DT_VERSIONTAGNUM 16
+
+/* Sun added these machine-independent extensions in the "processor-specific"
+   range.  Be compatible.  */
+#define DT_AUXILIARY    0x7ffffffd      /* Shared object to load before self */
+#define DT_FILTER       0x7fffffff      /* Shared object to get values from */
+#define DT_EXTRATAGIDX(tag)    ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
+#define DT_EXTRANUM    3
+
+/* Values of `d_un.d_val' in the DT_FLAGS entry.  */
+#define DF_ORIGIN      0x00000001      /* Object may use DF_ORIGIN */
+#define DF_SYMBOLIC    0x00000002      /* Symbol resolutions starts here */
+#define DF_TEXTREL     0x00000004      /* Object contains text relocations */
+#define DF_BIND_NOW    0x00000008      /* No lazy binding for this object */
+
+/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
+   entry in the dynamic section.  */
+#define DF_1_NOW       0x00000001      /* Set RTLD_NOW for this object.  */
+#define DF_1_GLOBAL    0x00000002      /* Set RTLD_GLOBAL for this object.  */
+#define DF_1_GROUP     0x00000004      /* Set RTLD_GROUP for this object.  */
+#define DF_1_NODELETE  0x00000008      /* Set RTLD_NODELETE for this object.*/
+#define DF_1_LOADFLTR  0x00000010      /* Trigger filtee loading at runtime.*/
+#define DF_1_INITFIRST 0x00000020      /* Set RTLD_INITFIRST for this object*/
+#define DF_1_NOOPEN    0x00000040      /* Set RTLD_NOOPEN for this object.  */
+#define DF_1_ORIGIN    0x00000080      /* $ORIGIN must be handled.  */
+#define DF_1_DIRECT    0x00000100      /* Direct binding enabled.  */
+#define DF_1_TRANS     0x00000200
+#define DF_1_INTERPOSE 0x00000400      /* Object is used to interpose.  */
+#define DF_1_NODEFLIB  0x00000800      /* Ignore default lib search path.  */
+#define DF_1_NODUMP    0x00001000      /* Object can't be dldump'ed.  */
+#define DF_1_CONFALT   0x00002000      /* Configuration alternative created.*/
+#define DF_1_ENDFILTEE 0x00004000      /* Filtee terminates filters search. */
+#define        DF_1_DISPRELDNE 0x00008000      /* Disp reloc applied at build time. */
+#define        DF_1_DISPRELPND 0x00010000      /* Disp reloc applied at run-time.  */
+
+/* Flags for the feature selection in DT_FEATURE_1.  */
+#define DTF_1_PARINIT  0x00000001
+#define DTF_1_CONFEXP  0x00000002
+
+/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry.  */
+#define DF_P1_LAZYLOAD 0x00000001      /* Lazyload following object.  */
+#define DF_P1_GROUPPERM        0x00000002      /* Symbols from next object are not
+                                          generally available.  */
+
+/* Version definition sections.  */
+
+typedef struct
+{
+  Elf32_Half   vd_version;             /* Version revision */
+  Elf32_Half   vd_flags;               /* Version information */
+  Elf32_Half   vd_ndx;                 /* Version Index */
+  Elf32_Half   vd_cnt;                 /* Number of associated aux entries */
+  Elf32_Word   vd_hash;                /* Version name hash value */
+  Elf32_Word   vd_aux;                 /* Offset in bytes to verdaux array */
+  Elf32_Word   vd_next;                /* Offset in bytes to next verdef
+                                          entry */
+} Elf32_Verdef;
+
+typedef struct
+{
+  Elf64_Half   vd_version;             /* Version revision */
+  Elf64_Half   vd_flags;               /* Version information */
+  Elf64_Half   vd_ndx;                 /* Version Index */
+  Elf64_Half   vd_cnt;                 /* Number of associated aux entries */
+  Elf64_Word   vd_hash;                /* Version name hash value */
+  Elf64_Word   vd_aux;                 /* Offset in bytes to verdaux array */
+  Elf64_Word   vd_next;                /* Offset in bytes to next verdef
+                                          entry */
+} Elf64_Verdef;
+
+
+/* Legal values for vd_version (version revision).  */
+#define VER_DEF_NONE   0               /* No version */
+#define VER_DEF_CURRENT        1               /* Current version */
+#define VER_DEF_NUM    2               /* Given version number */
+
+/* Legal values for vd_flags (version information flags).  */
+#define VER_FLG_BASE   0x1             /* Version definition of file itself */
+#define VER_FLG_WEAK   0x2             /* Weak version identifier */
+
+/* Versym symbol index values.  */
+#define        VER_NDX_LOCAL           0       /* Symbol is local.  */
+#define        VER_NDX_GLOBAL          1       /* Symbol is global.  */
+#define        VER_NDX_LORESERVE       0xff00  /* Beginning of reserved entries.  */
+#define        VER_NDX_ELIMINATE       0xff01  /* Symbol is to be eliminated.  */
+
+/* Auxialiary version information.  */
+
+typedef struct
+{
+  Elf32_Word   vda_name;               /* Version or dependency names */
+  Elf32_Word   vda_next;               /* Offset in bytes to next verdaux
+                                          entry */
+} Elf32_Verdaux;
+
+typedef struct
+{
+  Elf64_Word   vda_name;               /* Version or dependency names */
+  Elf64_Word   vda_next;               /* Offset in bytes to next verdaux
+                                          entry */
+} Elf64_Verdaux;
+
+
+/* Version dependency section.  */
+
+typedef struct
+{
+  Elf32_Half   vn_version;             /* Version of structure */
+  Elf32_Half   vn_cnt;                 /* Number of associated aux entries */
+  Elf32_Word   vn_file;                /* Offset of filename for this
+                                          dependency */
+  Elf32_Word   vn_aux;                 /* Offset in bytes to vernaux array */
+  Elf32_Word   vn_next;                /* Offset in bytes to next verneed
+                                          entry */
+} Elf32_Verneed;
+
+typedef struct
+{
+  Elf64_Half   vn_version;             /* Version of structure */
+  Elf64_Half   vn_cnt;                 /* Number of associated aux entries */
+  Elf64_Word   vn_file;                /* Offset of filename for this
+                                          dependency */
+  Elf64_Word   vn_aux;                 /* Offset in bytes to vernaux array */
+  Elf64_Word   vn_next;                /* Offset in bytes to next verneed
+                                          entry */
+} Elf64_Verneed;
+
+
+/* Legal values for vn_version (version revision).  */
+#define VER_NEED_NONE   0              /* No version */
+#define VER_NEED_CURRENT 1             /* Current version */
+#define VER_NEED_NUM    2              /* Given version number */
+
+/* Auxiliary needed version information.  */
+
+typedef struct
+{
+  Elf32_Word   vna_hash;               /* Hash value of dependency name */
+  Elf32_Half   vna_flags;              /* Dependency specific information */
+  Elf32_Half   vna_other;              /* Unused */
+  Elf32_Word   vna_name;               /* Dependency name string offset */
+  Elf32_Word   vna_next;               /* Offset in bytes to next vernaux
+                                          entry */
+} Elf32_Vernaux;
+
+typedef struct
+{
+  Elf64_Word   vna_hash;               /* Hash value of dependency name */
+  Elf64_Half   vna_flags;              /* Dependency specific information */
+  Elf64_Half   vna_other;              /* Unused */
+  Elf64_Word   vna_name;               /* Dependency name string offset */
+  Elf64_Word   vna_next;               /* Offset in bytes to next vernaux
+                                          entry */
+} Elf64_Vernaux;
+
+
+/* Legal values for vna_flags.  */
+#define VER_FLG_WEAK   0x2             /* Weak version identifier */
+
+
+/* Auxiliary vector.  */
+
+/* This vector is normally only used by the program interpreter.  The
+   usual definition in an ABI supplement uses the name auxv_t.  The
+   vector is not usually defined in a standard <elf.h> file, but it
+   can't hurt.  We rename it to avoid conflicts.  The sizes of these
+   types are an arrangement between the exec server and the program
+   interpreter, so we don't fully specify them here.  */
+
+typedef struct
+{
+  int a_type;                  /* Entry type */
+  union
+    {
+      long int a_val;          /* Integer value */
+      void *a_ptr;             /* Pointer value */
+      void (*a_fcn) (void);    /* Function pointer value */
+    } a_un;
+} Elf32_auxv_t;
+
+typedef struct
+{
+  long int a_type;             /* Entry type */
+  union
+    {
+      long int a_val;          /* Integer value */
+      void *a_ptr;             /* Pointer value */
+      void (*a_fcn) (void);    /* Function pointer value */
+    } a_un;
+} Elf64_auxv_t;
+
+/* Legal values for a_type (entry type).  */
+
+#define AT_NULL                0               /* End of vector */
+#define AT_IGNORE      1               /* Entry should be ignored */
+#define AT_EXECFD      2               /* File descriptor of program */
+#define AT_PHDR                3               /* Program headers for program */
+#define AT_PHENT       4               /* Size of program header entry */
+#define AT_PHNUM       5               /* Number of program headers */
+#define AT_PAGESZ      6               /* System page size */
+#define AT_BASE                7               /* Base address of interpreter */
+#define AT_FLAGS       8               /* Flags */
+#define AT_ENTRY       9               /* Entry point of program */
+#define AT_NOTELF      10              /* Program is not ELF */
+#define AT_UID         11              /* Real uid */
+#define AT_EUID                12              /* Effective uid */
+#define AT_GID         13              /* Real gid */
+#define AT_EGID                14              /* Effective gid */
+#define AT_CLKTCK      17              /* Frequency of times() */
+
+/* Some more special a_type values describing the hardware.  */
+#define AT_PLATFORM    15              /* String identifying platform.  */
+#define AT_HWCAP       16              /* Machine dependent hints about
+                                          processor capabilities.  */
+
+/* This entry gives some information about the FPU initialization
+   performed by the kernel.  */
+#define AT_FPUCW       18              /* Used FPU control word.  */
+
+/* Cache block sizes.  */
+#define AT_DCACHEBSIZE 19              /* Data cache block size.  */
+#define AT_ICACHEBSIZE 20              /* Instruction cache block size.  */
+#define AT_UCACHEBSIZE 21              /* Unified cache block size.  */
+
+/* A special ignored value for PPC, used by the kernel to control the
+   interpretation of the AUXV. Must be > 16.  */
+#define AT_IGNOREPPC   22              /* Entry should be ignored */
+
+
+/* Note section contents.  Each entry in the note section begins with
+   a header of a fixed form.  */
+
+typedef struct
+{
+  Elf32_Word n_namesz;                 /* Length of the note's name.  */
+  Elf32_Word n_descsz;                 /* Length of the note's descriptor.  */
+  Elf32_Word n_type;                   /* Type of the note.  */
+} Elf32_Nhdr;
+
+typedef struct
+{
+  Elf64_Word n_namesz;                 /* Length of the note's name.  */
+  Elf64_Word n_descsz;                 /* Length of the note's descriptor.  */
+  Elf64_Word n_type;                   /* Type of the note.  */
+} Elf64_Nhdr;
+
+/* Known names of notes.  */
+
+/* Solaris entries in the note section have this name.  */
+#define ELF_NOTE_SOLARIS       "SUNW Solaris"
+
+/* Note entries for GNU systems have this name.  */
+#define ELF_NOTE_GNU           "GNU"
+
+
+/* Defined types of notes for Solaris.  */
+
+/* Value of descriptor (one word) is desired pagesize for the binary.  */
+#define ELF_NOTE_PAGESIZE_HINT 1
+
+
+/* Defined note types for GNU systems.  */
+
+/* ABI information.  The descriptor consists of words:
+   word 0: OS descriptor
+   word 1: major version of the ABI
+   word 2: minor version of the ABI
+   word 3: subminor version of the ABI
+*/
+#define ELF_NOTE_ABI           1
+
+/* Known OSes.  These value can appear in word 0 of an ELF_NOTE_ABI
+   note section entry.  */
+#define ELF_NOTE_OS_LINUX      0
+#define ELF_NOTE_OS_GNU                1
+#define ELF_NOTE_OS_SOLARIS2   2
+
+
+/* Move records.  */
+typedef struct
+{
+  Elf32_Xword m_value;         /* Symbol value.  */
+  Elf32_Word m_info;           /* Size and index.  */
+  Elf32_Word m_poffset;                /* Symbol offset.  */
+  Elf32_Half m_repeat;         /* Repeat count.  */
+  Elf32_Half m_stride;         /* Stride info.  */
+} Elf32_Move;
+
+typedef struct
+{
+  Elf64_Xword m_value;         /* Symbol value.  */
+  Elf64_Xword m_info;          /* Size and index.  */
+  Elf64_Xword m_poffset;       /* Symbol offset.  */
+  Elf64_Half m_repeat;         /* Repeat count.  */
+  Elf64_Half m_stride;         /* Stride info.  */
+} Elf64_Move;
+
+/* Macro to construct move records.  */
+#define ELF32_M_SYM(info)      ((info) >> 8)
+#define ELF32_M_SIZE(info)     ((unsigned char) (info))
+#define ELF32_M_INFO(sym, size)        (((sym) << 8) + (unsigned char) (size))
+
+#define ELF64_M_SYM(info)      ELF32_M_SYM (info)
+#define ELF64_M_SIZE(info)     ELF32_M_SIZE (info)
+#define ELF64_M_INFO(sym, size)        ELF32_M_INFO (sym, size)
+
+
+/* Motorola 68k specific definitions.  */
+
+/* Values for Elf32_Ehdr.e_flags.  */
+#define EF_CPU32       0x00810000
+
+/* m68k relocs.  */
+
+#define R_68K_NONE     0               /* No reloc */
+#define R_68K_32       1               /* Direct 32 bit  */
+#define R_68K_16       2               /* Direct 16 bit  */
+#define R_68K_8                3               /* Direct 8 bit  */
+#define R_68K_PC32     4               /* PC relative 32 bit */
+#define R_68K_PC16     5               /* PC relative 16 bit */
+#define R_68K_PC8      6               /* PC relative 8 bit */
+#define R_68K_GOT32    7               /* 32 bit PC relative GOT entry */
+#define R_68K_GOT16    8               /* 16 bit PC relative GOT entry */
+#define R_68K_GOT8     9               /* 8 bit PC relative GOT entry */
+#define R_68K_GOT32O   10              /* 32 bit GOT offset */
+#define R_68K_GOT16O   11              /* 16 bit GOT offset */
+#define R_68K_GOT8O    12              /* 8 bit GOT offset */
+#define R_68K_PLT32    13              /* 32 bit PC relative PLT address */
+#define R_68K_PLT16    14              /* 16 bit PC relative PLT address */
+#define R_68K_PLT8     15              /* 8 bit PC relative PLT address */
+#define R_68K_PLT32O   16              /* 32 bit PLT offset */
+#define R_68K_PLT16O   17              /* 16 bit PLT offset */
+#define R_68K_PLT8O    18              /* 8 bit PLT offset */
+#define R_68K_COPY     19              /* Copy symbol at runtime */
+#define R_68K_GLOB_DAT 20              /* Create GOT entry */
+#define R_68K_JMP_SLOT 21              /* Create PLT entry */
+#define R_68K_RELATIVE 22              /* Adjust by program base */
+/* Keep this the last entry.  */
+#define R_68K_NUM      23
+
+/* Intel 80386 specific definitions.  */
+
+/* i386 relocs.  */
+
+#define R_386_NONE     0               /* No reloc */
+#define R_386_32       1               /* Direct 32 bit  */
+#define R_386_PC32     2               /* PC relative 32 bit */
+#define R_386_GOT32    3               /* 32 bit GOT entry */
+#define R_386_PLT32    4               /* 32 bit PLT address */
+#define R_386_COPY     5               /* Copy symbol at runtime */
+#define R_386_GLOB_DAT 6               /* Create GOT entry */
+#define R_386_JMP_SLOT 7               /* Create PLT entry */
+#define R_386_RELATIVE 8               /* Adjust by program base */
+#define R_386_GOTOFF   9               /* 32 bit offset to GOT */
+#define R_386_GOTPC    10              /* 32 bit PC relative offset to GOT */
+/* Keep this the last entry.  */
+#define R_386_NUM      11
+
+/* SUN SPARC specific definitions.  */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_REGISTER   13              /* Global register reserved to app. */
+
+/* Values for Elf64_Ehdr.e_flags.  */
+
+#define EF_SPARCV9_MM          3
+#define EF_SPARCV9_TSO         0
+#define EF_SPARCV9_PSO         1
+#define EF_SPARCV9_RMO         2
+#define EF_SPARC_LEDATA                0x800000 /* little endian data */
+#define EF_SPARC_EXT_MASK      0xFFFF00
+#define EF_SPARC_32PLUS                0x000100 /* generic V8+ features */
+#define EF_SPARC_SUN_US1       0x000200 /* Sun UltraSPARC1 extensions */
+#define EF_SPARC_HAL_R1                0x000400 /* HAL R1 extensions */
+#define EF_SPARC_SUN_US3       0x000800 /* Sun UltraSPARCIII extensions */
+
+/* SPARC relocs.  */
+
+#define R_SPARC_NONE   0               /* No reloc */
+#define R_SPARC_8      1               /* Direct 8 bit */
+#define R_SPARC_16     2               /* Direct 16 bit */
+#define R_SPARC_32     3               /* Direct 32 bit */
+#define R_SPARC_DISP8  4               /* PC relative 8 bit */
+#define R_SPARC_DISP16 5               /* PC relative 16 bit */
+#define R_SPARC_DISP32 6               /* PC relative 32 bit */
+#define R_SPARC_WDISP30        7               /* PC relative 30 bit shifted */
+#define R_SPARC_WDISP22        8               /* PC relative 22 bit shifted */
+#define R_SPARC_HI22   9               /* High 22 bit */
+#define R_SPARC_22     10              /* Direct 22 bit */
+#define R_SPARC_13     11              /* Direct 13 bit */
+#define R_SPARC_LO10   12              /* Truncated 10 bit */
+#define R_SPARC_GOT10  13              /* Truncated 10 bit GOT entry */
+#define R_SPARC_GOT13  14              /* 13 bit GOT entry */
+#define R_SPARC_GOT22  15              /* 22 bit GOT entry shifted */
+#define R_SPARC_PC10   16              /* PC relative 10 bit truncated */
+#define R_SPARC_PC22   17              /* PC relative 22 bit shifted */
+#define R_SPARC_WPLT30 18              /* 30 bit PC relative PLT address */
+#define R_SPARC_COPY   19              /* Copy symbol at runtime */
+#define R_SPARC_GLOB_DAT 20            /* Create GOT entry */
+#define R_SPARC_JMP_SLOT 21            /* Create PLT entry */
+#define R_SPARC_RELATIVE 22            /* Adjust by program base */
+#define R_SPARC_UA32   23              /* Direct 32 bit unaligned */
+
+/* Additional Sparc64 relocs.  */
+
+#define R_SPARC_PLT32  24              /* Direct 32 bit ref to PLT entry */
+#define R_SPARC_HIPLT22        25              /* High 22 bit PLT entry */
+#define R_SPARC_LOPLT10        26              /* Truncated 10 bit PLT entry */
+#define R_SPARC_PCPLT32        27              /* PC rel 32 bit ref to PLT entry */
+#define R_SPARC_PCPLT22        28              /* PC rel high 22 bit PLT entry */
+#define R_SPARC_PCPLT10        29              /* PC rel trunc 10 bit PLT entry */
+#define R_SPARC_10     30              /* Direct 10 bit */
+#define R_SPARC_11     31              /* Direct 11 bit */
+#define R_SPARC_64     32              /* Direct 64 bit */
+#define R_SPARC_OLO10  33              /* 10bit with secondary 13bit addend */
+#define R_SPARC_HH22   34              /* Top 22 bits of direct 64 bit */
+#define R_SPARC_HM10   35              /* High middle 10 bits of ... */
+#define R_SPARC_LM22   36              /* Low middle 22 bits of ... */
+#define R_SPARC_PC_HH22        37              /* Top 22 bits of pc rel 64 bit */
+#define R_SPARC_PC_HM10        38              /* High middle 10 bit of ... */
+#define R_SPARC_PC_LM22        39              /* Low miggle 22 bits of ... */
+#define R_SPARC_WDISP16        40              /* PC relative 16 bit shifted */
+#define R_SPARC_WDISP19        41              /* PC relative 19 bit shifted */
+#define R_SPARC_7      43              /* Direct 7 bit */
+#define R_SPARC_5      44              /* Direct 5 bit */
+#define R_SPARC_6      45              /* Direct 6 bit */
+#define R_SPARC_DISP64 46              /* PC relative 64 bit */
+#define R_SPARC_PLT64  47              /* Direct 64 bit ref to PLT entry */
+#define R_SPARC_HIX22  48              /* High 22 bit complemented */
+#define R_SPARC_LOX10  49              /* Truncated 11 bit complemented */
+#define R_SPARC_H44    50              /* Direct high 12 of 44 bit */
+#define R_SPARC_M44    51              /* Direct mid 22 of 44 bit */
+#define R_SPARC_L44    52              /* Direct low 10 of 44 bit */
+#define R_SPARC_REGISTER 53            /* Global register usage */
+#define R_SPARC_UA64   54              /* Direct 64 bit unaligned */
+#define R_SPARC_UA16   55              /* Direct 16 bit unaligned */
+/* Keep this the last entry.  */
+#define R_SPARC_NUM    56
+
+/* For Sparc64, legal values for d_tag of Elf64_Dyn.  */
+
+#define DT_SPARC_REGISTER 0x70000001
+#define DT_SPARC_NUM   2
+
+/* Bits present in AT_HWCAP, primarily for Sparc32.  */
+
+#define HWCAP_SPARC_FLUSH      1       /* The cpu supports flush insn.  */
+#define HWCAP_SPARC_STBAR      2
+#define HWCAP_SPARC_SWAP       4
+#define HWCAP_SPARC_MULDIV     8
+#define HWCAP_SPARC_V9         16      /* The cpu is v9, so v8plus is ok.  */
+#define HWCAP_SPARC_ULTRA3     32
+
+/* MIPS R3000 specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_MIPS_NOREORDER   1          /* A .noreorder directive was used */
+#define EF_MIPS_PIC        2           /* Contains PIC code */
+#define EF_MIPS_CPIC       4           /* Uses PIC calling sequence */
+#define EF_MIPS_XGOT       8
+#define EF_MIPS_64BIT_WHIRL 16
+#define EF_MIPS_ABI2       32
+#define EF_MIPS_ABI_ON32    64
+#define EF_MIPS_ARCH       0xf0000000  /* MIPS architecture level */
+
+/* Legal values for MIPS architecture level.  */
+
+#define EF_MIPS_ARCH_1     0x00000000  /* -mips1 code.  */
+#define EF_MIPS_ARCH_2     0x10000000  /* -mips2 code.  */
+#define EF_MIPS_ARCH_3     0x20000000  /* -mips3 code.  */
+#define EF_MIPS_ARCH_4     0x30000000  /* -mips4 code.  */
+#define EF_MIPS_ARCH_5     0x40000000  /* -mips5 code.  */
+#define EF_MIPS_ARCH_32            0x60000000  /* MIPS32 code.  */
+#define EF_MIPS_ARCH_64            0x70000000  /* MIPS64 code.  */
+
+/* The following are non-official names and should not be used.  */
+
+#define E_MIPS_ARCH_1    0x00000000    /* -mips1 code.  */
+#define E_MIPS_ARCH_2    0x10000000    /* -mips2 code.  */
+#define E_MIPS_ARCH_3    0x20000000    /* -mips3 code.  */
+#define E_MIPS_ARCH_4    0x30000000    /* -mips4 code.  */
+#define E_MIPS_ARCH_5    0x40000000    /* -mips5 code.  */
+#define E_MIPS_ARCH_32   0x60000000    /* MIPS32 code.  */
+#define E_MIPS_ARCH_64   0x70000000    /* MIPS64 code.  */
+
+/* Special section indices.  */
+
+#define SHN_MIPS_ACOMMON    0xff00     /* Allocated common symbols */
+#define SHN_MIPS_TEXT      0xff01      /* Allocated test symbols.  */
+#define SHN_MIPS_DATA      0xff02      /* Allocated data symbols.  */
+#define SHN_MIPS_SCOMMON    0xff03     /* Small common symbols */
+#define SHN_MIPS_SUNDEFINED 0xff04     /* Small undefined symbols */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_MIPS_LIBLIST       0x70000000 /* Shared objects used in link */
+#define SHT_MIPS_MSYM         0x70000001
+#define SHT_MIPS_CONFLICT      0x70000002 /* Conflicting symbols */
+#define SHT_MIPS_GPTAB        0x70000003 /* Global data area sizes */
+#define SHT_MIPS_UCODE        0x70000004 /* Reserved for SGI/MIPS compilers */
+#define SHT_MIPS_DEBUG        0x70000005 /* MIPS ECOFF debugging information*/
+#define SHT_MIPS_REGINFO       0x70000006 /* Register usage information */
+#define SHT_MIPS_PACKAGE       0x70000007
+#define SHT_MIPS_PACKSYM       0x70000008
+#define SHT_MIPS_RELD         0x70000009
+#define SHT_MIPS_IFACE         0x7000000b
+#define SHT_MIPS_CONTENT       0x7000000c
+#define SHT_MIPS_OPTIONS       0x7000000d /* Miscellaneous options.  */
+#define SHT_MIPS_SHDR         0x70000010
+#define SHT_MIPS_FDESC        0x70000011
+#define SHT_MIPS_EXTSYM               0x70000012
+#define SHT_MIPS_DENSE        0x70000013
+#define SHT_MIPS_PDESC        0x70000014
+#define SHT_MIPS_LOCSYM               0x70000015
+#define SHT_MIPS_AUXSYM               0x70000016
+#define SHT_MIPS_OPTSYM               0x70000017
+#define SHT_MIPS_LOCSTR               0x70000018
+#define SHT_MIPS_LINE         0x70000019
+#define SHT_MIPS_RFDESC               0x7000001a
+#define SHT_MIPS_DELTASYM      0x7000001b
+#define SHT_MIPS_DELTAINST     0x7000001c
+#define SHT_MIPS_DELTACLASS    0x7000001d
+#define SHT_MIPS_DWARF         0x7000001e /* DWARF debugging information.  */
+#define SHT_MIPS_DELTADECL     0x7000001f
+#define SHT_MIPS_SYMBOL_LIB    0x70000020
+#define SHT_MIPS_EVENTS               0x70000021 /* Event section.  */
+#define SHT_MIPS_TRANSLATE     0x70000022
+#define SHT_MIPS_PIXIE        0x70000023
+#define SHT_MIPS_XLATE        0x70000024
+#define SHT_MIPS_XLATE_DEBUG   0x70000025
+#define SHT_MIPS_WHIRL        0x70000026
+#define SHT_MIPS_EH_REGION     0x70000027
+#define SHT_MIPS_XLATE_OLD     0x70000028
+#define SHT_MIPS_PDR_EXCEPTION 0x70000029
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_MIPS_GPREL  0x10000000     /* Must be part of global data area */
+#define SHF_MIPS_MERGE  0x20000000
+#define SHF_MIPS_ADDR   0x40000000
+#define SHF_MIPS_STRINGS 0x80000000
+#define SHF_MIPS_NOSTRIP 0x08000000
+#define SHF_MIPS_LOCAL  0x04000000
+#define SHF_MIPS_NAMES  0x02000000
+#define SHF_MIPS_NODUPE         0x01000000
+
+
+/* Symbol tables.  */
+
+/* MIPS specific values for `st_other'.  */
+#define STO_MIPS_DEFAULT               0x0
+#define STO_MIPS_INTERNAL              0x1
+#define STO_MIPS_HIDDEN                        0x2
+#define STO_MIPS_PROTECTED             0x3
+#define STO_MIPS_SC_ALIGN_UNUSED       0xff
+
+/* MIPS specific values for `st_info'.  */
+#define STB_MIPS_SPLIT_COMMON          13
+
+/* Entries found in sections of type SHT_MIPS_GPTAB.  */
+
+typedef union
+{
+  struct
+    {
+      Elf32_Word gt_current_g_value;   /* -G value used for compilation */
+      Elf32_Word gt_unused;            /* Not used */
+    } gt_header;                       /* First entry in section */
+  struct
+    {
+      Elf32_Word gt_g_value;           /* If this value were used for -G */
+      Elf32_Word gt_bytes;             /* This many bytes would be used */
+    } gt_entry;                                /* Subsequent entries in section */
+} Elf32_gptab;
+
+/* Entry found in sections of type SHT_MIPS_REGINFO.  */
+
+typedef struct
+{
+  Elf32_Word   ri_gprmask;             /* General registers used */
+  Elf32_Word   ri_cprmask[4];          /* Coprocessor registers used */
+  Elf32_Sword  ri_gp_value;            /* $gp register value */
+} Elf32_RegInfo;
+
+/* Entries found in sections of type SHT_MIPS_OPTIONS.  */
+
+typedef struct
+{
+  unsigned char kind;          /* Determines interpretation of the
+                                  variable part of descriptor.  */
+  unsigned char size;          /* Size of descriptor, including header.  */
+  Elf32_Section section;       /* Section header index of section affected,
+                                  0 for global options.  */
+  Elf32_Word info;             /* Kind-specific information.  */
+} Elf_Options;
+
+/* Values for `kind' field in Elf_Options.  */
+
+#define ODK_NULL       0       /* Undefined.  */
+#define ODK_REGINFO    1       /* Register usage information.  */
+#define ODK_EXCEPTIONS 2       /* Exception processing options.  */
+#define ODK_PAD                3       /* Section padding options.  */
+#define ODK_HWPATCH    4       /* Hardware workarounds performed */
+#define ODK_FILL       5       /* record the fill value used by the linker. */
+#define ODK_TAGS       6       /* reserve space for desktop tools to write. */
+#define ODK_HWAND      7       /* HW workarounds.  'AND' bits when merging. */
+#define ODK_HWOR       8       /* HW workarounds.  'OR' bits when merging.  */
+
+/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries.  */
+
+#define OEX_FPU_MIN    0x1f    /* FPE's which MUST be enabled.  */
+#define OEX_FPU_MAX    0x1f00  /* FPE's which MAY be enabled.  */
+#define OEX_PAGE0      0x10000 /* page zero must be mapped.  */
+#define OEX_SMM                0x20000 /* Force sequential memory mode?  */
+#define OEX_FPDBUG     0x40000 /* Force floating point debug mode?  */
+#define OEX_PRECISEFP  OEX_FPDBUG
+#define OEX_DISMISS    0x80000 /* Dismiss invalid address faults?  */
+
+#define OEX_FPU_INVAL  0x10
+#define OEX_FPU_DIV0   0x08
+#define OEX_FPU_OFLO   0x04
+#define OEX_FPU_UFLO   0x02
+#define OEX_FPU_INEX   0x01
+
+/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry.  */
+
+#define OHW_R4KEOP     0x1     /* R4000 end-of-page patch.  */
+#define OHW_R8KPFETCH  0x2     /* may need R8000 prefetch patch.  */
+#define OHW_R5KEOP     0x4     /* R5000 end-of-page patch.  */
+#define OHW_R5KCVTL    0x8     /* R5000 cvt.[ds].l bug.  clean=1.  */
+
+#define OPAD_PREFIX    0x1
+#define OPAD_POSTFIX   0x2
+#define OPAD_SYMBOL    0x4
+
+/* Entry found in `.options' section.  */
+
+typedef struct
+{
+  Elf32_Word hwp_flags1;       /* Extra flags.  */
+  Elf32_Word hwp_flags2;       /* Extra flags.  */
+} Elf_Options_Hw;
+
+/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries.  */
+
+#define OHWA0_R4KEOP_CHECKED   0x00000001
+#define OHWA1_R4KEOP_CLEAN     0x00000002
+
+/* MIPS relocs.  */
+
+#define R_MIPS_NONE            0       /* No reloc */
+#define R_MIPS_16              1       /* Direct 16 bit */
+#define R_MIPS_32              2       /* Direct 32 bit */
+#define R_MIPS_REL32           3       /* PC relative 32 bit */
+#define R_MIPS_26              4       /* Direct 26 bit shifted */
+#define R_MIPS_HI16            5       /* High 16 bit */
+#define R_MIPS_LO16            6       /* Low 16 bit */
+#define R_MIPS_GPREL16         7       /* GP relative 16 bit */
+#define R_MIPS_LITERAL         8       /* 16 bit literal entry */
+#define R_MIPS_GOT16           9       /* 16 bit GOT entry */
+#define R_MIPS_PC16            10      /* PC relative 16 bit */
+#define R_MIPS_CALL16          11      /* 16 bit GOT entry for function */
+#define R_MIPS_GPREL32         12      /* GP relative 32 bit */
+
+#define R_MIPS_SHIFT5          16
+#define R_MIPS_SHIFT6          17
+#define R_MIPS_64              18
+#define R_MIPS_GOT_DISP                19
+#define R_MIPS_GOT_PAGE                20
+#define R_MIPS_GOT_OFST                21
+#define R_MIPS_GOT_HI16                22
+#define R_MIPS_GOT_LO16                23
+#define R_MIPS_SUB             24
+#define R_MIPS_INSERT_A                25
+#define R_MIPS_INSERT_B                26
+#define R_MIPS_DELETE          27
+#define R_MIPS_HIGHER          28
+#define R_MIPS_HIGHEST         29
+#define R_MIPS_CALL_HI16       30
+#define R_MIPS_CALL_LO16       31
+#define R_MIPS_SCN_DISP                32
+#define R_MIPS_REL16           33
+#define R_MIPS_ADD_IMMEDIATE   34
+#define R_MIPS_PJUMP           35
+#define R_MIPS_RELGOT          36
+#define R_MIPS_JALR            37
+/* Keep this the last entry.  */
+#define R_MIPS_NUM             38
+
+/* Legal values for p_type field of Elf32_Phdr.  */
+
+#define PT_MIPS_REGINFO        0x70000000      /* Register usage information */
+#define PT_MIPS_RTPROC  0x70000001     /* Runtime procedure table. */
+#define PT_MIPS_OPTIONS 0x70000002
+
+/* Special program header types.  */
+
+#define PF_MIPS_LOCAL  0x10000000
+
+/* Legal values for d_tag field of Elf32_Dyn.  */
+
+#define DT_MIPS_RLD_VERSION  0x70000001        /* Runtime linker interface version */
+#define DT_MIPS_TIME_STAMP   0x70000002        /* Timestamp */
+#define DT_MIPS_ICHECKSUM    0x70000003        /* Checksum */
+#define DT_MIPS_IVERSION     0x70000004        /* Version string (string tbl index) */
+#define DT_MIPS_FLAGS       0x70000005 /* Flags */
+#define DT_MIPS_BASE_ADDRESS 0x70000006        /* Base address */
+#define DT_MIPS_MSYM        0x70000007
+#define DT_MIPS_CONFLICT     0x70000008        /* Address of CONFLICT section */
+#define DT_MIPS_LIBLIST             0x70000009 /* Address of LIBLIST section */
+#define DT_MIPS_LOCAL_GOTNO  0x7000000a        /* Number of local GOT entries */
+#define DT_MIPS_CONFLICTNO   0x7000000b        /* Number of CONFLICT entries */
+#define DT_MIPS_LIBLISTNO    0x70000010        /* Number of LIBLIST entries */
+#define DT_MIPS_SYMTABNO     0x70000011        /* Number of DYNSYM entries */
+#define DT_MIPS_UNREFEXTNO   0x70000012        /* First external DYNSYM */
+#define DT_MIPS_GOTSYM      0x70000013 /* First GOT entry in DYNSYM */
+#define DT_MIPS_HIPAGENO     0x70000014        /* Number of GOT page table entries */
+#define DT_MIPS_RLD_MAP             0x70000016 /* Address of run time loader map.  */
+#define DT_MIPS_DELTA_CLASS  0x70000017        /* Delta C++ class definition.  */
+#define DT_MIPS_DELTA_CLASS_NO    0x70000018 /* Number of entries in
+                                               DT_MIPS_DELTA_CLASS.  */
+#define DT_MIPS_DELTA_INSTANCE    0x70000019 /* Delta C++ class instances.  */
+#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
+                                               DT_MIPS_DELTA_INSTANCE.  */
+#define DT_MIPS_DELTA_RELOC  0x7000001b /* Delta relocations.  */
+#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
+                                            DT_MIPS_DELTA_RELOC.  */
+#define DT_MIPS_DELTA_SYM    0x7000001d /* Delta symbols that Delta
+                                          relocations refer to.  */
+#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
+                                          DT_MIPS_DELTA_SYM.  */
+#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
+                                            class declaration.  */
+#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
+                                               DT_MIPS_DELTA_CLASSSYM.  */
+#define DT_MIPS_CXX_FLAGS    0x70000022 /* Flags indicating for C++ flavor.  */
+#define DT_MIPS_PIXIE_INIT   0x70000023
+#define DT_MIPS_SYMBOL_LIB   0x70000024
+#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
+#define DT_MIPS_LOCAL_GOTIDX 0x70000026
+#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
+#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
+#define DT_MIPS_OPTIONS             0x70000029 /* Address of .options.  */
+#define DT_MIPS_INTERFACE    0x7000002a /* Address of .interface.  */
+#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
+#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
+#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
+                                                   function stored in GOT.  */
+#define DT_MIPS_PERF_SUFFIX  0x7000002e /* Default suffix of dso to be added
+                                          by rld on dlopen() calls.  */
+#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
+#define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */
+#define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */
+#define DT_MIPS_NUM         0x32
+
+/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
+
+#define RHF_NONE                  0            /* No flags */
+#define RHF_QUICKSTART            (1 << 0)     /* Use quickstart */
+#define RHF_NOTPOT                (1 << 1)     /* Hash size not power of 2 */
+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2)    /* Ignore LD_LIBRARY_PATH */
+#define RHF_NO_MOVE               (1 << 3)
+#define RHF_SGI_ONLY              (1 << 4)
+#define RHF_GUARANTEE_INIT        (1 << 5)
+#define RHF_DELTA_C_PLUS_PLUS     (1 << 6)
+#define RHF_GUARANTEE_START_INIT   (1 << 7)
+#define RHF_PIXIE                 (1 << 8)
+#define RHF_DEFAULT_DELAY_LOAD    (1 << 9)
+#define RHF_REQUICKSTART          (1 << 10)
+#define RHF_REQUICKSTARTED        (1 << 11)
+#define RHF_CORD                  (1 << 12)
+#define RHF_NO_UNRES_UNDEF        (1 << 13)
+#define RHF_RLD_ORDER_SAFE        (1 << 14)
+
+/* Entries found in sections of type SHT_MIPS_LIBLIST.  */
+
+typedef struct
+{
+  Elf32_Word l_name;           /* Name (string table index) */
+  Elf32_Word l_time_stamp;     /* Timestamp */
+  Elf32_Word l_checksum;       /* Checksum */
+  Elf32_Word l_version;                /* Interface version */
+  Elf32_Word l_flags;          /* Flags */
+} Elf32_Lib;
+
+typedef struct
+{
+  Elf64_Word l_name;           /* Name (string table index) */
+  Elf64_Word l_time_stamp;     /* Timestamp */
+  Elf64_Word l_checksum;       /* Checksum */
+  Elf64_Word l_version;                /* Interface version */
+  Elf64_Word l_flags;          /* Flags */
+} Elf64_Lib;
+
+
+/* Legal values for l_flags.  */
+
+#define LL_NONE                  0
+#define LL_EXACT_MATCH   (1 << 0)      /* Require exact match */
+#define LL_IGNORE_INT_VER (1 << 1)     /* Ignore interface version */
+#define LL_REQUIRE_MINOR  (1 << 2)
+#define LL_EXPORTS       (1 << 3)
+#define LL_DELAY_LOAD    (1 << 4)
+#define LL_DELTA         (1 << 5)
+
+/* Entries found in sections of type SHT_MIPS_CONFLICT.  */
+
+typedef Elf32_Addr Elf32_Conflict;
+
+
+/* HPPA specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_PARISC_TRAPNIL      0x00010000 /* Trap nil pointer dereference.  */
+#define EF_PARISC_EXT          0x00020000 /* Program uses arch. extensions. */
+#define EF_PARISC_LSB          0x00040000 /* Program expects little endian. */
+#define EF_PARISC_WIDE         0x00080000 /* Program expects wide mode.  */
+#define EF_PARISC_NO_KABP      0x00100000 /* No kernel assisted branch
+                                             prediction.  */
+#define EF_PARISC_LAZYSWAP     0x00400000 /* Allow lazy swapping.  */
+#define EF_PARISC_ARCH         0x0000ffff /* Architecture version.  */
+
+/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
+
+#define EFA_PARISC_1_0             0x020b /* PA-RISC 1.0 big-endian.  */
+#define EFA_PARISC_1_1             0x0210 /* PA-RISC 1.1 big-endian.  */
+#define EFA_PARISC_2_0             0x0214 /* PA-RISC 2.0 big-endian.  */
+
+/* Additional section indeces.  */
+
+#define SHN_PARISC_ANSI_COMMON 0xff00     /* Section for tenatively declared
+                                             symbols in ANSI C.  */
+#define SHN_PARISC_HUGE_COMMON 0xff01     /* Common blocks in huge model.  */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_PARISC_EXT         0x70000000 /* Contains product specific ext. */
+#define SHT_PARISC_UNWIND      0x70000001 /* Unwind information.  */
+#define SHT_PARISC_DOC         0x70000002 /* Debug info for optimized code. */
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_PARISC_SHORT       0x20000000 /* Section with short addressing. */
+#define SHF_PARISC_HUGE                0x40000000 /* Section far from gp.  */
+#define SHF_PARISC_SBP         0x80000000 /* Static branch prediction code. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_PARISC_MILLICODE   13      /* Millicode function entry point.  */
+
+#define STT_HP_OPAQUE          (STT_LOOS + 0x1)
+#define STT_HP_STUB            (STT_LOOS + 0x2)
+
+/* HPPA relocs.  */
+
+#define R_PARISC_NONE          0       /* No reloc.  */
+#define R_PARISC_DIR32         1       /* Direct 32-bit reference.  */
+#define R_PARISC_DIR21L                2       /* Left 21 bits of eff. address.  */
+#define R_PARISC_DIR17R                3       /* Right 17 bits of eff. address.  */
+#define R_PARISC_DIR17F                4       /* 17 bits of eff. address.  */
+#define R_PARISC_DIR14R                6       /* Right 14 bits of eff. address.  */
+#define R_PARISC_PCREL32       9       /* 32-bit rel. address.  */
+#define R_PARISC_PCREL21L      10      /* Left 21 bits of rel. address.  */
+#define R_PARISC_PCREL17R      11      /* Right 17 bits of rel. address.  */
+#define R_PARISC_PCREL17F      12      /* 17 bits of rel. address.  */
+#define R_PARISC_PCREL14R      14      /* Right 14 bits of rel. address.  */
+#define R_PARISC_DPREL21L      18      /* Left 21 bits of rel. address.  */
+#define R_PARISC_DPREL14R      22      /* Right 14 bits of rel. address.  */
+#define R_PARISC_GPREL21L      26      /* GP-relative, left 21 bits.  */
+#define R_PARISC_GPREL14R      30      /* GP-relative, right 14 bits.  */
+#define R_PARISC_LTOFF21L      34      /* LT-relative, left 21 bits.  */
+#define R_PARISC_LTOFF14R      38      /* LT-relative, right 14 bits.  */
+#define R_PARISC_SECREL32      41      /* 32 bits section rel. address.  */
+#define R_PARISC_SEGBASE       48      /* No relocation, set segment base.  */
+#define R_PARISC_SEGREL32      49      /* 32 bits segment rel. address.  */
+#define R_PARISC_PLTOFF21L     50      /* PLT rel. address, left 21 bits.  */
+#define R_PARISC_PLTOFF14R     54      /* PLT rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_FPTR32  57      /* 32 bits LT-rel. function pointer. */
+#define R_PARISC_LTOFF_FPTR21L 58      /* LT-rel. fct ptr, left 21 bits. */
+#define R_PARISC_LTOFF_FPTR14R 62      /* LT-rel. fct ptr, right 14 bits. */
+#define R_PARISC_FPTR64                64      /* 64 bits function address.  */
+#define R_PARISC_PLABEL32      65      /* 32 bits function address.  */
+#define R_PARISC_PCREL64       72      /* 64 bits PC-rel. address.  */
+#define R_PARISC_PCREL22F      74      /* 22 bits PC-rel. address.  */
+#define R_PARISC_PCREL14WR     75      /* PC-rel. address, right 14 bits.  */
+#define R_PARISC_PCREL14DR     76      /* PC rel. address, right 14 bits.  */
+#define R_PARISC_PCREL16F      77      /* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16WF     78      /* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16DF     79      /* 16 bits PC-rel. address.  */
+#define R_PARISC_DIR64         80      /* 64 bits of eff. address.  */
+#define R_PARISC_DIR14WR       83      /* 14 bits of eff. address.  */
+#define R_PARISC_DIR14DR       84      /* 14 bits of eff. address.  */
+#define R_PARISC_DIR16F                85      /* 16 bits of eff. address.  */
+#define R_PARISC_DIR16WF       86      /* 16 bits of eff. address.  */
+#define R_PARISC_DIR16DF       87      /* 16 bits of eff. address.  */
+#define R_PARISC_GPREL64       88      /* 64 bits of GP-rel. address.  */
+#define R_PARISC_GPREL14WR     91      /* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL14DR     92      /* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL16F      93      /* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16WF     94      /* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16DF     95      /* 16 bits GP-rel. address.  */
+#define R_PARISC_LTOFF64       96      /* 64 bits LT-rel. address.  */
+#define R_PARISC_LTOFF14WR     99      /* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF14DR     100     /* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF16F      101     /* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16WF     102     /* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16DF     103     /* 16 bits LT-rel. address.  */
+#define R_PARISC_SECREL64      104     /* 64 bits section rel. address.  */
+#define R_PARISC_SEGREL64      112     /* 64 bits segment rel. address.  */
+#define R_PARISC_PLTOFF14WR    115     /* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF14DR    116     /* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF16F     117     /* 16 bits LT-rel. address.  */
+#define R_PARISC_PLTOFF16WF    118     /* 16 bits PLT-rel. address.  */
+#define R_PARISC_PLTOFF16DF    119     /* 16 bits PLT-rel. address.  */
+#define R_PARISC_LTOFF_FPTR64  120     /* 64 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR14WR        123     /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR14DR        124     /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR16F 125     /* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16WF        126     /* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16DF        127     /* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LORESERVE     128
+#define R_PARISC_COPY          128     /* Copy relocation.  */
+#define R_PARISC_IPLT          129     /* Dynamic reloc, imported PLT */
+#define R_PARISC_EPLT          130     /* Dynamic reloc, exported PLT */
+#define R_PARISC_TPREL32       153     /* 32 bits TP-rel. address.  */
+#define R_PARISC_TPREL21L      154     /* TP-rel. address, left 21 bits.  */
+#define R_PARISC_TPREL14R      158     /* TP-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_TP21L   162     /* LT-TP-rel. address, left 21 bits. */
+#define R_PARISC_LTOFF_TP14R   166     /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14F   167     /* 14 bits LT-TP-rel. address.  */
+#define R_PARISC_TPREL64       216     /* 64 bits TP-rel. address.  */
+#define R_PARISC_TPREL14WR     219     /* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL14DR     220     /* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL16F      221     /* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16WF     222     /* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16DF     223     /* 16 bits TP-rel. address.  */
+#define R_PARISC_LTOFF_TP64    224     /* 64 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP14WR  227     /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14DR  228     /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP16F   229     /* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16WF  230     /* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16DF  231     /* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_HIRESERVE     255
+
+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PT_HP_TLS              (PT_LOOS + 0x0)
+#define PT_HP_CORE_NONE                (PT_LOOS + 0x1)
+#define PT_HP_CORE_VERSION     (PT_LOOS + 0x2)
+#define PT_HP_CORE_KERNEL      (PT_LOOS + 0x3)
+#define PT_HP_CORE_COMM                (PT_LOOS + 0x4)
+#define PT_HP_CORE_PROC                (PT_LOOS + 0x5)
+#define PT_HP_CORE_LOADABLE    (PT_LOOS + 0x6)
+#define PT_HP_CORE_STACK       (PT_LOOS + 0x7)
+#define PT_HP_CORE_SHM         (PT_LOOS + 0x8)
+#define PT_HP_CORE_MMF         (PT_LOOS + 0x9)
+#define PT_HP_PARALLEL         (PT_LOOS + 0x10)
+#define PT_HP_FASTBIND         (PT_LOOS + 0x11)
+#define PT_HP_OPT_ANNOT                (PT_LOOS + 0x12)
+#define PT_HP_HSL_ANNOT                (PT_LOOS + 0x13)
+#define PT_HP_STACK            (PT_LOOS + 0x14)
+
+#define PT_PARISC_ARCHEXT      0x70000000
+#define PT_PARISC_UNWIND       0x70000001
+
+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PF_PARISC_SBP          0x08000000
+
+#define PF_HP_PAGE_SIZE                0x00100000
+#define PF_HP_FAR_SHARED       0x00200000
+#define PF_HP_NEAR_SHARED      0x00400000
+#define PF_HP_CODE             0x01000000
+#define PF_HP_MODIFY           0x02000000
+#define PF_HP_LAZYSWAP         0x04000000
+#define PF_HP_SBP              0x08000000
+
+
+/* Alpha specific definitions.  */
+
+/* Legal values for e_flags field of Elf64_Ehdr.  */
+
+#define EF_ALPHA_32BIT         1       /* All addresses must be < 2GB.  */
+#define EF_ALPHA_CANRELAX      2       /* Relocations for relaxing exist.  */
+
+/* Legal values for sh_type field of Elf64_Shdr.  */
+
+/* These two are primerily concerned with ECOFF debugging info.  */
+#define SHT_ALPHA_DEBUG                0x70000001
+#define SHT_ALPHA_REGINFO      0x70000002
+
+/* Legal values for sh_flags field of Elf64_Shdr.  */
+
+#define SHF_ALPHA_GPREL                0x10000000
+
+/* Legal values for st_other field of Elf64_Sym.  */
+#define STO_ALPHA_NOPV         0x80    /* No PV required.  */
+#define STO_ALPHA_STD_GPLOAD   0x88    /* PV only used for initial ldgp.  */
+
+/* Alpha relocs.  */
+
+#define R_ALPHA_NONE           0       /* No reloc */
+#define R_ALPHA_REFLONG                1       /* Direct 32 bit */
+#define R_ALPHA_REFQUAD                2       /* Direct 64 bit */
+#define R_ALPHA_GPREL32                3       /* GP relative 32 bit */
+#define R_ALPHA_LITERAL                4       /* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE         5       /* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP         6       /* Add displacement to GP */
+#define R_ALPHA_BRADDR         7       /* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT           8       /* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16         9       /* PC relative 16 bit */
+#define R_ALPHA_SREL32         10      /* PC relative 32 bit */
+#define R_ALPHA_SREL64         11      /* PC relative 64 bit */
+#define R_ALPHA_GPRELHIGH      17      /* GP relative 32 bit, high 16 bits */
+#define R_ALPHA_GPRELLOW       18      /* GP relative 32 bit, low 16 bits */
+#define R_ALPHA_GPREL16                19      /* GP relative 16 bit */
+#define R_ALPHA_COPY           24      /* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT       25      /* Create GOT entry */
+#define R_ALPHA_JMP_SLOT       26      /* Create PLT entry */
+#define R_ALPHA_RELATIVE       27      /* Adjust by program base */
+/* Keep this the last entry.  */
+#define R_ALPHA_NUM            28
+
+
+/* PowerPC specific declarations */
+
+/* Values for Elf32/64_Ehdr.e_flags.  */
+#define EF_PPC_EMB             0x80000000      /* PowerPC embedded flag */
+
+/* Cygnus local bits below */
+#define EF_PPC_RELOCATABLE     0x00010000      /* PowerPC -mrelocatable flag*/
+#define EF_PPC_RELOCATABLE_LIB 0x00008000      /* PowerPC -mrelocatable-lib
+                                                  flag */
+
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE             0
+#define R_PPC_ADDR32           1       /* 32bit absolute address */
+#define R_PPC_ADDR24           2       /* 26bit address, 2 bits ignored.  */
+#define R_PPC_ADDR16           3       /* 16bit absolute address */
+#define R_PPC_ADDR16_LO                4       /* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI                5       /* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA                6       /* adjusted high 16bit */
+#define R_PPC_ADDR14           7       /* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN   8
+#define R_PPC_ADDR14_BRNTAKEN  9
+#define R_PPC_REL24            10      /* PC relative 26 bit */
+#define R_PPC_REL14            11      /* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN    12
+#define R_PPC_REL14_BRNTAKEN   13
+#define R_PPC_GOT16            14
+#define R_PPC_GOT16_LO         15
+#define R_PPC_GOT16_HI         16
+#define R_PPC_GOT16_HA         17
+#define R_PPC_PLTREL24         18
+#define R_PPC_COPY             19
+#define R_PPC_GLOB_DAT         20
+#define R_PPC_JMP_SLOT         21
+#define R_PPC_RELATIVE         22
+#define R_PPC_LOCAL24PC                23
+#define R_PPC_UADDR32          24
+#define R_PPC_UADDR16          25
+#define R_PPC_REL32            26
+#define R_PPC_PLT32            27
+#define R_PPC_PLTREL32         28
+#define R_PPC_PLT16_LO         29
+#define R_PPC_PLT16_HI         30
+#define R_PPC_PLT16_HA         31
+#define R_PPC_SDAREL16         32
+#define R_PPC_SECTOFF          33
+#define R_PPC_SECTOFF_LO       34
+#define R_PPC_SECTOFF_HI       35
+#define R_PPC_SECTOFF_HA       36
+/* Keep this the last entry.  */
+#define R_PPC_NUM              37
+
+/* The remaining relocs are from the Embedded ELF ABI, and are not
+   in the SVR4 ELF ABI.  */
+#define R_PPC_EMB_NADDR32      101
+#define R_PPC_EMB_NADDR16      102
+#define R_PPC_EMB_NADDR16_LO   103
+#define R_PPC_EMB_NADDR16_HI   104
+#define R_PPC_EMB_NADDR16_HA   105
+#define R_PPC_EMB_SDAI16       106
+#define R_PPC_EMB_SDA2I16      107
+#define R_PPC_EMB_SDA2REL      108
+#define R_PPC_EMB_SDA21                109     /* 16 bit offset in SDA */
+#define R_PPC_EMB_MRKREF       110
+#define R_PPC_EMB_RELSEC16     111
+#define R_PPC_EMB_RELST_LO     112
+#define R_PPC_EMB_RELST_HI     113
+#define R_PPC_EMB_RELST_HA     114
+#define R_PPC_EMB_BIT_FLD      115
+#define R_PPC_EMB_RELSDA       116     /* 16 bit relative offset in SDA */
+
+/* Diab tool relocations.  */
+#define R_PPC_DIAB_SDA21_LO    180     /* like EMB_SDA21, but lower 16 bit */
+#define R_PPC_DIAB_SDA21_HI    181     /* like EMB_SDA21, but high 16 bit */
+#define R_PPC_DIAB_SDA21_HA    182     /* like EMB_SDA21, adjusted high 16 */
+#define R_PPC_DIAB_RELSDA_LO   183     /* like EMB_RELSDA, but lower 16 bit */
+#define R_PPC_DIAB_RELSDA_HI   184     /* like EMB_RELSDA, but high 16 bit */
+#define R_PPC_DIAB_RELSDA_HA   185     /* like EMB_RELSDA, adjusted high 16 */
+
+/* This is a phony reloc to handle any old fashioned TOC16 references
+   that may still be in object files.  */
+#define R_PPC_TOC16            255
+
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_ARM_RELEXEC     0x01
+#define EF_ARM_HASENTRY    0x02
+#define EF_ARM_INTERWORK   0x04
+#define EF_ARM_APCS_26     0x08
+#define EF_ARM_APCS_FLOAT  0x10
+#define EF_ARM_PIC         0x20
+#define EF_ARM_ALIGN8      0x40                /* 8-bit structure alignment is in use */
+#define EF_ARM_NEW_ABI     0x80
+#define EF_ARM_OLD_ABI     0x100
+
+/* Other constants defined in the ARM ELF spec. version B-01.  */
+/* NB. These conflict with values defined above.  */
+#define EF_ARM_SYMSARESORTED   0x04
+#define EF_ARM_DYNSYMSUSESEGIDX 0x08
+#define EF_ARM_MAPSYMSFIRST    0x10
+#define EF_ARM_EABIMASK                0XFF000000
+
+#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)
+#define EF_ARM_EABI_UNKNOWN  0x00000000
+#define EF_ARM_EABI_VER1     0x01000000
+#define EF_ARM_EABI_VER2     0x02000000
+
+/* Additional symbol types for Thumb */
+#define STT_ARM_TFUNC      0xd
+
+/* ARM-specific values for sh_flags */
+#define SHF_ARM_ENTRYSECT  0x10000000   /* Section contains an entry point */
+#define SHF_ARM_COMDEF     0x80000000   /* Section may be multiply defined
+                                          in the input to a link step */
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB          0x10000000   /* Segment contains the location
+                                          addressed by the static base */
+
+/* ARM relocs.  */
+#define R_ARM_NONE             0       /* No reloc */
+#define R_ARM_PC24             1       /* PC relative 26 bit branch */
+#define R_ARM_ABS32            2       /* Direct 32 bit  */
+#define R_ARM_REL32            3       /* PC relative 32 bit */
+#define R_ARM_PC13             4
+#define R_ARM_ABS16            5       /* Direct 16 bit */
+#define R_ARM_ABS12            6       /* Direct 12 bit */
+#define R_ARM_THM_ABS5         7
+#define R_ARM_ABS8             8       /* Direct 8 bit */
+#define R_ARM_SBREL32          9
+#define R_ARM_THM_PC22         10
+#define R_ARM_THM_PC8          11
+#define R_ARM_AMP_VCALL9       12
+#define R_ARM_SWI24            13
+#define R_ARM_THM_SWI8         14
+#define R_ARM_XPC25            15
+#define R_ARM_THM_XPC22                16
+#define R_ARM_COPY             20      /* Copy symbol at runtime */
+#define R_ARM_GLOB_DAT         21      /* Create GOT entry */
+#define R_ARM_JUMP_SLOT                22      /* Create PLT entry */
+#define R_ARM_RELATIVE         23      /* Adjust by program base */
+#define R_ARM_GOTOFF           24      /* 32 bit offset to GOT */
+#define R_ARM_GOTPC            25      /* 32 bit PC relative offset to GOT */
+#define R_ARM_GOT32            26      /* 32 bit GOT entry */
+#define R_ARM_PLT32            27      /* 32 bit PLT address */
+#define R_ARM_ALU_PCREL_7_0    32
+#define R_ARM_ALU_PCREL_15_8   33
+#define R_ARM_ALU_PCREL_23_15  34
+#define R_ARM_LDR_SBREL_11_0   35
+#define R_ARM_ALU_SBREL_19_12  36
+#define R_ARM_ALU_SBREL_27_20  37
+#define R_ARM_GNU_VTENTRY      100
+#define R_ARM_GNU_VTINHERIT    101
+#define R_ARM_THM_PC11         102     /* thumb unconditional branch */
+#define R_ARM_THM_PC9          103     /* thumb conditional branch */
+#define R_ARM_RXPC25           249
+#define R_ARM_RSBREL32         250
+#define R_ARM_THM_RPC22                251
+#define R_ARM_RREL32           252
+#define R_ARM_RABS22           253
+#define R_ARM_RPC24            254
+#define R_ARM_RBASE            255
+/* Keep this the last entry.  */
+#define R_ARM_NUM              256
+
+/* IA-64 specific declarations.  */
+
+/* Processor specific flags for the Ehdr e_flags field.  */
+#define EF_IA_64_MASKOS                0x0000000f      /* os-specific flags */
+#define EF_IA_64_ABI64         0x00000010      /* 64-bit ABI */
+#define EF_IA_64_ARCH          0xff000000      /* arch. version mask */
+
+/* Processor specific values for the Phdr p_type field.  */
+#define PT_IA_64_ARCHEXT       (PT_LOPROC + 0) /* arch extension bits */
+#define PT_IA_64_UNWIND                (PT_LOPROC + 1) /* ia64 unwind bits */
+
+/* Processor specific flags for the Phdr p_flags field.  */
+#define PF_IA_64_NORECOV       0x80000000      /* spec insns w/o recovery */
+
+/* Processor specific values for the Shdr sh_type field.  */
+#define SHT_IA_64_EXT          (SHT_LOPROC + 0) /* extension bits */
+#define SHT_IA_64_UNWIND       (SHT_LOPROC + 1) /* unwind bits */
+
+/* Processor specific flags for the Shdr sh_flags field.  */
+#define SHF_IA_64_SHORT                0x10000000      /* section near gp */
+#define SHF_IA_64_NORECOV      0x20000000      /* spec insns w/o recovery */
+
+/* Processor specific values for the Dyn d_tag field.  */
+#define DT_IA_64_PLT_RESERVE   (DT_LOPROC + 0)
+#define DT_IA_64_NUM           1
+
+/* IA-64 relocations.  */
+#define R_IA64_NONE            0x00    /* none */
+#define R_IA64_IMM14           0x21    /* symbol + addend, add imm14 */
+#define R_IA64_IMM22           0x22    /* symbol + addend, add imm22 */
+#define R_IA64_IMM64           0x23    /* symbol + addend, mov imm64 */
+#define R_IA64_DIR32MSB                0x24    /* symbol + addend, data4 MSB */
+#define R_IA64_DIR32LSB                0x25    /* symbol + addend, data4 LSB */
+#define R_IA64_DIR64MSB                0x26    /* symbol + addend, data8 MSB */
+#define R_IA64_DIR64LSB                0x27    /* symbol + addend, data8 LSB */
+#define R_IA64_GPREL22         0x2a    /* @gprel(sym + add), add imm22 */
+#define R_IA64_GPREL64I                0x2b    /* @gprel(sym + add), mov imm64 */
+#define R_IA64_GPREL32MSB      0x2c    /* @gprel(sym + add), data4 MSB */
+#define R_IA64_GPREL32LSB      0x2d    /* @gprel(sym + add), data4 LSB */
+#define R_IA64_GPREL64MSB      0x2e    /* @gprel(sym + add), data8 MSB */
+#define R_IA64_GPREL64LSB      0x2f    /* @gprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF22         0x32    /* @ltoff(sym + add), add imm22 */
+#define R_IA64_LTOFF64I                0x33    /* @ltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF22                0x3a    /* @pltoff(sym + add), add imm22 */
+#define R_IA64_PLTOFF64I       0x3b    /* @pltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF64MSB     0x3e    /* @pltoff(sym + add), data8 MSB */
+#define R_IA64_PLTOFF64LSB     0x3f    /* @pltoff(sym + add), data8 LSB */
+#define R_IA64_FPTR64I         0x43    /* @fptr(sym + add), mov imm64 */
+#define R_IA64_FPTR32MSB       0x44    /* @fptr(sym + add), data4 MSB */
+#define R_IA64_FPTR32LSB       0x45    /* @fptr(sym + add), data4 LSB */
+#define R_IA64_FPTR64MSB       0x46    /* @fptr(sym + add), data8 MSB */
+#define R_IA64_FPTR64LSB       0x47    /* @fptr(sym + add), data8 LSB */
+#define R_IA64_PCREL60B                0x48    /* @pcrel(sym + add), brl */
+#define R_IA64_PCREL21B                0x49    /* @pcrel(sym + add), ptb, call */
+#define R_IA64_PCREL21M                0x4a    /* @pcrel(sym + add), chk.s */
+#define R_IA64_PCREL21F                0x4b    /* @pcrel(sym + add), fchkf */
+#define R_IA64_PCREL32MSB      0x4c    /* @pcrel(sym + add), data4 MSB */
+#define R_IA64_PCREL32LSB      0x4d    /* @pcrel(sym + add), data4 LSB */
+#define R_IA64_PCREL64MSB      0x4e    /* @pcrel(sym + add), data8 MSB */
+#define R_IA64_PCREL64LSB      0x4f    /* @pcrel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_FPTR22    0x52    /* @ltoff(@fptr(s+a)), imm22 */
+#define R_IA64_LTOFF_FPTR64I   0x53    /* @ltoff(@fptr(s+a)), imm64 */
+#define R_IA64_LTOFF_FPTR32MSB 0x54    /* @ltoff(@fptr(s+a)), data4 MSB */
+#define R_IA64_LTOFF_FPTR32LSB 0x55    /* @ltoff(@fptr(s+a)), data4 LSB */
+#define R_IA64_LTOFF_FPTR64MSB 0x56    /* @ltoff(@fptr(s+a)), data8 MSB */
+#define R_IA64_LTOFF_FPTR64LSB 0x57    /* @ltoff(@fptr(s+a)), data8 LSB */
+#define R_IA64_SEGREL32MSB     0x5c    /* @segrel(sym + add), data4 MSB */
+#define R_IA64_SEGREL32LSB     0x5d    /* @segrel(sym + add), data4 LSB */
+#define R_IA64_SEGREL64MSB     0x5e    /* @segrel(sym + add), data8 MSB */
+#define R_IA64_SEGREL64LSB     0x5f    /* @segrel(sym + add), data8 LSB */
+#define R_IA64_SECREL32MSB     0x64    /* @secrel(sym + add), data4 MSB */
+#define R_IA64_SECREL32LSB     0x65    /* @secrel(sym + add), data4 LSB */
+#define R_IA64_SECREL64MSB     0x66    /* @secrel(sym + add), data8 MSB */
+#define R_IA64_SECREL64LSB     0x67    /* @secrel(sym + add), data8 LSB */
+#define R_IA64_REL32MSB                0x6c    /* data 4 + REL */
+#define R_IA64_REL32LSB                0x6d    /* data 4 + REL */
+#define R_IA64_REL64MSB                0x6e    /* data 8 + REL */
+#define R_IA64_REL64LSB                0x6f    /* data 8 + REL */
+#define R_IA64_LTV32MSB                0x74    /* symbol + addend, data4 MSB */
+#define R_IA64_LTV32LSB                0x75    /* symbol + addend, data4 LSB */
+#define R_IA64_LTV64MSB                0x76    /* symbol + addend, data8 MSB */
+#define R_IA64_LTV64LSB                0x77    /* symbol + addend, data8 LSB */
+#define R_IA64_PCREL21BI       0x79    /* @pcrel(sym + add), 21bit inst */
+#define R_IA64_PCREL22         0x7a    /* @pcrel(sym + add), 22bit inst */
+#define R_IA64_PCREL64I                0x7b    /* @pcrel(sym + add), 64bit inst */
+#define R_IA64_IPLTMSB         0x80    /* dynamic reloc, imported PLT, MSB */
+#define R_IA64_IPLTLSB         0x81    /* dynamic reloc, imported PLT, LSB */
+#define R_IA64_COPY            0x84    /* copy relocation */
+#define R_IA64_SUB             0x85    /* Addend and symbol difference */
+#define R_IA64_LTOFF22X                0x86    /* LTOFF22, relaxable.  */
+#define R_IA64_LDXMOV          0x87    /* Use of LTOFF22X.  */
+#define R_IA64_TPREL14         0x91    /* @tprel(sym + add), imm14 */
+#define R_IA64_TPREL22         0x92    /* @tprel(sym + add), imm22 */
+#define R_IA64_TPREL64I                0x93    /* @tprel(sym + add), imm64 */
+#define R_IA64_TPREL64MSB      0x96    /* @tprel(sym + add), data8 MSB */
+#define R_IA64_TPREL64LSB      0x97    /* @tprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_TPREL22   0x9a    /* @ltoff(@tprel(s+a)), imm2 */
+#define R_IA64_DTPMOD64MSB     0xa6    /* @dtpmod(sym + add), data8 MSB */
+#define R_IA64_DTPMOD64LSB     0xa7    /* @dtpmod(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPMOD22  0xaa    /* @ltoff(@dtpmod(sym + add)), imm22 */
+#define R_IA64_DTPREL14                0xb1    /* @dtprel(sym + add), imm14 */
+#define R_IA64_DTPREL22                0xb2    /* @dtprel(sym + add), imm22 */
+#define R_IA64_DTPREL64I       0xb3    /* @dtprel(sym + add), imm64 */
+#define R_IA64_DTPREL32MSB     0xb4    /* @dtprel(sym + add), data4 MSB */
+#define R_IA64_DTPREL32LSB     0xb5    /* @dtprel(sym + add), data4 LSB */
+#define R_IA64_DTPREL64MSB     0xb6    /* @dtprel(sym + add), data8 MSB */
+#define R_IA64_DTPREL64LSB     0xb7    /* @dtprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPREL22  0xba    /* @ltoff(@dtprel(s+a)), imm22 */
+
+/* SH specific declarations */
+
+/* SH relocs.  */
+#define        R_SH_NONE               0
+#define        R_SH_DIR32              1
+#define        R_SH_REL32              2
+#define        R_SH_DIR8WPN            3
+#define        R_SH_IND12W             4
+#define        R_SH_DIR8WPL            5
+#define        R_SH_DIR8WPZ            6
+#define        R_SH_DIR8BP             7
+#define        R_SH_DIR8W              8
+#define        R_SH_DIR8L              9
+#define        R_SH_SWITCH16           25
+#define        R_SH_SWITCH32           26
+#define        R_SH_USES               27
+#define        R_SH_COUNT              28
+#define        R_SH_ALIGN              29
+#define        R_SH_CODE               30
+#define        R_SH_DATA               31
+#define        R_SH_LABEL              32
+#define        R_SH_SWITCH8            33
+#define        R_SH_GNU_VTINHERIT      34
+#define        R_SH_GNU_VTENTRY        35
+#define        R_SH_GOT32              160
+#define        R_SH_PLT32              161
+#define        R_SH_COPY               162
+#define        R_SH_GLOB_DAT           163
+#define        R_SH_JMP_SLOT           164
+#define        R_SH_RELATIVE           165
+#define        R_SH_GOTOFF             166
+#define        R_SH_GOTPC              167
+/* Keep this the last entry.  */
+#define        R_SH_NUM                256
+
+/* Additional s390 relocs */
+
+#define R_390_NONE     0              /* No reloc.  */
+#define R_390_8                1              /* Direct 8 bit.  */
+#define R_390_12       2              /* Direct 12 bit.  */
+#define R_390_16       3              /* Direct 16 bit.  */
+#define R_390_32       4              /* Direct 32 bit.  */
+#define R_390_PC32     5              /* PC relative 32 bit.  */
+#define R_390_GOT12    6              /* 12 bit GOT offset.  */
+#define R_390_GOT32    7              /* 32 bit GOT offset.  */
+#define R_390_PLT32    8              /* 32 bit PC relative PLT address.  */
+#define R_390_COPY     9              /* Copy symbol at runtime.  */
+#define R_390_GLOB_DAT 10             /* Create GOT entry.  */
+#define R_390_JMP_SLOT 11             /* Create PLT entry.  */
+#define R_390_RELATIVE 12             /* Adjust by program base.  */
+#define R_390_GOTOFF   13             /* 32 bit offset to GOT.  */
+#define R_390_GOTPC    14             /* 32 bit PC relative offset to GOT.  */
+#define R_390_GOT16    15             /* 16 bit GOT offset.  */
+#define R_390_PC16     16             /* PC relative 16 bit.  */
+#define R_390_PC16DBL  17             /* PC relative 16 bit shifted by 1.  */
+#define R_390_PLT16DBL 18             /* 16 bit PC rel. PLT shifted by 1.  */
+#define R_390_PC32DBL  19             /* PC relative 32 bit shifted by 1.  */
+#define R_390_PLT32DBL 20             /* 32 bit PC rel. PLT shifted by 1.  */
+#define R_390_GOTPCDBL 21             /* 32 bit PC rel. GOT shifted by 1.  */
+#define R_390_64       22             /* Direct 64 bit.  */
+#define R_390_PC64     23             /* PC relative 64 bit.  */
+#define R_390_GOT64    24             /* 64 bit GOT offset.  */
+#define R_390_PLT64    25             /* 64 bit PC relative PLT address.  */
+#define R_390_GOTENT   26             /* 32 bit PC rel. to GOT entry >> 1. */
+
+/* Keep this the last entry.  */
+#define R_390_NUM      27
+
+/* CRIS relocations.  */
+#define R_CRIS_NONE            0
+#define R_CRIS_8               1
+#define R_CRIS_16              2
+#define R_CRIS_32              3
+#define R_CRIS_8_PCREL         4
+#define R_CRIS_16_PCREL                5
+#define R_CRIS_32_PCREL                6
+#define R_CRIS_GNU_VTINHERIT   7
+#define R_CRIS_GNU_VTENTRY     8
+#define R_CRIS_COPY            9
+#define R_CRIS_GLOB_DAT                10
+#define R_CRIS_JUMP_SLOT       11
+#define R_CRIS_RELATIVE                12
+#define R_CRIS_16_GOT          13
+#define R_CRIS_32_GOT          14
+#define R_CRIS_16_GOTPLT       15
+#define R_CRIS_32_GOTPLT       16
+#define R_CRIS_32_GOTREL       17
+#define R_CRIS_32_PLT_GOTREL   18
+#define R_CRIS_32_PLT_PCREL    19
+
+#define R_CRIS_NUM             20
+
+/* AMD x86-64 relocations.  */
+#define R_X86_64_NONE          0       /* No reloc */
+#define R_X86_64_64            1       /* Direct 64 bit  */
+#define R_X86_64_PC32          2       /* PC relative 32 bit signed */
+#define R_X86_64_GOT32         3       /* 32 bit GOT entry */
+#define R_X86_64_PLT32         4       /* 32 bit PLT address */
+#define R_X86_64_COPY          5       /* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT      6       /* Create GOT entry */
+#define R_X86_64_JUMP_SLOT     7       /* Create PLT entry */
+#define R_X86_64_RELATIVE      8       /* Adjust by program base */
+#define R_X86_64_GOTPCREL      9       /* 32 bit signed pc relative
+                                          offset to GOT */
+#define R_X86_64_32            10      /* Direct 32 bit zero extended */
+#define R_X86_64_32S           11      /* Direct 32 bit sign extended */
+#define R_X86_64_16            12      /* Direct 16 bit zero extended */
+#define R_X86_64_PC16          13      /* 16 bit sign extended pc relative */
+#define R_X86_64_8             14      /* Direct 8 bit sign extended  */
+#define R_X86_64_PC8           15      /* 8 bit sign extended pc relative */
+
+#define R_X86_64_NUM           16
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* elf.h */
diff --git a/jit/jit-elf-read.c b/jit/jit-elf-read.c
new file mode 100644 (file)
index 0000000..223f36f
--- /dev/null
@@ -0,0 +1,1558 @@
+/*
+ * jit-elf-read.c - Routines to read ELF-format binaries.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-rules.h"
+#include "jit-elf-defs.h"
+#include "jit-memory.h"
+#include <config.h>
+#ifdef JIT_WIN32_PLATFORM
+       #ifdef HAVE_SYS_TYPES_H
+               #include <sys/types.h>
+       #endif
+       #include <windows.h>
+       #include <io.h>
+       #include <fcntl.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+       #include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+       #include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+       #include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+       #include <unistd.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+       #include <sys/mman.h>
+       #if defined(HAVE_MMAP) && defined(HAVE_MUNMAP) && defined(HAVE_MPROTECT)
+               #define JIT_USE_MMAP_TO_LOAD 1
+               #ifndef MAP_ANON
+                       #ifdef MAP_ANONYMOUS
+                               #define MAP_ANON        MAP_ANONYMOUS
+                       #else
+                               #define MAP_ANON        0
+                       #endif
+               #endif
+               #ifndef MAP_FIXED
+                       #define MAP_FIXED               0
+               #endif
+               #ifndef MAP_COPY
+                       #define MAP_COPY                MAP_PRIVATE
+               #endif
+       #endif
+#endif
+#endif
+#include <stdio.h>
+
+/*@
+
+The @code{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.
+
+@section Reading ELF binaries
+
+@*/
+
+/*
+ * Determine whether we should be using the 32-bit or 64-bit ELF structures.
+ */
+#ifdef JIT_NATIVE_INT32
+       typedef Elf32_Ehdr  Elf_Ehdr;
+       typedef Elf32_Shdr  Elf_Shdr;
+       typedef Elf32_Phdr  Elf_Phdr;
+       typedef Elf32_Addr  Elf_Addr;
+       typedef Elf32_Word  Elf_Word;
+       typedef Elf32_Xword Elf_Xword;
+       typedef Elf32_Off   Elf_Off;
+       typedef Elf32_Dyn   Elf_Dyn;
+       typedef Elf32_Sym   Elf_Sym;
+#else
+       typedef Elf64_Ehdr  Elf_Ehdr;
+       typedef Elf64_Shdr  Elf_Shdr;
+       typedef Elf64_Phdr  Elf_Phdr;
+       typedef Elf64_Addr  Elf_Addr;
+       typedef Elf64_Word  Elf_Word;
+       typedef Elf64_Xword Elf_Xword;
+       typedef Elf64_Off   Elf_Off;
+       typedef Elf64_Dyn   Elf_Dyn;
+       typedef Elf64_Sym   Elf_Sym;
+#endif
+
+/*
+ * Deal with platform differences in the file descriptor routines.
+ */
+#ifdef JIT_WIN32_NATIVE
+       #define sys_open                _open
+       #define sys_close               _close
+       #define sys_read                _read
+       #define sys_lseek               _lseek
+#else
+       #define sys_open                open
+       #define sys_close               close
+       #define sys_read                read
+       #define sys_lseek               lseek
+#endif
+#ifndef O_BINARY
+       #define O_BINARY                0
+#endif
+
+/*
+ * Define the relocation function type.
+ */
+typedef int (*jit_reloc_func)(jit_readelf_t readelf, void *address,
+                                                         int type, jit_nuint value, int has_addend,
+                                                         jit_nuint addend);
+
+/*
+ * Get the relocation function for a particular machine type.
+ */
+static jit_reloc_func get_reloc(unsigned int machine);
+
+/*
+ * Structure of an ELF binary once it has been loaded into memory.
+ */
+struct jit_readelf
+{
+       Elf_Ehdr                ehdr;
+       unsigned char  *phdrs;
+       unsigned char  *shdrs;
+       char               *regular_strings;
+       jit_nuint               regular_strings_size;
+       char               *dynamic_strings;
+       jit_nuint               dynamic_strings_size;
+       Elf_Sym            *symbol_table;
+       jit_nuint               symbol_table_size;
+       Elf_Word           *symbol_hash;
+       jit_nuint               symbol_hash_size;
+       Elf_Word                symbol_hash_buckets;
+       jit_reloc_func  reloc_func;
+       void               *map_address;
+       jit_nuint               map_size;
+       int                             free_with_munmap;
+};
+
+/*
+ * Flag that indicates that an auxillary section was malloc'ed,
+ * and isn't part of the main memory range at "map_address".
+ */
+#define        JIT_ELF_IS_MALLOCED                     0x01000000
+
+/*
+ * Get the address of a particular phdr.
+ */
+static Elf_Phdr *get_phdr(jit_readelf_t readelf, unsigned int index)
+{
+       if(index < readelf->ehdr.e_phnum &&
+          readelf->ehdr.e_phentsize >= sizeof(Elf_Phdr))
+       {
+               return (Elf_Phdr *)
+                       (readelf->phdrs +
+                        index * ((unsigned int)(readelf->ehdr.e_phentsize)));
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*
+ * Get the address of a particular shdr.
+ */
+static Elf_Shdr *get_shdr(jit_readelf_t readelf, unsigned int index)
+{
+       if(index < readelf->ehdr.e_shnum &&
+          readelf->ehdr.e_shentsize >= sizeof(Elf_Shdr))
+       {
+               return (Elf_Shdr *)
+                       (readelf->shdrs +
+                        index * ((unsigned int)(readelf->ehdr.e_shentsize)));
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*
+ * Find a specific string in the regular string table.
+ */
+static const char *get_string(jit_readelf_t readelf, Elf_Word _index)
+{
+       jit_nuint index = (jit_nuint)_index;
+       if(index < readelf->regular_strings_size)
+       {
+               return readelf->regular_strings + index;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*
+ * Find a specific string in the dynamic string table.
+ */
+static const char *get_dyn_string(jit_readelf_t readelf, Elf_Addr _index)
+{
+       jit_nuint index = (jit_nuint)_index;
+       if(index < readelf->dynamic_strings_size)
+       {
+               return readelf->dynamic_strings + index;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*
+ * Map all of the program segments into memory and set up the bss section.
+ */
+static int map_program(jit_readelf_t readelf, int fd)
+{
+       Elf_Off file_size;
+       Elf_Off memory_size;
+       Elf_Off start, end;
+       Elf_Phdr *phdr;
+       unsigned int index;
+       void *base_address;
+       unsigned char *segment_address;
+
+       /* Get the maximum file and memory sizes for the program.
+          The bytes between "file_size" and "memory_size" are bss */
+       file_size = 0;
+       memory_size = 0;
+       for(index = 0; index < readelf->ehdr.e_phnum; ++index)
+       {
+               phdr = get_phdr(readelf, index);
+               if(!phdr)
+               {
+                       continue;
+               }
+               start = phdr->p_offset;
+               end = start + phdr->p_filesz;
+               if(end > file_size)
+               {
+                       file_size = end;
+               }
+               start = phdr->p_vaddr;
+               end = start + phdr->p_memsz;
+               if(end > memory_size)
+               {
+                       memory_size = end;
+               }
+       }
+       if(memory_size < file_size)
+       {
+               memory_size = file_size;
+       }
+
+       /* Try to map the program segments into memory using mmap */
+       base_address = 0;
+#ifdef JIT_USE_MMAP_TO_LOAD
+       {
+               Elf_Off page_size;
+               Elf_Off rounded_file_size;
+               Elf_Off temp_start;
+               Elf_Off temp_end;
+               int zero_fd, prot;
+
+               /* Round the total memory and file sizes up to the CPU page size */
+               page_size = (Elf_Off)(jit_exec_page_size());
+               end = memory_size;
+               if((end % page_size) != 0)
+               {
+                       end += page_size - (end % page_size);
+               }
+               rounded_file_size = file_size;
+               if((rounded_file_size % page_size) != 0)
+               {
+                       rounded_file_size += page_size - (rounded_file_size % page_size);
+               }
+
+               /* Allocate memory for the program from /dev/zero.  Once we have
+                  the memory, we will overlay the program segments on top */
+               zero_fd = sys_open("/dev/zero", O_RDWR, 0);
+               if(zero_fd < -1)
+               {
+                       goto failed_mmap;
+               }
+               base_address = mmap(0, (size_t)end, PROT_READ | PROT_WRITE,
+                                                       MAP_ANON | MAP_PRIVATE, zero_fd, 0);
+               close(zero_fd);
+               if(base_address == (void *)(jit_nint)(-1))
+               {
+                       base_address = 0;
+                       goto failed_mmap;
+               }
+
+               /* Lay down the program sections at their mapped locations */
+               for(index = 0; index < readelf->ehdr.e_phnum; ++index)
+               {
+                       phdr = get_phdr(readelf, index);
+                       if(phdr)
+                       {
+                               temp_start = phdr->p_offset;
+                               temp_end = temp_start + phdr->p_filesz;
+                               temp_start -= (temp_start % page_size);
+                               if((temp_end % page_size) != 0)
+                               {
+                                       temp_end += page_size - (temp_end % page_size);
+                               }
+                               start = phdr->p_vaddr;
+                               start -= (start % page_size);
+                               if(temp_start < temp_end)
+                               {
+                                       segment_address =
+                                               ((unsigned char *)base_address) + (jit_nuint)start;
+                                       prot = 0;
+                                       if((phdr->p_flags & PF_X) != 0)
+                                       {
+                                               prot |= PROT_EXEC;
+                                       }
+                                       if((phdr->p_flags & PF_W) != 0)
+                                       {
+                                               prot |= PROT_WRITE;
+                                       }
+                                       if((phdr->p_flags & PF_R) != 0)
+                                       {
+                                               prot |= PROT_READ;
+                                       }
+                                       if(mmap(segment_address, (size_t)(temp_end - temp_start),
+                                                   prot, MAP_COPY | MAP_FILE | MAP_FIXED, fd,
+                                                       (off_t)temp_start) == (void *)(jit_nint)(-1))
+                                       {
+                                               munmap(base_address, (size_t)end);
+                                               base_address = 0;
+                                               goto failed_mmap;
+                                       }
+                               }
+                       }
+               }
+
+               /* We need to free the memory with munmap when the program is closed */
+               readelf->free_with_munmap = 1;
+
+               /* Clear the left-over ".bss" bits that did not get cleared above */
+               for(index = 0; index < readelf->ehdr.e_phnum; ++index)
+               {
+                       phdr = get_phdr(readelf, index);
+                       if(phdr && phdr->p_filesz < phdr->p_memsz)
+                       {
+                               temp_start = phdr->p_vaddr + phdr->p_filesz;
+                               start = (temp_start % page_size);
+                               temp_start -= start;
+                               if(start != 0)
+                               {
+                                       segment_address =
+                                               ((unsigned char *)base_address) +
+                                               (jit_nuint)temp_start;
+                                       mprotect(segment_address, (size_t)page_size,
+                                                        PROT_READ | PROT_WRITE);
+                                       jit_memzero(segment_address + (jit_nuint)start,
+                                                           (unsigned int)(page_size - start));
+                                       prot = 0;
+                                       if((phdr->p_flags & PF_X) != 0)
+                                       {
+                                               prot |= PROT_EXEC;
+                                       }
+                                       if((phdr->p_flags & PF_W) != 0)
+                                       {
+                                               prot |= PROT_WRITE;
+                                       }
+                                       if((phdr->p_flags & PF_R) != 0)
+                                       {
+                                               prot |= PROT_READ;
+                                       }
+                                       mprotect(segment_address, (size_t)page_size, prot);
+                               }
+                       }
+               }
+       }
+failed_mmap:
+#endif /* JIT_USE_MMAP_TO_LOAD */
+
+       /* If we haven't mapped the file yet, then fall back to "malloc" */
+       if(!base_address)
+       {
+               base_address = jit_malloc_exec(memory_size);
+               if(!base_address)
+               {
+                       return 0;
+               }
+               for(index = 0; index < readelf->ehdr.e_phnum; ++index)
+               {
+                       phdr = get_phdr(readelf, index);
+                       if(phdr)
+                       {
+                               segment_address = ((unsigned char *)base_address) +
+                                                                 (jit_nuint)(phdr->p_vaddr);
+                               if(lseek(fd, (off_t)(phdr->p_offset), 0) != phdr->p_offset ||
+                      read(fd, segment_address, (size_t)(phdr->p_filesz))
+                                               != (size_t)(phdr->p_filesz))
+                               {
+                                       jit_free_exec(base_address, memory_size);
+                                       return 0;
+                               }
+                       }
+               }
+       }
+
+       /* Record the mapped address and size for later */
+       readelf->map_address = base_address;
+       readelf->map_size = memory_size;
+       return 1;
+}
+
+/*
+ * Map an auxillary section into memory and return its base address.
+ * Returns NULL if we ran out of memory.
+ */
+static void *map_section(int fd, Elf_Off offset, Elf_Xword file_size,
+                                                Elf_Xword memory_size, Elf_Word flags)
+{
+       void *address;
+       if(memory_size < file_size)
+       {
+               memory_size = file_size;
+       }
+       address = jit_malloc_exec(memory_size);
+       if(!address)
+       {
+               return 0;
+       }
+       if(lseek(fd, offset, 0) != offset)
+       {
+               jit_free_exec(address, memory_size);
+               return 0;
+       }
+       if(read(fd, address, (size_t)file_size) != file_size)
+       {
+               jit_free_exec(address, memory_size);
+               return 0;
+       }
+       return address;
+}
+
+/*
+ * Unmap an auxillary section from memory.
+ */
+static void unmap_section(void *address, Elf_Xword file_size,
+                                                 Elf_Xword memory_size, Elf_Word flags)
+{
+       if(memory_size < file_size)
+       {
+               memory_size = file_size;
+       }
+       if((flags & JIT_ELF_IS_MALLOCED) != 0)
+       {
+               jit_free_exec(address, (unsigned int)memory_size);
+       }
+}
+
+/*
+ * Iterate over the contents of the ".dynamic" section.
+ */
+typedef struct
+{
+       Elf_Dyn    *dyn;
+       jit_nuint       size;
+
+} jit_dynamic_iter_t;
+static void dynamic_iter_init(jit_dynamic_iter_t *iter, jit_readelf_t readelf)
+{
+       iter->dyn = jit_readelf_get_section_by_type
+               (readelf, SHT_DYNAMIC, &(iter->size));
+}
+static int dynamic_iter_next
+       (jit_dynamic_iter_t *iter, jit_uint *type, Elf_Addr *value)
+{
+       if(iter->size >= sizeof(Elf_Dyn))
+       {
+               *type = (jit_uint)(iter->dyn->d_tag);
+               *value = iter->dyn->d_un.d_ptr;
+               if(*type == DT_NULL)
+               {
+                       /* Explicitly-marked end of the list */
+                       return 0;
+               }
+               ++(iter->dyn);
+               iter->size -= sizeof(Elf_Dyn);
+               return 1;
+       }
+       else
+       {
+               /* Implicitly-marked end of the list */
+               return 0;
+       }
+}
+static int dynamic_for_type
+       (jit_readelf_t readelf, jit_uint type, Elf_Addr *value)
+{
+       Elf_Addr temp_value;
+       jit_dynamic_iter_t iter;
+       jit_uint iter_type;
+       dynamic_iter_init(&iter, readelf);
+       while(dynamic_iter_next(&iter, &iter_type, &temp_value))
+       {
+               if(iter_type == type)
+               {
+                       if(value)
+                       {
+                               *value = temp_value;
+                       }
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Load interesting values from the ".dynamic" section, for quicker lookups.
+ */
+static void load_dynamic_section(jit_readelf_t readelf, int flags)
+{
+       Elf_Addr value;
+       Elf_Addr value2;
+       jit_dynamic_iter_t iter;
+       jit_uint type;
+       jit_nuint size;
+
+       /* Get the position and size of the dynamic string table */
+       if(dynamic_for_type(readelf, DT_STRTAB, &value) &&
+          dynamic_for_type(readelf, DT_STRSZ, &value2))
+       {
+               readelf->dynamic_strings = jit_readelf_map_vaddr
+                       (readelf, (jit_nuint)value);
+               if(readelf->dynamic_strings)
+               {
+                       readelf->dynamic_strings_size = (jit_nuint)value2;
+               }
+       }
+
+       /* Get the position and size of the dynamic symbol table */
+       readelf->symbol_table = jit_readelf_get_section_by_type
+               (readelf, SHT_DYNSYM, &size);
+       if(readelf->symbol_table)
+       {
+               if(dynamic_for_type(readelf, DT_SYMENT, &value) &&
+                  value == sizeof(Elf_Sym))
+               {
+                       readelf->symbol_table_size = size / sizeof(Elf_Sym);
+                       readelf->symbol_hash = jit_readelf_get_section_by_type
+                               (readelf, SHT_HASH, &size);
+                       if(readelf->symbol_hash)
+                       {
+                               readelf->symbol_hash_size = size / sizeof(Elf_Word);
+                               if(readelf->symbol_hash_size >= 2)
+                               {
+                                       readelf->symbol_hash_buckets = readelf->symbol_hash[0];
+                               }
+                       }
+               }
+               else
+               {
+                       readelf->symbol_table = 0;
+               }
+       }
+
+       /* Bail out if we don't need to print debugging information */
+       if((flags & JIT_READELF_FLAG_DEBUG) == 0)
+       {
+               return;
+       }
+
+       /* Iterate through the ".dynamic" section, dumping all that we find */
+       dynamic_iter_init(&iter, readelf);
+       while(dynamic_iter_next(&iter, &type, &value))
+       {
+               switch(type)
+               {
+                       case DT_NEEDED:
+                       {
+                               printf("needed library: %s\n", get_dyn_string(readelf, value));
+                       }
+                       break;
+
+                       case DT_PLTRELSZ:
+                       {
+                               printf("total size of PLT relocs: %ld\n", (long)value);
+                       }
+                       break;
+
+                       case DT_PLTGOT:
+                       {
+                               printf("address of PLTGOT table: 0x%lx\n", (long)value);
+                       }
+                       break;
+
+                       case DT_HASH:
+                       {
+                               printf("address of symbol hash table: 0x%lx\n", (long)value);
+                       }
+                       break;
+
+                       case DT_STRTAB:
+                       {
+                               printf("address of string table: 0x%lx\n", (long)value);
+                       }
+                       break;
+
+                       case DT_SYMTAB:
+                       {
+                               printf("address of symbol table: 0x%lx\n", (long)value);
+                       }
+                       break;
+
+                       case DT_STRSZ:
+                       {
+                               printf("size of string table: %ld\n", (long)value);
+                       }
+                       break;
+
+                       case DT_SYMENT:
+                       {
+                               printf("size of one symbol table entry: %ld\n", (long)value);
+                       }
+                       break;
+
+                       case DT_INIT:
+                       {
+                               printf("address of init function: 0x%lx\n", (long)value);
+                       }
+                       break;
+
+                       case DT_FINI:
+                       {
+                               printf("address of fini function: 0x%lx\n", (long)value);
+                       }
+                       break;
+
+                       case DT_SONAME:
+                       {
+                               printf("library name: %s\n", get_dyn_string(readelf, value));
+                       }
+                       break;
+
+                       case DT_REL:
+                       {
+                               printf("address of Rel relocs: 0x%lx\n", (long)value);
+                       }
+                       break;
+
+                       case DT_RELSZ:
+                       {
+                               printf("total size of Rel relocs: %ld\n", (long)value);
+                       }
+                       break;
+
+                       case DT_RELENT:
+                       {
+                               printf("size of one Rel reloc: %ld\n", (long)value);
+                       }
+                       break;
+
+                       case DT_PLTREL:
+                       {
+                               printf("type of PLT relocs: %ld\n", (long)value);
+                       }
+                       break;
+
+                       case DT_JMPREL:
+                       {
+                               printf("address of PLT relocs: 0x%lx\n", (long)value);
+                       }
+                       break;
+
+                       default:
+                       {
+                               printf("dynamic info of type 0x%x: 0x%lx\n",
+                                          (int)type, (long)value);
+                       }
+                       break;
+               }
+       }
+
+       /* Iterate through the symbol table, dumping all of the entries */
+       for(size = 0; size < readelf->symbol_table_size; ++size)
+       {
+               printf("%08lX %02X%02X %2d %s\n",
+                          (long)(readelf->symbol_table[size].st_value),
+                          (int)(readelf->symbol_table[size].st_info),
+                          (int)(readelf->symbol_table[size].st_other),
+                          (int)(readelf->symbol_table[size].st_shndx),
+                          get_dyn_string(readelf, readelf->symbol_table[size].st_name));
+       }
+       printf("number of symbols: %ld\n", (long)(readelf->symbol_table_size));
+       printf("number of symbol hash entries: %ld\n",
+                  (long)(readelf->symbol_hash_size));
+}
+
+/*@
+ * @deftypefun int jit_readelf_open ({jit_readelf_t *} readelf, {const char *} filename, int force)
+ * Open the specified @code{filename} and load the ELF binary that is
+ * contained within it.  Returns one of the following result codes:
+ *
+ * @table @code
+ * @vindex JIT_READELF_OK
+ * @item JIT_READELF_OK
+ * The ELF binary was opened successfully.
+ *
+ * @vindex JIT_READELF_CANNOT_OPEN
+ * @item JIT_READELF_CANNOT_OPEN
+ * Could not open the file at the filesystem level (reason in @code{errno}).
+ *
+ * @vindex JIT_READELF_NOT_ELF
+ * @item JIT_READELF_NOT_ELF
+ * The file was opened, but it is not an ELF binary.
+ *
+ * @vindex JIT_READELF_WRONG_ARCH
+ * @item JIT_READELF_WRONG_ARCH
+ * The file is an ELF binary, but it does not pertain to the architecture
+ * of this machine.
+ *
+ * @vindex JIT_READELF_BAD_FORMAT
+ * @item JIT_READELF_BAD_FORMAT
+ * The file is an ELF binary, but the format is corrupted in some fashion.
+ *
+ * @vindex JIT_READELF_MEMORY
+ * @item JIT_READELF_MEMORY
+ * There is insufficient memory to open the ELF binary.
+ * @end table
+ *
+ * The following flags may be supplied to alter the manner in which
+ * the ELF binary is loaded:
+ *
+ * @table @code
+ * @vindex JIT_READELF_FLAG_FORCE
+ * @item JIT_READELF_FLAG_FORCE
+ * Force @code{jit_readelf_open} to open the ELF binary, even if
+ * the architecture does not match this machine.  Useful for debugging.
+ *
+ * @vindex JIT_READELF_FLAG_DEBUG
+ * @item JIT_READELF_FLAG_DEBUG
+ * Print additional debug information to stdout.
+ * @end table
+ * @end deftypefun
+@*/
+int jit_readelf_open(jit_readelf_t *_readelf, const char *filename, int flags)
+{
+       int fd;
+       Elf_Ehdr ehdr;
+       Elf_Phdr *phdr;
+       Elf_Shdr *shdr;
+       jit_elf_info_t elf_info;
+       jit_readelf_t readelf;
+       unsigned int phdr_size;
+       unsigned int shdr_size;
+       unsigned int index;
+       void *address;
+       union
+       {
+               jit_ushort value;
+               unsigned char bytes[2];
+
+       } un;
+
+       /* Get the machine and ABI values that we expect in the header */
+       _jit_gen_get_elf_info(&elf_info);
+
+       /* Open the file and read the ELF magic number information */
+       if((fd = sys_open(filename, O_RDONLY | O_BINARY, 0)) < 0)
+       {
+               return JIT_READELF_CANNOT_OPEN;
+       }
+       if(sys_read(fd, ehdr.e_ident, EI_NIDENT) != EI_NIDENT)
+       {
+               sys_close(fd);
+               return JIT_READELF_NOT_ELF;
+       }
+
+       /* Determine if the magic number matches what we expect to see */
+       if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
+          ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3)
+       {
+               sys_close(fd);
+               return JIT_READELF_NOT_ELF;
+       }
+#ifdef JIT_NATIVE_INT32
+       if(ehdr.e_ident[EI_CLASS] != ELFCLASS32)
+       {
+               sys_close(fd);
+               return JIT_READELF_WRONG_ARCH;
+       }
+#else
+       if(ehdr.e_ident[EI_CLASS] != ELFCLASS64)
+       {
+               sys_close(fd);
+               return JIT_READELF_WRONG_ARCH;
+       }
+#endif
+       un.value = 0x0102;
+       if(un.bytes[0] == 0x01)
+       {
+               /* Looking for a big-endian binary */
+               if(ehdr.e_ident[EI_DATA] != ELFDATA2MSB)
+               {
+                       sys_close(fd);
+                       return JIT_READELF_WRONG_ARCH;
+               }
+       }
+       else
+       {
+               /* Looking for a little-endian binary */
+               if(ehdr.e_ident[EI_DATA] != ELFDATA2LSB)
+               {
+                       sys_close(fd);
+                       return JIT_READELF_WRONG_ARCH;
+               }
+       }
+       if(ehdr.e_ident[EI_VERSION] != EV_CURRENT)
+       {
+               sys_close(fd);
+               return JIT_READELF_BAD_FORMAT;
+       }
+
+       /* Read the rest of the ELF header and validate it */
+       if(sys_read(fd, &(ehdr.e_type), sizeof(Elf_Ehdr) - EI_NIDENT)
+                       != (sizeof(Elf_Ehdr) - EI_NIDENT))
+       {
+               sys_close(fd);
+               return JIT_READELF_BAD_FORMAT;
+       }
+       if(ehdr.e_type != ET_DYN)
+       {
+               /* We can only load files that are marked as dynamic shared objects */
+               sys_close(fd);
+               return JIT_READELF_WRONG_ARCH;
+       }
+       if((flags & JIT_READELF_FLAG_FORCE) == 0)
+       {
+               if(ehdr.e_machine != elf_info.machine ||
+                  ehdr.e_ident[EI_OSABI] != elf_info.abi ||
+                  ehdr.e_ident[EI_ABIVERSION] != elf_info.abi_version)
+               {
+                       /* The ELF binary does not pertain to this machine or ABI type */
+                       sys_close(fd);
+                       return JIT_READELF_WRONG_ARCH;
+               }
+       }
+       if(ehdr.e_version != EV_CURRENT)
+       {
+               sys_close(fd);
+               return JIT_READELF_BAD_FORMAT;
+       }
+       if(ehdr.e_ehsize < sizeof(ehdr))
+       {
+               sys_close(fd);
+               return JIT_READELF_BAD_FORMAT;
+       }
+
+       /* Allocate space for the ELF reader object */
+       if((readelf = jit_cnew(struct jit_readelf)) == 0)
+       {
+               sys_close(fd);
+               return JIT_READELF_MEMORY;
+       }
+       readelf->ehdr = ehdr;
+       phdr_size = ((unsigned int)(ehdr.e_phnum)) *
+                               ((unsigned int)(ehdr.e_phentsize));
+       shdr_size = ((unsigned int)(ehdr.e_shnum)) *
+                               ((unsigned int)(ehdr.e_shentsize));
+       if(phdr_size > 0)
+       {
+               readelf->phdrs = (unsigned char *)jit_malloc(phdr_size);
+               if(!(readelf->phdrs))
+               {
+                       jit_free(readelf);
+                       sys_close(fd);
+                       return JIT_READELF_MEMORY;
+               }
+       }
+       if(shdr_size > 0)
+       {
+               readelf->shdrs = (unsigned char *)jit_malloc(shdr_size);
+               if(!(readelf->shdrs))
+               {
+                       jit_free(readelf->phdrs);
+                       jit_free(readelf);
+                       sys_close(fd);
+                       return JIT_READELF_MEMORY;
+               }
+       }
+
+       /* Seek to the program and section header tables and read them */
+       if(phdr_size > 0)
+       {
+               if(lseek(fd, ehdr.e_phoff, 0) != ehdr.e_phoff ||
+                  read(fd, readelf->phdrs, phdr_size) != phdr_size)
+               {
+                       jit_free(readelf->shdrs);
+                       jit_free(readelf->phdrs);
+                       jit_free(readelf);
+                       sys_close(fd);
+                       return JIT_READELF_BAD_FORMAT;
+               }
+       }
+       if(shdr_size > 0)
+       {
+               if(lseek(fd, ehdr.e_shoff, 0) != ehdr.e_shoff ||
+                  read(fd, readelf->shdrs, shdr_size) != shdr_size)
+               {
+                       jit_free(readelf->shdrs);
+                       jit_free(readelf->phdrs);
+                       jit_free(readelf);
+                       sys_close(fd);
+                       return JIT_READELF_BAD_FORMAT;
+               }
+       }
+
+       /* Load the program segments */
+       if(!map_program(readelf, fd))
+       {
+               jit_readelf_close(readelf);
+               sys_close(fd);
+               return JIT_READELF_MEMORY;
+       }
+
+       /* Load the auxillary sections */
+       if(shdr_size > 0)
+       {
+               for(index = 0; index < ehdr.e_shnum; ++index)
+               {
+                       shdr = get_shdr(readelf, index);
+                       if(!shdr)
+                       {
+                               continue;
+                       }
+                       if((shdr->sh_flags & SHF_ALLOC) != 0 || shdr->sh_addr != 0)
+                       {
+                               /* This may be mapped inside one of the program segments.
+                                  If so, we don't want to load a second copy of it */
+                               address = jit_readelf_map_vaddr(readelf, shdr->sh_addr);
+                               if(address)
+                               {
+                                       continue;
+                               }
+                       }
+                       if(shdr->sh_size == 0)
+                       {
+                               /* Ignore zero-sized segments */
+                               continue;
+                       }
+                       address = map_section
+                               (fd, shdr->sh_offset, shdr->sh_size, shdr->sh_size,
+                                ((shdr->sh_flags & SHF_WRITE) != 0 ? (PF_W | PF_R) : PF_R));
+                       if(!address)
+                       {
+                               jit_readelf_close(readelf);
+                               sys_close(fd);
+                               return JIT_READELF_MEMORY;
+                       }
+                       shdr->sh_offset = (Elf_Off)(jit_nuint)address;
+                       shdr->sh_flags |= JIT_ELF_IS_MALLOCED;
+               }
+       }
+
+       /* Close the file descriptor because we don't need it any more */
+       sys_close(fd);
+
+       /* Find the regular string table */
+       shdr = get_shdr(readelf, ehdr.e_shstrndx);
+       if(shdr)
+       {
+               if((shdr->sh_flags & JIT_ELF_IS_MALLOCED) != 0)
+               {
+                       readelf->regular_strings = (char *)(jit_nuint)(shdr->sh_offset);
+               }
+               else
+               {
+                       readelf->regular_strings =
+                               (char *)jit_readelf_map_vaddr(readelf, shdr->sh_addr);
+               }
+               if(readelf->regular_strings)
+               {
+                       readelf->regular_strings_size = (jit_nuint)(shdr->sh_size);
+               }
+       }
+
+       /* Dump debug information about the program segments and sections */
+       if((flags & JIT_READELF_FLAG_DEBUG) != 0)
+       {
+               printf("header: machine=%d, abi=%d, abi_version=%d\n",
+                          (int)(ehdr.e_machine), (int)(ehdr.e_ident[EI_OSABI]),
+                          (int)(ehdr.e_ident[EI_ABIVERSION]));
+               for(index = 0; index < ehdr.e_phnum; ++index)
+               {
+                       phdr = get_phdr(readelf, index);
+                       if(phdr)
+                       {
+                               printf("program segment: type=%d, flags=0x%x, "
+                                                       "vaddr=0x%lx, file_size=%ld, memory_size=%ld\n",
+                                      (int)(phdr->p_type),
+                                      (int)(phdr->p_flags & ~JIT_ELF_IS_MALLOCED),
+                                      (long)(phdr->p_vaddr),
+                                      (long)(phdr->p_filesz),
+                                      (long)(phdr->p_memsz));
+                       }
+               }
+               for(index = 0; index < ehdr.e_shnum; ++index)
+               {
+                       shdr = get_shdr(readelf, index);
+                       if(shdr)
+                       {
+                               printf("section %2d: name=\"%s\", type=%d, flags=0x%x, "
+                                                       "vaddr=0x%lx, size=%ld\n",
+                                          index,
+                                      get_string(readelf, shdr->sh_name),
+                                      (int)(shdr->sh_type),
+                                      (int)(shdr->sh_flags & ~JIT_ELF_IS_MALLOCED),
+                                          (long)(shdr->sh_addr),
+                                      (long)(shdr->sh_size));
+                       }
+               }
+       }
+
+       /* Get the relocation function for this machine type */
+       readelf->reloc_func = get_reloc((unsigned int)(ehdr.e_machine));
+
+       /* Load useful values from the dynamic section that we want to cache */
+       load_dynamic_section(readelf, flags);
+
+       /* The ELF binary is loaded and ready to go */
+       *_readelf = readelf;
+       return JIT_READELF_OK;
+}
+
+/*@
+ * @deftypefun void jit_readelf_close (jit_readelf_t readelf)
+ * Close an ELF reader, reclaiming all of the memory that was used.
+ * @end deftypefun
+@*/
+void jit_readelf_close(jit_readelf_t readelf)
+{
+       unsigned int index;
+       Elf_Shdr *shdr;
+       if(!readelf)
+       {
+               return;
+       }
+#ifdef JIT_USE_MMAP_TO_LOAD
+       if(readelf->free_with_munmap)
+       {
+               munmap(readelf->map_address, (size_t)(readelf->map_size));
+       }
+       else
+#endif
+       {
+               jit_free_exec(readelf->map_address, readelf->map_size);
+       }
+       for(index = 0; index < readelf->ehdr.e_shnum; ++index)
+       {
+               shdr = get_shdr(readelf, index);
+               if(shdr && (shdr->sh_flags & JIT_ELF_IS_MALLOCED) != 0)
+               {
+                       unmap_section
+                               ((void *)(jit_nuint)(shdr->sh_offset),
+                                shdr->sh_size, shdr->sh_size, shdr->sh_flags);
+               }
+       }
+       jit_free(readelf->phdrs);
+       jit_free(readelf->shdrs);
+       jit_free(readelf);
+}
+
+/*@
+ * @deftypefun {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.
+ * @end deftypefun
+@*/
+const char *jit_readelf_get_name(jit_readelf_t readelf)
+{
+       Elf_Addr value;
+       if(dynamic_for_type(readelf, DT_SONAME, &value))
+       {
+               return get_dyn_string(readelf, value);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun void *jit_readelf_get_symbol (jit_readelf_t readelf, {const char *} name)
+ * Look up the symbol called @code{name} in the ELF binary represented
+ * by @code{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
+ * @code{jit_readelf_add_to_context} and @code{jit_readelf_resolve_all}.
+ * You should not call functions within this ELF binary until after you
+ * have fully resolved it.
+ * @end deftypefun
+@*/
+void *jit_readelf_get_symbol(jit_readelf_t readelf, const char *name)
+{
+       unsigned long hash;
+       unsigned long temp;
+       unsigned int index;
+       jit_nuint num_symbols;
+       Elf_Sym *symbol;
+       const char *symbol_name;
+
+       /* Bail out if we have insufficient information to resolve the name */
+       if(!readelf || !name || !(readelf->symbol_table))
+       {
+               return 0;
+       }
+
+       /* Hash the name to get the starting index in the symbol hash */
+       hash = 0;
+       index = 0;
+       while(name[index] != 0)
+       {
+               hash = (hash << 4) + (unsigned long)(name[index] & 0xFF);
+               temp = (hash & 0xF0000000);
+               if(temp != 0)
+               {
+                       hash ^= temp | (temp >> 24);
+               }
+               ++index;
+       }
+
+       /* Look in the hash table for the name */
+       if(readelf->symbol_hash_buckets != 0)
+       {
+               hash %= (unsigned long)(readelf->symbol_hash_buckets);
+               temp = (unsigned long)(readelf->symbol_hash[hash + 2]);
+               while(temp != 0 && temp < readelf->symbol_table_size)
+               {
+                       symbol = &(readelf->symbol_table[temp]);
+                       symbol_name = get_dyn_string(readelf, symbol->st_name);
+                       if(symbol_name && !jit_strcmp(symbol_name, name))
+                       {
+                               /* Ignore symbols in section 0, as they are external */
+                               if(symbol->st_shndx)
+                               {
+                                       return jit_readelf_map_vaddr
+                                               (readelf, (jit_nuint)(symbol->st_value));
+                               }
+                               break;
+                       }
+                       temp = (unsigned long)(readelf->symbol_hash
+                               [temp + readelf->symbol_hash_buckets + 2]);
+               }
+               return 0;
+       }
+
+       /* There is no hash table, so search for the symbol the hard way */
+       symbol = readelf->symbol_table;
+       for(num_symbols = readelf->symbol_table_size;
+               num_symbols > 0; --num_symbols)
+       {
+               symbol_name = get_dyn_string(readelf, symbol->st_name);
+               if(symbol_name && !jit_strcmp(symbol_name, name))
+               {
+                       /* Ignore symbols in section 0, as they are external */
+                       if(symbol->st_shndx)
+                       {
+                               return jit_readelf_map_vaddr
+                                       (readelf, (jit_nuint)(symbol->st_value));
+                       }
+               }
+               ++symbol;
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun {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. @code{.foovm}) to prevent clashes with
+ * system-defined section names.  The prefix @code{.libjit} is reserved
+ * for use by @code{libjit} itself.
+ * @end deftypefun
+@*/
+void *jit_readelf_get_section
+       (jit_readelf_t readelf, const char *name, jit_nuint *size)
+{
+       unsigned int index;
+       Elf_Shdr *shdr;
+       const char *temp_name;
+       if(!readelf || !name)
+       {
+               return 0;
+       }
+       for(index = 0; index < readelf->ehdr.e_shnum; ++index)
+       {
+               shdr = get_shdr(readelf, index);
+               if(shdr)
+               {
+                       temp_name = get_string(readelf, shdr->sh_name);
+                       if(temp_name && !jit_strcmp(name, temp_name))
+                       {
+                               if(size)
+                               {
+                                       *size = (jit_nuint)(shdr->sh_size);
+                               }
+                               if((shdr->sh_flags & JIT_ELF_IS_MALLOCED) != 0)
+                               {
+                                       return (void *)(jit_nuint)(shdr->sh_offset);
+                               }
+                               else
+                               {
+                                       return jit_readelf_map_vaddr
+                                               (readelf, (jit_nuint)(shdr->sh_addr));
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun {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 @code{SHT_*} constants in @code{jit-elf-defs.h}).  This is mostly
+ * for internal use, but some virtual machines may find it useful for
+ * debugging purposes.
+ * @end deftypefun
+@*/
+void *jit_readelf_get_section_by_type
+       (jit_readelf_t readelf, jit_int type, jit_nuint *size)
+{
+       unsigned int index;
+       Elf_Shdr *shdr;
+       if(!readelf)
+       {
+               return 0;
+       }
+       for(index = 0; index < readelf->ehdr.e_shnum; ++index)
+       {
+               shdr = get_shdr(readelf, index);
+               if(shdr && type == (jit_int)(shdr->sh_type))
+               {
+                       if(size)
+                       {
+                               *size = (jit_nuint)(shdr->sh_size);
+                       }
+                       if((shdr->sh_flags & JIT_ELF_IS_MALLOCED) != 0)
+                       {
+                               return (void *)(jit_nuint)(shdr->sh_offset);
+                       }
+                       else
+                       {
+                               return jit_readelf_map_vaddr
+                                       (readelf, (jit_nuint)(shdr->sh_addr));
+                       }
+               }
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun {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 @code{vaddr} could not be mapped.
+ * @end deftypefun
+@*/
+void *jit_readelf_map_vaddr(jit_readelf_t readelf, jit_nuint vaddr)
+{
+       unsigned int index;
+       Elf_Phdr *phdr;
+       if(!readelf)
+       {
+               return 0;
+       }
+       for(index = 0; index < readelf->ehdr.e_phnum; ++index)
+       {
+               phdr = get_phdr(readelf, index);
+               if(phdr && vaddr >= phdr->p_vaddr &&
+                  vaddr < (phdr->p_vaddr + phdr->p_memsz))
+               {
+                       return (void *)(((unsigned char *)(readelf->map_address)) + vaddr);
+               }
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun {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 @code{jit_readelf_open} as well,
+ * so that all of the necessary symbols can be resolved.
+ * @end deftypefun
+@*/
+unsigned int jit_readelf_num_needed(jit_readelf_t readelf)
+{
+       jit_dynamic_iter_t iter;
+       unsigned int count = 0;
+       jit_int type;
+       Elf_Addr value;
+       dynamic_iter_init(&iter, readelf);
+       while(dynamic_iter_next(&iter, &type, &value))
+       {
+               if(type == DT_NEEDED)
+               {
+                       ++count;
+               }
+       }
+       return count;
+}
+
+/*@
+ * @deftypefun {const char *} jit_readelf_get_needed (jit_readelf_t readelf, {unsigned int} index)
+ * Get the name of the dependent library at position @code{index} within
+ * the needed libraries list of this ELF binary.  Returns NULL if
+ * the @code{index} is invalid.
+ * @end deftypefun
+@*/
+const char *jit_readelf_get_needed(jit_readelf_t readelf, unsigned int index)
+{
+       jit_dynamic_iter_t iter;
+       jit_int type;
+       Elf_Addr value;
+       dynamic_iter_init(&iter, readelf);
+       while(dynamic_iter_next(&iter, &type, &value))
+       {
+               if(type == DT_NEEDED)
+               {
+                       if(index == 0)
+                       {
+                               return get_dyn_string(readelf, value);
+                       }
+                       --index;
+               }
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun 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 @code{jit_readelf_close} has not been
+ * called explicitly yet.
+ *
+ * The functions in the ELF binary cannot be used until you also call
+ * @code{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.
+ * @end deftypefun
+@*/
+void jit_readelf_add_to_context(jit_readelf_t readelf, jit_context_t context)
+{
+       /* TODO */
+}
+
+/*@
+ * @deftypefun 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 @code{context} but which were not resolved
+ * in the previous call to this function.  If @code{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.
+ * @end deftypefun
+@*/
+int jit_readelf_resolve_all(jit_context_t context, int print_failures)
+{
+       /* TODO */
+       return 0;
+}
+
+/************************************************************************
+
+                            Warning!  Warning!  Warning!
+
+The following code is very system-dependent, as every ELF target has its
+own peculiar mechanism for performing relocations.  Consult your target's
+documentation for the precise details.
+
+To make things a little easier, you only need to support the relocation
+types that you intend to use in the JIT's ELF writer.  And many types
+only pertain to ELF executable or object files, which we don't use.
+
+************************************************************************/
+
+#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
+
+/*
+ * Apply relocations for i386 platforms.
+ */
+static int i386_reloc(jit_readelf_t readelf, void *address, int type,
+                                         jit_nuint value, int has_addend, jit_nuint addend)
+{
+       if(type == R_386_32)
+       {
+               if(has_addend)
+               {
+                       *((jit_nuint *)address) = value + addend;
+               }
+               else
+               {
+                       *((jit_nuint *)address) += value;
+               }
+               return 1;
+       }
+       else if(type == R_386_PC32)
+       {
+               value -= (jit_nuint)address;
+               if(has_addend)
+               {
+                       *((jit_nuint *)address) = value + addend;
+               }
+               else
+               {
+                       *((jit_nuint *)address) += value;
+               }
+               return 1;
+       }
+       return 0;
+}
+
+#endif /* i386 */
+
+#if defined(__arm) || defined(__arm__)
+
+/*
+ * Apply relocations for ARM platforms.
+ */
+static int arm_reloc(jit_readelf_t readelf, void *address, int type,
+                                        jit_nuint value, int has_addend, jit_nuint addend)
+{
+       if(type == R_ARM_PC24)
+       {
+               value -= (jit_nuint)address;
+               if(has_addend)
+               {
+                       *((jit_nuint *)address) =
+                               (*((jit_nuint *)address) & 0xFF000000) + value + addend;
+               }
+               else
+               {
+                       *((jit_nuint *)address) += value;
+               }
+               return 1;
+       }
+       else if(type == R_ARM_ABS32)
+       {
+               if(has_addend)
+               {
+                       *((jit_nuint *)address) = value + addend;
+               }
+               else
+               {
+                       *((jit_nuint *)address) += value;
+               }
+               return 1;
+       }
+       else if(type == R_ARM_REL32)
+       {
+               value -= (jit_nuint)address;
+               if(has_addend)
+               {
+                       *((jit_nuint *)address) = value + addend;
+               }
+               else
+               {
+                       *((jit_nuint *)address) += value;
+               }
+               return 1;
+       }
+       return 0;
+}
+
+#endif /* arm */
+
+/*
+ * Apply relocations for the interpreted platform.
+ */
+static int interp_reloc(jit_readelf_t readelf, void *address, int type,
+                                               jit_nuint value, int has_addend, jit_nuint addend)
+{
+       /* We only have one type of relocation for the interpreter: direct */
+       if(type == 1)
+       {
+               *((jit_nuint *)address) = value;
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*
+ * Get the relocation function for a particular machine type.
+ */
+static jit_reloc_func get_reloc(unsigned int machine)
+{
+#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
+       if(machine == EM_386)
+       {
+               return i386_reloc;
+       }
+#endif
+#if defined(__arm) || defined(__arm__)
+       if(machine == EM_ARM)
+       {
+               return arm_reloc;
+       }
+#endif
+       if(machine == 0x4C6A)           /* "Lj" for the libjit interpreter */
+       {
+               return interp_reloc;
+       }
+       return 0;
+}
diff --git a/jit/jit-elf-write.c b/jit/jit-elf-write.c
new file mode 100644 (file)
index 0000000..0e654a2
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * jit-elf-write.c - Routines to write ELF-format binaries.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-elf-defs.h"
+#include "jit-memory.h"
+#include "jit-rules.h"
+
+/*@
+
+@section Writing ELF binaries
+
+@*/
+
+/*
+ * Determine whether we should be using the 32-bit or 64-bit ELF structures.
+ */
+#ifdef JIT_NATIVE_INT32
+       typedef Elf32_Ehdr  Elf_Ehdr;
+       typedef Elf32_Shdr  Elf_Shdr;
+       typedef Elf32_Phdr  Elf_Phdr;
+       typedef Elf32_Addr  Elf_Addr;
+       typedef Elf32_Half  Elf_Half;
+       typedef Elf32_Word  Elf_Word;
+       typedef Elf32_Xword Elf_Xword;
+       typedef Elf32_Off   Elf_Off;
+       typedef Elf32_Dyn   Elf_Dyn;
+       typedef Elf32_Sym   Elf_Sym;
+#else
+       typedef Elf64_Ehdr  Elf_Ehdr;
+       typedef Elf64_Shdr  Elf_Shdr;
+       typedef Elf64_Phdr  Elf_Phdr;
+       typedef Elf64_Addr  Elf_Addr;
+       typedef Elf64_Half  Elf_Half;
+       typedef Elf64_Word  Elf_Word;
+       typedef Elf64_Xword Elf_Xword;
+       typedef Elf64_Off   Elf_Off;
+       typedef Elf64_Dyn   Elf_Dyn;
+       typedef Elf64_Sym   Elf_Sym;
+#endif
+
+/*
+ * Information about the contents of a section.
+ */
+typedef struct jit_section *jit_section_t;
+struct jit_section
+{
+       Elf_Shdr                        shdr;
+       char                       *data;
+       unsigned int            data_len;
+};
+
+/*
+ * Control structure for writing an ELF binary.
+ */
+struct jit_writeelf
+{
+       Elf_Ehdr                        ehdr;
+       jit_section_t       sections;
+       int                                     num_sections;
+       int                                     regular_string_section;
+       int                                     dynamic_string_section;
+};
+
+/*
+ * Get a string from the regular string section.
+ */
+static const char *get_string(jit_writeelf_t writeelf, Elf_Word index)
+{
+       if(writeelf->regular_string_section < 0)
+       {
+               /* The regular string section has not been created yet */
+               return 0;
+       }
+       else
+       {
+               /* Retrieve the pointer to the string's starting point */
+               return writeelf->sections[writeelf->regular_string_section].data +
+                                       (jit_nuint)index;
+       }
+}
+
+/*
+ * Add a string to the regular string section.  We don't worry about
+ * duplicate names because we only store section names here.  And
+ * section names are only added when a new section is created.
+ */
+static Elf_Word add_string(jit_writeelf_t writeelf, const char *name)
+{
+       jit_section_t section;
+       char *data;
+       Elf_Word index;
+       unsigned int name_len = jit_strlen(name) + 1;
+       section = &(writeelf->sections[writeelf->regular_string_section]);
+       data = (char *)jit_realloc(section->data, section->data_len + name_len);
+       if(!data)
+       {
+               return 0;
+       }
+       section->data = data;
+       jit_strcpy(data + section->data_len, name);
+       index = (Elf_Word)(section->data_len);
+       section->data_len += name_len;
+       return index;
+}
+
+/*
+ * Get a string from the dynamic string section.
+ */
+static const char *get_dyn_string(jit_writeelf_t writeelf, Elf_Word index)
+{
+       if(writeelf->dynamic_string_section < 0)
+       {
+               /* The dynamic string section has not been created yet */
+               return 0;
+       }
+       else
+       {
+               /* Retrieve the pointer to the string's starting point */
+               return writeelf->sections[writeelf->dynamic_string_section].data +
+                                       (jit_nuint)index;
+       }
+}
+
+/*
+ * Add a string to the dynamic string section.
+ *
+ * TODO: use a hash table to cache previous names.
+ */
+static Elf_Word add_dyn_string(jit_writeelf_t writeelf, const char *name)
+{
+       jit_section_t section;
+       char *data;
+       Elf_Word index;
+       unsigned int name_len = jit_strlen(name) + 1;
+       section = &(writeelf->sections[writeelf->dynamic_string_section]);
+       data = (char *)jit_realloc(section->data, section->data_len + name_len);
+       if(!data)
+       {
+               return 0;
+       }
+       section->data = data;
+       jit_strcpy(data + section->data_len, name);
+       index = (Elf_Word)(section->data_len);
+       section->data_len += name_len;
+       return index;
+}
+
+/*
+ * Get or add a section.
+ */
+static jit_section_t get_section
+       (jit_writeelf_t writeelf, const char *name, jit_int type,
+        Elf_Word flags, Elf_Word entry_size, Elf_Word alignment)
+{
+       int index;
+       jit_section_t section;
+
+       /* Search the section table for an existing section by this name */
+       for(index = 0; index < writeelf->num_sections; ++index)
+       {
+               section = &(writeelf->sections[index]);
+               if(!jit_strcmp(get_string(writeelf, section->shdr.sh_name), name))
+               {
+                       return section;
+               }
+       }
+
+       /* Create a new section and clear it */
+       section = (jit_section_t)jit_realloc
+               (writeelf->sections,
+                (writeelf->num_sections + 1) * sizeof(struct jit_section));
+       if(!section)
+       {
+               return 0;
+       }
+       writeelf->sections = section;
+       section += writeelf->num_sections;
+       jit_memzero(section, sizeof(struct jit_section));
+
+       /* Set the section's name.  If this is the first section created,
+          then it is the string table itself, and we have to add the
+          name to the section itself to start the ball rolling */
+       if(writeelf->regular_string_section < 0)
+       {
+               section->data = (char *)jit_malloc(jit_strlen(name) + 2);
+               if(!(section->data))
+               {
+                       return 0;
+               }
+               section->data_len = jit_strlen(name) + 2;
+               section->data[0] = '\0';        /* Empty string is always first */
+               jit_strcpy(section->data + 1, name);
+               section->shdr.sh_name = 1;
+               writeelf->regular_string_section = writeelf->num_sections;
+       }
+       else
+       {
+               section->shdr.sh_name = add_string(writeelf, name);
+               if(!(section->shdr.sh_name))
+               {
+                       return 0;
+               }
+       }
+
+       /* Set the other section properties */
+       section->shdr.sh_type = (Elf_Word)type;
+       section->shdr.sh_flags = flags;
+       section->shdr.sh_entsize = entry_size;
+       section->shdr.sh_addralign = alignment;
+
+       /* Increase the section count and return */
+       ++(writeelf->num_sections);
+       return section;
+}
+
+/*
+ * Append data to a section.
+ */
+static int add_to_section
+       (jit_section_t section, const void *buf, unsigned int len)
+{
+       char *data = (char *)jit_realloc(section->data, section->data_len + len);
+       if(!data)
+       {
+               return 0;
+       }
+       section->data = data;
+       jit_memcpy(data + section->data_len, buf, len);
+       section->data_len += len;
+       return 1;
+}
+
+/*
+ * Add an entry to the dynamic linking information section.
+ */
+static int add_dyn_info
+       (jit_writeelf_t writeelf, int type, Elf_Addr value, int modify_existing)
+{
+       jit_section_t section;
+       Elf_Dyn dyn;
+
+       /* Get or create the ".dynamic" section */
+       section = get_section(writeelf, ".dynamic", SHT_DYNAMIC,
+                                                 SHF_WRITE | SHF_ALLOC,
+                                                 sizeof(Elf_Dyn), sizeof(Elf_Dyn));
+       if(!section)
+       {
+               return 0;
+       }
+
+       /* See if we already have this entry, and modify it as appropriate */
+       if(modify_existing)
+       {
+               Elf_Dyn *existing = (Elf_Dyn *)(section->data);
+               unsigned int num = section->data_len / sizeof(Elf_Dyn);
+               while(num > 0)
+               {
+                       if(existing->d_tag == type)
+                       {
+                               existing->d_un.d_ptr = value;
+                               return 1;
+                       }
+                       ++existing;
+                       --num;
+               }
+       }
+
+       /* Format the dynamic entry */
+       jit_memzero(&dyn, sizeof(dyn));
+       dyn.d_tag = type;
+       dyn.d_un.d_ptr = value;
+
+       /* Add the entry to the section's contents */
+       return add_to_section(section, &dyn, sizeof(dyn));
+}
+
+/*@
+ * @deftypefun jit_writeelf_t jit_writeelf_create ({const char *} library_name)
+ * Create an object to assist with the process of writing an ELF binary.
+ * The @code{library_name} will be embedded into the binary.  Returns NULL
+ * if out of memory.
+ * @end deftypefun
+@*/
+jit_writeelf_t jit_writeelf_create(const char *library_name)
+{
+       jit_writeelf_t writeelf;
+       Elf_Word name_index;
+       union
+       {
+               jit_ushort value;
+               unsigned char bytes[2];
+
+       } un;
+       jit_elf_info_t elf_info;
+
+       /* Create the writer control structure */
+       writeelf = jit_cnew(struct jit_writeelf);
+       if(!writeelf)
+       {
+               return 0;
+       }
+       writeelf->regular_string_section = -1;
+       writeelf->dynamic_string_section = -1;
+
+       /* Create the regular string section for section names,
+          which must be the first section that we create */
+       if(!get_section(writeelf, ".shstrtab", SHT_STRTAB, 0, 0, 0))
+       {
+               jit_writeelf_destroy(writeelf);
+               return 0;
+       }
+
+       /* Create the dynamic string section, for dynamic linking symbols */
+       if(!get_section(writeelf, ".dynstr", SHT_STRTAB, SHF_ALLOC, 0, 0))
+       {
+               jit_writeelf_destroy(writeelf);
+               return 0;
+       }
+       writeelf->dynamic_string_section = writeelf->num_sections - 1;
+       if(!add_dyn_string(writeelf, ""))
+       {
+               jit_writeelf_destroy(writeelf);
+               return 0;
+       }
+
+       /* Add the library name to the dynamic linking information section */
+       name_index = add_dyn_string(writeelf, library_name);
+       if(!name_index)
+       {
+               jit_writeelf_destroy(writeelf);
+               return 0;
+       }
+       if(!add_dyn_info(writeelf, DT_SONAME, (Elf_Addr)name_index, 0))
+       {
+               jit_writeelf_destroy(writeelf);
+               return 0;
+       }
+
+       /* Fill in the Ehdr fields */
+       writeelf->ehdr.e_ident[EI_MAG0] = ELFMAG0;
+       writeelf->ehdr.e_ident[EI_MAG1] = ELFMAG1;
+       writeelf->ehdr.e_ident[EI_MAG2] = ELFMAG2;
+       writeelf->ehdr.e_ident[EI_MAG3] = ELFMAG3;
+#ifdef JIT_NATIVE_INT32
+       writeelf->ehdr.e_ident[EI_CLASS] = ELFCLASS32;
+#else
+       writeelf->ehdr.e_ident[EI_CLASS] = ELFCLASS64;
+#endif
+       un.value = 0x0102;
+       if(un.bytes[0] == 0x01)
+       {
+               writeelf->ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
+       }
+       else
+       {
+               writeelf->ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+       }
+       writeelf->ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+       _jit_gen_get_elf_info(&elf_info);
+       writeelf->ehdr.e_ident[EI_OSABI] = (unsigned char)(elf_info.abi);
+       writeelf->ehdr.e_ident[EI_ABIVERSION] =
+               (unsigned char)(elf_info.abi_version);
+       writeelf->ehdr.e_machine = (Elf_Half)(elf_info.machine);
+       writeelf->ehdr.e_version = EV_CURRENT;
+       writeelf->ehdr.e_ehsize = sizeof(writeelf->ehdr);
+
+       /* Every ELF binary that we generate will need "libjit.so" */
+       if(!jit_writeelf_add_needed(writeelf, "libjit.so"))
+       {
+               jit_writeelf_destroy(writeelf);
+               return 0;
+       }
+
+       /* We are ready to go */
+       return writeelf;
+}
+
+/*@
+ * @deftypefun void jit_writeelf_destroy (jit_writeelf_t writeelf)
+ * Destroy the memory structures that were used while @code{writeelf}
+ * was being built.
+ * @end deftypefun
+@*/
+void jit_writeelf_destroy(jit_writeelf_t writeelf)
+{
+       int index;
+       if(!writeelf)
+       {
+               return;
+       }
+       for(index = 0; index < writeelf->num_sections; ++index)
+       {
+               jit_free(writeelf->sections[index].data);
+       }
+       jit_free(writeelf->sections);
+       jit_free(writeelf);
+}
+
+/*@
+ * @deftypefun int jit_writeelf_write (jit_writeelf_t writeelf, {const char *} filename)
+ * Write a fully-built ELF binary to @code{filename}.  Returns zero
+ * if an error occurred (reason in @code{errno}).
+ * @end deftypefun
+@*/
+int jit_writeelf_write(jit_writeelf_t writeelf, const char *filename)
+{
+       /* TODO */
+       return 1;
+}
+
+/*@
+ * @deftypefun int jit_writeelf_add_function (jit_writeelf_t writeelf, jit_function_t func, {const char *} name)
+ * Write the code for @code{func} to the ELF binary represented by
+ * @code{writeelf}.  The function must already be compiled, and its
+ * context must have the @code{JIT_OPTION_PRE_COMPILE} option set
+ * to a non-zero value.  Returns zero if out of memory or the
+ * parameters are invalid.
+ * @end deftypefun
+@*/
+int jit_writeelf_add_function
+       (jit_writeelf_t writeelf, jit_function_t func, const char *name)
+{
+       /* TODO */
+       return 1;
+}
+
+/*@
+ * @deftypefun int jit_writeelf_add_needed (jit_writeelf_t writeelf, {const char *} library_name)
+ * Add @code{library_name} to the list of dependent libraries that are needed
+ * when the ELF binary is reloaded.  If @code{library_name} is already on
+ * the list, then this request will be silently ignored.  Returns
+ * zero if out of memory or the parameters are invalid.
+ * @end deftypefun
+@*/
+int jit_writeelf_add_needed(jit_writeelf_t writeelf, const char *library_name)
+{
+       jit_section_t section;
+       Elf_Dyn *dyn;
+       unsigned int num_dyn;
+       Elf_Word name_index;
+       if(!writeelf || !library_name)
+       {
+               return 0;
+       }
+       section = get_section(writeelf, ".dynamic", SHT_DYNAMIC,
+                                                 SHF_WRITE | SHF_ALLOC,
+                                                 sizeof(Elf_Dyn), sizeof(Elf_Dyn));
+       if(!section)
+       {
+               return 0;
+       }
+       dyn = (Elf_Dyn *)(section->data);
+       num_dyn = section->data_len / sizeof(Elf_Dyn);
+       while(num_dyn > 0)
+       {
+               if(dyn->d_tag == DT_NEEDED &&
+                  !jit_strcmp(get_dyn_string(writeelf, (Elf_Word)(dyn->d_un.d_ptr)),
+                                          library_name))
+               {
+                       return 1;
+               }
+               ++dyn;
+               --num_dyn;
+       }
+       name_index = add_dyn_string(writeelf, library_name);
+       if(!name_index)
+       {
+               return 0;
+       }
+       if(!add_dyn_info(writeelf, DT_NEEDED, (Elf_Addr)name_index, 0))
+       {
+               return 0;
+       }
+       return 1;
+}
+
+/*@
+ * @deftypefun int jit_writeelf_write_section (jit_writeelf_t writeelf, {const char *} name, jit_int type, {const void *} buf, {unsigned int} len, int discardable)
+ * Write auxillary data to a section called @code{name}.  If @code{type}
+ * is not zero, then it indicates an ELF section type.  This is used
+ * by virtual machines to store auxillary data that can be retrieved
+ * later using @code{jit_readelf_get_section}.  If the section already
+ * contains data, then this will append the new data.  If @code{discardable}
+ * is non-zero, then it is OK for this section to be discarded when the
+ * ELF binary is stripped.  Returns zero if out of memory or the
+ * parameters are invalid.
+ * @end deftypefun
+@*/
+int jit_writeelf_write_section
+       (jit_writeelf_t writeelf, const char *name, jit_int type,
+        const void *buf, unsigned int len, int discardable)
+{
+       jit_section_t section;
+       if(!writeelf || !name)
+       {
+               return 0;
+       }
+       if(!type)
+       {
+               /* Application-specific section type, for storing unspecified data */
+               type = (jit_int)(SHT_LOUSER + 0x1234);
+       }
+       if(discardable)
+       {
+               section = get_section(writeelf, name, type, 0, 1, 1);
+       }
+       else
+       {
+               section = get_section(writeelf, name, type, SHF_ALLOC, 1, 1);
+       }
+       if(!section)
+       {
+               return 0;
+       }
+       if(len > 0)
+       {
+               return add_to_section(section, buf, len);;
+       }
+       else
+       {
+               return 1;
+       }
+}
diff --git a/jit/jit-except.cpp b/jit/jit-except.cpp
new file mode 100644 (file)
index 0000000..ee527cb
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * jit-except.cpp - Exception handling functions.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+
+This file must be compiled with a C++ compiler, because it uses
+C++ exceptions to manage JIT exception throws.  It is otherwise
+straight vanilla ANSI C.
+
+*/
+
+#include "jit-internal.h"
+#include "jit-rules.h"
+#include <config.h>
+#ifdef HAVE_STDLIB_H
+       #include <stdlib.h>
+#endif
+#if defined(JIT_BACKEND_INTERP)
+       #include "jit-interp.h"
+#endif
+#include <stdio.h>
+#include <setjmp.h>
+
+/*@
+
+@cindex jit-except.h
+
+@*/
+
+/*@
+ * @deftypefun {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 @code{libjit}
+ * is concerned, an exception is just a pointer.  The precise meaning of the
+ * data at the pointer is determined by the front end.
+ * @end deftypefun
+@*/
+extern "C" void *jit_exception_get_last(void)
+{
+       jit_thread_control_t control = _jit_thread_get_control();
+       if(control)
+       {
+               return control->last_exception;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{jit_exception_get_last}.
+ * This is normally used by @code{jit_function_apply} to save the
+ * exception object before returning to regular code.
+ * @end deftypefun
+@*/
+extern "C" void jit_exception_set_last(void *object)
+{
+       jit_thread_control_t control = _jit_thread_get_control();
+       if(control)
+       {
+               control->last_exception = object;
+       }
+}
+
+/*@
+ * @deftypefun void jit_exception_clear_last (void)
+ * Clear the last exception object that occurred on this thread.
+ * This is equivalent to calling @code{jit_exception_set_last}
+ * with a parameter of NULL.
+ * @end deftypefun
+@*/
+extern "C" void jit_exception_clear_last(void)
+{
+       jit_exception_set_last(0);
+}
+
+/*@
+ * @deftypefun void jit_exception_throw ({void *} object)
+ * Throw an exception object within the current thread.  As far as
+ * @code{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.
+ * @end deftypefun
+@*/
+extern "C" void jit_exception_throw(void *object)
+{
+#if defined(JIT_BACKEND_INTERP)
+       throw new jit_exception(object);
+#else
+       jit_thread_control_t control = _jit_thread_get_control();
+       jit_backtrace_t trace;
+       if(control)
+       {
+               trace = control->backtrace_head;
+               while(trace != 0 && trace->pc != 0 && trace->catch_pc == 0)
+               {
+                       trace = trace->parent;
+               }
+               if(trace)
+               {
+                       if(trace->catch_pc)
+                       {
+                               /* We have a native "catch" clause at this level */
+                               _jit_backtrace_set(trace->parent);
+                               _jit_gen_unwind_stack(trace->sp, trace->catch_pc, object);
+                       }
+                       else
+                       {
+                               /* The next higher level is "jit_function_apply_vararg",
+                                  so use "longjmp" to unwind the stack to that position */
+                               jit_exception_set_last(object);
+                               longjmp(*((jmp_buf *)(trace->sp)), 1);
+                       }
+               }
+       }
+#endif
+}
+
+/*@
+ * @deftypefun 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 @code{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:
+ *
+ * @table @code
+ * @vindex JIT_RESULT_OK
+ * @item JIT_RESULT_OK
+ * The operation was performed successfully (value is 1).
+ *
+ * @vindex JIT_RESULT_OVERFLOW
+ * @item JIT_RESULT_OVERFLOW
+ * The operation resulted in an overflow exception (value is 0).
+ *
+ * @vindex JIT_RESULT_ARITHMETIC
+ * @item 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).
+ *
+ * @vindex JIT_RESULT_DIVISION_BY_ZERO
+ * @item JIT_RESULT_DIVISION_BY_ZERO
+ * The operation resulted in a division by zero exception (value is -2).
+ *
+ * @vindex JIT_RESULT_COMPILE_ERROR
+ * @item JIT_RESULT_COMPILE_ERROR
+ * An error occurred when attempting to dynamically compile a function
+ * (value is -3).
+ *
+ * @vindex JIT_RESULT_OUT_OF_MEMORY
+ * @item JIT_RESULT_OUT_OF_MEMORY
+ * The system ran out of memory while performing an operation (value is -4).
+ *
+ * @vindex JIT_RESULT_NULL_REFERENCE
+ * @item JIT_RESULT_NULL_REFERENCE
+ * An attempt was made to dereference a NULL pointer (value is -5).
+ *
+ * @vindex JIT_RESULT_NULL_FUNCTION
+ * @item JIT_RESULT_NULL_FUNCTION
+ * An attempt was made to call a function with a NULL function pointer
+ * (value is -6).
+ *
+ * @vindex JIT_RESULT_CALLED_NESTED
+ * @item JIT_RESULT_CALLED_NESTED
+ * An attempt was made to call a nested function from a non-nested context
+ * (value is -7).
+ * @end table
+ * @end deftypefun
+@*/
+extern "C" void jit_exception_builtin(int exception_type)
+{
+       jit_exception_func handler;
+       void *object;
+       static const char * const messages[9] = {
+               "Success",
+               "Overflow during checked arithmetic operation",
+               "Arithmetic exception (dividing the minimum integer by -1)",
+               "Division by zero",
+               "Error during function compilation",
+               "Out of memory",
+               "Null pointer dereferenced",
+               "Null function pointer called",
+               "Nested function called from non-nested context"
+       };
+       #define num_messages    (sizeof(messages) / sizeof(const char *))
+
+       /* Get the exception handler for this thread */
+       handler = jit_exception_get_handler();
+
+       /* Invoke the exception handler to create an appropriate object */
+       if(handler)
+       {
+               object = (*handler)(exception_type);
+               if(object)
+               {
+                       jit_exception_throw(object);
+               }
+       }
+
+       /* We don't have an exception handler, so print a message and exit */
+       fputs("A builtin JIT exception could not be handled:\n", stderr);
+       exception_type = -(exception_type - 1);
+       if(exception_type >= 0 && exception_type < (int)num_messages)
+       {
+               fputs(messages[exception_type], stderr);
+       }
+       else
+       {
+               fprintf(stderr, "Unknown builtin exception %d",
+                               (-exception_type) + 1);
+       }
+       putc('\n', stderr);
+       exit(1);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+extern "C" jit_exception_func jit_exception_set_handler
+       (jit_exception_func handler)
+{
+       jit_exception_func previous;
+       jit_thread_control_t control = _jit_thread_get_control();
+       if(control)
+       {
+               previous = control->exception_handler;
+               control->exception_handler = handler;
+               return previous;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_exception_func jit_exception_get_handler (void)
+ * Get the builtin exception handler for the current thread.
+ * @end deftypefun
+@*/
+extern "C" jit_exception_func jit_exception_get_handler(void)
+{
+       jit_thread_control_t control = _jit_thread_get_control();
+       if(control)
+       {
+               return control->exception_handler;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*
+ * Structure of a stack trace.
+ */
+struct jit_stack_trace
+{
+       unsigned int            size;
+       void                       *items[1];
+};
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+extern "C" jit_stack_trace_t jit_exception_get_stack_trace(void)
+{
+       jit_thread_control_t control;
+       jit_backtrace_t top;
+       jit_backtrace_t item;
+       unsigned int size;
+       jit_stack_trace_t trace;
+       
+       /* Count the number of items in the current thread's call stack */
+       control = _jit_thread_get_control();
+       if(!control)
+       {
+               return 0;
+       }
+       size = 0;
+       top = control->backtrace_head;
+       item = top;
+       while(item != 0)
+       {
+               ++size;
+               item = item->parent;
+       }
+
+       /* Allocate memory for the stack trace */
+       trace = (jit_stack_trace_t)jit_malloc
+               (sizeof(struct jit_stack_trace) +
+                size * sizeof(void *) - sizeof(void *));
+       if(!trace)
+       {
+               return 0;
+       }
+       trace->size = size;
+
+       /* Populate the stack trace with the items we counted earlier */
+       size = 0;
+       item = top;
+       while(item != 0)
+       {
+               trace->items[size] = item->pc;
+               ++size;
+               item = item->parent;
+       }
+       return trace;
+}
+
+/*@
+ * @deftypefun {unsigned int} jit_stack_trace_get_size (jit_stack_trace_t trace)
+ * Get the size of a stack trace.
+ * @end deftypefun
+@*/
+extern "C" unsigned int jit_stack_trace_get_size(jit_stack_trace_t trace)
+{
+       if(trace)
+       {
+               return trace->size;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{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
+ * @code{posn} within the stack trace.
+ * @end deftypefun
+@*/
+extern "C" jit_function_t jit_stack_trace_get_function
+       (jit_context_t context, jit_stack_trace_t trace, unsigned int posn)
+{
+       if(trace && posn < trace->size)
+       {
+               jit_cache_t cache = _jit_context_get_cache(context);
+               if(cache)
+               {
+                       return (jit_function_t)_jit_cache_get_method
+                               (cache, trace->items[posn], 0);
+               }
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun {void *} jit_stack_trace_get_pc (jit_stack_trace_t trace, {unsigned int} posn)
+ * Get the program counter that corresponds to position @code{posn}
+ * within a stack trace.  This is the point within the function
+ * where execution had reached at the time of the trace.
+ * @end deftypefun
+@*/
+extern "C" void *jit_stack_trace_get_pc
+       (jit_stack_trace_t trace, unsigned int posn)
+{
+       if(trace && posn < trace->size)
+       {
+               return trace->items[posn];
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun {unsigned int} jit_stack_trace_get_offset (jit_stack_trace_t trace, {unsigned int} posn)
+ * Get the bytecode offset that is recorded for position @code{posn}
+ * within a stack trace.  This will be @code{JIT_NO_OFFSET} if there
+ * is no bytecode offset associated with @code{posn}.
+ * @end deftypefun
+@*/
+extern "C" unsigned int jit_stack_trace_get_offset
+       (jit_context_t context, jit_stack_trace_t trace, unsigned int posn)
+{
+       /* TODO */
+       return 0;
+}
+
+/*@
+ * @deftypefun void jit_stack_trace_free (jit_stack_trace_t trace)
+ * Free the memory associated with a stack trace.
+ * @end deftypefun
+@*/
+extern "C" void jit_stack_trace_free(jit_stack_trace_t trace)
+{
+       if(trace)
+       {
+               jit_free(trace);
+       }
+}
+
+extern "C" void _jit_backtrace_push
+       (jit_backtrace_t trace, void *pc, void *catch_pc, void *sp)
+{
+       jit_thread_control_t control = _jit_thread_get_control();
+       if(control)
+       {
+               trace->parent = control->backtrace_head;
+               trace->pc = pc;
+               trace->catch_pc = catch_pc;
+               trace->sp = sp;
+               trace->security_object = 0;
+               trace->free_security_object = 0;
+               control->backtrace_head = trace;
+       }
+       else
+       {
+               trace->parent = 0;
+               trace->pc = pc;
+               trace->catch_pc = catch_pc;
+               trace->sp = sp;
+               trace->security_object = 0;
+               trace->free_security_object = 0;
+       }
+}
+
+extern "C" void _jit_backtrace_pop(void)
+{
+       jit_thread_control_t control = _jit_thread_get_control();
+       jit_backtrace_t trace;
+       if(control)
+       {
+               trace = control->backtrace_head;
+               if(trace)
+               {
+                       control->backtrace_head = trace->parent;
+                       if(trace->security_object && trace->free_security_object)
+                       {
+                               (*(trace->free_security_object))(trace->security_object);
+                       }
+               }
+       }
+}
+
+extern "C" void _jit_backtrace_set(jit_backtrace_t trace)
+{
+       jit_thread_control_t control = _jit_thread_get_control();
+       if(control)
+       {
+               control->backtrace_head = trace;
+       }
+}
diff --git a/jit/jit-function.c b/jit/jit-function.c
new file mode 100644 (file)
index 0000000..0fc1cf0
--- /dev/null
@@ -0,0 +1,1380 @@
+/*
+ * jit-function.c - Functions for manipulating function blocks.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-memory.h"
+#include "jit-rules.h"
+#include "jit-reg-alloc.h"
+#include "jit-apply-func.h"
+#include <setjmp.h>
+
+/*@
+ * @deftypefun 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
+ * @code{jit_function_compile} to convert it into its executable form.
+ *
+ * It is recommended that you call @code{jit_context_build_start} before
+ * calling @code{jit_function_create}, and then call
+ * @code{jit_context_build_end} after you have called
+ * @code{jit_function_compile}.  This will protect the JIT's internal
+ * data structures within a multi-threaded environment.
+ * @end deftypefun
+@*/
+jit_function_t jit_function_create(jit_context_t context, jit_type_t signature)
+{
+       jit_function_t func;
+
+       /* Allocate memory for the function and clear it */
+       func = jit_cnew(struct _jit_function);
+       if(!func)
+       {
+               return 0;
+       }
+
+       /* Initialize the function block */
+       func->context = context;
+       func->signature = jit_type_copy(signature);
+
+#if defined(jit_redirector_size) && !defined(JIT_BACKEND_INTERP)
+       /* If we aren't using interpretation, then point the function's
+          initial entry point at the redirector, which in turn will
+          invoke the on-demand compiler */
+       func->entry_point = _jit_create_redirector
+               (func->redirector, (void *)_jit_function_compile_on_demand,
+                func, jit_type_get_abi(signature));
+       func->closure_entry = func->entry_point;
+#endif
+
+       /* Add the function to the context list */
+       func->next = 0;
+       func->prev = context->last_function;
+       if(context->last_function)
+       {
+               context->last_function->next = func;
+       }
+       else
+       {
+               context->functions = func;
+       }
+       context->last_function = func;
+
+       /* Return the function to the caller */
+       return func;
+}
+
+/*@
+ * @deftypefun 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
+ * @code{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.
+ * @end deftypefun
+@*/
+jit_function_t jit_function_create_nested
+               (jit_context_t context, jit_type_t signature, jit_function_t parent)
+{
+       jit_function_t func;
+       func = jit_function_create(context, signature);
+       if(!func)
+       {
+               return 0;
+       }
+       func->nested_parent = parent;
+       return func;
+}
+
+int _jit_function_ensure_builder(jit_function_t func)
+{
+       /* Handle the easy cases first */
+       if(!func)
+       {
+               return 0;
+       }
+       if(func->builder)
+       {
+               return 1;
+       }
+
+       /* Allocate memory for the builder and clear it */
+       func->builder = jit_cnew(struct _jit_builder);
+       if(!(func->builder))
+       {
+               return 0;
+       }
+
+       /* Initialize the function builder */
+       jit_memory_pool_init(&(func->builder->value_pool), struct _jit_value);
+       jit_memory_pool_init(&(func->builder->insn_pool), struct _jit_insn);
+       jit_memory_pool_init(&(func->builder->meta_pool), struct _jit_meta);
+
+       /* Create the initial entry block */
+       if(!_jit_block_init(func))
+       {
+               _jit_function_free_builder(func);
+               return 0;
+       }
+
+       /* Create instructions to initialize the incoming arguments */
+       if(!_jit_create_entry_insns(func))
+       {
+               _jit_function_free_builder(func);
+               return 0;
+       }
+
+       /* The builder is ready to go */
+       return 1;
+}
+
+void _jit_function_free_builder(jit_function_t func)
+{
+       if(func->builder)
+       {
+               _jit_block_free(func);
+               jit_memory_pool_free(&(func->builder->insn_pool), 0);
+               jit_memory_pool_free(&(func->builder->value_pool), _jit_value_free);
+               jit_memory_pool_free(&(func->builder->meta_pool), _jit_meta_free_one);
+               jit_free(func->builder->param_values);
+               jit_free(func->builder->insns);
+               jit_free(func->builder->label_blocks);
+               jit_free(func->builder);
+               func->builder = 0;
+       }
+}
+
+void _jit_function_destroy(jit_function_t func)
+{
+       if(!func)
+       {
+               return;
+       }
+       if(func->next)
+       {
+               func->next->prev = func->prev;
+       }
+       else
+       {
+               func->context->last_function = func->prev;
+       }
+       if(func->prev)
+       {
+               func->prev->next = func->next;
+       }
+       else
+       {
+               func->context->functions = func->next;
+       }
+       _jit_function_free_builder(func);
+       jit_meta_destroy(&(func->meta));
+       jit_free(func);
+}
+
+/*@
+ * @deftypefun 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 @code{func} object is completely destroyed and
+ * detached from its owning context.  The function is left alone if
+ * it was already compiled.
+ * @end deftypefun
+@*/
+void jit_function_abandon(jit_function_t func)
+{
+       if(func && func->builder)
+       {
+               if(func->is_compiled)
+               {
+                       /* We already compiled this function previously, but we
+                          have tried to recompile it with new contents.  Throw
+                          away the builder, but keep the original version */
+                       _jit_function_free_builder(func);
+               }
+               else
+               {
+                       /* This function was never compiled, so abandon entirely */
+                       _jit_function_destroy(func);
+               }
+       }
+}
+
+/*@
+ * @deftypefun jit_context_t jit_function_get_context (jit_function_t func)
+ * Get the context associated with a function.
+ * @end deftypefun
+@*/
+jit_context_t jit_function_get_context(jit_function_t func)
+{
+       if(func)
+       {
+               return func->context;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_type_t jit_function_get_signature (jit_function_t func)
+ * Get the signature associated with a function.
+ * @end deftypefun
+@*/
+jit_type_t jit_function_get_signature(jit_function_t func)
+{
+       if(func)
+       {
+               return func->signature;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{type} already has some metadata associated with it, then
+ * the previous value will be freed.
+ *
+ * If @code{build_only} is non-zero, then the metadata will be freed
+ * when the function is compiled with @code{jit_function_compile}.
+ * Otherwise the metadata will persist until the JIT context is destroyed,
+ * or @code{jit_function_free_meta} is called for the specified @code{type}.
+ *
+ * Metadata type values of 10000 or greater are reserved for internal use.
+ * @end deftypefun
+@*/
+int jit_function_set_meta(jit_function_t func, int type, void *data,
+                                             jit_meta_free_func free_data, int build_only)
+{
+       if(build_only)
+       {
+               if(!_jit_function_ensure_builder(func))
+               {
+                       return 0;
+               }
+               return jit_meta_set(&(func->builder->meta), type, data,
+                                                       free_data, func);
+       }
+       else
+       {
+               return jit_meta_set(&(func->meta), type, data, free_data, 0);
+       }
+}
+
+/*@
+ * @deftypefun {void *} jit_function_get_meta (jit_function_t func, int type)
+ * Get the metadata associated with a particular tag.  Returns NULL
+ * if @code{type} does not have any metadata associated with it.
+ * @end deftypefun
+@*/
+void *jit_function_get_meta(jit_function_t func, int type)
+{
+       void *data = jit_meta_get(func->meta, type);
+       if(!data && func->builder)
+       {
+               data = jit_meta_get(func->builder->meta, type);
+       }
+       return data;
+}
+
+/*@
+ * @deftypefun void jit_function_free_meta (jit_function_t func, int type)
+ * Free metadata of a specific type on a function.  Does nothing if
+ * the @code{type} does not have any metadata associated with it.
+ * @end deftypefun
+@*/
+void jit_function_free_meta(jit_function_t func, int type)
+{
+       jit_meta_free(&(func->meta), type);
+       if(func->builder)
+       {
+               jit_meta_free(&(func->builder->meta), type);
+       }
+}
+
+/*@
+ * @deftypefun jit_function_t jit_function_next (jit_context_t context, jit_function_t prev)
+ * Iterate over the defined functions in creation order.  The @code{prev}
+ * argument should be NULL on the first call.  Returns NULL at the end.
+ * @end deftypefun
+@*/
+jit_function_t jit_function_next(jit_context_t context, jit_function_t prev)
+{
+       if(prev)
+       {
+               return prev->next;
+       }
+       else if(context)
+       {
+               return context->functions;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_function_t jit_function_previous (jit_context_t context, jit_function_t prev)
+ * Iterate over the defined functions in reverse creation order.
+ * @end deftypefun
+@*/
+jit_function_t jit_function_previous(jit_context_t context,
+                                                                        jit_function_t prev)
+{
+       if(prev)
+       {
+               return prev->prev;
+       }
+       else if(context)
+       {
+               return context->last_function;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{jit_function_create}.
+ * @end deftypefun
+@*/
+jit_block_t jit_function_get_entry(jit_function_t func)
+{
+       if(func && func->builder)
+       {
+               return func->builder->entry;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_block_t jit_function_get_current (jit_function_t func)
+ * Get the current block for a function.  New blocks are created by
+ * certain @code{jit_insn_xxx} calls.
+ * @end deftypefun
+@*/
+jit_block_t jit_function_get_current(jit_function_t func)
+{
+       if(func && func->builder)
+       {
+               return func->builder->current_block;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_function_t jit_function_get_nested_parent (jit_function_t func)
+ * Get the nested parent for a function, or NULL if @code{func}
+ * does not have a nested parent.
+ * @end deftypefun
+@*/
+jit_function_t jit_function_get_nested_parent(jit_function_t func)
+{
+       if(func)
+       {
+               return func->nested_parent;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*
+ * Call "finally" blocks that are relevant for a transition from
+ * "src" to "dest".  "dest" should be NULL for a return instruction.
+ */
+static void call_finally_blocks(jit_gencode_t gen, jit_function_t func,
+                                                               jit_block_eh_t src, jit_block_eh_t dest)
+{
+       jit_block_eh_t temp;
+
+       /* Bail out if we are branching to an inner scope, because we
+          don't need to call "finally" clauses to go further in */
+       temp = dest;
+       while(temp != 0)
+       {
+               if(temp == src)
+               {
+                       return;
+               }
+               temp = temp->parent;
+       }
+
+       /* Find the common ancestor of "src" and "dest" */
+       while(dest != 0)
+       {
+               temp = src;
+               while(temp != 0 && temp != dest)
+               {
+                       temp = temp->parent;
+               }
+               if(temp != 0)
+               {
+                       break;
+               }
+               dest = dest->parent;
+       }
+
+       /* Output all finally blocks between "src" and "dest" */
+       while(src != dest)
+       {
+               if(src->catch_label != jit_label_undefined &&
+                  !(src->finally_on_fault))
+               {
+                       /* Call "finally" from the body of the "try" */
+                       if(src->finally_label != jit_label_undefined)
+                       {
+                               _jit_gen_call_finally(gen, func, src->finally_label);
+                       }
+               }
+               else if(src->catch_label == jit_label_undefined)
+               {
+                       /* Call "finally" from the body of the "catch" */
+                       if(src->finally_label != jit_label_undefined)
+                       {
+                               _jit_gen_call_finally(gen, func, src->finally_label);
+                       }
+               }
+               src = src->parent;
+       }
+}
+
+/*
+ * Compile a single basic block within a function.
+ */
+static void compile_block(jit_gencode_t gen, jit_function_t func,
+                                                 jit_block_t block)
+{
+       jit_insn_iter_t iter;
+       jit_insn_t insn;
+       jit_block_t branch_block;
+
+       /* Iterate over all blocks in the function */
+       jit_insn_iter_init(&iter, block);
+       while((insn = jit_insn_iter_next(&iter)) != 0)
+       {
+               switch(insn->opcode)
+               {
+                       case JIT_OP_NOP:                break;          /* Ignore NOP's */
+
+                       case JIT_OP_CHECK_NULL:
+                       {
+                               /* Determine if we can optimize the null check away */
+                               if(!_jit_insn_check_is_redundant(&iter))
+                               {
+                                       _jit_gen_insn(gen, func, block, insn);
+                               }
+                       }
+                       break;
+
+                       case JIT_OP_PREPARE_FOR_LEAVE:
+                       {
+                               /* Call the finally clauses that are relevant to the
+                                  "JIT_OP_BRANCH" instruction that follows */
+                               _jit_regs_spill_all(gen);
+                               insn = jit_insn_iter_next(&iter);
+                               branch_block = jit_block_from_label
+                                       (func, (jit_label_t)(insn->dest));
+                               call_finally_blocks
+                                       (gen, func, block->block_eh, branch_block->block_eh);
+                               _jit_gen_insn(gen, func, block, insn);
+                       }
+                       break;
+
+                       case JIT_OP_PREPARE_FOR_RETURN:
+                       {
+                               /* Call all finally clauses on the way out of the function */
+                               _jit_regs_spill_all(gen);
+                               call_finally_blocks(gen, func, block->block_eh, 0);
+                       }
+                       break;
+
+                       case JIT_OP_INCOMING_REG:
+                       {
+                               /* Assign a register to an incoming value */
+                               _jit_regs_set_incoming
+                                       (gen, (int)jit_value_get_nint_constant(insn->value2),
+                                        insn->value1);
+                       }
+                       break;
+
+                       case JIT_OP_INCOMING_FRAME_POSN:
+                       {
+                               /* Set the frame position for an incoming value */
+                               insn->value1->frame_offset =
+                                       jit_value_get_nint_constant(insn->value2);
+                               insn->value1->in_register = 0;
+                               insn->value1->in_frame = 1;
+                               insn->value1->has_frame_offset = 1;
+                       }
+                       break;
+
+                       case JIT_OP_OUTGOING_REG:
+                       {
+                               /* Copy a value into an outgoing register */
+                               _jit_regs_set_outgoing
+                                       (gen, (int)jit_value_get_nint_constant(insn->value2),
+                                        insn->value1);
+                       }
+                       break;
+
+                       case JIT_OP_RETURN_REG:
+                       {
+                               /* Assign a register to a return value */
+                               _jit_regs_set_incoming
+                                       (gen, (int)jit_value_get_nint_constant(insn->value2),
+                                        insn->value1);
+                               _jit_gen_insn(gen, func, block, insn);
+                       }
+                       break;
+
+                       default:
+                       {
+                               /* Generate code for the instruction with the back end */
+                               _jit_gen_insn(gen, func, block, insn);
+                       }
+                       break;
+               }
+       }
+}
+
+/*
+ * Information that is stored for an exception region in the cache.
+ */
+typedef struct jit_cache_eh *jit_cache_eh_t;
+struct jit_cache_eh
+{
+       jit_label_t             handler_label;
+       unsigned char  *handler;
+       jit_cache_eh_t  previous;
+};
+
+/*@
+ * @deftypefun 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 @code{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
+ * @code{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 @code{jit_function_compile}
+ * a second time.
+ * @end deftypefun
+@*/
+int jit_function_compile(jit_function_t func)
+{
+       struct jit_gencode gen;
+       jit_cache_t cache;
+       void *start;
+       void *recompilable_start = 0;
+       void *end;
+       jit_block_t block;
+       jit_block_eh_t eh;
+       jit_block_eh_t new_eh;
+       jit_cache_eh_t cache_eh;
+       jit_cache_eh_t cache_new_eh;
+       int result;
+#ifdef JIT_PROLOG_SIZE
+       int have_prolog;
+#endif
+
+       /* Bail out if we have nothing to do */
+       if(!func)
+       {
+               return 0;
+       }
+       if(func->is_compiled && !(func->builder))
+       {
+               /* The function is already compiled, and we don't need to recompile */
+               return 1;
+       }
+       if(!(func->builder))
+       {
+               /* We don't have anything to compile at all */
+               return 0;
+       }
+
+       /* We need the cache lock while we are compiling the function */
+       jit_mutex_lock(&(func->context->cache_lock));
+
+       /* Get the method cache */
+       cache = _jit_context_get_cache(func->context);
+       if(!cache)
+       {
+               jit_mutex_unlock(&(func->context->cache_lock));
+               return 0;
+       }
+
+       /* Initialize the code generation state */
+       jit_memzero(&gen, sizeof(gen));
+
+       /* Compute liveness and "next use" information for this function */
+       _jit_function_compute_liveness(func);
+
+       /* We may need to perform output twice, if the first attempt fails
+          due to a lack of space in the current method cache page */
+       do
+       {
+               /* Start function output to the cache */
+               start = _jit_cache_start_method
+                       (cache, &(gen.posn), JIT_FUNCTION_ALIGNMENT, func);
+               if(!start)
+               {
+#ifdef jit_extra_gen_cleanup
+                       /* Clean up the extra code generation state */
+                       jit_extra_gen_cleanup(gen);
+#endif
+                       jit_mutex_unlock(&(func->context->cache_lock));
+                       return 0;
+               }
+
+#ifdef jit_extra_gen_init
+               /* Initialize information that may need to be reset each loop */
+               jit_extra_gen_init(&gen);
+#endif
+
+#ifdef JIT_PROLOG_SIZE
+               /* Output space for the function prolog */
+               if(jit_cache_check_for_n(&(gen.posn), JIT_PROLOG_SIZE))
+               {
+                       gen.posn.ptr += JIT_PROLOG_SIZE;
+                       have_prolog = 1;
+               }
+               else
+               {
+                       have_prolog = 0;
+               }
+#endif
+
+               /* Clear the register assignments for the first block */
+               _jit_regs_init_for_block(&gen);
+
+               /* Generate code for the blocks in the function */
+               block = 0;
+               eh = 0;
+               cache_eh = 0;
+               while((block = jit_block_next(func, block)) != 0)
+               {
+                       /* If this block is never entered, then discard it */
+                       if(!(block->entered_via_top) && !(block->entered_via_branch))
+                       {
+                               continue;
+                       }
+
+                       /* Start a new exception region in the cache if necessary */
+                       new_eh = block->block_eh;
+                       if(new_eh && new_eh->catch_label == jit_label_undefined)
+                       {
+                               new_eh = 0;
+                       }
+                       if(new_eh != eh)
+                       {
+                               eh = new_eh;
+                               cache_new_eh = _jit_cache_alloc
+                                       (&(gen.posn), sizeof(struct jit_cache_eh));
+                               if(cache_new_eh)
+                               {
+                                       if(eh)
+                                       {
+                                               cache_new_eh->handler_label = eh->catch_label;
+                                       }
+                                       else
+                                       {
+                                               cache_new_eh->handler_label = jit_label_undefined;
+                                       }
+                                       cache_new_eh->handler = 0;
+                                       cache_new_eh->previous = cache_eh;
+                                       _jit_cache_new_region(&(gen.posn), cache_new_eh);
+                                       cache_eh = cache_new_eh;
+                               }
+                       }
+
+                       /* Notify the back end that the block is starting */
+                       _jit_gen_start_block(&gen, block);
+       
+                       /* Generate the block's code */
+                       compile_block(&gen, func, block);
+       
+                       /* Spill all live register values back to their frame positions */
+                       _jit_regs_spill_all(&gen);
+
+                       /* Notify the back end that the block is finished */
+                       _jit_gen_end_block(&gen, block);
+       
+                       /* Clear the local register assignments, ready for the next block */
+                       _jit_regs_init_for_block(&gen);
+               }
+
+               /* Fix up the labels for the exception regions */
+               while(cache_eh != 0)
+               {
+                       if(cache_eh->handler_label != jit_label_undefined)
+                       {
+                               block = jit_block_from_label(func, cache_eh->handler_label);
+                               if(block)
+                               {
+                                       cache_eh->handler = (unsigned char *)(block->address);
+                               }
+                       }
+                       cache_eh = cache_eh->previous;
+               }
+
+               /* Output the function epilog.  All return paths will jump to here */
+               _jit_gen_epilog(&gen, func);
+               end = gen.posn.ptr;
+
+#ifdef JIT_PROLOG_SIZE
+               /* Back-patch the function prolog and get the real entry point */
+               if(have_prolog)
+               {
+                       start = _jit_gen_prolog(&gen, func, start);
+               }
+#endif
+
+               /* If the function is recompilable, then we need an extra entry
+                  point to properly redirect previous references to the function */
+               if(func->is_recompilable)
+               {
+                       recompilable_start = _jit_gen_redirector(&gen, func);
+               }
+
+               /* End the function's output process */
+               result = _jit_cache_end_method(&(gen.posn));
+       }
+       while(result == JIT_CACHE_END_RESTART);
+
+#ifdef jit_extra_gen_cleanup
+       /* Clean up the extra code generation state */
+       jit_extra_gen_cleanup(gen);
+#endif
+
+       /* Bail out if we ran out of memory while translating the function */
+       if(result != JIT_CACHE_END_OK)
+       {
+               jit_mutex_unlock(&(func->context->cache_lock));
+               return 0;
+       }
+
+#ifndef JIT_BACKEND_INTERP
+       /* Perform a CPU cache flush, to make the code executable */
+       jit_flush_exec(start, (unsigned int)(((unsigned char *)end) -
+                                                                                ((unsigned char *)start)));
+#endif
+
+       /* Intuit "nothrow" and "noreturn" flags for this function */
+       if(!(func->builder->may_throw))
+       {
+               func->no_throw = 1;
+       }
+       if(!(func->builder->ordinary_return))
+       {
+               func->no_return = 1;
+       }
+
+       /* Record the entry point */
+       func->entry_point = start;
+       if(recompilable_start)
+       {
+               func->closure_entry = recompilable_start;
+       }
+       else
+       {
+               func->closure_entry = start;
+       }
+       func->is_compiled = 1;
+
+       /* Free the builder structure, which we no longer require */
+       _jit_function_free_builder(func);
+
+       /* The function has been compiled successfully */
+       jit_mutex_unlock(&(func->context->cache_lock));
+       return 1;
+}
+
+/*@
+ * @deftypefun int jit_function_recompile (jit_function_t func)
+ * Force @code{func} to be recompiled, by calling its on-demand
+ * compiler again.  It is highly recommended that you set the
+ * recompilable flag with @code{jit_function_set_recompilable}
+ * when you initially create the function.
+ *
+ * This function returns one of @code{JIT_RESULT_OK},
+ * @code{JIT_RESULT_COMPILE_ERROR}, or @code{JIT_RESULT_OUT_OF_MEMORY}.
+ * @end deftypefun
+@*/
+int jit_function_recompile(jit_function_t func)
+{
+       int result;
+
+       /* Lock down the context */
+       jit_context_build_start(func->context);
+
+       /* Call the user's on-demand compiler if we don't have a builder yet.
+          Bail out with an error if there is no on-demand compiler */
+       if(!(func->builder))
+       {
+               if(func->on_demand)
+               {
+                       result = (*(func->on_demand))(func);
+                       if(result != JIT_RESULT_OK)
+                       {
+                               _jit_function_free_builder(func);
+                               jit_context_build_end(func->context);
+                               return result;
+                       }
+               }
+               else
+               {
+                       jit_context_build_end(func->context);
+                       return JIT_RESULT_COMPILE_ERROR;
+               }
+       }
+
+       /* Compile the function */
+       if(!jit_function_compile(func))
+       {
+               _jit_function_free_builder(func);
+               jit_context_build_end(func->context);
+               return JIT_RESULT_OUT_OF_MEMORY;
+       }
+
+       /* Unlock the context and report that we are ready to go */
+       jit_context_build_end(func->context);
+       return JIT_RESULT_OK;
+}
+
+/*@
+ * @deftypefun int jit_function_is_compiled (jit_function_t func)
+ * Determine if a function has already been compiled.
+ * @end deftypefun
+@*/
+int jit_function_is_compiled(jit_function_t func)
+{
+       if(func)
+       {
+               return func->is_compiled;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{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 @code{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.
+ * @end deftypefun
+@*/
+void jit_function_set_recompilable(jit_function_t func)
+{
+       if(func)
+       {
+               func->is_recompilable = 1;
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{jit_function_compile} again.
+ *
+ * Future uses of the function with @code{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.
+ * @end deftypefun
+@*/
+void jit_function_clear_recompilable(jit_function_t func)
+{
+       if(func)
+       {
+               func->is_recompilable = 0;
+       }
+}
+
+/*@
+ * @deftypefun int jit_function_is_recompilable (jit_function_t func)
+ * Determine if this function is recompilable.
+ * @end deftypefun
+@*/
+int jit_function_is_recompilable(jit_function_t func)
+{
+       if(func)
+       {
+               return func->is_recompilable;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+#ifdef JIT_BACKEND_INTERP
+
+/*
+ * Closure handling function for "jit_function_to_closure".
+ */
+static void function_closure(jit_type_t signature, void *result,
+                                                        void **args, void *user_data)
+{
+       if(!jit_function_apply((jit_function_t)user_data, args, result))
+       {
+               /* We cannot report the exception through the closure,
+                  so we have no choice but to rethrow it up the stack */
+               jit_exception_throw(jit_exception_get_last());
+       }
+}
+
+#endif /* JIT_BACKEND_INTERP */
+
+/*@
+ * @deftypefun {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.
+ * @end deftypefun
+@*/
+void *jit_function_to_closure(jit_function_t func)
+{
+       if(!func)
+       {
+               return 0;
+       }
+#ifdef JIT_BACKEND_INTERP
+       return jit_closure_create(func->context, func->signature,
+                                                         function_closure, (void *)func);
+#else
+       /* On native platforms, use the closure entry point */
+       return func->closure_entry;
+#endif
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_function_t jit_function_from_closure(jit_context_t context, void *closure)
+{
+       void *cookie;
+       if(!context || !(context->cache))
+       {
+               return 0;
+       }
+       return (jit_function_t)_jit_cache_get_method
+               (context->cache, closure, &cookie);
+}
+
+/*@
+ * @deftypefun 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 @code{catch} handler for the same location.
+ * Returns NULL if the program counter does not correspond to a function
+ * under the control of @code{context}.
+ * @end deftypefun
+@*/
+jit_function_t jit_function_from_pc
+       (jit_context_t context, void *pc, void **handler)
+{
+       jit_function_t func;
+       void *cookie;
+
+       /* Bail out if we don't have a function cache yet */
+       if(!context || !(context->cache))
+       {
+               return 0;
+       }
+
+       /* Get the function and the exception handler cookie */
+       func = (jit_function_t)_jit_cache_get_method(context->cache, pc, &cookie);
+       if(!func)
+       {
+               return 0;
+       }
+
+       /* Convert the cookie into a handler address */
+       if(handler)
+       {
+               if(cookie)
+               {
+                       *handler = ((jit_cache_eh_t)cookie)->handler;
+               }
+               else
+               {
+                       *handler = 0;
+               }
+       }
+       return func;
+}
+
+/*@
+ * @deftypefun {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
+ * @code{jit_insn_call_vtable} instruction.
+ *
+ * Using @code{jit_insn_call_vtable} is generally more efficient than
+ * @code{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 @code{jit_insn_call_indirect}.
+ * @end deftypefun
+@*/
+void *jit_function_to_vtable_pointer(jit_function_t func)
+{
+#ifdef JIT_BACKEND_INTERP
+       /* In the interpreted version, the function pointer is used in vtables */
+       return func;
+#else
+       /* On native platforms, the closure entry point is the vtable pointer */
+       if(func)
+       {
+               return func->closure_entry;
+       }
+       else
+       {
+               return 0;
+       }
+#endif
+}
+
+/*@
+ * @deftypefun 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 @code{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, @code{libjit} takes the following
+ * actions:
+ *
+ * @enumerate
+ * @item
+ * The context is locked by calling @code{jit_context_build_start}.
+ *
+ * @item
+ * If the function has already been compiled, @code{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.
+ *
+ * @item
+ * 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 @code{JIT_RESULT_OK}, @code{JIT_RESULT_COMPILE_ERROR},
+ * or @code{JIT_RESULT_OUT_OF_MEMORY}.
+ *
+ * @item
+ * If the user's on-demand function hasn't already done so, @code{libjit}
+ * will call @code{jit_function_compile} to compile the function.
+ *
+ * @item
+ * The context is unlocked by calling @code{jit_context_build_end} and
+ * @code{libjit} jumps to the newly-compiled entry point.  If an error
+ * occurs, a built-in exception of type @code{JIT_RESULT_COMPILE_ERROR}
+ * or @code{JIT_RESULT_OUT_OF_MEMORY} will be thrown.
+ * @end enumerate
+ *
+ * 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 @code{jit_function_create}.
+ * @end deftypefun
+@*/
+void jit_function_set_on_demand_compiler
+               (jit_function_t func, jit_on_demand_func on_demand)
+{
+       func->on_demand = on_demand;
+}
+
+void *_jit_function_compile_on_demand(jit_function_t func)
+{
+       void *entry = 0;
+       int result = JIT_RESULT_OK;
+
+       /* Lock down the context */
+       jit_context_build_start(func->context);
+
+       /* If we are already compiled, then bail out */
+       if(func->is_compiled)
+       {
+               entry = func->entry_point;
+               jit_context_build_end(func->context);
+               return entry;
+       }
+
+       /* Call the user's on-demand compiler.  Bail out with an error
+          if the user didn't supply an on-demand compiler */
+       if(func->on_demand)
+       {
+               result = (*(func->on_demand))(func);
+               if(result == JIT_RESULT_OK)
+               {
+                       /* Compile the function if the user didn't do so */
+                       if(!(func->is_compiled))
+                       {
+                               if(jit_function_compile(func))
+                               {
+                                       entry = func->entry_point;
+                               }
+                               else
+                               {
+                                       result = JIT_RESULT_OUT_OF_MEMORY;
+                               }
+                       }
+                       else
+                       {
+                               entry = func->entry_point;
+                       }
+               }
+               _jit_function_free_builder(func);
+       }
+       else
+       {
+               result = JIT_RESULT_COMPILE_ERROR;
+       }
+
+       /* Unlock the context and report the result */
+       jit_context_build_end(func->context);
+       if(result != JIT_RESULT_OK)
+       {
+               jit_exception_builtin(result);
+       }
+       return entry;
+}
+
+/*@
+ * @deftypefun int jit_function_apply (jit_function_t func, {void **} args, {void *} return_area)
+ * Call the function @code{func} with the supplied arguments.  Each element
+ * in @code{args} is a pointer to one of the arguments, and @code{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 @code{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 @code{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.
+ * @end deftypefun
+ *
+ * @deftypefun int jit_function_apply_vararg (jit_function_t func, jit_type_t signature, {void **} args, {void *} return_area)
+ * Call the function @code{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 @code{jit_function_apply}.
+ * @end deftypefun
+@*/
+#if !defined(JIT_BACKEND_INTERP)
+/* The interpreter version is in "jit-interp.cpp" */
+
+int jit_function_apply(jit_function_t func, void **args, void *return_area)
+{
+       if(!func)
+       {
+               return 0;
+       }
+       else
+       {
+               return jit_function_apply_vararg
+                       (func, func->signature, args, return_area);
+       }
+}
+
+int jit_function_apply_vararg
+       (jit_function_t func, jit_type_t signature, void **args, void *return_area)
+{
+       struct jit_backtrace call_trace;
+       void *entry;
+       jmp_buf buf;
+
+       /* Create a backtrace entry that blocks exceptions from
+          flowing further than this up the stack */
+       _jit_backtrace_push(&call_trace, 0, 0, &jbuf);
+
+       /* Establish a "setjmp" point here so that we can unwind the
+          stack when an exception occurs that is blocked by us */
+       if(setjmp(jbuf) != 0)
+       {
+               _jit_backtrace_set(call_trace.parent);
+               return 1;
+       }
+
+       /* Get the function's entry point */
+       if(!func)
+       {
+               jit_exception_builtin(JIT_RESULT_NULL_FUNCTION);
+               return 0;
+       }
+       if(func->nested_parent)
+       {
+               jit_exception_builtin(JIT_RESULT_CALLED_NESTED);
+               return 0;
+       }
+       if(func->is_compiled)
+       {
+               entry = func->entry_point;
+       }
+       else
+       {
+               entry = _jit_function_compile_on_demand(func);
+       }
+
+       /* Get the default signature if necessary */
+       if(!signature)
+       {
+               signature = func->signature;
+       }
+
+       /* Clear the exception state */
+       jit_exception_clear_last();
+
+       /* Apply the function.  If it returns, then there is no exception */
+       jit_apply(signature, func->entry_point, args,
+                         jit_type_num_params(func->signature), return_area);
+
+       /* Restore the backtrace context and exit */
+       _jit_backtrace_set(call_trace.parent);
+       return 0;
+}
+
+#endif /* !JIT_BACKEND_INTERP */
+
+/*@
+ * @deftypefun void jit_function_set_optimization_level (jit_function_t func, {unsigned int} level)
+ * Set the optimization level for @code{func}.  Increasing values indicate
+ * that the @code{libjit} dynamic compiler should expend more effort to
+ * generate better code for this function.  Usually you would increase
+ * this value just before forcing @code{func} to recompile.
+ *
+ * When the optimization level reaches the value returned by
+ * @code{jit_function_get_max_optimization_level()}, there is usually
+ * little point in continuing to recompile the function because
+ * @code{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 @code{func} again even once it has
+ * reached the maximum optimization level.
+ * @end deftypefun
+@*/
+void jit_function_set_optimization_level
+       (jit_function_t func, unsigned int level)
+{
+       unsigned int max_level = jit_function_get_max_optimization_level();
+       if(level > max_level)
+       {
+               level = max_level;
+       }
+       if(func)
+       {
+               func->optimization_level = (int)level;
+       }
+}
+
+/*@
+ * @deftypefun {unsigned int} jit_function_get_optimization_level (jit_function_t func)
+ * Get the current optimization level for @code{func}.
+ * @end deftypefun
+@*/
+unsigned int jit_function_get_optimization_level(jit_function_t func)
+{
+       if(func)
+       {
+               return (unsigned int)(func->optimization_level);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun {unsigned int} jit_function_get_max_optimization_level (void)
+ * Get the maximum optimization level that is supported by @code{libjit}.
+ * @end deftypefun
+@*/
+unsigned int jit_function_get_max_optimization_level(void)
+{
+       /* TODO - implement more than basic optimization */
+       return 0;
+}
diff --git a/jit/jit-gen-arm.c b/jit/jit-gen-arm.c
new file mode 100644 (file)
index 0000000..938f592
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * jit-gen-arm.c - Machine-dependent definitions for ARM.
+ *
+ * Copyright (C) 2003, 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-gen-arm.h"
+
+#if defined(__arm) || defined(__arm__)
+
+arm_inst_ptr _arm_mov_reg_imm(arm_inst_ptr inst, int reg, int value)
+{
+       /* Handle bytes in various positions */
+       if((value & 0x000000FF) == value)
+       {
+               arm_mov_reg_imm8(inst, reg, value);
+               return inst;
+       }
+       else if((value & 0x0000FF00) == value)
+       {
+               arm_mov_reg_imm8_rotate(inst, reg, (value >> 8), 12);
+               return inst;
+       }
+       else if((value & 0x00FF0000) == value)
+       {
+               arm_mov_reg_imm8_rotate(inst, reg, (value >> 16), 8);
+               return inst;
+       }
+       else if((value & 0xFF000000) == value)
+       {
+               arm_mov_reg_imm8_rotate(inst, reg, ((value >> 24) & 0xFF), 4);
+               return inst;
+       }
+
+       /* Handle inverted bytes in various positions */
+       value = ~value;
+       if((value & 0x000000FF) == value)
+       {
+               arm_mov_reg_imm8(inst, reg, value);
+               arm_alu_reg(inst, ARM_MVN, reg, reg);
+               return inst;
+       }
+       else if((value & 0x0000FF00) == value)
+       {
+               arm_mov_reg_imm8_rotate(inst, reg, (value >> 8), 12);
+               arm_alu_reg(inst, ARM_MVN, reg, reg);
+               return inst;
+       }
+       else if((value & 0x00FF0000) == value)
+       {
+               arm_mov_reg_imm8_rotate(inst, reg, (value >> 16), 8);
+               arm_alu_reg(inst, ARM_MVN, reg, reg);
+               return inst;
+       }
+       else if((value & 0xFF000000) == value)
+       {
+               arm_mov_reg_imm8_rotate(inst, reg, ((value >> 24) & 0xFF), 4);
+               arm_alu_reg(inst, ARM_MVN, reg, reg);
+               return inst;
+       }
+
+       /* Build the value the hard way, byte by byte */
+       value = ~value;
+       if((value & 0xFF000000) != 0)
+       {
+               arm_mov_reg_imm8_rotate(inst, reg, ((value >> 24) & 0xFF), 4);
+               if((value & 0x00FF0000) != 0)
+               {
+                       arm_alu_reg_imm8_rotate
+                               (inst, ARM_ADD, reg, reg, ((value >> 16) & 0xFF), 8);
+               }
+               if((value & 0x0000FF00) != 0)
+               {
+                       arm_alu_reg_imm8_rotate
+                               (inst, ARM_ADD, reg, reg, ((value >> 8) & 0xFF), 12);
+               }
+               if((value & 0x000000FF) != 0)
+               {
+                       arm_alu_reg_imm8(inst, ARM_ADD, reg, reg, (value & 0xFF));
+               }
+       }
+       else if((value & 0x00FF0000) != 0)
+       {
+               arm_mov_reg_imm8_rotate(inst, reg, ((value >> 16) & 0xFF), 8);
+               if((value & 0x0000FF00) != 0)
+               {
+                       arm_alu_reg_imm8_rotate
+                               (inst, ARM_ADD, reg, reg, ((value >> 8) & 0xFF), 12);
+               }
+               if((value & 0x000000FF) != 0)
+               {
+                       arm_alu_reg_imm8(inst, ARM_ADD, reg, reg, (value & 0xFF));
+               }
+       }
+       else if((value & 0x0000FF00) != 0)
+       {
+               arm_mov_reg_imm8_rotate(inst, reg, ((value >> 8) & 0xFF), 12);
+               if((value & 0x000000FF) != 0)
+               {
+                       arm_alu_reg_imm8(inst, ARM_ADD, reg, reg, (value & 0xFF));
+               }
+       }
+       else
+       {
+               arm_mov_reg_imm8(inst, reg, (value & 0xFF));
+       }
+       return inst;
+}
+
+arm_inst_ptr _arm_alu_reg_imm(arm_inst_ptr inst, int opc,
+                                                 int dreg, int sreg, int imm,
+                                                 int saveWork)
+{
+       int tempreg;
+       if(saveWork)
+       {
+               if(dreg != ARM_R2 && sreg != ARM_R2)
+               {
+                       tempreg = ARM_R2;
+               }
+               else if(dreg != ARM_R3 && sreg != ARM_R3)
+               {
+                       tempreg = ARM_R3;
+               }
+               else
+               {
+                       tempreg = ARM_R4;
+               }
+               arm_push_reg(inst, tempreg);
+       }
+       else
+       {
+               tempreg = ARM_WORK;
+       }
+       _arm_mov_reg_imm(inst, tempreg, imm);
+       arm_alu_reg_reg(inst, opc, dreg, sreg, tempreg);
+       if(saveWork)
+       {
+               arm_pop_reg(inst, tempreg);
+       }
+       return inst;
+}
+
+#endif /* arm */
diff --git a/jit/jit-gen-arm.h b/jit/jit-gen-arm.h
new file mode 100644 (file)
index 0000000..0b0f368
--- /dev/null
@@ -0,0 +1,761 @@
+/*
+ * arm_codegen.h - Code generation macros for the ARM processor.
+ *
+ * Copyright (C) 2003, 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _ARM_CODEGEN_H
+#define        _ARM_CODEGEN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Register numbers.
+ */
+typedef enum
+{
+       ARM_R0   = 0,
+       ARM_R1   = 1,
+       ARM_R2   = 2,
+       ARM_R3   = 3,
+       ARM_R4   = 4,
+       ARM_R5   = 5,
+       ARM_R6   = 6,
+       ARM_R7   = 7,
+       ARM_R8   = 8,
+       ARM_R9   = 9,
+       ARM_R10  = 10,
+       ARM_R11  = 11,
+       ARM_R12  = 12,
+       ARM_R13  = 13,
+       ARM_R14  = 14,
+       ARM_R15  = 15,
+       ARM_FP   = ARM_R11,                     /* Frame pointer */
+       ARM_LINK = ARM_R14,                     /* Link register */
+       ARM_PC   = ARM_R15,                     /* Program counter */
+       ARM_WORK = ARM_R12,                     /* Work register that we can destroy */
+       ARM_SP   = ARM_R13,                     /* Stack pointer */
+
+} ARM_REG;
+
+/*
+ * Condition codes.
+ */
+typedef enum
+{
+       ARM_CC_EQ    = 0,                       /* Equal */
+       ARM_CC_NE    = 1,                       /* Not equal */
+       ARM_CC_CS    = 2,                       /* Carry set */
+       ARM_CC_CC    = 3,                       /* Carry clear */
+       ARM_CC_MI    = 4,                       /* Negative */
+       ARM_CC_PL    = 5,                       /* Positive */
+       ARM_CC_VS    = 6,                       /* Overflow set */
+       ARM_CC_VC    = 7,                       /* Overflow clear */
+       ARM_CC_HI    = 8,                       /* Higher */
+       ARM_CC_LS    = 9,                       /* Lower or same */
+       ARM_CC_GE    = 10,                      /* Signed greater than or equal */
+       ARM_CC_LT    = 11,                      /* Signed less than */
+       ARM_CC_GT    = 12,                      /* Signed greater than */
+       ARM_CC_LE    = 13,                      /* Signed less than or equal */
+       ARM_CC_AL    = 14,                      /* Always */
+       ARM_CC_NV    = 15,                      /* Never */
+       ARM_CC_GE_UN = ARM_CC_CS,       /* Unsigned greater than or equal */
+       ARM_CC_LT_UN = ARM_CC_CC,       /* Unsigned less than */
+       ARM_CC_GT_UN = ARM_CC_HI,       /* Unsigned greater than */
+       ARM_CC_LE_UN = ARM_CC_LS,       /* Unsigned less than or equal */
+
+} ARM_CC;
+
+/*
+ * Arithmetic and logical operations.
+ */
+typedef enum
+{
+       ARM_AND = 0,                            /* Bitwise AND */
+       ARM_EOR = 1,                            /* Bitwise XOR */
+       ARM_SUB = 2,                            /* Subtract */
+       ARM_RSB = 3,                            /* Reverse subtract */
+       ARM_ADD = 4,                            /* Add */
+       ARM_ADC = 5,                            /* Add with carry */
+       ARM_SBC = 6,                            /* Subtract with carry */
+       ARM_RSC = 7,                            /* Reverse subtract with carry */
+       ARM_TST = 8,                            /* Test with AND */
+       ARM_TEQ = 9,                            /* Test with XOR */
+       ARM_CMP = 10,                           /* Test with SUB (compare) */
+       ARM_CMN = 11,                           /* Test with ADD */
+       ARM_ORR = 12,                           /* Bitwise OR */
+       ARM_MOV = 13,                           /* Move */
+       ARM_BIC = 14,                           /* Test with Op1 & ~Op2 */
+       ARM_MVN = 15,                           /* Bitwise NOT */
+
+} ARM_OP;
+
+/*
+ * Shift operators.
+ */
+typedef enum
+{
+       ARM_SHL = 0,                            /* Logical left */
+       ARM_SHR = 1,                            /* Logical right */
+       ARM_SAR = 2,                            /* Arithmetic right */
+       ARM_ROR = 3,                            /* Rotate right */
+
+} ARM_SHIFT;
+
+/*
+ * Number of registers that are used for parameters (r0-r3).
+ */
+#define        ARM_NUM_PARAM_REGS      4
+
+/*
+ * Type for instruction pointers (word-based, not byte-based).
+ */
+typedef unsigned int *arm_inst_ptr;
+
+/*
+ * Build an instruction prefix from a condition code and a mask value.
+ */
+#define        arm_build_prefix(cond,mask)     \
+                       ((((unsigned int)(cond)) << 28) | ((unsigned int)(mask)))
+
+/*
+ * Build an "always" instruction prefix for a regular instruction.
+ */
+#define arm_prefix(mask)       (arm_build_prefix(ARM_CC_AL, (mask)))
+
+/*
+ * Build special "always" prefixes.
+ */
+#define        arm_always                      (arm_build_prefix(ARM_CC_AL, 0))
+#define        arm_always_cc           (arm_build_prefix(ARM_CC_AL, (1 << 20)))
+#define        arm_always_imm          (arm_build_prefix(ARM_CC_AL, (1 << 25)))
+
+/*
+ * Arithmetic or logical operation which doesn't set condition codes.
+ */
+#define        arm_alu_reg_reg(inst,opc,dreg,sreg1,sreg2)      \
+                       do { \
+                               *(inst)++ = arm_always | \
+                                                       (((unsigned int)(opc)) << 21) | \
+                                                       (((unsigned int)(dreg)) << 12) | \
+                                                       (((unsigned int)(sreg1)) << 16) | \
+                                                        ((unsigned int)(sreg2)); \
+                       } while (0)
+#define        arm_alu_reg_imm8(inst,opc,dreg,sreg,imm)        \
+                       do { \
+                               *(inst)++ = arm_always_imm | \
+                                                       (((unsigned int)(opc)) << 21) | \
+                                                       (((unsigned int)(dreg)) << 12) | \
+                                                       (((unsigned int)(sreg)) << 16) | \
+                                                        ((unsigned int)((imm) & 0xFF)); \
+                       } while (0)
+#define        arm_alu_reg_imm8_cond(inst,opc,dreg,sreg,imm,cond)      \
+                       do { \
+                               *(inst)++ = arm_build_prefix((cond), (1 << 25)) | \
+                                                       (((unsigned int)(opc)) << 21) | \
+                                                       (((unsigned int)(dreg)) << 12) | \
+                                                       (((unsigned int)(sreg)) << 16) | \
+                                                        ((unsigned int)((imm) & 0xFF)); \
+                       } while (0)
+#define        arm_alu_reg_imm8_rotate(inst,opc,dreg,sreg,imm,rotate)  \
+                       do { \
+                               *(inst)++ = arm_always_imm | \
+                                                       (((unsigned int)(opc)) << 21) | \
+                                                       (((unsigned int)(dreg)) << 12) | \
+                                                       (((unsigned int)(sreg)) << 16) | \
+                                                       (((unsigned int)(rotate)) << 8) | \
+                                                        ((unsigned int)((imm) & 0xFF)); \
+                       } while (0)
+extern arm_inst_ptr _arm_alu_reg_imm(arm_inst_ptr inst, int opc, int dreg,
+                                                                int sreg, int imm, int saveWork);
+#define        arm_alu_reg_imm(inst,opc,dreg,sreg,imm) \
+                       do { \
+                               int __alu_imm = (int)(imm); \
+                               if(__alu_imm >= 0 && __alu_imm < 256) \
+                               { \
+                                       arm_alu_reg_imm8 \
+                                               ((inst), (opc), (dreg), (sreg), __alu_imm); \
+                               } \
+                               else \
+                               { \
+                                       (inst) = _arm_alu_reg_imm \
+                                               ((inst), (opc), (dreg), (sreg), __alu_imm, 0); \
+                               } \
+                       } while (0)
+#define        arm_alu_reg_imm_save_work(inst,opc,dreg,sreg,imm)       \
+                       do { \
+                               int __alu_imm_save = (int)(imm); \
+                               if(__alu_imm_save >= 0 && __alu_imm_save < 256) \
+                               { \
+                                       arm_alu_reg_imm8 \
+                                               ((inst), (opc), (dreg), (sreg), __alu_imm_save); \
+                               } \
+                               else \
+                               { \
+                                       (inst) = _arm_alu_reg_imm \
+                                               ((inst), (opc), (dreg), (sreg), __alu_imm_save, 1); \
+                               } \
+                       } while (0)
+#define arm_alu_reg(inst,opc,dreg,sreg)        \
+                       do { \
+                               *(inst)++ = arm_always | \
+                                                       (((unsigned int)(opc)) << 21) | \
+                                                       (((unsigned int)(dreg)) << 12) | \
+                                                        ((unsigned int)(sreg)); \
+                       } while (0)
+#define arm_alu_reg_cond(inst,opc,dreg,sreg,cond)      \
+                       do { \
+                               *(inst)++ = arm_build_prefix((cond), 0) | \
+                                                       (((unsigned int)(opc)) << 21) | \
+                                                       (((unsigned int)(dreg)) << 12) | \
+                                                        ((unsigned int)(sreg)); \
+                       } while (0)
+
+/*
+ * Arithmetic or logical operation which sets condition codes.
+ */
+#define        arm_alu_cc_reg_reg(inst,opc,dreg,sreg1,sreg2)   \
+                       do { \
+                               *(inst)++ = arm_always_cc | \
+                                                       (((unsigned int)(opc)) << 21) | \
+                                                       (((unsigned int)(dreg)) << 12) | \
+                                                       (((unsigned int)(sreg1)) << 16) | \
+                                                        ((unsigned int)(sreg2)); \
+                       } while (0)
+#define        arm_alu_cc_reg_imm8(inst,opc,dreg,sreg,imm)     \
+                       do { \
+                               *(inst)++ = arm_always_imm | arm_always_cc | \
+                                                       (((unsigned int)(opc)) << 21) | \
+                                                       (((unsigned int)(dreg)) << 12) | \
+                                                       (((unsigned int)(sreg)) << 16) | \
+                                                        ((unsigned int)((imm) & 0xFF)); \
+                       } while (0)
+#define arm_alu_cc_reg(inst,opc,dreg,sreg)     \
+                       do { \
+                               *(inst)++ = arm_always_cc | \
+                                                       (((unsigned int)(opc)) << 21) | \
+                                                       (((unsigned int)(dreg)) << 12) | \
+                                                        ((unsigned int)(sreg)); \
+                       } while (0)
+
+/*
+ * Test operation, which sets the condition codes but has no other result.
+ */
+#define arm_test_reg_reg(inst,opc,sreg1,sreg2) \
+                       do { \
+                               arm_alu_cc_reg_reg((inst), (opc), 0, (sreg1), (sreg2)); \
+                       } while (0)
+#define arm_test_reg_imm8(inst,opc,sreg,imm)   \
+                       do { \
+                               arm_alu_cc_reg_imm8((inst), (opc), 0, (sreg), (imm)); \
+                       } while (0)
+#define arm_test_reg_imm(inst,opc,sreg,imm)    \
+                       do { \
+                               int __test_imm = (int)(imm); \
+                               if(__test_imm >= 0 && __test_imm < 256) \
+                               { \
+                                       arm_alu_cc_reg_imm8((inst), (opc), 0, (sreg), __test_imm); \
+                               } \
+                               else \
+                               { \
+                                       arm_mov_reg_imm((inst), ARM_WORK, __test_imm); \
+                                       arm_test_reg_reg((inst), (opc), (sreg), ARM_WORK); \
+                               } \
+                       } while (0)
+
+/*
+ * Move a value between registers.
+ */
+#define        arm_mov_reg_reg(inst,dreg,sreg) \
+                       do { \
+                               arm_alu_reg((inst), ARM_MOV, (dreg), (sreg)); \
+                       } while (0)
+
+/*
+ * Move an immediate value into a register.  This is hard because
+ * ARM lacks an instruction to load a 32-bit immediate value directly.
+ * We handle the simple cases and then bail out to a function for the rest.
+ */
+#define        arm_mov_reg_imm8(inst,reg,imm)  \
+                       do { \
+                               arm_alu_reg_imm8((inst), ARM_MOV, (reg), 0, (imm)); \
+                       } while (0)
+#define        arm_mov_reg_imm8_rotate(inst,reg,imm,rotate)    \
+                       do { \
+                               arm_alu_reg_imm8_rotate((inst), ARM_MOV, (reg), \
+                                                                               0, (imm), (rotate)); \
+                       } while (0)
+extern arm_inst_ptr _arm_mov_reg_imm(arm_inst_ptr inst, int reg, int value);
+#define        arm_mov_reg_imm(inst,reg,imm)   \
+                       do { \
+                               int __imm = (int)(imm); \
+                               if(__imm >= 0 && __imm < 256) \
+                               { \
+                                       arm_mov_reg_imm8((inst), (reg), __imm); \
+                               } \
+                               else if((reg) == ARM_PC) \
+                               { \
+                                       (inst) = _arm_mov_reg_imm((inst), ARM_WORK, __imm); \
+                                       arm_mov_reg_reg((inst), ARM_PC, ARM_WORK); \
+                               } \
+                               else if(__imm > -256 && __imm < 0) \
+                               { \
+                                       arm_mov_reg_imm8((inst), (reg), ~(__imm)); \
+                                       arm_alu_reg((inst), ARM_MVN, (reg), (reg)); \
+                               } \
+                               else \
+                               { \
+                                       (inst) = _arm_mov_reg_imm((inst), (reg), __imm); \
+                               } \
+                       } while (0)
+
+/*
+ * Clear a register to zero.
+ */
+#define        arm_clear_reg(inst,reg) \
+                       do { \
+                               arm_mov_reg_imm8((inst), (reg), 0); \
+                       } while (0)
+
+/*
+ * No-operation instruction.
+ */
+#define        arm_nop(inst)   arm_mov_reg_reg((inst), ARM_R0, ARM_R0)
+
+/*
+ * Perform a shift operation.
+ */
+#define        arm_shift_reg_reg(inst,opc,dreg,sreg1,sreg2) \
+                       do { \
+                               *(inst)++ = arm_always | \
+                                                       (((unsigned int)ARM_MOV) << 21) | \
+                                                       (((unsigned int)(dreg)) << 12) | \
+                                                       (((unsigned int)(sreg2)) << 8) | \
+                                                       (((unsigned int)(opc)) << 5) | \
+                                                        ((unsigned int)(1 << 4)) | \
+                                                        ((unsigned int)(sreg1)); \
+                       } while (0)
+#define        arm_shift_reg_imm8(inst,opc,dreg,sreg,imm) \
+                       do { \
+                               *(inst)++ = arm_always | \
+                                                       (((unsigned int)ARM_MOV) << 21) | \
+                                                       (((unsigned int)(dreg)) << 12) | \
+                                                       (((unsigned int)(opc)) << 5) | \
+                                                       (((unsigned int)(imm)) << 7) | \
+                                                        ((unsigned int)(sreg)); \
+                       } while (0)
+
+/*
+ * Perform a multiplication instruction.  Note: ARM instruction rules
+ * say that dreg should not be the same as sreg2, so we swap the order
+ * of the arguments if that situation occurs.  We assume that sreg1
+ * and sreg2 are distinct registers.
+ */
+#define arm_mul_reg_reg(inst,dreg,sreg1,sreg2) \
+                       do { \
+                               if((dreg) != (sreg2)) \
+                               { \
+                                       *(inst)++ = arm_prefix(0x00000090) | \
+                                                               (((unsigned int)(dreg)) << 16) | \
+                                                               (((unsigned int)(sreg1)) << 8) | \
+                                                                ((unsigned int)(sreg2)); \
+                               } \
+                               else \
+                               { \
+                                       *(inst)++ = arm_prefix(0x00000090) | \
+                                                               (((unsigned int)(dreg)) << 16) | \
+                                                               (((unsigned int)(sreg2)) << 8) | \
+                                                                ((unsigned int)(sreg1)); \
+                               } \
+                       } while (0)
+
+/*
+ * Branch or jump immediate by a byte offset.  The offset is
+ * assumed to be +/- 32 Mbytes.
+ */
+#define        arm_branch_imm(inst,cond,imm)   \
+                       do { \
+                               *(inst)++ = arm_build_prefix((cond), 0x0A000000) | \
+                                                       (((unsigned int)(((int)(imm)) >> 2)) & \
+                                                               0x00FFFFFF); \
+                       } while (0)
+#define        arm_jump_imm(inst,imm)  arm_branch_imm((inst), ARM_CC_AL, (imm))
+
+/*
+ * Branch or jump to a specific target location.  The offset is
+ * assumed to be +/- 32 Mbytes.
+ */
+#define        arm_branch(inst,cond,target)    \
+                       do { \
+                               int __br_offset = (int)(((unsigned char *)(target)) - \
+                                                                  (((unsigned char *)(inst)) + 8)); \
+                               arm_branch_imm((inst), (cond), __br_offset); \
+                       } while (0)
+#define        arm_jump(inst,target)   arm_branch((inst), ARM_CC_AL, (target))
+
+/*
+ * Jump to a specific target location that may be greater than
+ * 32 Mbytes away from the current location.
+ */
+#define        arm_jump_long(inst,target)      \
+                       do { \
+                               int __jmp_offset = (int)(((unsigned char *)(target)) - \
+                                                                   (((unsigned char *)(inst)) + 8)); \
+                               if(__jmp_offset >= -0x04000000 && __jmp_offset < 0x04000000) \
+                               { \
+                                       arm_jump_imm((inst), __jmp_offset); \
+                               } \
+                               else \
+                               { \
+                                       arm_mov_reg_imm((inst), ARM_PC, (int)(target)); \
+                               } \
+                       } while (0)
+
+/*
+ * Back-patch a branch instruction.
+ */
+#define        arm_patch(inst,target)  \
+                       do { \
+                               int __p_offset = (int)(((unsigned char *)(target)) - \
+                                                                 (((unsigned char *)(inst)) + 8)); \
+                               __p_offset = (__p_offset >> 2) & 0x00FFFFFF; \
+                               *((int *)(inst)) = (*((int *)(inst)) & 0xFF000000) | \
+                                       __p_offset; \
+                       } while (0)
+
+/*
+ * Call a subroutine immediate by a byte offset.
+ */
+#define        arm_call_imm(inst,imm)  \
+                       do { \
+                               *(inst)++ = arm_prefix(0x0B000000) | \
+                                                       (((unsigned int)(((int)(imm)) >> 2)) & \
+                                                               0x00FFFFFF); \
+                       } while (0)
+
+/*
+ * Call a subroutine at a specific target location.
+ */
+#define        arm_call(inst,target)   \
+                       do { \
+                               int __call_offset = (int)(((unsigned char *)(target)) - \
+                                                                    (((unsigned char *)(inst)) + 8)); \
+                               if(__call_offset >= -0x04000000 && __call_offset < 0x04000000) \
+                               { \
+                                       arm_call_imm((inst), __call_offset); \
+                               } \
+                               else \
+                               { \
+                                       arm_mov_reg_imm((inst), ARM_WORK, (int)(target)); \
+                                       arm_mov_reg_reg((inst), ARM_LINK, ARM_PC); \
+                                       arm_mov_reg_reg((inst), ARM_PC, ARM_WORK); \
+                               } \
+                       } while (0)
+
+/*
+ * Return from a subroutine, where the return address is in the link register.
+ */
+#define        arm_return(inst)        \
+                       do { \
+                               arm_mov_reg_reg((inst), ARM_PC, ARM_LINK); \
+                       } while (0)
+
+/*
+ * Push a register onto the system stack.
+ */
+#define        arm_push_reg(inst,reg)  \
+                       do { \
+                               *(inst)++ = arm_prefix(0x05200004) | \
+                                                       (((unsigned int)ARM_SP) << 16) | \
+                                                       (((unsigned int)(reg)) << 12); \
+                       } while (0)
+
+/*
+ * Pop a register from the system stack.
+ */
+#define        arm_pop_reg(inst,reg)   \
+                       do { \
+                               *(inst)++ = arm_prefix(0x04900004) | \
+                                                       (((unsigned int)ARM_SP) << 16) | \
+                                                       (((unsigned int)(reg)) << 12); \
+                       } while (0)
+
+/*
+ * Set up a local variable frame, and save the registers in "regset".
+ */
+#define        arm_setup_frame(inst,regset)    \
+                       do { \
+                               arm_mov_reg_reg((inst), ARM_WORK, ARM_SP); \
+                               *(inst)++ = arm_prefix(0x0920D800) | \
+                                                       (((unsigned int)ARM_SP) << 16) | \
+                                                       (((unsigned int)(regset))); \
+                               arm_alu_reg_imm8((inst), ARM_SUB, ARM_FP, ARM_WORK, 4); \
+                       } while (0)
+
+/*
+ * Pop a local variable frame, restore the registers in "regset",
+ * and return to the caller.
+ */
+#define        arm_pop_frame(inst,regset)      \
+                       do { \
+                               *(inst)++ = arm_prefix(0x0910A800) | \
+                                                       (((unsigned int)ARM_FP) << 16) | \
+                                                       (((unsigned int)(regset))); \
+                       } while (0)
+
+/*
+ * Pop a local variable frame, in preparation for a tail call.
+ * This restores "lr" to its original value, but does not set "pc".
+ */
+#define        arm_pop_frame_tail(inst,regset) \
+                       do { \
+                               *(inst)++ = arm_prefix(0x09106800) | \
+                                                       (((unsigned int)ARM_FP) << 16) | \
+                                                       (((unsigned int)(regset))); \
+                       } while (0)
+
+/*
+ * Load a word value from a pointer and then advance the pointer.
+ */
+#define        arm_load_advance(inst,dreg,sreg)        \
+                       do { \
+                               *(inst)++ = arm_prefix(0x04900004) | \
+                                                       (((unsigned int)(sreg)) << 16) | \
+                                                       (((unsigned int)(dreg)) << 12); \
+                       } while (0)
+
+/*
+ * Load a value from an address into a register.
+ */
+#define arm_load_membase_either(inst,reg,basereg,imm,mask)     \
+                       do { \
+                               int __mb_offset = (int)(imm); \
+                               if(__mb_offset >= 0 && __mb_offset < (1 << 12)) \
+                               { \
+                                       *(inst)++ = arm_prefix(0x05900000 | (mask)) | \
+                                                               (((unsigned int)(basereg)) << 16) | \
+                                                               (((unsigned int)(reg)) << 12) | \
+                                                                ((unsigned int)__mb_offset); \
+                               } \
+                               else if(__mb_offset > -(1 << 12) && __mb_offset < 0) \
+                               { \
+                                       *(inst)++ = arm_prefix(0x05100000 | (mask)) | \
+                                                               (((unsigned int)(basereg)) << 16) | \
+                                                               (((unsigned int)(reg)) << 12) | \
+                                                                ((unsigned int)(-__mb_offset)); \
+                               } \
+                               else \
+                               { \
+                                       arm_mov_reg_imm((inst), ARM_WORK, __mb_offset); \
+                                       *(inst)++ = arm_prefix(0x07900000 | (mask)) | \
+                                                               (((unsigned int)(basereg)) << 16) | \
+                                                               (((unsigned int)(reg)) << 12) | \
+                                                                ((unsigned int)ARM_WORK); \
+                               } \
+                       } while (0)
+#define        arm_load_membase(inst,reg,basereg,imm)  \
+                       do { \
+                               arm_load_membase_either((inst), (reg), (basereg), (imm), 0); \
+                       } while (0)
+#define        arm_load_membase_byte(inst,reg,basereg,imm)     \
+                       do { \
+                               arm_load_membase_either((inst), (reg), (basereg), (imm), \
+                                                                               0x00400000); \
+                       } while (0)
+#define        arm_load_membase_sbyte(inst,reg,basereg,imm)    \
+                       do { \
+                               arm_load_membase_either((inst), (reg), (basereg), (imm), \
+                                                                               0x00400000); \
+                               arm_shift_reg_imm8((inst), ARM_SHL, (reg), (reg), 24); \
+                               arm_shift_reg_imm8((inst), ARM_SAR, (reg), (reg), 24); \
+                       } while (0)
+#define        arm_load_membase_ushort(inst,reg,basereg,imm)   \
+                       do { \
+                               arm_load_membase_byte((inst), ARM_WORK, (basereg), (imm)); \
+                               arm_load_membase_byte((inst), (reg), (basereg), (imm) + 1); \
+                               arm_shift_reg_imm8((inst), ARM_SHL, (reg), (reg), 8); \
+                               arm_alu_reg_reg((inst), ARM_ORR, (reg), (reg), ARM_WORK); \
+                       } while (0)
+#define        arm_load_membase_short(inst,reg,basereg,imm)    \
+                       do { \
+                               arm_load_membase_byte((inst), ARM_WORK, (basereg), (imm)); \
+                               arm_load_membase_byte((inst), (reg), (basereg), (imm) + 1); \
+                               arm_shift_reg_imm8((inst), ARM_SHL, (reg), (reg), 24); \
+                               arm_shift_reg_imm8((inst), ARM_SAR, (reg), (reg), 16); \
+                               arm_alu_reg_reg((inst), ARM_ORR, (reg), (reg), ARM_WORK); \
+                       } while (0)
+
+/*
+ * Store a value from a register into an address.
+ *
+ * Note: storing a 16-bit value destroys the value in the register.
+ */
+#define arm_store_membase_either(inst,reg,basereg,imm,mask)    \
+                       do { \
+                               int __sm_offset = (int)(imm); \
+                               if(__sm_offset >= 0 && __sm_offset < (1 << 12)) \
+                               { \
+                                       *(inst)++ = arm_prefix(0x05800000 | (mask)) | \
+                                                               (((unsigned int)(basereg)) << 16) | \
+                                                               (((unsigned int)(reg)) << 12) | \
+                                                                ((unsigned int)__sm_offset); \
+                               } \
+                               else if(__sm_offset > -(1 << 12) && __sm_offset < 0) \
+                               { \
+                                       *(inst)++ = arm_prefix(0x05000000 | (mask)) | \
+                                                               (((unsigned int)(basereg)) << 16) | \
+                                                               (((unsigned int)(reg)) << 12) | \
+                                                                ((unsigned int)(-__sm_offset)); \
+                               } \
+                               else \
+                               { \
+                                       arm_mov_reg_imm((inst), ARM_WORK, __sm_offset); \
+                                       *(inst)++ = arm_prefix(0x07800000 | (mask)) | \
+                                                               (((unsigned int)(basereg)) << 16) | \
+                                                               (((unsigned int)(reg)) << 12) | \
+                                                                ((unsigned int)ARM_WORK); \
+                               } \
+                       } while (0)
+#define        arm_store_membase(inst,reg,basereg,imm) \
+                       do { \
+                               arm_store_membase_either((inst), (reg), (basereg), (imm), 0); \
+                       } while (0)
+#define        arm_store_membase_byte(inst,reg,basereg,imm)    \
+                       do { \
+                               arm_store_membase_either((inst), (reg), (basereg), (imm), \
+                                                                                0x00400000); \
+                       } while (0)
+#define        arm_store_membase_sbyte(inst,reg,basereg,imm)   \
+                       do { \
+                               arm_store_membase_byte((inst), (reg), (basereg), (imm)); \
+                       } while (0)
+#define        arm_store_membase_short(inst,reg,basereg,imm)   \
+                       do { \
+                               arm_store_membase_either((inst), (reg), (basereg), (imm), \
+                                                                                0x00400000); \
+                               arm_shift_reg_imm8((inst), ARM_SHR, (reg), (reg), 8); \
+                               arm_store_membase_either((inst), (reg), (basereg), \
+                                                                                (imm) + 1, 0x00400000); \
+                       } while (0)
+#define        arm_store_membase_ushort(inst,reg,basereg,imm)  \
+                       do { \
+                               arm_store_membase_short((inst), (reg), (basereg), (imm)); \
+                       } while (0)
+
+/*
+ * Load a value from an indexed address into a register.
+ */
+#define arm_load_memindex_either(inst,reg,basereg,indexreg,shift,mask) \
+                       do { \
+                               *(inst)++ = arm_prefix(0x07900000 | (mask)) | \
+                                                       (((unsigned int)(basereg)) << 16) | \
+                                                       (((unsigned int)(reg)) << 12) | \
+                                                       (((unsigned int)(shift)) << 7) | \
+                                                        ((unsigned int)(indexreg)); \
+                       } while (0)
+#define        arm_load_memindex(inst,reg,basereg,indexreg)    \
+                       do { \
+                               arm_load_memindex_either((inst), (reg), (basereg), \
+                                                                                (indexreg), 2, 0); \
+                       } while (0)
+#define        arm_load_memindex_byte(inst,reg,basereg,indexreg)       \
+                       do { \
+                               arm_load_memindex_either((inst), (reg), (basereg), \
+                                                                            (indexreg), 0, 0x00400000); \
+                       } while (0)
+#define        arm_load_memindex_sbyte(inst,reg,basereg,indexreg)      \
+                       do { \
+                               arm_load_memindex_either((inst), (reg), (basereg), \
+                                                                            (indexreg), 0, 0x00400000); \
+                               arm_shift_reg_imm8((inst), ARM_SHL, (reg), (reg), 24); \
+                               arm_shift_reg_imm8((inst), ARM_SAR, (reg), (reg), 24); \
+                       } while (0)
+#define        arm_load_memindex_ushort(inst,reg,basereg,indexreg)     \
+                       do { \
+                               arm_alu_reg_reg((inst), ARM_ADD, ARM_WORK, (basereg), \
+                                                               (indexreg)); \
+                               arm_alu_reg_reg((inst), ARM_ADD, ARM_WORK, ARM_WORK, \
+                                                               (indexreg)); \
+                               arm_load_membase_byte((inst), (reg), ARM_WORK, 0); \
+                               arm_load_membase_byte((inst), ARM_WORK, ARM_WORK, 1); \
+                               arm_shift_reg_imm8((inst), ARM_SHL, ARM_WORK, ARM_WORK, 8); \
+                               arm_alu_reg_reg((inst), ARM_ORR, (reg), (reg), ARM_WORK); \
+                       } while (0)
+#define        arm_load_memindex_short(inst,reg,basereg,indexreg)      \
+                       do { \
+                               arm_alu_reg_reg((inst), ARM_ADD, ARM_WORK, (basereg), \
+                                                               (indexreg)); \
+                               arm_alu_reg_reg((inst), ARM_ADD, ARM_WORK, ARM_WORK, \
+                                                               (indexreg)); \
+                               arm_load_membase_byte((inst), (reg), ARM_WORK, 0); \
+                               arm_load_membase_byte((inst), ARM_WORK, ARM_WORK, 1); \
+                               arm_shift_reg_imm8((inst), ARM_SHL, ARM_WORK, ARM_WORK, 24); \
+                               arm_shift_reg_imm8((inst), ARM_SAR, ARM_WORK, ARM_WORK, 16); \
+                               arm_alu_reg_reg((inst), ARM_ORR, (reg), (reg), ARM_WORK); \
+                       } while (0)
+
+/*
+ * Store a value from a register into an indexed address.
+ *
+ * Note: storing a 16-bit value destroys the values in the base
+ * register and the source register.
+ */
+#define arm_store_memindex_either(inst,reg,basereg,indexreg,shift,mask)        \
+                       do { \
+                               *(inst)++ = arm_prefix(0x07800000 | (mask)) | \
+                                                       (((unsigned int)(basereg)) << 16) | \
+                                                       (((unsigned int)(reg)) << 12) | \
+                                                       (((unsigned int)(shift)) << 7) | \
+                                                        ((unsigned int)(indexreg)); \
+                       } while (0)
+#define        arm_store_memindex(inst,reg,basereg,indexreg)   \
+                       do { \
+                               arm_store_memindex_either((inst), (reg), (basereg), \
+                                                                                 (indexreg), 2, 0); \
+                       } while (0)
+#define        arm_store_memindex_byte(inst,reg,basereg,indexreg)      \
+                       do { \
+                               arm_store_memindex_either((inst), (reg), (basereg), \
+                                                                                 (indexreg), 0, 0x00400000); \
+                       } while (0)
+#define        arm_store_memindex_sbyte(inst,reg,basereg,indexreg)     \
+                       do { \
+                               arm_store_memindex_byte((inst), (reg), (basereg), \
+                                                                               (indexreg)); \
+                       } while (0)
+#define        arm_store_memindex_short(inst,reg,basereg,indexreg)     \
+                       do { \
+                               arm_store_memindex_either((inst), (reg), (basereg), \
+                                                                                 (indexreg), 1, 0x00400000); \
+                               arm_alu_reg_imm8((inst), ARM_ADD, (basereg), (basereg), 1); \
+                               arm_shift_reg_imm8((inst), ARM_SHR, (reg), (reg), 8); \
+                               arm_store_memindex_either((inst), (reg), (basereg), \
+                                                                                 (indexreg), 1, 0x00400000); \
+                       } while (0)
+#define        arm_store_memindex_ushort(inst,reg,basereg,indexreg)    \
+                       do { \
+                               arm_store_memindex_short((inst), (reg), \
+                                                                                (basereg), (indexreg)); \
+                       } while (0)
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _ARM_CODEGEN_H */
diff --git a/jit/jit-gen-x86.h b/jit/jit-gen-x86.h
new file mode 100644 (file)
index 0000000..9bb99a5
--- /dev/null
@@ -0,0 +1,1592 @@
+/*
+ * jit-gen-x86.h: Macros for generating x86 code
+ *
+ * Authors:
+ *   Paolo Molaro (lupus@ximian.com)
+ *   Intel Corporation (ORP Project)
+ *   Sergey Chaban (serge@wildwestsoftware.com)
+ *   Dietmar Maurer (dietmar@ximian.com)
+ * 
+ * Copyright (C)  2000 Intel Corporation.  All rights reserved.
+ * Copyright (C)  2001, 2002 Ximian, Inc.
+ *
+ * This file originated with the Mono project (www.go-mono.com), and may
+ * be redistributed under the terms of the Lesser General Public License.
+ */
+
+#ifndef JIT_GEN_X86_H
+#define JIT_GEN_X86_H
+#define        jit_assert(x)   break
+/*
+// x86 register numbers
+*/
+typedef enum {
+       X86_EAX = 0,
+       X86_ECX = 1,
+       X86_EDX = 2,
+       X86_EBX = 3,
+       X86_ESP = 4,
+       X86_EBP = 5,
+       X86_ESI = 6,
+       X86_EDI = 7,
+       X86_NREG
+} X86_Reg_No;
+/*
+// opcodes for alu instructions
+*/
+typedef enum {
+       X86_ADD = 0,
+       X86_OR  = 1,
+       X86_ADC = 2,
+       X86_SBB = 3,
+       X86_AND = 4,
+       X86_SUB = 5,
+       X86_XOR = 6,
+       X86_CMP = 7,
+       X86_NALU
+} X86_ALU_Opcode;
+/*
+// opcodes for shift instructions
+*/
+typedef enum {
+       X86_SHLD,
+       X86_SHLR,
+       X86_ROL = 0,
+       X86_ROR = 1,
+       X86_RCL = 2,
+       X86_RCR = 3,
+       X86_SHL = 4,
+       X86_SHR = 5,
+       X86_SAR = 7,
+       X86_NSHIFT = 8
+} X86_Shift_Opcode;
+/*
+// opcodes for floating-point instructions
+*/
+typedef enum {
+       X86_FADD  = 0,
+       X86_FMUL  = 1,
+       X86_FCOM  = 2,
+       X86_FCOMP = 3,
+       X86_FSUB  = 4,
+       X86_FSUBR = 5,
+       X86_FDIV  = 6,
+       X86_FDIVR = 7,
+       X86_NFP   = 8
+} X86_FP_Opcode;
+/*
+// integer conditions codes
+*/
+typedef enum {
+       X86_CC_EQ = 0, X86_CC_E = 0, X86_CC_Z = 0,
+       X86_CC_NE = 1, X86_CC_NZ = 1,
+       X86_CC_LT = 2, X86_CC_B = 2, X86_CC_C = 2, X86_CC_NAE = 2,
+       X86_CC_LE = 3, X86_CC_BE = 3, X86_CC_NA = 3,
+       X86_CC_GT = 4, X86_CC_A = 4, X86_CC_NBE = 4,
+       X86_CC_GE = 5, X86_CC_AE = 5, X86_CC_NB = 5, X86_CC_NC = 5,
+       X86_CC_LZ = 6, X86_CC_S = 6,
+       X86_CC_GEZ = 7, X86_CC_NS = 7,
+       X86_CC_P = 8, X86_CC_PE = 8,
+       X86_CC_NP = 9, X86_CC_PO = 9,
+       X86_CC_O = 10,
+       X86_CC_NO = 11,
+       X86_NCC
+} X86_CC;
+/*
+// prefix code
+*/
+typedef enum {
+       X86_LOCK_PREFIX = 0xF0,
+       X86_REPNZ_PREFIX = 0xF2,
+       X86_REPZ_PREFIX = 0xF3, 
+       X86_REP_PREFIX = 0xF3,
+       X86_CS_PREFIX = 0x2E,
+       X86_SS_PREFIX = 0x36,
+       X86_DS_PREFIX = 0x3E,
+       X86_ES_PREFIX = 0x26,
+       X86_FS_PREFIX = 0x64,
+       X86_GS_PREFIX = 0x65,
+       X86_OPERAND_PREFIX = 0x66,
+       X86_ADDRESS_PREFIX = 0x67
+} X86_Prefix;
+
+static const unsigned char 
+x86_cc_unsigned_map [X86_NCC] = {
+       0x74, /* eq  */
+       0x75, /* ne  */
+       0x72, /* lt  */
+       0x76, /* le  */
+       0x77, /* gt  */
+       0x73, /* ge  */
+       0x78, /* lz  */
+       0x79, /* gez */
+       0x7a, /* p   */
+       0x7b, /* np  */
+       0x70, /* o  */
+       0x71, /* no  */
+};
+
+static const unsigned char 
+x86_cc_signed_map [X86_NCC] = {
+       0x74, /* eq  */
+       0x75, /* ne  */
+       0x7c, /* lt  */
+       0x7e, /* le  */
+       0x7f, /* gt  */
+       0x7d, /* ge  */
+       0x78, /* lz  */
+       0x79, /* gez */
+       0x7a, /* p   */
+       0x7b, /* np  */
+       0x70, /* o  */
+       0x71, /* no  */
+};
+
+typedef union {
+       int val;
+       unsigned char b [4];
+} x86_imm_buf;
+
+#define X86_NOBASEREG (-1)
+
+/*
+// bitvector mask for callee-saved registers
+*/
+#define X86_ESI_MASK (1<<X86_ESI)
+#define X86_EDI_MASK (1<<X86_EDI)
+#define X86_EBX_MASK (1<<X86_EBX)
+#define X86_EBP_MASK (1<<X86_EBP)
+
+#define X86_CALLEE_REGS ((1<<X86_EAX) | (1<<X86_ECX) | (1<<X86_EDX))
+#define X86_CALLER_REGS ((1<<X86_EBX) | (1<<X86_EBP) | (1<<X86_ESI) | (1<<X86_EDI))
+#define X86_BYTE_REGS   ((1<<X86_EAX) | (1<<X86_ECX) | (1<<X86_EDX) | (1<<X86_EBX))
+
+#define X86_IS_SCRATCH(reg) (X86_CALLER_REGS & (1 << (reg))) /* X86_EAX, X86_ECX, or X86_EDX */
+#define X86_IS_CALLEE(reg)  (X86_CALLEE_REGS & (1 << (reg)))   /* X86_ESI, X86_EDI, X86_EBX, or X86_EBP */
+
+/*
+// Frame structure:
+//
+//      +--------------------------------+
+//      | in_arg[0]       = var[0]          |
+//      | in_arg[1]          = var[1]       |
+//      |            . . .                              |
+//      | in_arg[n_arg-1] = var[n_arg-1] |
+//      +--------------------------------+
+//      |       return IP                |
+//      +--------------------------------+
+//      |       saved EBP                | <-- frame pointer (EBP)
+//      +--------------------------------+
+//      |            ...                 |  n_extra
+//      +--------------------------------+
+//      |          var[n_arg]               |
+//      |          var[n_arg+1]             |  local variables area
+//      |          . . .                 |
+//      |          var[n_var-1]             | 
+//      +--------------------------------+
+//      |                                           |
+//      |                                           |  
+//      |              spill area               | area for spilling mimic stack
+//      |                                           |
+//      +--------------------------------|
+//      |          ebx                   |
+//      |          ebp [ESP_Frame only]  |
+//      |             esi                   |  0..3 callee-saved regs
+//      |          edi                   | <-- stack pointer (ESP)
+//      +--------------------------------+
+//      |      stk0                         |
+//      |      stk1                         |  operand stack area/
+//      |      . . .                        |  out args
+//      |      stkn-1                       |
+//      +--------------------------------|
+//
+//
+*/
+
+
+/*
+ * useful building blocks
+ */
+#define x86_address_byte(inst,m,o,r) do { *(inst)++ = ((((m)&0x03)<<6)|(((o)&0x07)<<3)|(((r)&0x07))); } while (0)
+#define x86_imm_emit32(inst,imm)     \
+       do {    \
+                       x86_imm_buf imb; imb.val = (int) (imm); \
+                       *(inst)++ = imb.b [0];  \
+                       *(inst)++ = imb.b [1];  \
+                       *(inst)++ = imb.b [2];  \
+                       *(inst)++ = imb.b [3];  \
+       } while (0)
+#define x86_imm_emit16(inst,imm)     do { *(short*)(inst) = (imm); (inst) += 2; } while (0)
+#define x86_imm_emit8(inst,imm)      do { *(inst) = (unsigned char)((imm) & 0xff); ++(inst); } while (0)
+#define x86_is_imm8(imm)             (((int)(imm) >= -128 && (int)(imm) <= 127))
+#define x86_is_imm16(imm)            (((int)(imm) >= -(1<<16) && (int)(imm) <= ((1<<16)-1)))
+
+#define x86_reg_emit(inst,r,regno)   do { x86_address_byte ((inst), 3, (r), (regno)); } while (0)
+#define x86_reg8_emit(inst,r,regno,is_rh,is_rnoh)   do {x86_address_byte ((inst), 3, (is_rh)?((r)|4):(r), (is_rnoh)?((regno)|4):(regno));} while (0)
+#define x86_regp_emit(inst,r,regno)  do { x86_address_byte ((inst), 0, (r), (regno)); } while (0)
+#define x86_mem_emit(inst,r,disp)    do { x86_address_byte ((inst), 0, (r), 5); x86_imm_emit32((inst), (disp)); } while (0)
+
+#define x86_membase_emit(inst,r,basereg,disp)  do {\
+       if ((basereg) == X86_ESP) {     \
+               if ((disp) == 0) {      \
+                       x86_address_byte ((inst), 0, (r), X86_ESP);     \
+                       x86_address_byte ((inst), 0, X86_ESP, X86_ESP); \
+               } else if (x86_is_imm8((disp))) {       \
+                       x86_address_byte ((inst), 1, (r), X86_ESP);     \
+                       x86_address_byte ((inst), 0, X86_ESP, X86_ESP); \
+                       x86_imm_emit8 ((inst), (disp)); \
+               } else {        \
+                       x86_address_byte ((inst), 2, (r), X86_ESP);     \
+                       x86_address_byte ((inst), 0, X86_ESP, X86_ESP); \
+                       x86_imm_emit32 ((inst), (disp));        \
+               }       \
+               break;  \
+       }       \
+       if ((disp) == 0 && (basereg) != X86_EBP) {      \
+               x86_address_byte ((inst), 0, (r), (basereg));   \
+               break;  \
+       }       \
+       if (x86_is_imm8((disp))) {      \
+               x86_address_byte ((inst), 1, (r), (basereg));   \
+               x86_imm_emit8 ((inst), (disp)); \
+       } else {        \
+               x86_address_byte ((inst), 2, (r), (basereg));   \
+               x86_imm_emit32 ((inst), (disp));        \
+       }       \
+       } while (0)
+
+#define x86_memindex_emit(inst,r,basereg,disp,indexreg,shift)  \
+       do {    \
+               if ((basereg) == X86_NOBASEREG) {       \
+                       x86_address_byte ((inst), 0, (r), 4);   \
+                       x86_address_byte ((inst), (shift), (indexreg), 5);      \
+                       x86_imm_emit32 ((inst), (disp));        \
+               } else if ((disp) == 0 && (basereg) != X86_EBP) {       \
+                       x86_address_byte ((inst), 0, (r), 4);   \
+                       x86_address_byte ((inst), (shift), (indexreg), (basereg));      \
+               } else if (x86_is_imm8((disp))) {       \
+                       x86_address_byte ((inst), 1, (r), 4);   \
+                       x86_address_byte ((inst), (shift), (indexreg), (basereg));      \
+                       x86_imm_emit8 ((inst), (disp)); \
+               } else {        \
+                       x86_address_byte ((inst), 0, (r), 4);   \
+                       x86_address_byte ((inst), (shift), (indexreg), 5);      \
+                       x86_imm_emit32 ((inst), (disp));        \
+               }       \
+       } while (0)
+
+/*
+ * target is the position in the code where to jump to:
+ * target = code;
+ * .. output loop code...
+ * x86_mov_reg_imm (code, X86_EAX, 0);
+ * loop = code;
+ * x86_loop (code, -1);
+ * ... finish method
+ *
+ * patch displacement
+ * x86_patch (loop, target);
+ *
+ * ins should point at the start of the instruction that encodes a target.
+ * the instruction is inspected for validity and the correct displacement
+ * is inserted.
+ */
+#define x86_patch(ins,target)  \
+       do {    \
+               unsigned char* pos = (ins) + 1; \
+               int disp, size = 0;     \
+               switch (*(unsigned char*)(ins)) {       \
+               case 0xe8: case 0xe9: ++size; break; /* call, jump32 */ \
+               case 0x0f: if (!(*pos >= 0x70 && *pos <= 0x8f)) jit_assert (0); \
+                  ++size; ++pos; break; /* prefix for 32-bit disp */   \
+               case 0xe0: case 0xe1: case 0xe2: /* loop */     \
+               case 0xeb: /* jump8 */  \
+               /* conditional jump opcodes */  \
+               case 0x70: case 0x71: case 0x72: case 0x73:     \
+               case 0x74: case 0x75: case 0x76: case 0x77:     \
+               case 0x78: case 0x79: case 0x7a: case 0x7b:     \
+               case 0x7c: case 0x7d: case 0x7e: case 0x7f:     \
+                       break;  \
+               default: jit_assert (0);        \
+               }       \
+               disp = (target) - pos;  \
+               if (size) x86_imm_emit32 (pos, disp - 4);       \
+               else if (x86_is_imm8 (disp - 1)) x86_imm_emit8 (pos, disp - 1); \
+               else jit_assert (0);    \
+       } while (0)
+
+#define x86_breakpoint(inst) \
+       do {    \
+               *(inst)++ = 0xcc;       \
+       } while (0)
+
+#define x86_cld(inst) do { *(inst)++ =(unsigned char)0xfc; } while (0)
+#define x86_stosb(inst) do { *(inst)++ =(unsigned char)0xaa; } while (0)
+#define x86_stosl(inst) do { *(inst)++ =(unsigned char)0xab; } while (0)
+
+#define x86_prefix(inst,p) do { *(inst)++ =(unsigned char) (p); } while (0)
+
+#define x86_rdtsc(inst) \
+       do {    \
+               *(inst)++ = 0x0f;       \
+               *(inst)++ = 0x31;       \
+       } while (0)
+
+#define x86_cmpxchg_reg_reg(inst,dreg,reg)     \
+       do {    \
+               *(inst)++ = (unsigned char)0x0f;        \
+               *(inst)++ = (unsigned char)0xb1;        \
+               x86_reg_emit ((inst), (reg), (dreg));   \
+       } while (0)
+       
+#define x86_cmpxchg_mem_reg(inst,mem,reg)      \
+       do {    \
+               *(inst)++ = (unsigned char)0x0f;        \
+               *(inst)++ = (unsigned char)0xb1;        \
+               x86_mem_emit ((inst), (reg), (mem));    \
+       } while (0)
+       
+#define x86_cmpxchg_membase_reg(inst,basereg,disp,reg) \
+       do {    \
+               *(inst)++ = (unsigned char)0x0f;        \
+               *(inst)++ = (unsigned char)0xb1;        \
+               x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+       } while (0)
+
+#define x86_xchg_reg_reg(inst,dreg,reg,size)   \
+       do {    \
+               if ((size) == 1)        \
+                       *(inst)++ = (unsigned char)0x86;        \
+               else    \
+                       *(inst)++ = (unsigned char)0x87;        \
+               x86_reg_emit ((inst), (reg), (dreg));   \
+       } while (0)
+
+#define x86_xchg_mem_reg(inst,mem,reg,size)    \
+       do {    \
+               if ((size) == 1)        \
+                       *(inst)++ = (unsigned char)0x86;        \
+               else    \
+                       *(inst)++ = (unsigned char)0x87;        \
+               x86_mem_emit ((inst), (reg), (mem));    \
+       } while (0)
+
+#define x86_xchg_membase_reg(inst,basereg,disp,reg,size)       \
+       do {    \
+               if ((size) == 1)        \
+                       *(inst)++ = (unsigned char)0x86;        \
+               else    \
+                       *(inst)++ = (unsigned char)0x87;        \
+               x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+       } while (0)
+
+#define x86_inc_mem(inst,mem)  \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_mem_emit ((inst), 0, (mem));        \
+       } while (0)
+
+#define x86_inc_membase(inst,basereg,disp)     \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_membase_emit ((inst), 0, (basereg), (disp));        \
+       } while (0)
+
+#define x86_inc_reg(inst,reg) do { *(inst)++ = (unsigned char)0x40 + (reg); } while (0)
+
+#define x86_dec_mem(inst,mem)  \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_mem_emit ((inst), 1, (mem));        \
+       } while (0)
+
+#define x86_dec_membase(inst,basereg,disp)     \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_membase_emit ((inst), 1, (basereg), (disp));        \
+       } while (0)
+
+#define x86_dec_reg(inst,reg) do { *(inst)++ = (unsigned char)0x48 + (reg); } while (0)
+
+#define x86_not_mem(inst,mem)  \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_mem_emit ((inst), 2, (mem));        \
+       } while (0)
+
+#define x86_not_membase(inst,basereg,disp)     \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_membase_emit ((inst), 2, (basereg), (disp));        \
+       } while (0)
+
+#define x86_not_reg(inst,reg)  \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_reg_emit ((inst), 2, (reg));        \
+       } while (0)
+
+#define x86_neg_mem(inst,mem)  \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_mem_emit ((inst), 3, (mem));        \
+       } while (0)
+
+#define x86_neg_membase(inst,basereg,disp)     \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_membase_emit ((inst), 3, (basereg), (disp));        \
+       } while (0)
+
+#define x86_neg_reg(inst,reg)  \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_reg_emit ((inst), 3, (reg));        \
+       } while (0)
+
+#define x86_nop(inst) do { *(inst)++ = (unsigned char)0x90; } while (0)
+
+#define x86_alu_reg_imm(inst,opc,reg,imm)      \
+       do {    \
+               if ((reg) == X86_EAX) { \
+                       *(inst)++ = (((unsigned char)(opc)) << 3) + 5;  \
+                       x86_imm_emit32 ((inst), (imm)); \
+                       break;  \
+               }       \
+               if (x86_is_imm8((imm))) {       \
+                       *(inst)++ = (unsigned char)0x83;        \
+                       x86_reg_emit ((inst), (opc), (reg));    \
+                       x86_imm_emit8 ((inst), (imm));  \
+               } else {        \
+                       *(inst)++ = (unsigned char)0x81;        \
+                       x86_reg_emit ((inst), (opc), (reg));    \
+                       x86_imm_emit32 ((inst), (imm)); \
+               }       \
+       } while (0)
+
+#define x86_alu_mem_imm(inst,opc,mem,imm)      \
+       do {    \
+               if (x86_is_imm8((imm))) {       \
+                       *(inst)++ = (unsigned char)0x83;        \
+                       x86_mem_emit ((inst), (opc), (mem));    \
+                       x86_imm_emit8 ((inst), (imm));  \
+               } else {        \
+                       *(inst)++ = (unsigned char)0x81;        \
+                       x86_mem_emit ((inst), (opc), (mem));    \
+                       x86_imm_emit32 ((inst), (imm)); \
+               }       \
+       } while (0)
+
+#define x86_alu_membase_imm(inst,opc,basereg,disp,imm)         \
+       do {    \
+               if (x86_is_imm8((imm))) {       \
+                       *(inst)++ = (unsigned char)0x83;        \
+                       x86_membase_emit ((inst), (opc), (basereg), (disp));    \
+                       x86_imm_emit8 ((inst), (imm));  \
+               } else {        \
+                       *(inst)++ = (unsigned char)0x81;        \
+                       x86_membase_emit ((inst), (opc), (basereg), (disp));    \
+                       x86_imm_emit32 ((inst), (imm)); \
+               }       \
+       } while (0)
+
+#define x86_alu_mem_reg(inst,opc,mem,reg)      \
+       do {    \
+               *(inst)++ = (((unsigned char)(opc)) << 3) + 1;  \
+               x86_mem_emit ((inst), (reg), (mem));    \
+       } while (0)
+
+#define x86_alu_membase_reg(inst,opc,basereg,disp,reg) \
+       do {    \
+               *(inst)++ = (((unsigned char)(opc)) << 3) + 1;  \
+               x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+       } while (0)
+
+#define x86_alu_reg_reg(inst,opc,dreg,reg)     \
+       do {    \
+               *(inst)++ = (((unsigned char)(opc)) << 3) + 3;  \
+               x86_reg_emit ((inst), (dreg), (reg));   \
+       } while (0)
+
+/**
+ * @x86_alu_reg8_reg8:
+ * Supports ALU operations between two 8-bit registers.
+ * dreg := dreg opc reg
+ * X86_Reg_No enum is used to specify the registers.
+ * Additionally is_*_h flags are used to specify what part
+ * of a given 32-bit register is used - high (TRUE) or low (FALSE).
+ * For example: dreg = X86_EAX, is_dreg_h = TRUE -> use AH
+ */
+#define x86_alu_reg8_reg8(inst,opc,dreg,reg,is_dreg_h,is_reg_h)        \
+       do {    \
+               *(inst)++ = (((unsigned char)(opc)) << 3) + 2;  \
+               x86_reg8_emit ((inst), (dreg), (reg), (is_dreg_h), (is_reg_h)); \
+       } while (0)
+
+#define x86_alu_reg_mem(inst,opc,reg,mem)      \
+       do {    \
+               *(inst)++ = (((unsigned char)(opc)) << 3) + 3;  \
+               x86_mem_emit ((inst), (reg), (mem));    \
+       } while (0)
+
+#define x86_alu_reg_membase(inst,opc,reg,basereg,disp) \
+       do {    \
+               *(inst)++ = (((unsigned char)(opc)) << 3) + 3;  \
+               x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+       } while (0)
+
+#define x86_test_reg_imm(inst,reg,imm) \
+       do {    \
+               if ((reg) == X86_EAX) { \
+                       *(inst)++ = (unsigned char)0xa9;        \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xf7;        \
+                       x86_reg_emit ((inst), 0, (reg));        \
+               }       \
+               x86_imm_emit32 ((inst), (imm)); \
+       } while (0)
+
+#define x86_test_mem_imm(inst,mem,imm) \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_mem_emit ((inst), 0, (mem));        \
+               x86_imm_emit32 ((inst), (imm)); \
+       } while (0)
+
+#define x86_test_membase_imm(inst,basereg,disp,imm)    \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_membase_emit ((inst), 0, (basereg), (disp));        \
+               x86_imm_emit32 ((inst), (imm)); \
+       } while (0)
+
+#define x86_test_reg_reg(inst,dreg,reg)        \
+       do {    \
+               *(inst)++ = (unsigned char)0x85;        \
+               x86_reg_emit ((inst), (reg), (dreg));   \
+       } while (0)
+
+#define x86_test_mem_reg(inst,mem,reg) \
+       do {    \
+               *(inst)++ = (unsigned char)0x85;        \
+               x86_mem_emit ((inst), (reg), (mem));    \
+       } while (0)
+
+#define x86_test_membase_reg(inst,basereg,disp,reg)    \
+       do {    \
+               *(inst)++ = (unsigned char)0x85;        \
+               x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+       } while (0)
+
+#define x86_shift_reg_imm(inst,opc,reg,imm)    \
+       do {    \
+               if ((imm) == 1) {       \
+                       *(inst)++ = (unsigned char)0xd1;        \
+                       x86_reg_emit ((inst), (opc), (reg));    \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xc1;        \
+                       x86_reg_emit ((inst), (opc), (reg));    \
+                       x86_imm_emit8 ((inst), (imm));  \
+               }       \
+       } while (0)
+
+#define x86_shift_mem_imm(inst,opc,mem,imm)    \
+       do {    \
+               if ((imm) == 1) {       \
+                       *(inst)++ = (unsigned char)0xd1;        \
+                       x86_mem_emit ((inst), (opc), (mem));    \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xc1;        \
+                       x86_mem_emit ((inst), (opc), (mem));    \
+                       x86_imm_emit8 ((inst), (imm));  \
+               }       \
+       } while (0)
+
+#define x86_shift_membase_imm(inst,opc,basereg,disp,imm)       \
+       do {    \
+               if ((imm) == 1) {       \
+                       *(inst)++ = (unsigned char)0xd1;        \
+                       x86_membase_emit ((inst), (opc), (basereg), (disp));    \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xc1;        \
+                       x86_membase_emit ((inst), (opc), (basereg), (disp));    \
+                       x86_imm_emit8 ((inst), (imm));  \
+               }       \
+       } while (0)
+
+#define x86_shift_reg(inst,opc,reg)    \
+       do {    \
+               *(inst)++ = (unsigned char)0xd3;        \
+               x86_reg_emit ((inst), (opc), (reg));    \
+       } while (0)
+
+#define x86_shift_mem(inst,opc,mem)    \
+       do {    \
+               *(inst)++ = (unsigned char)0xd3;        \
+               x86_mem_emit ((inst), (opc), (mem));    \
+       } while (0)
+
+#define x86_shift_membase(inst,opc,basereg,disp)       \
+       do {    \
+               *(inst)++ = (unsigned char)0xd3;        \
+               x86_membase_emit ((inst), (opc), (basereg), (disp));    \
+       } while (0)
+
+/*
+ * Multi op shift missing.
+ */
+
+#define x86_shrd_reg(inst,dreg,reg)                     \
+        do {                                            \
+               *(inst)++ = (unsigned char)0x0f;        \
+               *(inst)++ = (unsigned char)0xad;        \
+               x86_reg_emit ((inst), (reg), (dreg));   \
+       } while (0)
+
+#define x86_shrd_reg_imm(inst,dreg,reg,shamt)           \
+        do {                                            \
+               *(inst)++ = (unsigned char)0x0f;        \
+               *(inst)++ = (unsigned char)0xac;        \
+               x86_reg_emit ((inst), (reg), (dreg));   \
+               x86_imm_emit8 ((inst), (shamt));        \
+       } while (0)
+
+#define x86_shld_reg(inst,dreg,reg)                     \
+        do {                                            \
+               *(inst)++ = (unsigned char)0x0f;        \
+               *(inst)++ = (unsigned char)0xa5;        \
+               x86_reg_emit ((inst), (reg), (dreg));   \
+       } while (0)
+
+#define x86_shld_reg_imm(inst,dreg,reg,shamt)           \
+        do {                                            \
+               *(inst)++ = (unsigned char)0x0f;        \
+               *(inst)++ = (unsigned char)0xa4;        \
+               x86_reg_emit ((inst), (reg), (dreg));   \
+               x86_imm_emit8 ((inst), (shamt));        \
+       } while (0)
+
+/*
+ * EDX:EAX = EAX * rm
+ */
+#define x86_mul_reg(inst,reg,is_signed)        \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_reg_emit ((inst), 4 + ((is_signed) ? 1 : 0), (reg));        \
+       } while (0)
+
+#define x86_mul_mem(inst,mem,is_signed)        \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_mem_emit ((inst), 4 + ((is_signed) ? 1 : 0), (mem));        \
+       } while (0)
+
+#define x86_mul_membase(inst,basereg,disp,is_signed)   \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_membase_emit ((inst), 4 + ((is_signed) ? 1 : 0), (basereg), (disp));        \
+       } while (0)
+
+/*
+ * r *= rm
+ */
+#define x86_imul_reg_reg(inst,dreg,reg)        \
+       do {    \
+               *(inst)++ = (unsigned char)0x0f;        \
+               *(inst)++ = (unsigned char)0xaf;        \
+               x86_reg_emit ((inst), (dreg), (reg));   \
+       } while (0)
+
+#define x86_imul_reg_mem(inst,reg,mem) \
+       do {    \
+               *(inst)++ = (unsigned char)0x0f;        \
+               *(inst)++ = (unsigned char)0xaf;        \
+               x86_mem_emit ((inst), (reg), (mem));    \
+       } while (0)
+
+#define x86_imul_reg_membase(inst,reg,basereg,disp)    \
+       do {    \
+               *(inst)++ = (unsigned char)0x0f;        \
+               *(inst)++ = (unsigned char)0xaf;        \
+               x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+       } while (0)
+
+/*
+ * dreg = rm * imm
+ */
+#define x86_imul_reg_reg_imm(inst,dreg,reg,imm)        \
+       do {    \
+               if (x86_is_imm8 ((imm))) {      \
+                       *(inst)++ = (unsigned char)0x6b;        \
+                       x86_reg_emit ((inst), (dreg), (reg));   \
+                       x86_imm_emit8 ((inst), (imm));  \
+               } else {        \
+                       *(inst)++ = (unsigned char)0x69;        \
+                       x86_reg_emit ((inst), (dreg), (reg));   \
+                       x86_imm_emit32 ((inst), (imm)); \
+               }       \
+       } while (0)
+
+#define x86_imul_reg_mem_imm(inst,reg,mem,imm) \
+       do {    \
+               if (x86_is_imm8 ((imm))) {      \
+                       *(inst)++ = (unsigned char)0x6b;        \
+                       x86_mem_emit ((inst), (reg), (mem));    \
+                       x86_imm_emit8 ((inst), (imm));  \
+               } else {        \
+                       *(inst)++ = (unsigned char)0x69;        \
+                       x86_reg_emit ((inst), (reg), (mem));    \
+                       x86_imm_emit32 ((inst), (imm)); \
+               }       \
+       } while (0)
+
+#define x86_imul_reg_membase_imm(inst,reg,basereg,disp,imm)    \
+       do {    \
+               if (x86_is_imm8 ((imm))) {      \
+                       *(inst)++ = (unsigned char)0x6b;        \
+                       x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+                       x86_imm_emit8 ((inst), (imm));  \
+               } else {        \
+                       *(inst)++ = (unsigned char)0x69;        \
+                       x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+                       x86_imm_emit32 ((inst), (imm)); \
+               }       \
+       } while (0)
+
+/*
+ * divide EDX:EAX by rm;
+ * eax = quotient, edx = remainder
+ */
+
+#define x86_div_reg(inst,reg,is_signed)        \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_reg_emit ((inst), 6 + ((is_signed) ? 1 : 0), (reg));        \
+       } while (0)
+
+#define x86_div_mem(inst,mem,is_signed)        \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_mem_emit ((inst), 6 + ((is_signed) ? 1 : 0), (mem));        \
+       } while (0)
+
+#define x86_div_membase(inst,basereg,disp,is_signed)   \
+       do {    \
+               *(inst)++ = (unsigned char)0xf7;        \
+               x86_membase_emit ((inst), 6 + ((is_signed) ? 1 : 0), (basereg), (disp));        \
+       } while (0)
+
+#define x86_mov_mem_reg(inst,mem,reg,size)     \
+       do {    \
+               switch ((size)) {       \
+               case 1: *(inst)++ = (unsigned char)0x88; break; \
+               case 2: *(inst)++ = (unsigned char)0x66; /* fall through */     \
+               case 4: *(inst)++ = (unsigned char)0x89; break; \
+               default: jit_assert (0);        \
+               }       \
+               x86_mem_emit ((inst), (reg), (mem));    \
+       } while (0)
+
+#define x86_mov_regp_reg(inst,regp,reg,size)   \
+       do {    \
+               switch ((size)) {       \
+               case 1: *(inst)++ = (unsigned char)0x88; break; \
+               case 2: *(inst)++ = (unsigned char)0x66; /* fall through */     \
+               case 4: *(inst)++ = (unsigned char)0x89; break; \
+               default: jit_assert (0);        \
+               }       \
+               x86_regp_emit ((inst), (reg), (regp));  \
+       } while (0)
+
+#define x86_mov_membase_reg(inst,basereg,disp,reg,size)        \
+       do {    \
+               switch ((size)) {       \
+               case 1: *(inst)++ = (unsigned char)0x88; break; \
+               case 2: *(inst)++ = (unsigned char)0x66; /* fall through */     \
+               case 4: *(inst)++ = (unsigned char)0x89; break; \
+               default: jit_assert (0);        \
+               }       \
+               x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+       } while (0)
+
+#define x86_mov_memindex_reg(inst,basereg,disp,indexreg,shift,reg,size)        \
+       do {    \
+               switch ((size)) {       \
+               case 1: *(inst)++ = (unsigned char)0x88; break; \
+               case 2: *(inst)++ = (unsigned char)0x66; /* fall through */     \
+               case 4: *(inst)++ = (unsigned char)0x89; break; \
+               default: jit_assert (0);        \
+               }       \
+               x86_memindex_emit ((inst), (reg), (basereg), (disp), (indexreg), (shift));      \
+       } while (0)
+
+#define x86_mov_reg_reg(inst,dreg,reg,size)    \
+       do {    \
+               switch ((size)) {       \
+               case 1: *(inst)++ = (unsigned char)0x8a; break; \
+               case 2: *(inst)++ = (unsigned char)0x66; /* fall through */     \
+               case 4: *(inst)++ = (unsigned char)0x8b; break; \
+               default: jit_assert (0);        \
+               }       \
+               x86_reg_emit ((inst), (dreg), (reg));   \
+       } while (0)
+
+#define x86_mov_reg_mem(inst,reg,mem,size)     \
+       do {    \
+               switch ((size)) {       \
+               case 1: *(inst)++ = (unsigned char)0x8a; break; \
+               case 2: *(inst)++ = (unsigned char)0x66; /* fall through */     \
+               case 4: *(inst)++ = (unsigned char)0x8b; break; \
+               default: jit_assert (0);        \
+               }       \
+               x86_mem_emit ((inst), (reg), (mem));    \
+       } while (0)
+
+#define x86_mov_reg_membase(inst,reg,basereg,disp,size)        \
+       do {    \
+               switch ((size)) {       \
+               case 1: *(inst)++ = (unsigned char)0x8a; break; \
+               case 2: *(inst)++ = (unsigned char)0x66; /* fall through */     \
+               case 4: *(inst)++ = (unsigned char)0x8b; break; \
+               default: jit_assert (0);        \
+               }       \
+               x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+       } while (0)
+
+#define x86_mov_reg_memindex(inst,reg,basereg,disp,indexreg,shift,size)        \
+       do {    \
+               switch ((size)) {       \
+               case 1: *(inst)++ = (unsigned char)0x8a; break; \
+               case 2: *(inst)++ = (unsigned char)0x66; /* fall through */     \
+               case 4: *(inst)++ = (unsigned char)0x8b; break; \
+               default: jit_assert (0);        \
+               }       \
+               x86_memindex_emit ((inst), (reg), (basereg), (disp), (indexreg), (shift));      \
+       } while (0)
+
+/*
+ * Note: x86_clear_reg () chacnges the condition code!
+ */
+#define x86_clear_reg(inst,reg) x86_alu_reg_reg((inst), X86_XOR, (reg), (reg))
+
+#define x86_mov_reg_imm(inst,reg,imm)  \
+       do {    \
+               *(inst)++ = (unsigned char)0xb8 + (reg);        \
+               x86_imm_emit32 ((inst), (imm)); \
+       } while (0)
+
+#define x86_mov_mem_imm(inst,mem,imm,size)     \
+       do {    \
+               if ((size) == 1) {      \
+                       *(inst)++ = (unsigned char)0xc6;        \
+                       x86_mem_emit ((inst), 0, (mem));        \
+                       x86_imm_emit8 ((inst), (imm));  \
+               } else if ((size) == 2) {       \
+                       *(inst)++ = (unsigned char)0x66;        \
+                       *(inst)++ = (unsigned char)0xc7;        \
+                       x86_mem_emit ((inst), 0, (mem));        \
+                       x86_imm_emit16 ((inst), (imm)); \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xc7;        \
+                       x86_mem_emit ((inst), 0, (mem));        \
+                       x86_imm_emit32 ((inst), (imm)); \
+               }       \
+       } while (0)
+
+#define x86_mov_membase_imm(inst,basereg,disp,imm,size)        \
+       do {    \
+               if ((size) == 1) {      \
+                       *(inst)++ = (unsigned char)0xc6;        \
+                       x86_membase_emit ((inst), 0, (basereg), (disp));        \
+                       x86_imm_emit8 ((inst), (imm));  \
+               } else if ((size) == 2) {       \
+                       *(inst)++ = (unsigned char)0x66;        \
+                       *(inst)++ = (unsigned char)0xc7;        \
+                       x86_membase_emit ((inst), 0, (basereg), (disp));        \
+                       x86_imm_emit16 ((inst), (imm)); \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xc7;        \
+                       x86_membase_emit ((inst), 0, (basereg), (disp));        \
+                       x86_imm_emit32 ((inst), (imm)); \
+               }       \
+       } while (0)
+
+#define x86_mov_memindex_imm(inst,basereg,disp,indexreg,shift,imm,size)        \
+       do {    \
+               if ((size) == 1) {      \
+                       *(inst)++ = (unsigned char)0xc6;        \
+                       x86_memindex_emit ((inst), 0, (basereg), (disp), (indexreg), (shift));  \
+                       x86_imm_emit8 ((inst), (imm));  \
+               } else if ((size) == 2) {       \
+                       *(inst)++ = (unsigned char)0x66;        \
+                       *(inst)++ = (unsigned char)0xc7;        \
+                       x86_memindex_emit ((inst), 0, (basereg), (disp), (indexreg), (shift));  \
+                       x86_imm_emit16 ((inst), (imm)); \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xc7;        \
+                       x86_memindex_emit ((inst), 0, (basereg), (disp), (indexreg), (shift));  \
+                       x86_imm_emit32 ((inst), (imm)); \
+               }       \
+       } while (0)
+
+#define x86_lea_mem(inst,reg,mem)      \
+       do {    \
+               *(inst)++ = (unsigned char)0x8d;        \
+               x86_mem_emit ((inst), (reg), (mem));    \
+       } while (0)
+
+#define x86_lea_membase(inst,reg,basereg,disp) \
+       do {    \
+               *(inst)++ = (unsigned char)0x8d;        \
+               x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+       } while (0)
+
+#define x86_lea_memindex(inst,reg,basereg,disp,indexreg,shift) \
+       do {    \
+               *(inst)++ = (unsigned char)0x8d;        \
+               x86_memindex_emit ((inst), (reg), (basereg), (disp), (indexreg), (shift));      \
+       } while (0)
+
+#define x86_widen_reg(inst,dreg,reg,is_signed,is_half) \
+       do {    \
+               unsigned char op = 0xb6;        \
+               *(inst)++ = (unsigned char)0x0f;        \
+               if ((is_signed)) op += 0x08;    \
+               if ((is_half)) op += 0x01;      \
+               *(inst)++ = op; \
+               x86_reg_emit ((inst), (dreg), (reg));   \
+       } while (0)
+
+#define x86_widen_mem(inst,dreg,mem,is_signed,is_half) \
+       do {    \
+               unsigned char op = 0xb6;        \
+               *(inst)++ = (unsigned char)0x0f;        \
+               if ((is_signed)) op += 0x08;    \
+               if ((is_half)) op += 0x01;      \
+               *(inst)++ = op; \
+               x86_mem_emit ((inst), (dreg), (mem));   \
+       } while (0)
+
+#define x86_widen_membase(inst,dreg,basereg,disp,is_signed,is_half)    \
+       do {    \
+               unsigned char op = 0xb6;        \
+               *(inst)++ = (unsigned char)0x0f;        \
+               if ((is_signed)) op += 0x08;    \
+               if ((is_half)) op += 0x01;      \
+               *(inst)++ = op; \
+               x86_membase_emit ((inst), (dreg), (basereg), (disp));   \
+       } while (0)
+
+#define x86_widen_memindex(inst,dreg,basereg,disp,indexreg,shift,is_signed,is_half)    \
+       do {    \
+               unsigned char op = 0xb6;        \
+               *(inst)++ = (unsigned char)0x0f;        \
+               if ((is_signed)) op += 0x08;    \
+               if ((is_half)) op += 0x01;      \
+               *(inst)++ = op; \
+               x86_memindex_emit ((inst), (dreg), (basereg), (disp), (indexreg), (shift));     \
+       } while (0)
+
+#define x86_cdq(inst)  do { *(inst)++ = (unsigned char)0x99; } while (0)
+#define x86_wait(inst) do { *(inst)++ = (unsigned char)0x9b; } while (0)
+
+#define x86_fp_op_mem(inst,opc,mem,is_double)  \
+       do {    \
+               *(inst)++ = (is_double) ? (unsigned char)0xdc : (unsigned char)0xd8;    \
+               x86_mem_emit ((inst), (opc), (mem));    \
+       } while (0)
+
+#define x86_fp_op_membase(inst,opc,basereg,disp,is_double)     \
+       do {    \
+               *(inst)++ = (is_double) ? (unsigned char)0xdc : (unsigned char)0xd8;    \
+               x86_membase_emit ((inst), (opc), (basereg), (disp));    \
+       } while (0)
+
+#define x86_fp_op(inst,opc,index)      \
+       do {    \
+               *(inst)++ = (unsigned char)0xd8;        \
+               *(inst)++ = (unsigned char)0xc0+((opc)<<3)+((index)&0x07);      \
+       } while (0)
+
+#define x86_fp_op_reg(inst,opc,index,pop_stack)        \
+       do {    \
+               static const unsigned char map[] = { 0, 1, 2, 3, 5, 4, 7, 6, 8};        \
+               *(inst)++ = (pop_stack) ? (unsigned char)0xde : (unsigned char)0xdc;    \
+               *(inst)++ = (unsigned char)0xc0+(map[(opc)]<<3)+((index)&0x07); \
+       } while (0)
+
+/**
+ * @x86_fp_int_op_membase
+ * Supports FPU operations between ST(0) and integer operand in memory.
+ * Operation encoded using X86_FP_Opcode enum.
+ * Operand is addressed by [basereg + disp].
+ * is_int specifies whether operand is int32 (TRUE) or int16 (FALSE).
+ */
+#define x86_fp_int_op_membase(inst,opc,basereg,disp,is_int)    \
+       do {    \
+               *(inst)++ = (is_int) ? (unsigned char)0xda : (unsigned char)0xde;       \
+               x86_membase_emit ((inst), opc, (basereg), (disp));      \
+       } while (0)
+
+#define x86_fstp(inst,index)   \
+       do {    \
+               *(inst)++ = (unsigned char)0xdd;        \
+               *(inst)++ = (unsigned char)0xd8+(index);        \
+       } while (0)
+
+#define x86_fcompp(inst)       \
+       do {    \
+               *(inst)++ = (unsigned char)0xde;        \
+               *(inst)++ = (unsigned char)0xd9;        \
+       } while (0)
+
+#define x86_fucompp(inst)      \
+       do {    \
+               *(inst)++ = (unsigned char)0xda;        \
+               *(inst)++ = (unsigned char)0xe9;        \
+       } while (0)
+
+#define x86_fnstsw(inst)       \
+       do {    \
+               *(inst)++ = (unsigned char)0xdf;        \
+               *(inst)++ = (unsigned char)0xe0;        \
+       } while (0)
+
+#define x86_fnstcw(inst,mem)   \
+       do {    \
+               *(inst)++ = (unsigned char)0xd9;        \
+               x86_mem_emit ((inst), 7, (mem));        \
+       } while (0)
+
+#define x86_fnstcw_membase(inst,basereg,disp)  \
+       do {    \
+               *(inst)++ = (unsigned char)0xd9;        \
+               x86_membase_emit ((inst), 7, (basereg), (disp));        \
+       } while (0)
+
+#define x86_fldcw(inst,mem)    \
+       do {    \
+               *(inst)++ = (unsigned char)0xd9;        \
+               x86_mem_emit ((inst), 5, (mem));        \
+       } while (0)
+
+#define x86_fldcw_membase(inst,basereg,disp)   \
+       do {    \
+               *(inst)++ = (unsigned char)0xd9;        \
+               x86_membase_emit ((inst), 5, (basereg), (disp));        \
+       } while (0)
+
+#define x86_fchs(inst) \
+       do {    \
+               *(inst)++ = (unsigned char)0xd9;        \
+               *(inst)++ = (unsigned char)0xe0;        \
+       } while (0)
+
+#define x86_frem(inst) \
+       do {    \
+               *(inst)++ = (unsigned char)0xd9;        \
+               *(inst)++ = (unsigned char)0xf8;        \
+       } while (0)
+
+#define x86_fxch(inst,index)   \
+       do {    \
+               *(inst)++ = (unsigned char)0xd9;        \
+               *(inst)++ = (unsigned char)0xc8 + ((index) & 0x07);     \
+       } while (0)
+
+#define x86_fcomi(inst,index)  \
+       do {    \
+               *(inst)++ = (unsigned char)0xdb;        \
+               *(inst)++ = (unsigned char)0xf0 + ((index) & 0x07);     \
+       } while (0)
+
+#define x86_fcomip(inst,index) \
+       do {    \
+               *(inst)++ = (unsigned char)0xdf;        \
+               *(inst)++ = (unsigned char)0xf0 + ((index) & 0x07);     \
+       } while (0)
+
+#define x86_fucomi(inst,index) \
+       do {    \
+               *(inst)++ = (unsigned char)0xdb;        \
+               *(inst)++ = (unsigned char)0xe8 + ((index) & 0x07);     \
+       } while (0)
+
+#define x86_fucomip(inst,index)        \
+       do {    \
+               *(inst)++ = (unsigned char)0xdf;        \
+               *(inst)++ = (unsigned char)0xe8 + ((index) & 0x07);     \
+       } while (0)
+
+#define x86_fld(inst,mem,is_double)    \
+       do {    \
+               *(inst)++ = (is_double) ? (unsigned char)0xdd : (unsigned char)0xd9;    \
+               x86_mem_emit ((inst), 0, (mem));        \
+       } while (0)
+
+#define x86_fld_membase(inst,basereg,disp,is_double)   \
+       do {    \
+               *(inst)++ = (is_double) ? (unsigned char)0xdd : (unsigned char)0xd9;    \
+               x86_membase_emit ((inst), 0, (basereg), (disp));        \
+       } while (0)
+
+#define x86_fld80_mem(inst,mem)        \
+       do {    \
+               *(inst)++ = (unsigned char)0xdb;        \
+               x86_mem_emit ((inst), 5, (mem));        \
+       } while (0)
+
+#define x86_fld80_membase(inst,basereg,disp)   \
+       do {    \
+               *(inst)++ = (unsigned char)0xdb;        \
+               x86_membase_emit ((inst), 5, (basereg), (disp));        \
+       } while (0)
+
+#define x86_fild(inst,mem,is_long)     \
+       do {    \
+               if ((is_long)) {        \
+                       *(inst)++ = (unsigned char)0xdf;        \
+                       x86_mem_emit ((inst), 5, (mem));        \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xdb;        \
+                       x86_mem_emit ((inst), 0, (mem));        \
+               }       \
+       } while (0)
+
+#define x86_fild_membase(inst,basereg,disp,is_long)    \
+       do {    \
+               if ((is_long)) {        \
+                       *(inst)++ = (unsigned char)0xdf;        \
+                       x86_membase_emit ((inst), 5, (basereg), (disp));        \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xdb;        \
+                       x86_membase_emit ((inst), 0, (basereg), (disp));        \
+               }       \
+       } while (0)
+
+#define x86_fld_reg(inst,index)        \
+       do {    \
+               *(inst)++ = (unsigned char)0xd9;        \
+               *(inst)++ = (unsigned char)0xc0 + ((index) & 0x07);     \
+       } while (0)
+
+#define x86_fldz(inst) \
+       do {    \
+               *(inst)++ = (unsigned char)0xd9;        \
+               *(inst)++ = (unsigned char)0xee;        \
+       } while (0)
+
+#define x86_fld1(inst) \
+       do {    \
+               *(inst)++ = (unsigned char)0xd9;        \
+               *(inst)++ = (unsigned char)0xe8;        \
+       } while (0)
+
+#define x86_fst(inst,mem,is_double,pop_stack)  \
+       do {    \
+               *(inst)++ = (is_double) ? (unsigned char)0xdd: (unsigned char)0xd9;     \
+               x86_mem_emit ((inst), 2 + ((pop_stack) ? 1 : 0), (mem));        \
+       } while (0)
+
+#define x86_fst_membase(inst,basereg,disp,is_double,pop_stack) \
+       do {    \
+               *(inst)++ = (is_double) ? (unsigned char)0xdd: (unsigned char)0xd9;     \
+               x86_membase_emit ((inst), 2 + ((pop_stack) ? 1 : 0), (basereg), (disp));        \
+       } while (0)
+
+#define x86_fst80_mem(inst,mem)        \
+       do {    \
+               *(inst)++ = (unsigned char)0xdb;        \
+               x86_mem_emit ((inst), 7, (mem));        \
+       } while (0)
+
+
+#define x86_fst80_membase(inst,basereg,disp)   \
+       do {    \
+               *(inst)++ = (unsigned char)0xdb;        \
+               x86_membase_emit ((inst), 7, (basereg), (disp));        \
+       } while (0)
+
+
+#define x86_fist_pop(inst,mem,is_long) \
+       do {    \
+               if ((is_long)) {        \
+                       *(inst)++ = (unsigned char)0xdf;        \
+                       x86_mem_emit ((inst), 7, (mem));        \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xdb;        \
+                       x86_mem_emit ((inst), 3, (mem));        \
+               }       \
+       } while (0)
+
+#define x86_fist_pop_membase(inst,basereg,disp,is_long)        \
+       do {    \
+               if ((is_long)) {        \
+                       *(inst)++ = (unsigned char)0xdf;        \
+                       x86_membase_emit ((inst), 7, (basereg), (disp));        \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xdb;        \
+                       x86_membase_emit ((inst), 3, (basereg), (disp));        \
+               }       \
+       } while (0)
+
+/**
+ * @x86_fist_membase
+ * Converts content of ST(0) to integer and stores it at memory location
+ * addressed by [basereg + disp].
+ * is_int specifies whether destination is int32 (TRUE) or int16 (FALSE).
+ */
+#define x86_fist_membase(inst,basereg,disp,is_int)     \
+       do {    \
+               if ((is_int)) { \
+                       *(inst)++ = (unsigned char)0xdb;        \
+                       x86_membase_emit ((inst), 2, (basereg), (disp));        \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xdf;        \
+                       x86_membase_emit ((inst), 2, (basereg), (disp));        \
+               }       \
+       } while (0)
+
+
+#define x86_push_reg(inst,reg) \
+       do {    \
+               *(inst)++ = (unsigned char)0x50 + (reg);        \
+       } while (0)
+
+#define x86_push_regp(inst,reg)        \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_regp_emit ((inst), 6, (reg));       \
+       } while (0)
+
+#define x86_push_mem(inst,mem) \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_mem_emit ((inst), 6, (mem));        \
+       } while (0)
+
+#define x86_push_membase(inst,basereg,disp)    \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_membase_emit ((inst), 6, (basereg), (disp));        \
+       } while (0)
+
+#define x86_push_memindex(inst,basereg,disp,indexreg,shift)    \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_memindex_emit ((inst), 6, (basereg), (disp), (indexreg), (shift));  \
+       } while (0)
+
+#define x86_push_imm(inst,imm) \
+       do {    \
+               *(inst)++ = (unsigned char)0x68;        \
+               x86_imm_emit32 ((inst), (imm)); \
+       } while (0)
+
+#define x86_pop_reg(inst,reg)  \
+       do {    \
+               *(inst)++ = (unsigned char)0x58 + (reg);        \
+       } while (0)
+
+#define x86_pop_mem(inst,mem)  \
+       do {    \
+               *(inst)++ = (unsigned char)0x87;        \
+               x86_mem_emit ((inst), 0, (mem));        \
+       } while (0)
+
+#define x86_pop_membase(inst,basereg,disp)     \
+       do {    \
+               *(inst)++ = (unsigned char)0x87;        \
+               x86_membase_emit ((inst), 0, (basereg), (disp));        \
+       } while (0)
+
+#define x86_pushad(inst) do { *(inst)++ = (unsigned char)0x60; } while (0)
+#define x86_pushfd(inst) do { *(inst)++ = (unsigned char)0x9c; } while (0)
+#define x86_popad(inst)  do { *(inst)++ = (unsigned char)0x61; } while (0)
+#define x86_popfd(inst)  do { *(inst)++ = (unsigned char)0x9d; } while (0)
+
+#define x86_loop(inst,imm)     \
+       do {    \
+               *(inst)++ = (unsigned char)0xe2;        \
+               x86_imm_emit8 ((inst), (imm));  \
+       } while (0)
+
+#define x86_loope(inst,imm)    \
+       do {    \
+               *(inst)++ = (unsigned char)0xe1;        \
+               x86_imm_emit8 ((inst), (imm));  \
+       } while (0)
+
+#define x86_loopne(inst,imm)   \
+       do {    \
+               *(inst)++ = (unsigned char)0xe0;        \
+               x86_imm_emit8 ((inst), (imm));  \
+       } while (0)
+
+#define x86_jump32(inst,imm)   \
+       do {    \
+               *(inst)++ = (unsigned char)0xe9;        \
+               x86_imm_emit32 ((inst), (imm)); \
+       } while (0)
+
+#define x86_jump8(inst,imm)    \
+       do {    \
+               *(inst)++ = (unsigned char)0xeb;        \
+               x86_imm_emit8 ((inst), (imm));  \
+       } while (0)
+
+#define x86_jump_reg(inst,reg) \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_reg_emit ((inst), 4, (reg));        \
+       } while (0)
+
+#define x86_jump_mem(inst,mem) \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_mem_emit ((inst), 4, (mem));        \
+       } while (0)
+
+#define x86_jump_membase(inst,basereg,disp)    \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_membase_emit ((inst), 4, (basereg), (disp));        \
+       } while (0)
+
+/*
+ * target is a pointer in our buffer.
+ */
+#define x86_jump_code(inst,target)     \
+       do {    \
+               int t = (unsigned char*)(target) - (inst) - 2;  \
+               if (x86_is_imm8(t)) {   \
+                       x86_jump8 ((inst), t);  \
+               } else {        \
+                       t -= 3; \
+                       x86_jump32 ((inst), t); \
+               }       \
+       } while (0)
+
+#define x86_jump_disp(inst,disp)       \
+       do {    \
+               int t = (disp) - 2;     \
+               if (x86_is_imm8(t)) {   \
+                       x86_jump8 ((inst), t);  \
+               } else {        \
+                       t -= 3; \
+                       x86_jump32 ((inst), t); \
+               }       \
+       } while (0)
+
+#define x86_branch8(inst,cond,imm,is_signed)   \
+       do {    \
+               if ((is_signed))        \
+                       *(inst)++ = x86_cc_signed_map [(cond)]; \
+               else    \
+                       *(inst)++ = x86_cc_unsigned_map [(cond)];       \
+               x86_imm_emit8 ((inst), (imm));  \
+       } while (0)
+
+#define x86_branch32(inst,cond,imm,is_signed)  \
+       do {    \
+               *(inst)++ = (unsigned char)0x0f;        \
+               if ((is_signed))        \
+                       *(inst)++ = x86_cc_signed_map [(cond)] + 0x10;  \
+               else    \
+                       *(inst)++ = x86_cc_unsigned_map [(cond)] + 0x10;        \
+               x86_imm_emit32 ((inst), (imm)); \
+       } while (0)
+
+#define x86_branch(inst,cond,target,is_signed) \
+       do {    \
+               int offset = (target) - (inst) - 2;     \
+               if (x86_is_imm8 ((offset)))     \
+                       x86_branch8 ((inst), (cond), offset, (is_signed));      \
+               else {  \
+                       offset -= 4;    \
+                       x86_branch32 ((inst), (cond), offset, (is_signed));     \
+               }       \
+       } while (0)
+
+#define x86_branch_disp(inst,cond,disp,is_signed)      \
+       do {    \
+               int offset = (disp) - 2;        \
+               if (x86_is_imm8 ((offset)))     \
+                       x86_branch8 ((inst), (cond), offset, (is_signed));      \
+               else {  \
+                       offset -= 4;    \
+                       x86_branch32 ((inst), (cond), offset, (is_signed));     \
+               }       \
+       } while (0)
+
+#define x86_set_reg(inst,cond,reg,is_signed)   \
+       do {    \
+               *(inst)++ = (unsigned char)0x0f;        \
+               if ((is_signed))        \
+                       *(inst)++ = x86_cc_signed_map [(cond)] + 0x20;  \
+               else    \
+                       *(inst)++ = x86_cc_unsigned_map [(cond)] + 0x20;        \
+               x86_reg_emit ((inst), 0, (reg));        \
+       } while (0)
+
+#define x86_set_mem(inst,cond,mem,is_signed)   \
+       do {    \
+               *(inst)++ = (unsigned char)0x0f;        \
+               if ((is_signed))        \
+                       *(inst)++ = x86_cc_signed_map [(cond)] + 0x20;  \
+               else    \
+                       *(inst)++ = x86_cc_unsigned_map [(cond)] + 0x20;        \
+               x86_mem_emit ((inst), 0, (mem));        \
+       } while (0)
+
+#define x86_set_membase(inst,cond,basereg,disp,is_signed)      \
+       do {    \
+               *(inst)++ = (unsigned char)0x0f;        \
+               if ((is_signed))        \
+                       *(inst)++ = x86_cc_signed_map [(cond)] + 0x20;  \
+               else    \
+                       *(inst)++ = x86_cc_unsigned_map [(cond)] + 0x20;        \
+               x86_membase_emit ((inst), 0, (basereg), (disp));        \
+       } while (0)
+
+#define x86_call_imm(inst,disp)        \
+       do {    \
+               *(inst)++ = (unsigned char)0xe8;        \
+               x86_imm_emit32 ((inst), (int)(disp));   \
+       } while (0)
+
+#define x86_call_reg(inst,reg) \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_reg_emit ((inst), 2, (reg));        \
+       } while (0)
+
+#define x86_call_mem(inst,mem) \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_mem_emit ((inst), 2, (mem));        \
+       } while (0)
+
+#define x86_call_membase(inst,basereg,disp)    \
+       do {    \
+               *(inst)++ = (unsigned char)0xff;        \
+               x86_membase_emit ((inst), 2, (basereg), (disp));        \
+       } while (0)
+
+#define x86_call_code(inst,target)     \
+       do {    \
+               int _x86_offset = (unsigned char*)(target) - (inst);    \
+               _x86_offset -= 5;       \
+               x86_call_imm ((inst), _x86_offset);     \
+       } while (0)
+
+#define x86_ret(inst) do { *(inst)++ = (unsigned char)0xc3; } while (0)
+
+#define x86_ret_imm(inst,imm)  \
+       do {    \
+               if ((imm) == 0) {       \
+                       x86_ret ((inst));       \
+               } else {        \
+                       *(inst)++ = (unsigned char)0xc2;        \
+                       x86_imm_emit16 ((inst), (imm)); \
+               }       \
+       } while (0)
+
+#define x86_cmov_reg(inst,cond,is_signed,dreg,reg)     \
+       do {    \
+               *(inst)++ = (unsigned char) 0x0f;       \
+               if ((is_signed))        \
+                       *(inst)++ = x86_cc_signed_map [(cond)] - 0x30;  \
+               else    \
+                       *(inst)++ = x86_cc_unsigned_map [(cond)] - 0x30;        \
+               x86_reg_emit ((inst), (dreg), (reg));   \
+       } while (0)
+
+#define x86_cmov_mem(inst,cond,is_signed,reg,mem)      \
+       do {    \
+               *(inst)++ = (unsigned char) 0x0f;       \
+               if ((is_signed))        \
+                       *(inst)++ = x86_cc_signed_map [(cond)] - 0x30;  \
+               else    \
+                       *(inst)++ = x86_cc_unsigned_map [(cond)] - 0x30;        \
+               x86_mem_emit ((inst), (reg), (mem));    \
+       } while (0)
+
+#define x86_cmov_membase(inst,cond,is_signed,reg,basereg,disp) \
+       do {    \
+               *(inst)++ = (unsigned char) 0x0f;       \
+               if ((is_signed))        \
+                       *(inst)++ = x86_cc_signed_map [(cond)] - 0x30;  \
+               else    \
+                       *(inst)++ = x86_cc_unsigned_map [(cond)] - 0x30;        \
+               x86_membase_emit ((inst), (reg), (basereg), (disp));    \
+       } while (0)
+
+#define x86_enter(inst,framesize)      \
+       do {    \
+               *(inst)++ = (unsigned char)0xc8;        \
+               x86_imm_emit16 ((inst), (framesize));   \
+               *(inst)++ = 0;  \
+       } while (0)
+       
+#define x86_leave(inst) do { *(inst)++ = (unsigned char)0xc9; } while (0)
+#define x86_sahf(inst)  do { *(inst)++ = (unsigned char)0x9e; } while (0)
+
+#define x86_fsin(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xfe; } while (0)
+#define x86_fcos(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xff; } while (0)
+#define x86_fabs(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xe1; } while (0)
+#define x86_fpatan(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xf3; } while (0)
+#define x86_fprem(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xf8; } while (0)
+#define x86_fprem1(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xf5; } while (0)
+#define x86_frndint(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xfc; } while (0)
+#define x86_fsqrt(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xfa; } while (0)
+#define x86_fptan(inst) do { *(inst)++ = (unsigned char)0xd9; *(inst)++ = (unsigned char)0xf2; } while (0)
+
+#define x86_padding(inst,size) \
+       do {    \
+               switch ((size)) {       \
+               case 1: x86_nop ((inst)); break;        \
+               case 2: *(inst)++ = 0x8b;       \
+                       *(inst)++ = 0xc0; break;        \
+               case 3: *(inst)++ = 0x8d; *(inst)++ = 0x6d;     \
+                       *(inst)++ = 0x00; break;        \
+               case 4: *(inst)++ = 0x8d; *(inst)++ = 0x64;     \
+                       *(inst)++ = 0x24; *(inst)++ = 0x00;     \
+                       break;  \
+               case 5: *(inst)++ = 0x8d; *(inst)++ = 0x64;     \
+                       *(inst)++ = 0x24; *(inst)++ = 0x00;     \
+                       x86_nop ((inst)); break;        \
+               case 6: *(inst)++ = 0x8d; *(inst)++ = 0xad;     \
+                       *(inst)++ = 0x00; *(inst)++ = 0x00;     \
+                       *(inst)++ = 0x00; *(inst)++ = 0x00;     \
+                       break;  \
+               case 7: *(inst)++ = 0x8d; *(inst)++ = 0xa4;     \
+                       *(inst)++ = 0x24; *(inst)++ = 0x00;     \
+                       *(inst)++ = 0x00; *(inst)++ = 0x00;     \
+                       *(inst)++ = 0x00; break;        \
+               default: jit_assert (0);        \
+               }       \
+       } while (0)
+
+#define x86_prolog(inst,frame_size,reg_mask)   \
+       do {    \
+               unsigned i, m = 1;      \
+               x86_enter ((inst), (frame_size));       \
+               for (i = 0; i < X86_NREG; ++i, m <<= 1) {       \
+                       if ((reg_mask) & m)     \
+                               x86_push_reg ((inst), i);       \
+               }       \
+       } while (0)
+
+#define x86_epilog(inst,reg_mask)      \
+       do {    \
+               unsigned i, m = 1 << X86_EDI;   \
+               for (i = X86_EDI; m != 0; i--, m=m>>1) {        \
+                       if ((reg_mask) & m)     \
+                               x86_pop_reg ((inst), i);        \
+               }       \
+               x86_leave ((inst));     \
+               x86_ret ((inst));       \
+       } while (0)
+
+#endif /* JIT_GEN_X86_H */
diff --git a/jit/jit-init.c b/jit/jit-init.c
new file mode 100644 (file)
index 0000000..5146d05
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * jit-init.c - Initialization routines for the JIT.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-rules.h"
+
+/*@
+ * @deftypefun void jit_init (void)
+ * This is normally the first function that you call when using
+ * @code{libjit}.  It initializes the library and prepares for
+ * JIT operations.
+ *
+ * The @code{jit_context_create} function also calls this, so you can
+ * avoid using @code{jit_init} if @code{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.
+ * @end deftypefun
+@*/
+void jit_init(void)
+{
+       /* Make sure that the thread subsystem is initialized */
+       _jit_thread_init();
+
+       /* Initialize the backend */
+       _jit_init_backend();
+}
+
+/*@
+ * @deftypefun 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 @code{jit_init}.
+ * @end deftypefun
+@*/
+int jit_uses_interpreter(void)
+{
+#if defined(JIT_BACKEND_INTERP)
+       return 1;
+#else
+       return 0;
+#endif
+}
diff --git a/jit/jit-insn.c b/jit/jit-insn.c
new file mode 100644 (file)
index 0000000..efafa90
--- /dev/null
@@ -0,0 +1,6237 @@
+/*
+ * jit-insn.c - Functions for manipulating instructions.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-rules.h"
+#include <config.h>
+#if HAVE_ALLOCA_H
+       #include <alloca.h>
+#endif
+#ifdef JIT_WIN32_PLATFORM
+       #include <malloc.h>
+       #ifndef alloca
+               #define alloca  _alloca
+       #endif
+#endif
+
+/*@
+
+@cindex jit-insn.h
+
+@*/
+
+/*
+ * Opcode description blocks.  These describe the alternative opcodes
+ * and intrinsic functions to use for various kinds of arguments.
+ */
+typedef struct
+{
+       unsigned short  ioper;                                  /* Primary operator for "int" */
+       unsigned short  iuoper;                                 /* Primary operator for "uint" */
+       unsigned short  loper;                                  /* Primary operator for "long" */
+       unsigned short  luoper;                                 /* Primary operator for "ulong" */
+       unsigned short  foper;                                  /* Primary operator for "float32" */
+       unsigned short  doper;                                  /* Primary operator for "float64" */
+       unsigned short  nfoper;                                 /* Primary operator for "nfloat" */
+       void               *ifunc;                                      /* Function for "int" */
+       const char         *iname;                                      /* Intrinsic name for "int" */
+       const jit_intrinsic_descr_t *idesc;             /* Descriptor for "int" */
+       void               *iufunc;                                     /* Function for "uint" */
+       const char         *iuname;                                     /* Intrinsic name for "uint" */
+       const jit_intrinsic_descr_t *iudesc;    /* Descriptor for "uint" */
+       void               *lfunc;                                      /* Function for "long" */
+       const char         *lname;                                      /* Intrinsic name for "long" */
+       const jit_intrinsic_descr_t *ldesc;             /* Descriptor for "long" */
+       void               *lufunc;                                     /* Function for "ulong" */
+       const char         *luname;                                     /* Intrinsic name for "ulong" */
+       const jit_intrinsic_descr_t *ludesc;    /* Descriptor for "ulong" */
+       void               *ffunc;                                      /* Function for "float32" */
+       const char         *fname;                                      /* Intrinsic name for "float32" */
+       const jit_intrinsic_descr_t *fdesc;             /* Descriptor for "float32" */
+       void               *dfunc;                                      /* Function for "float64" */
+       const char         *dname;                                      /* Intrinsic name for "float64" */
+       const jit_intrinsic_descr_t *ddesc;             /* Descriptor for "float64" */
+       void               *nffunc;                                     /* Function for "nfloat" */
+       const char         *nfname;                                     /* Intrinsic name for "nfloat" */
+       const jit_intrinsic_descr_t *nfdesc;    /* Descriptor for "nfloat" */
+
+} jit_opcode_descr;
+#define        jit_intrinsic(name,descr)               (void *)name, #name, &descr
+#define        jit_no_intrinsic                                0, 0, 0
+
+/*
+ * Some common intrinsic descriptors that are used in this file.
+ */
+static jit_intrinsic_descr_t const descr_i_ii = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_int_def,
+       (jit_type_t)&_jit_type_int_def
+};
+static jit_intrinsic_descr_t const descr_e_pi_ii = {
+       (jit_type_t)&_jit_type_int_def,
+       (jit_type_t)&_jit_type_int_def,
+       (jit_type_t)&_jit_type_int_def,
+       (jit_type_t)&_jit_type_int_def
+};
+static jit_intrinsic_descr_t const descr_i_iI = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_int_def,
+       (jit_type_t)&_jit_type_uint_def
+};
+static jit_intrinsic_descr_t const descr_i_i = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_int_def,
+       0
+};
+static jit_intrinsic_descr_t const descr_I_II = {
+       (jit_type_t)&_jit_type_uint_def,
+       0,
+       (jit_type_t)&_jit_type_uint_def,
+       (jit_type_t)&_jit_type_uint_def
+};
+static jit_intrinsic_descr_t const descr_e_pI_II = {
+       (jit_type_t)&_jit_type_uint_def,
+       (jit_type_t)&_jit_type_uint_def,
+       (jit_type_t)&_jit_type_uint_def,
+       (jit_type_t)&_jit_type_uint_def
+};
+static jit_intrinsic_descr_t const descr_I_I = {
+       (jit_type_t)&_jit_type_uint_def,
+       0,
+       (jit_type_t)&_jit_type_uint_def,
+       0
+};
+static jit_intrinsic_descr_t const descr_i_II = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_uint_def,
+       (jit_type_t)&_jit_type_uint_def
+};
+static jit_intrinsic_descr_t const descr_l_ll = {
+       (jit_type_t)&_jit_type_long_def,
+       0,
+       (jit_type_t)&_jit_type_long_def,
+       (jit_type_t)&_jit_type_long_def
+};
+static jit_intrinsic_descr_t const descr_e_pl_ll = {
+       (jit_type_t)&_jit_type_long_def,
+       (jit_type_t)&_jit_type_long_def,
+       (jit_type_t)&_jit_type_long_def,
+       (jit_type_t)&_jit_type_long_def
+};
+static jit_intrinsic_descr_t const descr_l_lI = {
+       (jit_type_t)&_jit_type_long_def,
+       0,
+       (jit_type_t)&_jit_type_long_def,
+       (jit_type_t)&_jit_type_uint_def
+};
+static jit_intrinsic_descr_t const descr_l_l = {
+       (jit_type_t)&_jit_type_long_def,
+       0,
+       (jit_type_t)&_jit_type_long_def,
+       0
+};
+static jit_intrinsic_descr_t const descr_i_ll = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_long_def,
+       (jit_type_t)&_jit_type_long_def
+};
+static jit_intrinsic_descr_t const descr_i_l = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_long_def,
+       0
+};
+static jit_intrinsic_descr_t const descr_L_LL = {
+       (jit_type_t)&_jit_type_ulong_def,
+       0,
+       (jit_type_t)&_jit_type_ulong_def,
+       (jit_type_t)&_jit_type_ulong_def
+};
+static jit_intrinsic_descr_t const descr_e_pL_LL = {
+       (jit_type_t)&_jit_type_ulong_def,
+       (jit_type_t)&_jit_type_ulong_def,
+       (jit_type_t)&_jit_type_ulong_def,
+       (jit_type_t)&_jit_type_ulong_def
+};
+static jit_intrinsic_descr_t const descr_L_LI = {
+       (jit_type_t)&_jit_type_ulong_def,
+       0,
+       (jit_type_t)&_jit_type_ulong_def,
+       (jit_type_t)&_jit_type_uint_def
+};
+static jit_intrinsic_descr_t const descr_L_L = {
+       (jit_type_t)&_jit_type_ulong_def,
+       0,
+       (jit_type_t)&_jit_type_ulong_def,
+       0
+};
+static jit_intrinsic_descr_t const descr_i_LL = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_ulong_def,
+       (jit_type_t)&_jit_type_ulong_def
+};
+static jit_intrinsic_descr_t const descr_f_ff = {
+       (jit_type_t)&_jit_type_float32_def,
+       0,
+       (jit_type_t)&_jit_type_float32_def,
+       (jit_type_t)&_jit_type_float32_def
+};
+static jit_intrinsic_descr_t const descr_f_f = {
+       (jit_type_t)&_jit_type_float32_def,
+       0,
+       (jit_type_t)&_jit_type_float32_def,
+       0
+};
+static jit_intrinsic_descr_t const descr_i_ff = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_float32_def,
+       (jit_type_t)&_jit_type_float32_def
+};
+static jit_intrinsic_descr_t const descr_i_f = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_float32_def,
+       0
+};
+static jit_intrinsic_descr_t const descr_d_dd = {
+       (jit_type_t)&_jit_type_float64_def,
+       0,
+       (jit_type_t)&_jit_type_float64_def,
+       (jit_type_t)&_jit_type_float64_def
+};
+static jit_intrinsic_descr_t const descr_d_d = {
+       (jit_type_t)&_jit_type_float64_def,
+       0,
+       (jit_type_t)&_jit_type_float64_def,
+       0
+};
+static jit_intrinsic_descr_t const descr_i_dd = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_float64_def,
+       (jit_type_t)&_jit_type_float64_def
+};
+static jit_intrinsic_descr_t const descr_i_d = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_float64_def,
+       0
+};
+static jit_intrinsic_descr_t const descr_D_DD = {
+       (jit_type_t)&_jit_type_nfloat_def,
+       0,
+       (jit_type_t)&_jit_type_nfloat_def,
+       (jit_type_t)&_jit_type_nfloat_def
+};
+static jit_intrinsic_descr_t const descr_D_D = {
+       (jit_type_t)&_jit_type_nfloat_def,
+       0,
+       (jit_type_t)&_jit_type_nfloat_def,
+       0
+};
+static jit_intrinsic_descr_t const descr_i_DD = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_nfloat_def,
+       (jit_type_t)&_jit_type_nfloat_def
+};
+static jit_intrinsic_descr_t const descr_i_D = {
+       (jit_type_t)&_jit_type_int_def,
+       0,
+       (jit_type_t)&_jit_type_nfloat_def,
+       0
+};
+
+/*
+ * Apply a unary operator.
+ */
+static jit_value_t apply_unary
+               (jit_function_t func, int oper, jit_value_t value1,
+                jit_type_t result_type)
+{
+       jit_value_t dest;
+       jit_insn_t insn;
+       if(!value1)
+       {
+               return 0;
+       }
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       dest = jit_value_create(func, result_type);
+       if(!dest)
+       {
+               return 0;
+       }
+       jit_value_ref(func, value1);
+       insn->opcode = (short)oper;
+       insn->dest = dest;
+       insn->value1 = value1;
+       return dest;
+}
+
+/*
+ * Apply a binary operator.
+ */
+static jit_value_t apply_binary
+               (jit_function_t func, int oper, jit_value_t value1,
+                jit_value_t value2, jit_type_t result_type)
+{
+       jit_value_t dest;
+       jit_insn_t insn;
+       if(!value1 || !value2)
+       {
+               return 0;
+       }
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       dest = jit_value_create(func, result_type);
+       if(!dest)
+       {
+               return 0;
+       }
+       jit_value_ref(func, value1);
+       jit_value_ref(func, value2);
+       insn->opcode = (short)oper;
+       insn->dest = dest;
+       insn->value1 = value1;
+       insn->value2 = value2;
+       return dest;
+}
+
+/*
+ * Create a note instruction, which doesn't have a result.
+ */
+static int create_note
+               (jit_function_t func, int oper, jit_value_t value1,
+                jit_value_t value2)
+{
+       jit_insn_t insn;
+       if(!value1 || !value2)
+       {
+               return 0;
+       }
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, value1);
+       jit_value_ref(func, value2);
+       insn->opcode = (short)oper;
+       insn->value1 = value1;
+       insn->value2 = value2;
+       return 1;
+}
+
+/*
+ * Create a unary note instruction, which doesn't have a result.
+ */
+static int create_unary_note
+               (jit_function_t func, int oper, jit_value_t value1)
+{
+       jit_insn_t insn;
+       if(!value1)
+       {
+               return 0;
+       }
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, value1);
+       insn->opcode = (short)oper;
+       insn->value1 = value1;
+       return 1;
+}
+
+/*
+ * Create a note instruction with no arguments, which doesn't have a result.
+ */
+static int create_noarg_note(jit_function_t func, int oper)
+{
+       jit_insn_t insn;
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       insn->opcode = (short)oper;
+       return 1;
+}
+
+/*
+ * Create a note instruction with only a destination.
+ */
+static jit_value_t create_dest_note
+       (jit_function_t func, int oper, jit_type_t type)
+{
+       jit_insn_t insn;
+       jit_value_t value;
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       value = jit_value_create(func, type);
+       if(!value)
+       {
+               return 0;
+       }
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, value);
+       insn->opcode = (short)oper;
+       insn->dest = value;
+       return value;
+}
+
+/*
+ * Get the common type to use for a binary operator.
+ */
+static jit_type_t common_binary(jit_type_t type1, jit_type_t type2,
+                                                               int int_only, int float_only)
+{
+       type1 = jit_type_promote_int(jit_type_normalize(type1));
+       type2 = jit_type_promote_int(jit_type_normalize(type2));
+       if(!float_only)
+       {
+               if(type1 == jit_type_int)
+               {
+                       if(type2 == jit_type_int || type2 == jit_type_uint)
+                       {
+                               return jit_type_int;
+                       }
+                       else if(type2 == jit_type_long || type2 == jit_type_ulong)
+                       {
+                               return jit_type_long;
+                       }
+               }
+               else if(type1 == jit_type_uint)
+               {
+                       if(type2 == jit_type_int || type2 == jit_type_uint ||
+                          type2 == jit_type_long || type2 == jit_type_ulong)
+                       {
+                               return type2;
+                       }
+               }
+               else if(type1 == jit_type_long)
+               {
+                       if(type2 == jit_type_int || type2 == jit_type_uint ||
+                          type2 == jit_type_long || type2 == jit_type_ulong)
+                       {
+                               return jit_type_long;
+                       }
+               }
+               else if(type1 == jit_type_ulong)
+               {
+                       if(type2 == jit_type_int || type2 == jit_type_long)
+                       {
+                               return jit_type_long;
+                       }
+                       else if(type2 == jit_type_uint || type2 == jit_type_ulong)
+                       {
+                               return jit_type_ulong;
+                       }
+               }
+               if(int_only)
+               {
+                       return jit_type_long;
+               }
+       }
+       if(type1 == jit_type_nfloat || type2 == jit_type_nfloat)
+       {
+               return jit_type_nfloat;
+       }
+       else if(type1 == jit_type_float64 || type2 == jit_type_float64)
+       {
+               return jit_type_float64;
+       }
+       else if(type1 == jit_type_float32 || type2 == jit_type_float32)
+       {
+               return jit_type_float32;
+       }
+       else
+       {
+               /* Probably integer arguments when "float_only" is set */
+               return jit_type_nfloat;
+       }
+}
+
+/*
+ * Apply an intrinsic.
+ */
+static jit_value_t apply_intrinsic
+               (jit_function_t func, const jit_opcode_descr *descr,
+                jit_value_t value1, jit_value_t value2, jit_type_t result_type)
+{
+       if(result_type == jit_type_int)
+       {
+               return jit_insn_call_intrinsic
+                       (func, descr->iname, descr->ifunc, descr->idesc, value1, value2);
+       }
+       else if(result_type == jit_type_uint)
+       {
+               return jit_insn_call_intrinsic
+                       (func, descr->iuname, descr->iufunc, descr->iudesc, value1, value2);
+       }
+       else if(result_type == jit_type_long)
+       {
+               return jit_insn_call_intrinsic
+                       (func, descr->lname, descr->lfunc, descr->ldesc, value1, value2);
+       }
+       else if(result_type == jit_type_ulong)
+       {
+               return jit_insn_call_intrinsic
+                       (func, descr->luname, descr->lufunc, descr->ludesc, value1, value2);
+       }
+       else if(result_type == jit_type_float32)
+       {
+               return jit_insn_call_intrinsic
+                       (func, descr->fname, descr->ffunc, descr->fdesc, value1, value2);
+       }
+       else if(result_type == jit_type_float64)
+       {
+               return jit_insn_call_intrinsic
+                       (func, descr->dname, descr->dfunc, descr->ddesc, value1, value2);
+       }
+       else
+       {
+               return jit_insn_call_intrinsic
+                       (func, descr->nfname, descr->nffunc, descr->nfdesc, value1, value2);
+       }
+}
+
+/*
+ * Apply a unary arithmetic operator, after coercing the
+ * argument to a suitable numeric type.
+ */
+static jit_value_t apply_unary_arith
+               (jit_function_t func, const jit_opcode_descr *descr,
+                jit_value_t value1, int int_only, int float_only,
+                int overflow_check)
+{
+       int oper;
+       jit_type_t result_type;
+       if(!value1)
+       {
+               return 0;
+       }
+       result_type = common_binary
+               (value1->type, value1->type, int_only, float_only);
+       if(result_type == jit_type_int)
+       {
+               oper = descr->ioper;
+       }
+       else if(result_type == jit_type_uint)
+       {
+               oper = descr->iuoper;
+       }
+       else if(result_type == jit_type_long)
+       {
+               oper = descr->loper;
+       }
+       else if(result_type == jit_type_ulong)
+       {
+               oper = descr->luoper;
+       }
+       else if(result_type == jit_type_float32)
+       {
+               oper = descr->foper;
+       }
+       else if(result_type == jit_type_float64)
+       {
+               oper = descr->doper;
+       }
+       else
+       {
+               oper = descr->nfoper;
+       }
+       value1 = jit_insn_convert(func, value1, result_type, overflow_check);
+       if(_jit_opcode_is_supported(oper))
+       {
+               return apply_unary(func, oper, value1, result_type);
+       }
+       else
+       {
+               return apply_intrinsic(func, descr, value1, 0, result_type);
+       }
+}
+
+/*
+ * Apply a binary arithmetic operator, after coercing both
+ * arguments to a common type.
+ */
+static jit_value_t apply_arith
+               (jit_function_t func, const jit_opcode_descr *descr,
+                jit_value_t value1, jit_value_t value2,
+                int int_only, int float_only, int overflow_check)
+{
+       int oper;
+       jit_type_t result_type;
+       if(!value1 || !value2)
+       {
+               return 0;
+       }
+       result_type = common_binary
+               (value1->type, value2->type, int_only, float_only);
+       if(result_type == jit_type_int)
+       {
+               oper = descr->ioper;
+       }
+       else if(result_type == jit_type_uint)
+       {
+               oper = descr->iuoper;
+       }
+       else if(result_type == jit_type_long)
+       {
+               oper = descr->loper;
+       }
+       else if(result_type == jit_type_ulong)
+       {
+               oper = descr->luoper;
+       }
+       else if(result_type == jit_type_float32)
+       {
+               oper = descr->foper;
+       }
+       else if(result_type == jit_type_float64)
+       {
+               oper = descr->doper;
+       }
+       else
+       {
+               oper = descr->nfoper;
+       }
+       value1 = jit_insn_convert(func, value1, result_type, overflow_check);
+       value2 = jit_insn_convert(func, value2, result_type, overflow_check);
+       if(_jit_opcode_is_supported(oper))
+       {
+               return apply_binary(func, oper, value1, value2, result_type);
+       }
+       else
+       {
+               return apply_intrinsic(func, descr, value1, value2, result_type);
+       }
+}
+
+/*
+ * Apply a binary shift operator, after coercing both
+ * arguments to suitable types.
+ */
+static jit_value_t apply_shift
+               (jit_function_t func, const jit_opcode_descr *descr,
+                jit_value_t value1, jit_value_t value2)
+{
+       int oper;
+       jit_type_t result_type;
+       jit_type_t count_type;
+       if(!value1 || !value2)
+       {
+               return 0;
+       }
+       result_type = common_binary(value1->type, value1->type, 1, 0);
+       if(result_type == jit_type_int)
+       {
+               oper = descr->ioper;
+       }
+       else if(result_type == jit_type_uint)
+       {
+               oper = descr->iuoper;
+       }
+       else if(result_type == jit_type_long)
+       {
+               oper = descr->loper;
+       }
+       else if(result_type == jit_type_ulong)
+       {
+               oper = descr->luoper;
+       }
+       else
+       {
+               /* Shouldn't happen */
+               oper = descr->loper;
+       }
+       count_type = jit_type_promote_int(jit_type_normalize(value2->type));
+       if(count_type != jit_type_int)
+       {
+               count_type = jit_type_uint;
+       }
+       value1 = jit_insn_convert(func, value1, result_type, 0);
+       value2 = jit_insn_convert(func, value2, count_type, 0);
+       if(_jit_opcode_is_supported(oper))
+       {
+               return apply_binary(func, oper, value1, value2, result_type);
+       }
+       else
+       {
+               return apply_intrinsic(func, descr, value1, value2, result_type);
+       }
+}
+
+/*
+ * Apply a binary comparison operator, after coercing both
+ * arguments to a common type.
+ */
+static jit_value_t apply_compare
+               (jit_function_t func, const jit_opcode_descr *descr,
+                jit_value_t value1, jit_value_t value2, int float_only)
+{
+       int oper;
+       jit_type_t result_type;
+       if(!value1 || !value2)
+       {
+               return 0;
+       }
+       result_type = common_binary(value1->type, value2->type, 0, float_only);
+       if(result_type == jit_type_int)
+       {
+               oper = descr->ioper;
+       }
+       else if(result_type == jit_type_uint)
+       {
+               oper = descr->iuoper;
+       }
+       else if(result_type == jit_type_long)
+       {
+               oper = descr->loper;
+       }
+       else if(result_type == jit_type_ulong)
+       {
+               oper = descr->luoper;
+       }
+       else if(result_type == jit_type_float32)
+       {
+               oper = descr->foper;
+       }
+       else if(result_type == jit_type_float64)
+       {
+               oper = descr->doper;
+       }
+       else
+       {
+               oper = descr->nfoper;
+       }
+       value1 = jit_insn_convert(func, value1, result_type, 0);
+       value2 = jit_insn_convert(func, value2, result_type, 0);
+       if(_jit_opcode_is_supported(oper))
+       {
+               return apply_binary(func, oper, value1, value2, jit_type_int);
+       }
+       else
+       {
+               return apply_intrinsic(func, descr, value1, value2, result_type);
+       }
+}
+
+/*
+ * Apply a unary test operator, after coercing the
+ * argument to an appropriate type.
+ */
+static jit_value_t apply_test
+               (jit_function_t func, const jit_opcode_descr *descr,
+                jit_value_t value1, int float_only)
+{
+       int oper;
+       jit_type_t result_type;
+       if(!value1)
+       {
+               return 0;
+       }
+       result_type = common_binary(value1->type, value1->type, 0, float_only);
+       if(result_type == jit_type_int)
+       {
+               oper = descr->ioper;
+       }
+       else if(result_type == jit_type_uint)
+       {
+               oper = descr->iuoper;
+       }
+       else if(result_type == jit_type_long)
+       {
+               oper = descr->loper;
+       }
+       else if(result_type == jit_type_ulong)
+       {
+               oper = descr->luoper;
+       }
+       else if(result_type == jit_type_float32)
+       {
+               oper = descr->foper;
+       }
+       else if(result_type == jit_type_float64)
+       {
+               oper = descr->doper;
+       }
+       else
+       {
+               oper = descr->nfoper;
+       }
+       value1 = jit_insn_convert(func, value1, result_type, 0);
+       if(_jit_opcode_is_supported(oper))
+       {
+               return apply_unary(func, oper, value1, jit_type_int);
+       }
+       else
+       {
+               return apply_intrinsic(func, descr, value1, 0, result_type);
+       }
+}
+
+/*@
+ * @deftypefun int jit_insn_get_opcode (jit_insn_t insn)
+ * Get the opcode that is associated with an instruction.
+ * @end deftypefun
+@*/
+int jit_insn_get_opcode(jit_insn_t insn)
+{
+       if(insn)
+       {
+               return insn->opcode;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_get_dest(jit_insn_t insn)
+{
+       if(insn && (insn->flags & JIT_INSN_DEST_OTHER_FLAGS) == 0)
+       {
+               return insn->dest;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_get_value1(jit_insn_t insn)
+{
+       if(insn && (insn->flags & JIT_INSN_VALUE1_OTHER_FLAGS) == 0)
+       {
+               return insn->value1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_get_value2(jit_insn_t insn)
+{
+       if(insn && (insn->flags & JIT_INSN_VALUE2_OTHER_FLAGS) == 0)
+       {
+               return insn->value2;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_label_t jit_insn_get_label(jit_insn_t insn)
+{
+       if(insn && (insn->flags & JIT_INSN_DEST_IS_LABEL) != 0)
+       {
+               return (jit_label_t)(insn->dest);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_function_t jit_insn_get_function(jit_insn_t insn)
+{
+       if(insn && (insn->flags & JIT_INSN_DEST_IS_FUNCTION) != 0)
+       {
+               return (jit_function_t)(insn->dest);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun {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.
+ * @end deftypefun
+@*/
+void *jit_insn_get_native(jit_insn_t insn)
+{
+       if(insn && (insn->flags & JIT_INSN_DEST_IS_NATIVE) != 0)
+       {
+               return (void *)(insn->dest);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun {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.
+ * @end deftypefun
+@*/
+const char *jit_insn_get_name(jit_insn_t insn)
+{
+       if(insn && (insn->flags & JIT_INSN_VALUE1_IS_NAME) != 0)
+       {
+               return (const char *)(insn->value1);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_type_t jit_insn_get_signature(jit_insn_t insn)
+{
+       if(insn && (insn->flags & JIT_INSN_VALUE2_IS_SIGNATURE) != 0)
+       {
+               return (jit_type_t)(insn->value2);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun int jit_insn_dest_is_value (jit_insn_t insn)
+ * Returns a non-zero value if the destination for @code{insn} is
+ * actually a source value.  This can happen with instructions
+ * such as @code{jit_insn_store_relative} where the instruction
+ * needs three source operands, and the real destination is a
+ * side-effect on one of the sources.
+ * @end deftypefun
+@*/
+int jit_insn_dest_is_value(jit_insn_t insn)
+{
+       if(insn && (insn->flags & JIT_INSN_DEST_IS_VALUE) != 0)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun void jit_insn_label (jit_function_t func, {jit_label_t *} label)
+ * Start a new block within the function @code{func} and give it the
+ * specified @code{label}.  Returns zero if out of memory.
+ *
+ * If the contents of @code{label} are @code{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.
+ * @end deftypefun
+@*/
+int jit_insn_label(jit_function_t func, jit_label_t *label)
+{
+       jit_block_t current;
+       jit_insn_t last;
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       current = func->builder->current_block;
+       last = _jit_block_get_last(current);
+       if(current->label == jit_label_undefined && !last)
+       {
+               /* We just started a new block after a branch instruction,
+                  so don't bother creating another new block */
+               if(*label == jit_label_undefined)
+               {
+                       *label = (func->builder->next_label)++;
+               }
+               current->label = *label;
+               current->entered_via_branch = 1;
+               if(!_jit_block_record_label(current))
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               /* Create a new block */
+               jit_block_t block = _jit_block_create(func, label);
+               if(!block)
+               {
+                       return 0;
+               }
+
+               /* The label indicates that something is branching to us */
+               block->entered_via_branch = 1;
+
+               /* Does the last block contain instructions? */
+               if(last)
+               {
+                       /* We will be entered via the top if the last block
+                          did not end in an unconditional branch and it
+                          is not explicitly marked as "dead" */
+                       if(last->opcode != JIT_OP_BR && !(current->ends_in_dead))
+                       {
+                               block->entered_via_top = 1;
+                       }
+               }
+               else
+               {
+                       /* We will be entered via the top if the last empty
+                          block was entered via any mechanism */
+                       block->entered_via_top =
+                               (current->entered_via_top ||
+                                current->entered_via_branch);
+               }
+
+               /* Set the new block as the current one */
+               func->builder->current_block = block;
+       }
+       return 1;
+}
+
+int _jit_load_opcode(int base_opcode, jit_type_t type,
+                                        jit_value_t value, int no_temps)
+{
+       type = jit_type_normalize(type);
+       if(!type)
+       {
+               return 0;
+       }
+       switch(type->kind)
+       {
+               case JIT_TYPE_SBYTE:
+               {
+                       return base_opcode;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_UBYTE:
+               {
+                       return base_opcode + 1;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_SHORT:
+               {
+                       return base_opcode + 2;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_USHORT:
+               {
+                       return base_opcode + 3;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_INT:
+               case JIT_TYPE_UINT:
+               {
+                       if(no_temps && value && (value->is_temporary || value->is_local))
+                       {
+                               return 0;
+                       }
+                       return base_opcode + 4;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_LONG:
+               case JIT_TYPE_ULONG:
+               {
+                       if(no_temps && value && (value->is_temporary || value->is_local))
+                       {
+                               return 0;
+                       }
+                       return base_opcode + 5;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_FLOAT32:
+               {
+                       if(no_temps && value && (value->is_temporary || value->is_local))
+                       {
+                               return 0;
+                       }
+                       return base_opcode + 6;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_FLOAT64:
+               {
+                       if(no_temps && value && (value->is_temporary || value->is_local))
+                       {
+                               return 0;
+                       }
+                       return base_opcode + 7;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_NFLOAT:
+               {
+                       if(no_temps && value && (value->is_temporary || value->is_local))
+                       {
+                               return 0;
+                       }
+                       return base_opcode + 8;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_STRUCT:
+               case JIT_TYPE_UNION:
+               {
+                       return base_opcode + 9;
+               }
+               /* Not reached */
+       }
+       return 0;
+}
+
+int _jit_store_opcode(int base_opcode, int small_base, jit_type_t type)
+{
+       /* Copy instructions are in two ranges: adjust for them */
+       if(small_base)
+       {
+               base_opcode -= 2;
+       }
+       else
+       {
+               small_base = base_opcode;
+       }
+
+       /* Determine which opcode to use */
+       type = jit_type_normalize(type);
+       switch(type->kind)
+       {
+               case JIT_TYPE_SBYTE:
+               case JIT_TYPE_UBYTE:
+               {
+                       return small_base;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_SHORT:
+               case JIT_TYPE_USHORT:
+               {
+                       return small_base + 1;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_INT:
+               case JIT_TYPE_UINT:
+               {
+                       return base_opcode + 2;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_LONG:
+               case JIT_TYPE_ULONG:
+               {
+                       return base_opcode + 3;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_FLOAT32:
+               {
+                       return base_opcode + 4;
+               }
+               break;
+
+               case JIT_TYPE_FLOAT64:
+               {
+                       return base_opcode + 5;
+               }
+               break;
+               /* Not reached */
+
+               case JIT_TYPE_NFLOAT:
+               {
+                       return base_opcode + 6;
+               }
+               /* Not reached */
+
+               case JIT_TYPE_STRUCT:
+               case JIT_TYPE_UNION:
+               {
+                       return base_opcode + 7;
+               }
+               /* Not reached */
+
+               default:
+               {
+                       /* Shouldn't happen, but do something sane anyway */
+                       return base_opcode + 2;
+               }
+               /* Not reached */
+       }
+}
+
+/*@
+ * @deftypefun jit_value_t jit_insn_load (jit_function_t func, jit_value_t value)
+ * Load the contents of @code{value} into a new temporary, essentially
+ * duplicating the value.  Constants are not duplicated.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_load(jit_function_t func, jit_value_t value)
+{
+       if(!value)
+       {
+               return 0;
+       }
+       else if(value->is_constant)
+       {
+               return value;
+       }
+       else
+       {
+               int opcode = _jit_load_opcode
+                       (JIT_OP_COPY_LOAD_SBYTE, value->type, value, 0);
+               return apply_unary(func, opcode, value, value->type);
+       }
+}
+
+/*@
+ * @deftypefun jit_value_t jit_insn_dup (jit_function_t func, jit_value_t value)
+ * This is the same as @code{jit_insn_load}, but the name may better
+ * reflect how it is used in some front ends.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_dup(jit_function_t func, jit_value_t value)
+{
+       return jit_insn_load(func, value);
+}
+
+/*@
+ * @deftypefun jit_value_t jit_insn_load_small (jit_function_t func, jit_value_t value)
+ * If @code{value} is of type @code{sbyte}, @code{byte}, @code{short},
+ * @code{ushort}, a structure, or a union, then make a copy of it and
+ * return the temporary copy.  Otherwise return @code{value} as-is.
+ *
+ * This is useful where you want to use @code{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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_load_small(jit_function_t func, jit_value_t value)
+{
+       if(!value)
+       {
+               return 0;
+       }
+       else if(value->is_constant)
+       {
+               return value;
+       }
+       else
+       {
+               int opcode = _jit_load_opcode
+                       (JIT_OP_COPY_LOAD_SBYTE, value->type, value, 1);
+               if(opcode)
+               {
+                       return apply_unary(func, opcode, value, value->type);
+               }
+               else
+               {
+                       return value;
+               }
+       }
+}
+
+/*@
+ * @deftypefun void jit_insn_store (jit_function_t func, jit_value_t dest, jit_value_t value)
+ * Store the contents of @code{value} at the location referred to by
+ * @code{dest}.
+ * @end deftypefun
+@*/
+int jit_insn_store(jit_function_t func, jit_value_t dest, jit_value_t value)
+{
+       jit_insn_t insn;
+       if(!dest || !value)
+       {
+               return 0;
+       }
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       value = jit_insn_convert(func, value, dest->type, 0);
+       if(!value)
+       {
+               return 0;
+       }
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, dest);
+       jit_value_ref(func, value);
+       insn->opcode = (short)_jit_store_opcode
+               (JIT_OP_COPY_INT, JIT_OP_COPY_STORE_BYTE, value->type);
+       insn->dest = dest;
+       insn->value1 = value;
+       return 1;
+}
+
+/*
+ * Scan back through the current block, looking for a relative adjustment
+ * that involves "value" as its destination.  Returns NULL if no such
+ * instruction was found, or it is blocked by a later use of "value".
+ * "addrof" will be set to a non-NULL value if the instruction just before
+ * the relative adjustment took the address of a local frame variable.
+ * This instruction is a candidate for being moved down to where the
+ * "load_relative" or "store_relative" occurs.
+ */
+static jit_insn_t previous_relative(jit_function_t func, jit_value_t value,
+                                                                       jit_insn_t *addrof)
+{
+       jit_insn_iter_t iter;
+       jit_insn_t insn;
+       jit_insn_t insn2;
+       jit_insn_t insn3;
+
+       /* Clear "addrof" first */
+       *addrof = 0;
+
+       /* If the value is not temporary, then it isn't a candidate */
+       if(!(value->is_temporary))
+       {
+               return 0;
+       }
+
+       /* Iterate back through the block looking for a suitable adjustment */
+       jit_insn_iter_init_last(&iter, func->builder->current_block);
+       while((insn = jit_insn_iter_previous(&iter)) != 0)
+       {
+               if(insn->opcode == JIT_OP_ADD_RELATIVE && insn->dest == value)
+               {
+                       /* See if the instruction just before the "add_relative"
+                          is an "address_of" that is being used by the add */
+                       insn3 = jit_insn_iter_previous(&iter);
+                       if(insn3)
+                       {
+                               jit_insn_iter_next(&iter);
+                               if(insn3->opcode != JIT_OP_ADDRESS_OF ||
+                                  insn3->dest != insn->value1 ||
+                                  !(insn3->dest->is_temporary))
+                               {
+                                       insn3 = 0;
+                               }
+                       }
+
+                       /* Scan forwards to ensure that "insn->value1" is not
+                          used anywhere in the instructions that follow */
+                       jit_insn_iter_next(&iter);
+                       while((insn2 = jit_insn_iter_next(&iter)) != 0)
+                       {
+                               if(insn2->dest == insn->value1 ||
+                                  insn2->value1 == insn->value1 ||
+                                  insn2->value2 == insn->value1)
+                               {
+                                       return 0;
+                               }
+                               if(insn3)
+                               {
+                                       /* We may need to disable the "address_of" instruction
+                                          if any of its values are used further on */
+                                       if(insn2->dest == insn3->dest ||
+                                      insn2->value1 == insn3->dest ||
+                                      insn2->value2 == insn3->dest ||
+                                          insn2->dest == insn3->value1 ||
+                                      insn2->value1 == insn3->value1 ||
+                                      insn2->value2 == insn3->value1)
+                                       {
+                                               insn3 = 0;
+                                       }
+                               }
+                       }
+                       if(insn3)
+                       {
+                               *addrof  = insn3;
+                       }
+                       return insn;
+               }
+               if(insn->dest == value || insn->value1 == value ||
+                  insn->value2 == value)
+               {
+                       /* This instruction uses "value" in some way, so it
+                          blocks any previous "add_relative" instructions */
+                       return 0;
+               }
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun 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 @code{type} from the effective address
+ * @code{(value + offset)}, where @code{value} is a pointer.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_load_relative
+               (jit_function_t func, jit_value_t value,
+                jit_nint offset, jit_type_t type)
+{
+       jit_insn_t insn;
+       jit_insn_t addrof;
+       if(!value)
+       {
+               return 0;
+       }
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       insn = previous_relative(func, value, &addrof);
+       if(insn)
+       {
+               /* We have a previous "add_relative" instruction for this
+                  pointer.  Remove it from the instruction stream and
+                  adjust the current offset accordingly */
+               offset += jit_value_get_nint_constant(insn->value2);
+               value = insn->value1;
+               insn->opcode = JIT_OP_NOP;
+               insn->dest = 0;
+               insn->value1 = 0;
+               insn->value2 = 0;
+               if(addrof)
+               {
+                       /* Shift the "address_of" instruction down too, to make
+                          it easier for the code generator to handle field
+                          accesses within local and global variables */
+                       value = jit_insn_address_of(func, addrof->value1);
+                       if(!value)
+                       {
+                               return 0;
+                       }
+                       addrof->opcode = JIT_OP_NOP;
+                       addrof->dest = 0;
+                       addrof->value1 = 0;
+                       addrof->value2 = 0;
+               }
+       }
+       return apply_binary
+               (func, _jit_load_opcode(JIT_OP_LOAD_RELATIVE_SBYTE, type, 0, 0), value,
+                jit_value_create_nint_constant(func, jit_type_nint, offset), type);
+}
+
+/*@
+ * @deftypefun int jit_insn_store_relative (jit_function_t func, jit_value_t dest, jit_nint offset, jit_value_t value)
+ * Store @code{value} at the effective address @code{(dest + offset)},
+ * where @code{dest} is a pointer.
+ * @end deftypefun
+@*/
+int jit_insn_store_relative
+               (jit_function_t func, jit_value_t dest,
+                jit_nint offset, jit_value_t value)
+{
+       jit_insn_t insn;
+       jit_insn_t addrof;
+       jit_value_t offset_value;
+       if(!dest || !value)
+       {
+               return 0;
+       }
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       insn = previous_relative(func, dest, &addrof);
+       if(insn)
+       {
+               /* We have a previous "add_relative" instruction for this
+                  pointer.  Remove it from the instruction stream and
+                  adjust the current offset accordingly */
+               offset += jit_value_get_nint_constant(insn->value2);
+               dest = insn->value1;
+               insn->opcode = JIT_OP_NOP;
+               insn->dest = 0;
+               insn->value1 = 0;
+               insn->value2 = 0;
+               if(addrof)
+               {
+                       /* Shift the "address_of" instruction down too, to make
+                          it easier for the code generator to handle field
+                          accesses within local and global variables */
+                       dest = jit_insn_address_of(func, addrof->value1);
+                       if(!dest)
+                       {
+                               return 0;
+                       }
+                       addrof->opcode = JIT_OP_NOP;
+                       addrof->dest = 0;
+                       addrof->value1 = 0;
+                       addrof->value2 = 0;
+               }
+       }
+       offset_value = jit_value_create_nint_constant(func, jit_type_nint, offset);
+       if(!offset_value)
+       {
+               return 0;
+       }
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, dest);
+       jit_value_ref(func, value);
+       insn->opcode = (short)_jit_store_opcode
+               (JIT_OP_STORE_RELATIVE_BYTE, 0, value->type);
+       insn->flags = JIT_INSN_DEST_IS_VALUE;
+       insn->dest = dest;
+       insn->value1 = value;
+       insn->value2 = offset_value;
+       return 1;
+}
+
+/*@
+ * @deftypefun jit_value_t jit_insn_add_relative (jit_function_t func, jit_value_t value, jit_nint offset)
+ * Add the constant @code{offset} to the specified pointer @code{value}.
+ * This is functionally identical to calling @code{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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_add_relative
+               (jit_function_t func, jit_value_t value, jit_nint offset)
+{
+       jit_insn_t insn;
+       jit_insn_t addrof;
+       if(!value)
+       {
+               return 0;
+       }
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       insn = previous_relative(func, value, &addrof);
+       if(insn)
+       {
+               /* Back-patch the "add_relative" instruction to adjust the offset */
+               insn->value2 = jit_value_create_nint_constant
+                       (func, jit_type_nint,
+                        jit_value_get_nint_constant(insn->value2) + offset);
+               return value;
+       }
+       else
+       {
+               /* Create a new "add_relative" instruction */
+               return apply_binary(func, JIT_OP_ADD_RELATIVE, value,
+                                                       jit_value_create_nint_constant
+                                                               (func, jit_type_nint, offset),
+                                                       jit_type_void_ptr);
+       }
+}
+
+/*@
+ * @deftypefun int jit_insn_check_null (jit_function_t func, jit_value_t value)
+ * Check @code{value} to see if it is NULL.  If it is, then throw the
+ * built-in @code{JIT_RESULT_NULL_REFERENCE} exception.
+ * @end deftypefun
+@*/
+int jit_insn_check_null(jit_function_t func, jit_value_t value)
+{
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       func->builder->may_throw = 1;
+       return create_unary_note(func, JIT_OP_CHECK_NULL, value);
+}
+
+int _jit_insn_check_is_redundant(const jit_insn_iter_t *iter)
+{
+       jit_insn_iter_t new_iter = *iter;
+       jit_insn_t insn;
+       jit_value_t value;
+
+       /* Back up to find the "check_null" instruction of interest */
+       insn = jit_insn_iter_previous(&new_iter);
+       value = insn->value1;
+
+       /* The value must be temporary or local, and not volatile or addressable.
+          Otherwise the value could be vulnerable to aliasing side-effects that
+          could make it NULL again even after we have checked it */
+       if(!(value->is_temporary) || !(value->is_local))
+       {
+               return 0;
+       }
+       if(value->is_volatile || value->is_addressable)
+       {
+               return 0;
+       }
+
+       /* Search back for a previous "check_null" instruction */
+       while((insn = jit_insn_iter_previous(&new_iter)) != 0)
+       {
+               if(insn->opcode == JIT_OP_CHECK_NULL && insn->value1 == value)
+               {
+                       /* This is the previous "check_null" that we were looking for */
+                       return 1;
+               }
+               if(insn->opcode >= JIT_OP_STORE_RELATIVE_BYTE &&
+                  insn->opcode <= JIT_OP_STORE_RELATIVE_STRUCT)
+               {
+                       /* This stores to the memory referenced by the destination,
+                          not to the destination itself, so it cannot affect "value" */
+                       continue;
+               }
+               if(insn->dest == value)
+               {
+                       /* The value was used as a destination, so we must check */
+                       return 0;
+               }
+       }
+
+       /* There was no previous "check_null" instruction for this value */
+       return 0;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_add
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const add_descr = {
+               JIT_OP_IADD,
+               JIT_OP_IADD,
+               JIT_OP_LADD,
+               JIT_OP_LADD,
+               JIT_OP_FADD,
+               JIT_OP_DADD,
+               JIT_OP_NFADD,
+               jit_intrinsic(jit_int_add, descr_i_ii),
+               jit_intrinsic(jit_uint_add, descr_I_II),
+               jit_intrinsic(jit_long_add, descr_l_ll),
+               jit_intrinsic(jit_ulong_add, descr_L_LL),
+               jit_intrinsic(jit_float32_add, descr_f_ff),
+               jit_intrinsic(jit_float64_add, descr_d_dd),
+               jit_intrinsic(jit_nfloat_add, descr_D_DD)
+       };
+       return apply_arith(func, &add_descr, value1, value2, 0, 0, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_add_ovf
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const add_ovf_descr = {
+               JIT_OP_IADD_OVF,
+               JIT_OP_IADD_OVF_UN,
+               JIT_OP_LADD_OVF,
+               JIT_OP_LADD_OVF_UN,
+               JIT_OP_FADD,
+               JIT_OP_DADD,
+               JIT_OP_NFADD,
+               jit_intrinsic(jit_int_add_ovf, descr_e_pi_ii),
+               jit_intrinsic(jit_uint_add_ovf, descr_e_pI_II),
+               jit_intrinsic(jit_long_add_ovf, descr_e_pl_ll),
+               jit_intrinsic(jit_ulong_add_ovf, descr_e_pL_LL),
+               jit_intrinsic(jit_float32_add, descr_f_ff),
+               jit_intrinsic(jit_float64_add, descr_d_dd),
+               jit_intrinsic(jit_nfloat_add, descr_D_DD)
+       };
+       return apply_arith(func, &add_ovf_descr, value1, value2, 0, 0, 1);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_sub
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const sub_descr = {
+               JIT_OP_ISUB,
+               JIT_OP_ISUB,
+               JIT_OP_LSUB,
+               JIT_OP_LSUB,
+               JIT_OP_FSUB,
+               JIT_OP_DSUB,
+               JIT_OP_NFSUB,
+               jit_intrinsic(jit_int_sub, descr_i_ii),
+               jit_intrinsic(jit_uint_sub, descr_I_II),
+               jit_intrinsic(jit_long_sub, descr_l_ll),
+               jit_intrinsic(jit_ulong_sub, descr_L_LL),
+               jit_intrinsic(jit_float32_sub, descr_f_ff),
+               jit_intrinsic(jit_float64_sub, descr_d_dd),
+               jit_intrinsic(jit_nfloat_sub, descr_D_DD)
+       };
+       return apply_arith(func, &sub_descr, value1, value2, 0, 0, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_sub_ovf
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const sub_ovf_descr = {
+               JIT_OP_ISUB_OVF,
+               JIT_OP_ISUB_OVF_UN,
+               JIT_OP_LSUB_OVF,
+               JIT_OP_LSUB_OVF_UN,
+               JIT_OP_FSUB,
+               JIT_OP_DSUB,
+               JIT_OP_NFSUB,
+               jit_intrinsic(jit_int_sub_ovf, descr_e_pi_ii),
+               jit_intrinsic(jit_uint_sub_ovf, descr_e_pI_II),
+               jit_intrinsic(jit_long_sub_ovf, descr_e_pl_ll),
+               jit_intrinsic(jit_ulong_sub_ovf, descr_e_pL_LL),
+               jit_intrinsic(jit_float32_sub, descr_f_ff),
+               jit_intrinsic(jit_float64_sub, descr_d_dd),
+               jit_intrinsic(jit_nfloat_sub, descr_D_DD)
+       };
+       return apply_arith(func, &sub_ovf_descr, value1, value2, 0, 0, 1);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_mul
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const mul_descr = {
+               JIT_OP_IMUL,
+               JIT_OP_IMUL,
+               JIT_OP_LMUL,
+               JIT_OP_LMUL,
+               JIT_OP_FMUL,
+               JIT_OP_DMUL,
+               JIT_OP_NFMUL,
+               jit_intrinsic(jit_int_mul, descr_i_ii),
+               jit_intrinsic(jit_uint_mul, descr_I_II),
+               jit_intrinsic(jit_long_mul, descr_l_ll),
+               jit_intrinsic(jit_ulong_mul, descr_L_LL),
+               jit_intrinsic(jit_float32_mul, descr_f_ff),
+               jit_intrinsic(jit_float64_mul, descr_d_dd),
+               jit_intrinsic(jit_nfloat_mul, descr_D_DD)
+       };
+       return apply_arith(func, &mul_descr, value1, value2, 0, 0, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_mul_ovf
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const mul_ovf_descr = {
+               JIT_OP_IMUL_OVF,
+               JIT_OP_IMUL_OVF_UN,
+               JIT_OP_LMUL_OVF,
+               JIT_OP_LMUL_OVF_UN,
+               JIT_OP_FMUL,
+               JIT_OP_DMUL,
+               JIT_OP_NFMUL,
+               jit_intrinsic(jit_int_mul_ovf, descr_e_pi_ii),
+               jit_intrinsic(jit_uint_mul_ovf, descr_e_pI_II),
+               jit_intrinsic(jit_long_mul_ovf, descr_e_pl_ll),
+               jit_intrinsic(jit_ulong_mul_ovf, descr_e_pL_LL),
+               jit_intrinsic(jit_float32_mul, descr_f_ff),
+               jit_intrinsic(jit_float64_mul, descr_d_dd),
+               jit_intrinsic(jit_nfloat_mul, descr_D_DD)
+       };
+       return apply_arith(func, &mul_ovf_descr, value1, value2, 0, 0, 1);
+}
+
+/*@
+ * @deftypefun 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).
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_div
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const div_descr = {
+               JIT_OP_IDIV,
+               JIT_OP_IDIV_UN,
+               JIT_OP_LDIV,
+               JIT_OP_LDIV_UN,
+               JIT_OP_FDIV,
+               JIT_OP_DDIV,
+               JIT_OP_NFDIV,
+               jit_intrinsic(jit_int_div, descr_e_pi_ii),
+               jit_intrinsic(jit_uint_div, descr_e_pI_II),
+               jit_intrinsic(jit_long_div, descr_e_pl_ll),
+               jit_intrinsic(jit_ulong_div, descr_e_pL_LL),
+               jit_intrinsic(jit_float32_div, descr_f_ff),
+               jit_intrinsic(jit_float64_div, descr_d_dd),
+               jit_intrinsic(jit_nfloat_div, descr_D_DD)
+       };
+       return apply_arith(func, &div_descr, value1, value2, 0, 0, 0);
+}
+
+/*@
+ * @deftypefun 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).
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_rem
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const rem_descr = {
+               JIT_OP_IREM,
+               JIT_OP_IREM_UN,
+               JIT_OP_LREM,
+               JIT_OP_LREM_UN,
+               JIT_OP_FREM,
+               JIT_OP_DREM,
+               JIT_OP_NFREM,
+               jit_intrinsic(jit_int_rem, descr_e_pi_ii),
+               jit_intrinsic(jit_uint_rem, descr_e_pI_II),
+               jit_intrinsic(jit_long_rem, descr_e_pl_ll),
+               jit_intrinsic(jit_ulong_rem, descr_e_pL_LL),
+               jit_intrinsic(jit_float32_rem, descr_f_ff),
+               jit_intrinsic(jit_float64_rem, descr_d_dd),
+               jit_intrinsic(jit_nfloat_rem, descr_D_DD)
+       };
+       return apply_arith(func, &rem_descr, value1, value2, 0, 0, 0);
+}
+
+/*@
+ * @deftypefun 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
+ * @code{jit_insn_rem}, except that it uses IEEE rules for computing
+ * the remainder of floating-point values.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_rem_ieee
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const rem_ieee_descr = {
+               JIT_OP_IREM,
+               JIT_OP_IREM_UN,
+               JIT_OP_LREM,
+               JIT_OP_LREM_UN,
+               JIT_OP_FREM_IEEE,
+               JIT_OP_DREM_IEEE,
+               JIT_OP_NFREM_IEEE,
+               jit_intrinsic(jit_int_rem, descr_e_pi_ii),
+               jit_intrinsic(jit_uint_rem, descr_e_pI_II),
+               jit_intrinsic(jit_long_rem, descr_e_pl_ll),
+               jit_intrinsic(jit_ulong_rem, descr_e_pL_LL),
+               jit_intrinsic(jit_float32_ieee_rem, descr_f_ff),
+               jit_intrinsic(jit_float64_ieee_rem, descr_d_dd),
+               jit_intrinsic(jit_nfloat_ieee_rem, descr_D_DD)
+       };
+       return apply_arith(func, &rem_ieee_descr, value1, value2, 0, 0, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_neg
+               (jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const neg_descr = {
+               JIT_OP_INEG,
+               JIT_OP_INEG,
+               JIT_OP_LNEG,
+               JIT_OP_LNEG,
+               JIT_OP_FNEG,
+               JIT_OP_DNEG,
+               JIT_OP_NFNEG,
+               jit_intrinsic(jit_int_neg, descr_i_i),
+               jit_intrinsic(jit_uint_neg, descr_I_I),
+               jit_intrinsic(jit_long_neg, descr_l_l),
+               jit_intrinsic(jit_ulong_neg, descr_L_L),
+               jit_intrinsic(jit_float32_neg, descr_f_f),
+               jit_intrinsic(jit_float64_neg, descr_d_d),
+               jit_intrinsic(jit_nfloat_neg, descr_D_D)
+       };
+       return apply_unary_arith(func, &neg_descr, value1, 0, 0, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_and
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const and_descr = {
+               JIT_OP_IAND,
+               JIT_OP_IAND,
+               JIT_OP_LAND,
+               JIT_OP_LAND,
+               0, 0, 0,
+               jit_intrinsic(jit_int_and, descr_i_ii),
+               jit_intrinsic(jit_uint_and, descr_I_II),
+               jit_intrinsic(jit_long_and, descr_l_ll),
+               jit_intrinsic(jit_ulong_and, descr_L_LL),
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic
+       };
+       return apply_arith(func, &and_descr, value1, value2, 1, 0, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_or
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const or_descr = {
+               JIT_OP_IOR,
+               JIT_OP_IOR,
+               JIT_OP_LOR,
+               JIT_OP_LOR,
+               0, 0, 0,
+               jit_intrinsic(jit_int_or, descr_i_ii),
+               jit_intrinsic(jit_uint_or, descr_I_II),
+               jit_intrinsic(jit_long_or, descr_l_ll),
+               jit_intrinsic(jit_ulong_or, descr_L_LL),
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic
+       };
+       return apply_arith(func, &or_descr, value1, value2, 1, 0, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_xor
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const xor_descr = {
+               JIT_OP_IXOR,
+               JIT_OP_IXOR,
+               JIT_OP_LXOR,
+               JIT_OP_LXOR,
+               0, 0, 0,
+               jit_intrinsic(jit_int_xor, descr_i_ii),
+               jit_intrinsic(jit_uint_xor, descr_I_II),
+               jit_intrinsic(jit_long_xor, descr_l_ll),
+               jit_intrinsic(jit_ulong_xor, descr_L_LL),
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic
+       };
+       return apply_arith(func, &xor_descr, value1, value2, 1, 0, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_not
+               (jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const not_descr = {
+               JIT_OP_INOT,
+               JIT_OP_INOT,
+               JIT_OP_LNOT,
+               JIT_OP_LNOT,
+               0, 0, 0,
+               jit_intrinsic(jit_int_not, descr_i_i),
+               jit_intrinsic(jit_uint_not, descr_I_I),
+               jit_intrinsic(jit_long_not, descr_l_l),
+               jit_intrinsic(jit_ulong_not, descr_L_L),
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic
+       };
+       return apply_unary_arith(func, &not_descr, value1, 1, 0, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_shl
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const shl_descr = {
+               JIT_OP_ISHL,
+               JIT_OP_ISHL,
+               JIT_OP_LSHL,
+               JIT_OP_LSHL,
+               0, 0, 0,
+               jit_intrinsic(jit_int_shl, descr_i_iI),
+               jit_intrinsic(jit_uint_shl, descr_I_II),
+               jit_intrinsic(jit_long_shl, descr_l_lI),
+               jit_intrinsic(jit_ulong_shl, descr_L_LI),
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic
+       };
+       return apply_shift(func, &shl_descr, value1, value2);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_shr
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const shr_descr = {
+               JIT_OP_ISHR,
+               JIT_OP_ISHR_UN,
+               JIT_OP_LSHR,
+               JIT_OP_LSHR_UN,
+               0, 0, 0,
+               jit_intrinsic(jit_int_shr, descr_i_iI),
+               jit_intrinsic(jit_uint_shr, descr_I_II),
+               jit_intrinsic(jit_long_shr, descr_l_lI),
+               jit_intrinsic(jit_ulong_shr, descr_L_LI),
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic
+       };
+       return apply_shift(func, &shr_descr, value1, value2);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_ushr
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const ushr_descr = {
+               JIT_OP_ISHR_UN,
+               JIT_OP_ISHR_UN,
+               JIT_OP_LSHR_UN,
+               JIT_OP_LSHR_UN,
+               0, 0, 0,
+               jit_intrinsic(jit_uint_shr, descr_I_II),
+               jit_intrinsic(jit_uint_shr, descr_I_II),
+               jit_intrinsic(jit_ulong_shr, descr_L_LI),
+               jit_intrinsic(jit_ulong_shr, descr_L_LI),
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic
+       };
+       return apply_shift(func, &ushr_descr, value1, value2);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_sshr
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const sshr_descr = {
+               JIT_OP_ISHR,
+               JIT_OP_ISHR,
+               JIT_OP_LSHR,
+               JIT_OP_LSHR,
+               0, 0, 0,
+               jit_intrinsic(jit_int_shr, descr_i_iI),
+               jit_intrinsic(jit_int_shr, descr_i_iI),
+               jit_intrinsic(jit_long_shr, descr_l_lI),
+               jit_intrinsic(jit_long_shr, descr_l_lI),
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic
+       };
+       return apply_shift(func, &sshr_descr, value1, value2);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_eq
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const eq_descr = {
+               JIT_OP_IEQ,
+               JIT_OP_IEQ,
+               JIT_OP_LEQ,
+               JIT_OP_LEQ,
+               JIT_OP_FEQ,
+               JIT_OP_DEQ,
+               JIT_OP_NFEQ,
+               jit_intrinsic(jit_int_eq, descr_i_ii),
+               jit_intrinsic(jit_uint_eq, descr_i_II),
+               jit_intrinsic(jit_long_eq, descr_i_ll),
+               jit_intrinsic(jit_ulong_eq, descr_i_LL),
+               jit_intrinsic(jit_float32_eq, descr_i_ff),
+               jit_intrinsic(jit_float64_eq, descr_i_dd),
+               jit_intrinsic(jit_nfloat_eq, descr_i_DD)
+       };
+       return apply_compare(func, &eq_descr, value1, value2, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_ne
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const ne_descr = {
+               JIT_OP_INE,
+               JIT_OP_INE,
+               JIT_OP_LNE,
+               JIT_OP_LNE,
+               JIT_OP_FNE,
+               JIT_OP_DNE,
+               JIT_OP_NFNE,
+               jit_intrinsic(jit_int_ne, descr_i_ii),
+               jit_intrinsic(jit_uint_ne, descr_i_II),
+               jit_intrinsic(jit_long_ne, descr_i_ll),
+               jit_intrinsic(jit_ulong_ne, descr_i_LL),
+               jit_intrinsic(jit_float32_ne, descr_i_ff),
+               jit_intrinsic(jit_float64_ne, descr_i_dd),
+               jit_intrinsic(jit_nfloat_ne, descr_i_DD)
+       };
+       return apply_compare(func, &ne_descr, value1, value2, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_lt
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const lt_descr = {
+               JIT_OP_ILT,
+               JIT_OP_ILT_UN,
+               JIT_OP_LLT,
+               JIT_OP_LLT_UN,
+               JIT_OP_FLT,
+               JIT_OP_DLT,
+               JIT_OP_NFLT,
+               jit_intrinsic(jit_int_lt, descr_i_ii),
+               jit_intrinsic(jit_uint_lt, descr_i_II),
+               jit_intrinsic(jit_long_lt, descr_i_ll),
+               jit_intrinsic(jit_ulong_lt, descr_i_LL),
+               jit_intrinsic(jit_float32_lt, descr_i_ff),
+               jit_intrinsic(jit_float64_lt, descr_i_dd),
+               jit_intrinsic(jit_nfloat_lt, descr_i_DD)
+       };
+       return apply_compare(func, &lt_descr, value1, value2, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_le
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const le_descr = {
+               JIT_OP_ILE,
+               JIT_OP_ILE_UN,
+               JIT_OP_LLE,
+               JIT_OP_LLE_UN,
+               JIT_OP_FLE,
+               JIT_OP_DLE,
+               JIT_OP_NFLE,
+               jit_intrinsic(jit_int_le, descr_i_ii),
+               jit_intrinsic(jit_uint_le, descr_i_II),
+               jit_intrinsic(jit_long_le, descr_i_ll),
+               jit_intrinsic(jit_ulong_le, descr_i_LL),
+               jit_intrinsic(jit_float32_le, descr_i_ff),
+               jit_intrinsic(jit_float64_le, descr_i_dd),
+               jit_intrinsic(jit_nfloat_le, descr_i_DD)
+       };
+       return apply_compare(func, &le_descr, value1, value2, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_gt
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const gt_descr = {
+               JIT_OP_IGT,
+               JIT_OP_IGT_UN,
+               JIT_OP_LGT,
+               JIT_OP_LGT_UN,
+               JIT_OP_FGT,
+               JIT_OP_DGT,
+               JIT_OP_NFGT,
+               jit_intrinsic(jit_int_gt, descr_i_ii),
+               jit_intrinsic(jit_uint_gt, descr_i_II),
+               jit_intrinsic(jit_long_gt, descr_i_ll),
+               jit_intrinsic(jit_ulong_gt, descr_i_LL),
+               jit_intrinsic(jit_float32_gt, descr_i_ff),
+               jit_intrinsic(jit_float64_gt, descr_i_dd),
+               jit_intrinsic(jit_nfloat_gt, descr_i_DD)
+       };
+       return apply_compare(func, &gt_descr, value1, value2, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_ge
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const ge_descr = {
+               JIT_OP_IGE,
+               JIT_OP_IGE_UN,
+               JIT_OP_LGE,
+               JIT_OP_LGE_UN,
+               JIT_OP_FGE,
+               JIT_OP_DGE,
+               JIT_OP_NFGE,
+               jit_intrinsic(jit_int_ge, descr_i_ii),
+               jit_intrinsic(jit_uint_ge, descr_i_II),
+               jit_intrinsic(jit_long_ge, descr_i_ll),
+               jit_intrinsic(jit_ulong_ge, descr_i_LL),
+               jit_intrinsic(jit_float32_ge, descr_i_ff),
+               jit_intrinsic(jit_float64_ge, descr_i_dd),
+               jit_intrinsic(jit_nfloat_ge, descr_i_DD)
+       };
+       return apply_compare(func, &ge_descr, value1, value2, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_cmpl
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const cmpl_descr = {
+               JIT_OP_ICMP,
+               JIT_OP_ICMP_UN,
+               JIT_OP_LCMP,
+               JIT_OP_LCMP_UN,
+               JIT_OP_FCMPL,
+               JIT_OP_DCMPL,
+               JIT_OP_NFCMPL,
+               jit_intrinsic(jit_int_cmp, descr_i_ii),
+               jit_intrinsic(jit_uint_cmp, descr_i_II),
+               jit_intrinsic(jit_long_cmp, descr_i_ll),
+               jit_intrinsic(jit_ulong_cmp, descr_i_LL),
+               jit_intrinsic(jit_float32_cmpl, descr_i_ff),
+               jit_intrinsic(jit_float64_cmpl, descr_i_dd),
+               jit_intrinsic(jit_nfloat_cmpl, descr_i_DD)
+       };
+       return apply_compare(func, &cmpl_descr, value1, value2, 0);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_cmpg
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const cmpg_descr = {
+               JIT_OP_ICMP,
+               JIT_OP_ICMP_UN,
+               JIT_OP_LCMP,
+               JIT_OP_LCMP_UN,
+               JIT_OP_FCMPG,
+               JIT_OP_DCMPG,
+               JIT_OP_NFCMPG,
+               jit_intrinsic(jit_int_cmp, descr_i_ii),
+               jit_intrinsic(jit_uint_cmp, descr_i_II),
+               jit_intrinsic(jit_long_cmp, descr_i_ll),
+               jit_intrinsic(jit_ulong_cmp, descr_i_LL),
+               jit_intrinsic(jit_float32_cmpg, descr_i_ff),
+               jit_intrinsic(jit_float64_cmpg, descr_i_dd),
+               jit_intrinsic(jit_nfloat_cmpg, descr_i_DD)
+       };
+       return apply_compare(func, &cmpg_descr, value1, value2, 0);
+}
+
+/*@
+ * @deftypefun 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 @code{jit_type_int}.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_to_bool(jit_function_t func, jit_value_t value1)
+{
+       jit_type_t type;
+       jit_block_t block;
+       jit_insn_t last;
+       int opcode;
+
+       /* Bail out if the parameters are invalid */
+       if(!value1)
+       {
+               return 0;
+       }
+
+       /* Ensure that we have a builder for this function */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* If the previous instruction was a comparison, then there is
+          nothing that we need to do to make the value boolean */
+       block = func->builder->current_block;
+       last = _jit_block_get_last(block);
+       if(value1->is_temporary && last && last->dest == value1)
+       {
+               opcode = last->opcode;
+               if(opcode >= JIT_OP_IEQ && opcode <= JIT_OP_NFGE_INV)
+               {
+                       return value1;
+               }
+       }
+
+       /* Perform a comparison to determine if the value is non-zero */
+       type = jit_type_promote_int(jit_type_normalize(value1->type));
+       if(type == jit_type_int || type == jit_type_uint)
+       {
+               return jit_insn_ne
+                       (func, value1,
+                        jit_value_create_nint_constant(func, jit_type_int, 0));
+       }
+       else if(type == jit_type_long || type == jit_type_ulong)
+       {
+               return jit_insn_ne
+                       (func, value1,
+                        jit_value_create_long_constant(func, jit_type_long, 0));
+       }
+       else if(type == jit_type_float32)
+       {
+               return jit_insn_ne
+                       (func, value1,
+                        jit_value_create_float32_constant
+                               (func, jit_type_float32, (jit_float32)0.0));
+       }
+       else if(type == jit_type_float64)
+       {
+               return jit_insn_ne
+                       (func, value1,
+                        jit_value_create_float64_constant
+                               (func, jit_type_float64, (jit_float64)0.0));
+       }
+       else
+       {
+               return jit_insn_ne
+                       (func, value1,
+                        jit_value_create_nfloat_constant
+                               (func, jit_type_nfloat, (jit_nfloat)0.0));
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{jit_type_int}
+ * (i.e. the inverse of @code{jit_insn_to_bool}).
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_to_not_bool(jit_function_t func, jit_value_t value1)
+{
+       jit_type_t type;
+       jit_block_t block;
+       jit_insn_t last;
+       int opcode;
+
+       /* Bail out if the parameters are invalid */
+       if(!value1)
+       {
+               return 0;
+       }
+
+       /* Ensure that we have a builder for this function */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* If the previous instruction was a comparison, then all
+          we have to do is invert the comparison opcode */
+       block = func->builder->current_block;
+       last = _jit_block_get_last(block);
+       if(value1->is_temporary && last && last->dest == value1)
+       {
+               opcode = last->opcode;
+               if(opcode >= JIT_OP_IEQ && opcode <= JIT_OP_NFGE_INV)
+               {
+                       switch(opcode)
+                       {
+                               case JIT_OP_IEQ:                opcode = JIT_OP_INE;      break;
+                               case JIT_OP_INE:                opcode = JIT_OP_IEQ;      break;
+                               case JIT_OP_ILT:                opcode = JIT_OP_IGE;      break;
+                               case JIT_OP_ILT_UN:             opcode = JIT_OP_IGE_UN;   break;
+                               case JIT_OP_ILE:                opcode = JIT_OP_IGT;      break;
+                               case JIT_OP_ILE_UN:             opcode = JIT_OP_IGT_UN;   break;
+                               case JIT_OP_IGT:                opcode = JIT_OP_ILE;      break;
+                               case JIT_OP_IGT_UN:             opcode = JIT_OP_ILE_UN;   break;
+                               case JIT_OP_IGE:                opcode = JIT_OP_ILT;      break;
+                               case JIT_OP_IGE_UN:             opcode = JIT_OP_ILT_UN;   break;
+                               case JIT_OP_LEQ:                opcode = JIT_OP_LNE;      break;
+                               case JIT_OP_LNE:                opcode = JIT_OP_LEQ;      break;
+                               case JIT_OP_LLT:                opcode = JIT_OP_LGE;      break;
+                               case JIT_OP_LLT_UN:             opcode = JIT_OP_LGE_UN;   break;
+                               case JIT_OP_LLE:                opcode = JIT_OP_LGT;      break;
+                               case JIT_OP_LLE_UN:             opcode = JIT_OP_LGT_UN;   break;
+                               case JIT_OP_LGT:                opcode = JIT_OP_LLE;      break;
+                               case JIT_OP_LGT_UN:             opcode = JIT_OP_LLE_UN;   break;
+                               case JIT_OP_LGE:                opcode = JIT_OP_LLT;      break;
+                               case JIT_OP_LGE_UN:             opcode = JIT_OP_LLT_UN;   break;
+                               case JIT_OP_FEQ:                opcode = JIT_OP_FNE_INV;  break;
+                               case JIT_OP_FNE:                opcode = JIT_OP_FEQ_INV;  break;
+                               case JIT_OP_FLT:                opcode = JIT_OP_FGE_INV;  break;
+                               case JIT_OP_FLE:                opcode = JIT_OP_FGT_INV;  break;
+                               case JIT_OP_FGT:                opcode = JIT_OP_FLE_INV;  break;
+                               case JIT_OP_FGE:                opcode = JIT_OP_FLT_INV;  break;
+                               case JIT_OP_FEQ_INV:    opcode = JIT_OP_FNE;      break;
+                               case JIT_OP_FNE_INV:    opcode = JIT_OP_FEQ;      break;
+                               case JIT_OP_FLT_INV:    opcode = JIT_OP_FGE;      break;
+                               case JIT_OP_FLE_INV:    opcode = JIT_OP_FGT;      break;
+                               case JIT_OP_FGT_INV:    opcode = JIT_OP_FLE;      break;
+                               case JIT_OP_FGE_INV:    opcode = JIT_OP_FLT;      break;
+                               case JIT_OP_DEQ:                opcode = JIT_OP_DNE_INV;  break;
+                               case JIT_OP_DNE:                opcode = JIT_OP_DEQ_INV;  break;
+                               case JIT_OP_DLT:                opcode = JIT_OP_DGE_INV;  break;
+                               case JIT_OP_DLE:                opcode = JIT_OP_DGT_INV;  break;
+                               case JIT_OP_DGT:                opcode = JIT_OP_DLE_INV;  break;
+                               case JIT_OP_DGE:                opcode = JIT_OP_DLT_INV;  break;
+                               case JIT_OP_DEQ_INV:    opcode = JIT_OP_DNE;      break;
+                               case JIT_OP_DNE_INV:    opcode = JIT_OP_DEQ;      break;
+                               case JIT_OP_DLT_INV:    opcode = JIT_OP_DGE;      break;
+                               case JIT_OP_DLE_INV:    opcode = JIT_OP_DGT;      break;
+                               case JIT_OP_DGT_INV:    opcode = JIT_OP_DLE;      break;
+                               case JIT_OP_DGE_INV:    opcode = JIT_OP_DLT;      break;
+                               case JIT_OP_NFEQ:               opcode = JIT_OP_NFNE_INV; break;
+                               case JIT_OP_NFNE:               opcode = JIT_OP_NFEQ_INV; break;
+                               case JIT_OP_NFLT:               opcode = JIT_OP_NFGE_INV; break;
+                               case JIT_OP_NFLE:               opcode = JIT_OP_NFGT_INV; break;
+                               case JIT_OP_NFGT:               opcode = JIT_OP_NFLE_INV; break;
+                               case JIT_OP_NFGE:               opcode = JIT_OP_NFLT_INV; break;
+                               case JIT_OP_NFEQ_INV:   opcode = JIT_OP_NFNE;     break;
+                               case JIT_OP_NFNE_INV:   opcode = JIT_OP_NFEQ;     break;
+                               case JIT_OP_NFLT_INV:   opcode = JIT_OP_NFGE;     break;
+                               case JIT_OP_NFLE_INV:   opcode = JIT_OP_NFGT;     break;
+                               case JIT_OP_NFGT_INV:   opcode = JIT_OP_NFLE;     break;
+                               case JIT_OP_NFGE_INV:   opcode = JIT_OP_NFLT;     break;
+                       }
+                       last->opcode = (short)opcode;
+                       return value1;
+               }
+       }
+
+       /* Perform a comparison to determine if the value is zero */
+       type = jit_type_promote_int(jit_type_normalize(value1->type));
+       if(type == jit_type_int || type == jit_type_uint)
+       {
+               return jit_insn_eq
+                       (func, value1,
+                        jit_value_create_nint_constant(func, jit_type_int, 0));
+       }
+       else if(type == jit_type_long || type == jit_type_ulong)
+       {
+               return jit_insn_eq
+                       (func, value1,
+                        jit_value_create_long_constant(func, jit_type_long, 0));
+       }
+       else if(type == jit_type_float32)
+       {
+               return jit_insn_eq
+                       (func, value1,
+                        jit_value_create_float32_constant
+                               (func, jit_type_float32, (jit_float32)0.0));
+       }
+       else if(type == jit_type_float64)
+       {
+               return jit_insn_eq
+                       (func, value1,
+                        jit_value_create_float64_constant
+                               (func, jit_type_float64, (jit_float64)0.0));
+       }
+       else
+       {
+               return jit_insn_eq
+                       (func, value1,
+                        jit_value_create_nfloat_constant
+                               (func, jit_type_nfloat, (jit_nfloat)0.0));
+       }
+}
+
+/*@
+ * @deftypefun jit_value_t jit_insn_acos (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_asin (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_atan (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_atan2 (jit_function_t func, jit_value_t value1, jit_value_t value2)
+ * @deftypefunx jit_value_t jit_insn_ceil (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_cos (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_cosh (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_exp (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_floor (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_log (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_log10 (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_pow (jit_function_t func, jit_value_t value1, jit_value_t value2)
+ * @deftypefunx jit_value_t jit_insn_rint (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_round (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_sin (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_sinh (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_sqrt (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_tan (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_tanh (jit_function_t func, jit_value_t value1)
+ * Apply a mathematical function to floating-point arguments.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_acos(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const acos_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FACOS,
+               JIT_OP_DACOS,
+               JIT_OP_NFACOS,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_acos, descr_f_f),
+               jit_intrinsic(jit_float64_acos, descr_d_d),
+               jit_intrinsic(jit_nfloat_acos, descr_D_D)
+       };
+       return apply_unary_arith(func, &acos_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_asin(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const asin_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FASIN,
+               JIT_OP_DASIN,
+               JIT_OP_NFASIN,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_asin, descr_f_f),
+               jit_intrinsic(jit_float64_asin, descr_d_d),
+               jit_intrinsic(jit_nfloat_asin, descr_D_D)
+       };
+       return apply_unary_arith(func, &asin_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_atan(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const atan_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FATAN,
+               JIT_OP_DATAN,
+               JIT_OP_NFATAN,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_atan, descr_f_f),
+               jit_intrinsic(jit_float64_atan, descr_d_d),
+               jit_intrinsic(jit_nfloat_atan, descr_D_D)
+       };
+       return apply_unary_arith(func, &atan_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_atan2
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const atan2_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FATAN2,
+               JIT_OP_DATAN2,
+               JIT_OP_NFATAN2,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_atan2, descr_f_ff),
+               jit_intrinsic(jit_float64_atan2, descr_d_dd),
+               jit_intrinsic(jit_nfloat_atan2, descr_D_DD)
+       };
+       return apply_arith(func, &atan2_descr, value1, value2, 0, 1, 0);
+}
+
+jit_value_t jit_insn_ceil(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const ceil_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FCEIL,
+               JIT_OP_DCEIL,
+               JIT_OP_NFCEIL,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_ceil, descr_f_f),
+               jit_intrinsic(jit_float64_ceil, descr_d_d),
+               jit_intrinsic(jit_nfloat_ceil, descr_D_D)
+       };
+       return apply_unary_arith(func, &ceil_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_cos(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const cos_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FCOS,
+               JIT_OP_DCOS,
+               JIT_OP_NFCOS,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_cos, descr_f_f),
+               jit_intrinsic(jit_float64_cos, descr_d_d),
+               jit_intrinsic(jit_nfloat_cos, descr_D_D)
+       };
+       return apply_unary_arith(func, &cos_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_cosh(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const cosh_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FCOSH,
+               JIT_OP_DCOSH,
+               JIT_OP_NFCOSH,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_cosh, descr_f_f),
+               jit_intrinsic(jit_float64_cosh, descr_d_d),
+               jit_intrinsic(jit_nfloat_cosh, descr_D_D)
+       };
+       return apply_unary_arith(func, &cosh_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_exp(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const exp_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FEXP,
+               JIT_OP_DEXP,
+               JIT_OP_NFEXP,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_exp, descr_f_f),
+               jit_intrinsic(jit_float64_exp, descr_d_d),
+               jit_intrinsic(jit_nfloat_exp, descr_D_D)
+       };
+       return apply_unary_arith(func, &exp_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_floor(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const floor_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FFLOOR,
+               JIT_OP_DFLOOR,
+               JIT_OP_NFFLOOR,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_floor, descr_f_f),
+               jit_intrinsic(jit_float64_floor, descr_d_d),
+               jit_intrinsic(jit_nfloat_floor, descr_D_D)
+       };
+       return apply_unary_arith(func, &floor_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_log(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const log_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FLOG,
+               JIT_OP_DLOG,
+               JIT_OP_NFLOG,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_log, descr_f_f),
+               jit_intrinsic(jit_float64_log, descr_d_d),
+               jit_intrinsic(jit_nfloat_log, descr_D_D)
+       };
+       return apply_unary_arith(func, &log_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_log10(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const log10_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FLOG10,
+               JIT_OP_DLOG10,
+               JIT_OP_NFLOG10,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_log10, descr_f_f),
+               jit_intrinsic(jit_float64_log10, descr_d_d),
+               jit_intrinsic(jit_nfloat_log10, descr_D_D)
+       };
+       return apply_unary_arith(func, &log10_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_pow
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const pow_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FPOW,
+               JIT_OP_DPOW,
+               JIT_OP_NFPOW,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_pow, descr_f_ff),
+               jit_intrinsic(jit_float64_pow, descr_d_dd),
+               jit_intrinsic(jit_nfloat_pow, descr_D_DD)
+       };
+       return apply_arith(func, &pow_descr, value1, value2, 0, 1, 0);
+}
+
+jit_value_t jit_insn_rint(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const rint_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FRINT,
+               JIT_OP_DRINT,
+               JIT_OP_NFRINT,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_rint, descr_f_f),
+               jit_intrinsic(jit_float64_rint, descr_d_d),
+               jit_intrinsic(jit_nfloat_rint, descr_D_D)
+       };
+       return apply_unary_arith(func, &rint_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_round(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const round_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FROUND,
+               JIT_OP_DROUND,
+               JIT_OP_NFROUND,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_round, descr_f_f),
+               jit_intrinsic(jit_float64_round, descr_d_d),
+               jit_intrinsic(jit_nfloat_round, descr_D_D)
+       };
+       return apply_unary_arith(func, &round_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_sin(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const sin_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FSIN,
+               JIT_OP_DSIN,
+               JIT_OP_NFSIN,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_sin, descr_f_f),
+               jit_intrinsic(jit_float64_sin, descr_d_d),
+               jit_intrinsic(jit_nfloat_sin, descr_D_D)
+       };
+       return apply_unary_arith(func, &sin_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_sinh(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const sinh_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FSINH,
+               JIT_OP_DSINH,
+               JIT_OP_NFSINH,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_sinh, descr_f_f),
+               jit_intrinsic(jit_float64_sinh, descr_d_d),
+               jit_intrinsic(jit_nfloat_sinh, descr_D_D)
+       };
+       return apply_unary_arith(func, &sinh_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_sqrt(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const sqrt_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FSQRT,
+               JIT_OP_DSQRT,
+               JIT_OP_NFSQRT,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_sqrt, descr_f_f),
+               jit_intrinsic(jit_float64_sqrt, descr_d_d),
+               jit_intrinsic(jit_nfloat_sqrt, descr_D_D)
+       };
+       return apply_unary_arith(func, &sqrt_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_tan(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const tan_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FTAN,
+               JIT_OP_DTAN,
+               JIT_OP_NFTAN,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_tan, descr_f_f),
+               jit_intrinsic(jit_float64_tan, descr_d_d),
+               jit_intrinsic(jit_nfloat_tan, descr_D_D)
+       };
+       return apply_unary_arith(func, &tan_descr, value1, 0, 1, 0);
+}
+
+jit_value_t jit_insn_tanh(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const tanh_descr = {
+               0, 0, 0, 0,
+               JIT_OP_FTANH,
+               JIT_OP_DTANH,
+               JIT_OP_NFTANH,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_tanh, descr_f_f),
+               jit_intrinsic(jit_float64_tanh, descr_d_d),
+               jit_intrinsic(jit_nfloat_tanh, descr_D_D)
+       };
+       return apply_unary_arith(func, &tanh_descr, value1, 0, 1, 0);
+}
+
+/*@
+ * @deftypefun jit_value_t jit_insn_is_nan (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_is_finite (jit_function_t func, jit_value_t value1)
+ * @deftypefunx 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_is_nan(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const is_nan_descr = {
+               0, 0, 0, 0,
+               JIT_OP_IS_FNAN,
+               JIT_OP_IS_DNAN,
+               JIT_OP_IS_NFNAN,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_is_nan, descr_i_f),
+               jit_intrinsic(jit_float64_is_nan, descr_i_d),
+               jit_intrinsic(jit_nfloat_is_nan, descr_i_D)
+       };
+       return apply_test(func, &is_nan_descr, value1, 1);
+}
+
+jit_value_t jit_insn_is_finite(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const is_finite_descr = {
+               0, 0, 0, 0,
+               JIT_OP_IS_FFINITE,
+               JIT_OP_IS_DFINITE,
+               JIT_OP_IS_NFFINITE,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_is_finite, descr_i_f),
+               jit_intrinsic(jit_float64_is_finite, descr_i_d),
+               jit_intrinsic(jit_nfloat_is_finite, descr_i_D)
+       };
+       return apply_test(func, &is_finite_descr, value1, 1);
+}
+
+jit_value_t jit_insn_is_inf(jit_function_t func, jit_value_t value1)
+{
+       static jit_opcode_descr const is_inf_descr = {
+               0, 0, 0, 0,
+               JIT_OP_IS_FINF,
+               JIT_OP_IS_DINF,
+               JIT_OP_IS_NFINF,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_no_intrinsic,
+               jit_intrinsic(jit_float32_is_inf, descr_i_f),
+               jit_intrinsic(jit_float64_is_inf, descr_i_d),
+               jit_intrinsic(jit_nfloat_is_inf, descr_i_D)
+       };
+       return apply_test(func, &is_inf_descr, value1, 1);
+}
+
+/*@
+ * @deftypefun jit_value_t jit_insn_abs (jit_function_t func, jit_value_t value1)
+ * @deftypefunx jit_value_t jit_insn_min (jit_function_t func, jit_value_t value1, jit_value_t value2)
+ * @deftypefunx jit_value_t jit_insn_max (jit_function_t func, jit_value_t value1, jit_value_t value2)
+ * @deftypefunx 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_abs(jit_function_t func, jit_value_t value1)
+{
+       int oper;
+       void *intrinsic;
+       const char *name;
+       jit_type_t result_type;
+       const jit_intrinsic_descr_t *descr;
+       if(!value1)
+       {
+               return 0;
+       }
+       result_type = common_binary(value1->type, value1->type, 0, 0);
+       if(result_type == jit_type_int)
+       {
+               oper = JIT_OP_IABS;
+               intrinsic = (void *)jit_int_abs;
+               name = "jit_int_abs";
+               descr = &descr_i_i;
+       }
+       else if(result_type == jit_type_uint)
+       {
+               oper = 0;
+               intrinsic = (void *)0;
+               name = 0;
+               descr = 0;
+       }
+       else if(result_type == jit_type_long)
+       {
+               oper = JIT_OP_LABS;
+               intrinsic = (void *)jit_long_abs;
+               name = "jit_long_abs";
+               descr = &descr_l_l;
+       }
+       else if(result_type == jit_type_ulong)
+       {
+               oper = 0;
+               intrinsic = (void *)0;
+               name = 0;
+               descr = 0;
+       }
+       else if(result_type == jit_type_float32)
+       {
+               oper = JIT_OP_FABS;
+               intrinsic = (void *)jit_float32_abs;
+               name = "jit_float32_abs";
+               descr = &descr_f_f;
+       }
+       else if(result_type == jit_type_float64)
+       {
+               oper = JIT_OP_DABS;
+               intrinsic = (void *)jit_float64_abs;
+               name = "jit_float64_abs";
+               descr = &descr_d_d;
+       }
+       else
+       {
+               oper = JIT_OP_NFABS;
+               intrinsic = (void *)jit_nfloat_abs;
+               name = "jit_nfloat_abs";
+               descr = &descr_D_D;
+       }
+       value1 = jit_insn_convert(func, value1, result_type, 0);
+       if(!oper)
+       {
+               /* Absolute value of an unsigned value */
+               return value1;
+       }
+       if(_jit_opcode_is_supported(oper))
+       {
+               return apply_unary(func, oper, value1, result_type);
+       }
+       else
+       {
+               return jit_insn_call_intrinsic
+                       (func, name, intrinsic, descr, value1, 0);
+       }
+}
+
+jit_value_t jit_insn_min
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const min_descr = {
+               JIT_OP_IMIN,
+               JIT_OP_IMIN_UN,
+               JIT_OP_LMIN,
+               JIT_OP_LMIN_UN,
+               JIT_OP_FMIN,
+               JIT_OP_DMIN,
+               JIT_OP_NFMIN,
+               jit_intrinsic(jit_int_min, descr_i_ii),
+               jit_intrinsic(jit_uint_min, descr_I_II),
+               jit_intrinsic(jit_long_min, descr_l_ll),
+               jit_intrinsic(jit_ulong_min, descr_L_LL),
+               jit_intrinsic(jit_float32_min, descr_f_ff),
+               jit_intrinsic(jit_float64_min, descr_d_dd),
+               jit_intrinsic(jit_nfloat_min, descr_D_DD)
+       };
+       return apply_arith(func, &min_descr, value1, value2, 0, 0, 0);
+}
+
+jit_value_t jit_insn_max
+               (jit_function_t func, jit_value_t value1, jit_value_t value2)
+{
+       static jit_opcode_descr const max_descr = {
+               JIT_OP_IMAX,
+               JIT_OP_IMAX_UN,
+               JIT_OP_LMAX,
+               JIT_OP_LMAX_UN,
+               JIT_OP_FMAX,
+               JIT_OP_DMAX,
+               JIT_OP_NFMAX,
+               jit_intrinsic(jit_int_max, descr_i_ii),
+               jit_intrinsic(jit_uint_max, descr_I_II),
+               jit_intrinsic(jit_long_max, descr_l_ll),
+               jit_intrinsic(jit_ulong_max, descr_L_LL),
+               jit_intrinsic(jit_float32_max, descr_f_ff),
+               jit_intrinsic(jit_float64_max, descr_d_dd),
+               jit_intrinsic(jit_nfloat_max, descr_D_DD)
+       };
+       return apply_arith(func, &max_descr, value1, value2, 0, 0, 0);
+}
+
+jit_value_t jit_insn_sign(jit_function_t func, jit_value_t value1)
+{
+       int oper;
+       void *intrinsic;
+       const char *name;
+       jit_type_t result_type;
+       const jit_intrinsic_descr_t *descr;
+       if(!value1)
+       {
+               return 0;
+       }
+       result_type = common_binary(value1->type, value1->type, 0, 0);
+       if(result_type == jit_type_int)
+       {
+               oper = JIT_OP_ISIGN;
+               intrinsic = (void *)jit_int_sign;
+               name = "jit_int_sign";
+               descr = &descr_i_i;
+       }
+       else if(result_type == jit_type_uint)
+       {
+               return jit_insn_ne
+                       (func, value1,
+                        jit_value_create_nint_constant(func, jit_type_uint, 0));
+       }
+       else if(result_type == jit_type_long)
+       {
+               oper = JIT_OP_LSIGN;
+               intrinsic = (void *)jit_long_sign;
+               name = "jit_long_sign";
+               descr = &descr_i_l;
+       }
+       else if(result_type == jit_type_ulong)
+       {
+               return jit_insn_ne
+                       (func, value1,
+                        jit_value_create_long_constant(func, jit_type_ulong, 0));
+       }
+       else if(result_type == jit_type_float32)
+       {
+               oper = JIT_OP_FSIGN;
+               intrinsic = (void *)jit_float32_sign;
+               name = "jit_float32_sign";
+               descr = &descr_i_f;
+       }
+       else if(result_type == jit_type_float64)
+       {
+               oper = JIT_OP_DSIGN;
+               intrinsic = (void *)jit_float64_sign;
+               name = "jit_float64_sign";
+               descr = &descr_i_d;
+       }
+       else
+       {
+               oper = JIT_OP_NFSIGN;
+               intrinsic = (void *)jit_nfloat_sign;
+               name = "jit_nfloat_sign";
+               descr = &descr_i_D;
+       }
+       value1 = jit_insn_convert(func, value1, result_type, 0);
+       if(_jit_opcode_is_supported(oper))
+       {
+               return apply_unary(func, oper, value1, result_type);
+       }
+       else
+       {
+               return jit_insn_call_intrinsic
+                       (func, name, intrinsic, descr, value1, 0);
+       }
+}
+
+/*
+ * Output instructions to handle "finally" clauses in the current context.
+ */
+static int handle_finally(jit_function_t func, int opcode)
+{
+       jit_block_eh_t eh = func->builder->current_handler;
+       while(eh != 0)
+       {
+               if(eh->finally_on_fault)
+               {
+                       /* The "finally" clause only applies to the "catch" block */
+                       if(!(eh->in_try_body) &&
+                          eh->finally_label != jit_label_undefined)
+                       {
+                               return create_noarg_note(func, opcode);
+                       }
+               }
+               else if(eh->finally_label != jit_label_undefined)
+               {
+                       /* The "finally" clause applies to "try" body and the "catch" */
+                       return create_noarg_note(func, opcode);
+               }
+               eh = eh->parent;
+       }
+       return 1;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+int jit_insn_branch(jit_function_t func, jit_label_t *label)
+{
+       jit_insn_t insn;
+       jit_block_t block;
+       if(!label)
+       {
+               return 0;
+       }
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       if(!handle_finally(func, JIT_OP_PREPARE_FOR_LEAVE))
+       {
+               return 0;
+       }
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       if(*label == jit_label_undefined)
+       {
+               *label = (func->builder->next_label)++;
+       }
+       insn->opcode = (short)JIT_OP_BR;
+       insn->flags = JIT_INSN_DEST_IS_LABEL;
+       insn->dest = (jit_value_t)(*label);
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       func->builder->current_block = block;
+       return 1;
+}
+
+/*@
+ * @deftypefun 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 @code{value} refers to a conditional expression that was created
+ * by @code{jit_insn_eq}, @code{jit_insn_ne}, etc, then the conditional
+ * expression will be replaced by an appropriate conditional branch
+ * instruction.
+ * @end deftypefun
+@*/
+int jit_insn_branch_if
+               (jit_function_t func, jit_value_t value, jit_label_t *label)
+{
+       jit_insn_t insn;
+       jit_block_t block;
+       jit_type_t type;
+       int opcode;
+       jit_value_t value2;
+
+       /* Bail out if the parameters are invalid */
+       if(!value || !label)
+       {
+               return 0;
+       }
+
+       /* Ensure that we have a function builder */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* Allocate a new label identifier, if necessary */
+       if(*label == jit_label_undefined)
+       {
+               *label = (func->builder->next_label)++;
+       }
+
+       /* Determine if we can replace a previous comparison instruction */
+       block = func->builder->current_block;
+       insn = _jit_block_get_last(block);
+       if(value->is_temporary && insn && insn->dest == value)
+       {
+               opcode = insn->opcode;
+               if(opcode >= JIT_OP_IEQ && opcode <= JIT_OP_NFGE_INV)
+               {
+                       switch(opcode)
+                       {
+                               case JIT_OP_IEQ:                opcode = JIT_OP_BR_IEQ;      break;
+                               case JIT_OP_INE:                opcode = JIT_OP_BR_INE;      break;
+                               case JIT_OP_ILT:                opcode = JIT_OP_BR_ILT;      break;
+                               case JIT_OP_ILT_UN:             opcode = JIT_OP_BR_ILT_UN;   break;
+                               case JIT_OP_ILE:                opcode = JIT_OP_BR_ILE;      break;
+                               case JIT_OP_ILE_UN:             opcode = JIT_OP_BR_ILE_UN;   break;
+                               case JIT_OP_IGT:                opcode = JIT_OP_BR_IGT;      break;
+                               case JIT_OP_IGT_UN:             opcode = JIT_OP_BR_IGT_UN;   break;
+                               case JIT_OP_IGE:                opcode = JIT_OP_BR_IGE;      break;
+                               case JIT_OP_IGE_UN:             opcode = JIT_OP_BR_IGE_UN;   break;
+                               case JIT_OP_LEQ:                opcode = JIT_OP_BR_LEQ;      break;
+                               case JIT_OP_LNE:                opcode = JIT_OP_BR_LNE;      break;
+                               case JIT_OP_LLT:                opcode = JIT_OP_BR_LLT;      break;
+                               case JIT_OP_LLT_UN:             opcode = JIT_OP_BR_LLT_UN;   break;
+                               case JIT_OP_LLE:                opcode = JIT_OP_BR_LLE;      break;
+                               case JIT_OP_LLE_UN:             opcode = JIT_OP_BR_LLE_UN;   break;
+                               case JIT_OP_LGT:                opcode = JIT_OP_BR_LGT;      break;
+                               case JIT_OP_LGT_UN:             opcode = JIT_OP_BR_LGT_UN;   break;
+                               case JIT_OP_LGE:                opcode = JIT_OP_BR_LGE;      break;
+                               case JIT_OP_LGE_UN:             opcode = JIT_OP_BR_LGE_UN;   break;
+                               case JIT_OP_FEQ:                opcode = JIT_OP_BR_FEQ;      break;
+                               case JIT_OP_FNE:                opcode = JIT_OP_BR_FNE;      break;
+                               case JIT_OP_FLT:                opcode = JIT_OP_BR_FLT;      break;
+                               case JIT_OP_FLE:                opcode = JIT_OP_BR_FLE;      break;
+                               case JIT_OP_FGT:                opcode = JIT_OP_BR_FGT;      break;
+                               case JIT_OP_FGE:                opcode = JIT_OP_BR_FGE;      break;
+                               case JIT_OP_FEQ_INV:    opcode = JIT_OP_BR_FEQ_INV;  break;
+                               case JIT_OP_FNE_INV:    opcode = JIT_OP_BR_FNE_INV;  break;
+                               case JIT_OP_FLT_INV:    opcode = JIT_OP_BR_FLT_INV;  break;
+                               case JIT_OP_FLE_INV:    opcode = JIT_OP_BR_FLE_INV;  break;
+                               case JIT_OP_FGT_INV:    opcode = JIT_OP_BR_FGT_INV;  break;
+                               case JIT_OP_FGE_INV:    opcode = JIT_OP_BR_FGE_INV;  break;
+                               case JIT_OP_DEQ:                opcode = JIT_OP_BR_DEQ;      break;
+                               case JIT_OP_DNE:                opcode = JIT_OP_BR_DNE;      break;
+                               case JIT_OP_DLT:                opcode = JIT_OP_BR_DLT;      break;
+                               case JIT_OP_DLE:                opcode = JIT_OP_BR_DLE;      break;
+                               case JIT_OP_DGT:                opcode = JIT_OP_BR_DGT;      break;
+                               case JIT_OP_DGE:                opcode = JIT_OP_BR_DGE;      break;
+                               case JIT_OP_DEQ_INV:    opcode = JIT_OP_BR_DEQ_INV;  break;
+                               case JIT_OP_DNE_INV:    opcode = JIT_OP_BR_DNE_INV;  break;
+                               case JIT_OP_DLT_INV:    opcode = JIT_OP_BR_DLT_INV;  break;
+                               case JIT_OP_DLE_INV:    opcode = JIT_OP_BR_DLE_INV;  break;
+                               case JIT_OP_DGT_INV:    opcode = JIT_OP_BR_DGT_INV;  break;
+                               case JIT_OP_DGE_INV:    opcode = JIT_OP_BR_DGE_INV;  break;
+                               case JIT_OP_NFEQ:               opcode = JIT_OP_BR_NFEQ;     break;
+                               case JIT_OP_NFNE:               opcode = JIT_OP_BR_NFNE;     break;
+                               case JIT_OP_NFLT:               opcode = JIT_OP_BR_NFLT;     break;
+                               case JIT_OP_NFLE:               opcode = JIT_OP_BR_NFLE;     break;
+                               case JIT_OP_NFGT:               opcode = JIT_OP_BR_NFGT;     break;
+                               case JIT_OP_NFGE:               opcode = JIT_OP_BR_NFGE;     break;
+                               case JIT_OP_NFEQ_INV:   opcode = JIT_OP_BR_NFEQ_INV; break;
+                               case JIT_OP_NFNE_INV:   opcode = JIT_OP_BR_NFNE_INV; break;
+                               case JIT_OP_NFLT_INV:   opcode = JIT_OP_BR_NFLT_INV; break;
+                               case JIT_OP_NFLE_INV:   opcode = JIT_OP_BR_NFLE_INV; break;
+                               case JIT_OP_NFGT_INV:   opcode = JIT_OP_BR_NFGT_INV; break;
+                               case JIT_OP_NFGE_INV:   opcode = JIT_OP_BR_NFGE_INV; break;
+                       }
+                       insn->opcode = (short)opcode;
+                       insn->flags = JIT_INSN_DEST_IS_LABEL;
+                       insn->dest = (jit_value_t)(*label);
+                       goto add_block;
+               }
+       }
+
+       /* Coerce the result to something comparable and determine the opcode */
+       type = jit_type_promote_int(jit_type_normalize(value->type));
+       if(type == jit_type_int || type == jit_type_uint)
+       {
+               opcode = JIT_OP_BR_ITRUE;
+               value2 = 0;
+       }
+       else if(type == jit_type_long || type == jit_type_ulong)
+       {
+               opcode = JIT_OP_BR_LTRUE;
+               value2 = 0;
+       }
+       else if(type == jit_type_float32)
+       {
+               opcode = JIT_OP_BR_FNE;
+               value2 = jit_value_create_float32_constant
+                       (func, jit_type_float32, (jit_float32)0.0);
+               if(!value2)
+               {
+                       return 0;
+               }
+       }
+       else if(type == jit_type_float64)
+       {
+               opcode = JIT_OP_BR_DNE;
+               value2 = jit_value_create_float64_constant
+                       (func, jit_type_float64, (jit_float64)0.0);
+               if(!value2)
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               type = jit_type_nfloat;
+               opcode = JIT_OP_BR_NFNE;
+               value2 = jit_value_create_nfloat_constant
+                       (func, jit_type_nfloat, (jit_nfloat)0.0);
+               if(!value2)
+               {
+                       return 0;
+               }
+       }
+       value = jit_insn_convert(func, value, type, 0);
+       if(!value)
+       {
+               return 0;
+       }
+
+       /* Add a new branch instruction */
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, value);
+       jit_value_ref(func, value2);
+       insn->opcode = (short)opcode;
+       insn->flags = JIT_INSN_DEST_IS_LABEL;
+       insn->dest = (jit_value_t)(*label);
+       insn->value1 = value;
+       insn->value2 = value2;
+
+add_block:
+       /* Add a new block for the fall-through case */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       block->entered_via_top = 1;
+       func->builder->current_block = block;
+       return 1;
+}
+
+/*@
+ * @deftypefun 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 @code{value} refers to a conditional expression that was created
+ * by @code{jit_insn_eq}, @code{jit_insn_ne}, etc, then the conditional
+ * expression will be replaced by an appropriate conditional branch
+ * instruction.
+ * @end deftypefun
+@*/
+int jit_insn_branch_if_not
+               (jit_function_t func, jit_value_t value, jit_label_t *label)
+{
+       jit_insn_t insn;
+       jit_block_t block;
+       jit_type_t type;
+       int opcode;
+       jit_value_t value2;
+
+       /* Bail out if the parameters are invalid */
+       if(!value || !label)
+       {
+               return 0;
+       }
+
+       /* Ensure that we have a function builder */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* Allocate a new label identifier, if necessary */
+       if(*label == jit_label_undefined)
+       {
+               *label = (func->builder->next_label)++;
+       }
+
+       /* Determine if we can replace a previous comparison instruction */
+       block = func->builder->current_block;
+       insn = _jit_block_get_last(block);
+       if(value->is_temporary && insn && insn->dest == value)
+       {
+               opcode = insn->opcode;
+               if(opcode >= JIT_OP_IEQ && opcode <= JIT_OP_NFGE_INV)
+               {
+                       switch(opcode)
+                       {
+                               case JIT_OP_IEQ:                opcode = JIT_OP_BR_INE;      break;
+                               case JIT_OP_INE:                opcode = JIT_OP_BR_IEQ;      break;
+                               case JIT_OP_ILT:                opcode = JIT_OP_BR_IGE;      break;
+                               case JIT_OP_ILT_UN:             opcode = JIT_OP_BR_IGE_UN;   break;
+                               case JIT_OP_ILE:                opcode = JIT_OP_BR_IGT;      break;
+                               case JIT_OP_ILE_UN:             opcode = JIT_OP_BR_IGT_UN;   break;
+                               case JIT_OP_IGT:                opcode = JIT_OP_BR_ILE;      break;
+                               case JIT_OP_IGT_UN:             opcode = JIT_OP_BR_ILE_UN;   break;
+                               case JIT_OP_IGE:                opcode = JIT_OP_BR_ILT;      break;
+                               case JIT_OP_IGE_UN:             opcode = JIT_OP_BR_ILT_UN;   break;
+                               case JIT_OP_LEQ:                opcode = JIT_OP_BR_LNE;      break;
+                               case JIT_OP_LNE:                opcode = JIT_OP_BR_LEQ;      break;
+                               case JIT_OP_LLT:                opcode = JIT_OP_BR_LGE;      break;
+                               case JIT_OP_LLT_UN:             opcode = JIT_OP_BR_LGE_UN;   break;
+                               case JIT_OP_LLE:                opcode = JIT_OP_BR_LGT;      break;
+                               case JIT_OP_LLE_UN:             opcode = JIT_OP_BR_LGT_UN;   break;
+                               case JIT_OP_LGT:                opcode = JIT_OP_BR_LLE;      break;
+                               case JIT_OP_LGT_UN:             opcode = JIT_OP_BR_LLE_UN;   break;
+                               case JIT_OP_LGE:                opcode = JIT_OP_BR_LLT;      break;
+                               case JIT_OP_LGE_UN:             opcode = JIT_OP_BR_LLT_UN;   break;
+                               case JIT_OP_FEQ:                opcode = JIT_OP_BR_FNE_INV;  break;
+                               case JIT_OP_FNE:                opcode = JIT_OP_BR_FEQ_INV;  break;
+                               case JIT_OP_FLT:                opcode = JIT_OP_BR_FGE_INV;  break;
+                               case JIT_OP_FLE:                opcode = JIT_OP_BR_FGT_INV;  break;
+                               case JIT_OP_FGT:                opcode = JIT_OP_BR_FLE_INV;  break;
+                               case JIT_OP_FGE:                opcode = JIT_OP_BR_FLT_INV;  break;
+                               case JIT_OP_FEQ_INV:    opcode = JIT_OP_BR_FNE;      break;
+                               case JIT_OP_FNE_INV:    opcode = JIT_OP_BR_FEQ;      break;
+                               case JIT_OP_FLT_INV:    opcode = JIT_OP_BR_FGE;      break;
+                               case JIT_OP_FLE_INV:    opcode = JIT_OP_BR_FGT;      break;
+                               case JIT_OP_FGT_INV:    opcode = JIT_OP_BR_FLE;      break;
+                               case JIT_OP_FGE_INV:    opcode = JIT_OP_BR_FLT;      break;
+                               case JIT_OP_DEQ:                opcode = JIT_OP_BR_DNE_INV;  break;
+                               case JIT_OP_DNE:                opcode = JIT_OP_BR_DEQ_INV;  break;
+                               case JIT_OP_DLT:                opcode = JIT_OP_BR_DGE_INV;  break;
+                               case JIT_OP_DLE:                opcode = JIT_OP_BR_DGT_INV;  break;
+                               case JIT_OP_DGT:                opcode = JIT_OP_BR_DLE_INV;  break;
+                               case JIT_OP_DGE:                opcode = JIT_OP_BR_DLT_INV;  break;
+                               case JIT_OP_DEQ_INV:    opcode = JIT_OP_BR_DNE;      break;
+                               case JIT_OP_DNE_INV:    opcode = JIT_OP_BR_DEQ;      break;
+                               case JIT_OP_DLT_INV:    opcode = JIT_OP_BR_DGE;      break;
+                               case JIT_OP_DLE_INV:    opcode = JIT_OP_BR_DGT;      break;
+                               case JIT_OP_DGT_INV:    opcode = JIT_OP_BR_DLE;      break;
+                               case JIT_OP_DGE_INV:    opcode = JIT_OP_BR_DLT;      break;
+                               case JIT_OP_NFEQ:               opcode = JIT_OP_BR_NFNE_INV; break;
+                               case JIT_OP_NFNE:               opcode = JIT_OP_BR_NFEQ_INV; break;
+                               case JIT_OP_NFLT:               opcode = JIT_OP_BR_NFGE_INV; break;
+                               case JIT_OP_NFLE:               opcode = JIT_OP_BR_NFGT_INV; break;
+                               case JIT_OP_NFGT:               opcode = JIT_OP_BR_NFLE_INV; break;
+                               case JIT_OP_NFGE:               opcode = JIT_OP_BR_NFLT_INV; break;
+                               case JIT_OP_NFEQ_INV:   opcode = JIT_OP_BR_NFNE;     break;
+                               case JIT_OP_NFNE_INV:   opcode = JIT_OP_BR_NFEQ;     break;
+                               case JIT_OP_NFLT_INV:   opcode = JIT_OP_BR_NFGE;     break;
+                               case JIT_OP_NFLE_INV:   opcode = JIT_OP_BR_NFGT;     break;
+                               case JIT_OP_NFGT_INV:   opcode = JIT_OP_BR_NFLE;     break;
+                               case JIT_OP_NFGE_INV:   opcode = JIT_OP_BR_NFLT;     break;
+                       }
+                       insn->opcode = (short)opcode;
+                       insn->flags = JIT_INSN_DEST_IS_LABEL;
+                       insn->dest = (jit_value_t)(*label);
+                       goto add_block;
+               }
+       }
+
+       /* Coerce the result to something comparable and determine the opcode */
+       type = jit_type_promote_int(jit_type_normalize(value->type));
+       if(type == jit_type_int || type == jit_type_uint)
+       {
+               opcode = JIT_OP_BR_IFALSE;
+               value2 = 0;
+       }
+       else if(type == jit_type_long || type == jit_type_ulong)
+       {
+               opcode = JIT_OP_BR_LFALSE;
+               value2 = 0;
+       }
+       else if(type == jit_type_float32)
+       {
+               opcode = JIT_OP_BR_FEQ_INV;
+               value2 = jit_value_create_float32_constant
+                       (func, jit_type_float32, (jit_float32)0.0);
+               if(!value2)
+               {
+                       return 0;
+               }
+       }
+       else if(type == jit_type_float64)
+       {
+               opcode = JIT_OP_BR_DEQ_INV;
+               value2 = jit_value_create_float64_constant
+                       (func, jit_type_float64, (jit_float64)0.0);
+               if(!value2)
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               type = jit_type_nfloat;
+               opcode = JIT_OP_BR_NFEQ_INV;
+               value2 = jit_value_create_nfloat_constant
+                       (func, jit_type_nfloat, (jit_nfloat)0.0);
+               if(!value2)
+               {
+                       return 0;
+               }
+       }
+       value = jit_insn_convert(func, value, type, 0);
+       if(!value)
+       {
+               return 0;
+       }
+
+       /* Add a new branch instruction */
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, value);
+       jit_value_ref(func, value2);
+       insn->opcode = (short)opcode;
+       insn->flags = JIT_INSN_DEST_IS_LABEL;
+       insn->dest = (jit_value_t)(*label);
+       insn->value1 = value;
+       insn->value2 = value2;
+
+add_block:
+       /* Add a new block for the fall-through case */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       block->entered_via_top = 1;
+       func->builder->current_block = block;
+       return 1;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_address_of(jit_function_t func, jit_value_t value1)
+{
+       jit_type_t type;
+       jit_value_t result;
+       if(!value1)
+       {
+               return 0;
+       }
+       type = jit_type_create_pointer(jit_value_get_type(value1), 1);
+       if(!type)
+       {
+               return 0;
+       }
+       jit_value_set_addressable(value1);
+       result = apply_unary(func, JIT_OP_ADDRESS_OF, value1, type);
+       jit_type_free(type);
+       return result;
+}
+
+/*
+ * Information about the opcodes for a particular conversion.
+ */
+typedef struct jit_convert_info
+{
+       int                     cvt1;
+       jit_type_t      type1;
+       int                     cvt2;
+       jit_type_t      type2;
+       int                     cvt3;
+       jit_type_t      type3;
+
+} jit_convert_info_t;
+#define        CVT(opcode,name) opcode, (jit_type_t)&_jit_type_##name##_def
+#define        CVT_NONE                 0, 0
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_convert(jit_function_t func, jit_value_t value,
+                                                    jit_type_t type, int overflow_check)
+{
+       jit_type_t vtype;
+       const jit_convert_info_t *opcode_map;
+
+       /* Bail out if we previously ran out of memory on this function */
+       if(!value)
+       {
+               return 0;
+       }
+
+       /* Normalize the source and destination types */
+       type = jit_type_normalize(type);
+       vtype = jit_type_normalize(value->type);
+
+       /* If the types are identical, then return the source value as-is */
+       if(type == vtype)
+       {
+               return value;
+       }
+
+       /* If the source is a constant, then perform a constant conversion.
+          If an overflow might result, we perform the computation at runtime */
+       if(jit_value_is_constant(value))
+       {
+               jit_constant_t const_value;
+               const_value = jit_value_get_constant(value);
+               if(jit_constant_convert(&const_value, &const_value,
+                                                               type, overflow_check))
+               {
+                       return jit_value_create_constant(func, &const_value);
+               }
+       }
+
+       /* Promote the source type, to reduce the number of cases in
+          the switch statement below */
+       vtype = jit_type_promote_int(vtype);
+
+       /* Determine how to perform the conversion */
+       opcode_map = 0;
+       switch(type->kind)
+       {
+               case JIT_TYPE_SBYTE:
+               {
+                       /* Convert the value into a signed byte */
+                       static jit_convert_info_t const to_sbyte[] = {
+                               {CVT(JIT_OP_TRUNC_SBYTE, sbyte),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_SBYTE, sbyte),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_TRUNC_SBYTE, sbyte),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_INT, int),
+                                       CVT(JIT_OP_CHECK_SBYTE, sbyte),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, int),
+                                       CVT(JIT_OP_TRUNC_SBYTE, sbyte),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_SIGNED_LOW_WORD, int),
+                                       CVT(JIT_OP_CHECK_SBYTE, sbyte),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, int),
+                                       CVT(JIT_OP_TRUNC_SBYTE, sbyte),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_LOW_WORD, uint),
+                                       CVT(JIT_OP_CHECK_INT, int),
+                                       CVT(JIT_OP_CHECK_SBYTE, sbyte)},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_SBYTE, sbyte)},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_SBYTE, sbyte)},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_SBYTE, sbyte)},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_SBYTE, sbyte)},
+                               {CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_SBYTE, sbyte),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_SBYTE, sbyte),
+                                       CVT_NONE}
+                       };
+                       opcode_map = to_sbyte;
+               }
+               break;
+
+               case JIT_TYPE_UBYTE:
+               {
+                       /* Convert the value into an unsigned byte */
+                       static jit_convert_info_t const to_ubyte[] = {
+                               {CVT(JIT_OP_TRUNC_UBYTE, ubyte),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_UBYTE, ubyte),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_TRUNC_UBYTE, ubyte),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_UBYTE, ubyte),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, int),
+                                       CVT(JIT_OP_TRUNC_UBYTE, ubyte),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_SIGNED_LOW_WORD, int),
+                                       CVT(JIT_OP_CHECK_UBYTE, ubyte),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, int),
+                                       CVT(JIT_OP_TRUNC_UBYTE, ubyte),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_LOW_WORD, uint),
+                                       CVT(JIT_OP_CHECK_UBYTE, ubyte),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_UBYTE, ubyte)},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_UBYTE, ubyte)},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_UBYTE, ubyte)},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_UBYTE, ubyte)},
+                               {CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_UBYTE, ubyte),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_UBYTE, ubyte),
+                                       CVT_NONE}
+                       };
+                       opcode_map = to_ubyte;
+               }
+               break;
+
+               case JIT_TYPE_SHORT:
+               {
+                       /* Convert the value into a signed short */
+                       static jit_convert_info_t const to_short[] = {
+                               {CVT(JIT_OP_TRUNC_SHORT, short),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_SHORT, short),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_TRUNC_SHORT, short),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_INT, int),
+                                       CVT(JIT_OP_CHECK_SHORT, short),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, int),
+                                       CVT(JIT_OP_TRUNC_SHORT, short),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_SIGNED_LOW_WORD, int),
+                                       CVT(JIT_OP_CHECK_SHORT, short),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, int),
+                                       CVT(JIT_OP_TRUNC_SHORT, short),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_LOW_WORD, uint),
+                                       CVT(JIT_OP_CHECK_INT, int),
+                                       CVT(JIT_OP_CHECK_SHORT, short)},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_SHORT, short)},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_SHORT, short)},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_SHORT, short)},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_SHORT, short)},
+                               {CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_SHORT, short),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_SHORT, short),
+                                       CVT_NONE}
+                       };
+                       opcode_map = to_short;
+               }
+               break;
+
+               case JIT_TYPE_USHORT:
+               {
+                       /* Convert the value into an unsigned short */
+                       static jit_convert_info_t const to_ushort[] = {
+                               {CVT(JIT_OP_TRUNC_USHORT, ushort),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_USHORT, ushort),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_TRUNC_USHORT, ushort),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_USHORT, ushort),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, int),
+                                       CVT(JIT_OP_TRUNC_USHORT, ushort),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_SIGNED_LOW_WORD, int),
+                                       CVT(JIT_OP_CHECK_USHORT, ushort),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, int),
+                                       CVT(JIT_OP_TRUNC_USHORT, ushort),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_LOW_WORD, uint),
+                                       CVT(JIT_OP_CHECK_USHORT, ushort),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_USHORT, ushort)},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_USHORT, ushort)},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_USHORT, ushort)},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_USHORT, ushort)},
+                               {CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_TRUNC_USHORT, ushort),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT(JIT_OP_CHECK_USHORT, ushort),
+                                       CVT_NONE}
+                       };
+                       opcode_map = to_ushort;
+               }
+               break;
+
+               case JIT_TYPE_INT:
+               {
+                       /* Convert the value into a signed int */
+                       static jit_convert_info_t const to_int[] = {
+                               {CVT(JIT_OP_COPY_INT, int),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_INT, int),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_TRUNC_INT, int),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_INT, int),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, int),
+                                       CVT(JIT_OP_TRUNC_INT, int),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_SIGNED_LOW_WORD, int),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, int),
+                                       CVT(JIT_OP_TRUNC_INT, int),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_LOW_WORD, uint),
+                                       CVT(JIT_OP_CHECK_INT, int),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_NFLOAT_TO_INT, int),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_NFLOAT_TO_INT, int),
+                                       CVT_NONE,
+                                       CVT_NONE}
+                       };
+                       opcode_map = to_int;
+               }
+               break;
+
+               case JIT_TYPE_UINT:
+               {
+                       /* Convert the value into an unsigned int */
+                       static jit_convert_info_t const to_uint[] = {
+                               {CVT(JIT_OP_TRUNC_UINT, uint),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_UINT, uint),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_INT, uint),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_INT, uint),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, uint),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_LOW_WORD, uint),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LOW_WORD, uint),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_LOW_WORD, uint),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_UINT, uint),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_UINT, uint),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_UINT, uint),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_UINT, uint),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_NFLOAT_TO_UINT, uint),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_NFLOAT_TO_UINT, uint),
+                                       CVT_NONE,
+                                       CVT_NONE}
+                       };
+                       opcode_map = to_uint;
+               }
+               break;
+
+               case JIT_TYPE_LONG:
+               {
+                       /* Convert the value into a signed long */
+                       static jit_convert_info_t const to_long[] = {
+                               {CVT(JIT_OP_EXPAND_INT, long),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_EXPAND_INT, long),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_EXPAND_UINT, long),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_EXPAND_UINT, long),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_LONG, long),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_LONG, long),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_LONG, long),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_LONG, long),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_LONG, long),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_LONG, long),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_LONG, long),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_LONG, long),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_NFLOAT_TO_LONG, long),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_NFLOAT_TO_LONG, long),
+                                       CVT_NONE,
+                                       CVT_NONE}
+                       };
+                       opcode_map = to_long;
+               }
+               break;
+
+               case JIT_TYPE_ULONG:
+               {
+                       /* Convert the value into an unsigned long */
+                       static jit_convert_info_t const to_ulong[] = {
+                               {CVT(JIT_OP_EXPAND_INT, ulong),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_UINT, uint),
+                                       CVT(JIT_OP_EXPAND_UINT, ulong),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_EXPAND_UINT, ulong),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_EXPAND_UINT, ulong),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_LONG, ulong),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_ULONG, ulong),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_LONG, ulong),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_LONG, ulong),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_ULONG, ulong),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_ULONG, ulong),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_ULONG, ulong),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_CHECK_NFLOAT_TO_ULONG, ulong),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_NFLOAT_TO_ULONG, ulong),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_CHECK_NFLOAT_TO_ULONG, ulong),
+                                       CVT_NONE,
+                                       CVT_NONE}
+                       };
+                       opcode_map = to_ulong;
+               }
+               break;
+
+               case JIT_TYPE_FLOAT32:
+               {
+                       /* Convert the value into a 32-bit float */
+                       static jit_convert_info_t const to_float32[] = {
+                               {CVT(JIT_OP_INT_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_INT_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_UINT_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_UINT_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LONG_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LONG_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_ULONG_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_ULONG_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_FLOAT32, float32),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_FLOAT32, float32),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_NFLOAT_TO_FLOAT32, float32),
+                                       CVT_NONE,
+                                       CVT_NONE}
+                       };
+                       opcode_map = to_float32;
+               }
+               break;
+
+               case JIT_TYPE_FLOAT64:
+               {
+                       /* Convert the value into a 64-bit float */
+                       static jit_convert_info_t const to_float64[] = {
+                               {CVT(JIT_OP_INT_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_INT_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_UINT_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_UINT_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LONG_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LONG_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_ULONG_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_ULONG_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_FLOAT64, float64),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_FLOAT64, float64),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_NFLOAT_TO_FLOAT64, float64),
+                                       CVT_NONE,
+                                       CVT_NONE}
+                       };
+                       opcode_map = to_float64;
+               }
+               break;
+
+               case JIT_TYPE_NFLOAT:
+               {
+                       /* Convert the value into a native floating-point value */
+                       static jit_convert_info_t const to_nfloat[] = {
+                               {CVT(JIT_OP_INT_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_INT_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_UINT_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_UINT_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LONG_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_LONG_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_ULONG_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_ULONG_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT32_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_FLOAT64_TO_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE},
+                               {CVT(JIT_OP_COPY_NFLOAT, nfloat),
+                                       CVT_NONE,
+                                       CVT_NONE}
+                       };
+                       opcode_map = to_nfloat;
+               }
+               break;
+       }
+       if(opcode_map)
+       {
+               switch(vtype->kind)
+               {
+                       case JIT_TYPE_UINT:             opcode_map += 2; break;
+                       case JIT_TYPE_LONG:             opcode_map += 4; break;
+                       case JIT_TYPE_ULONG:    opcode_map += 6; break;
+                       case JIT_TYPE_FLOAT32:  opcode_map += 8; break;
+                       case JIT_TYPE_FLOAT64:  opcode_map += 10; break;
+                       case JIT_TYPE_NFLOAT:   opcode_map += 12; break;
+               }
+               if(overflow_check)
+               {
+                       opcode_map += 1;
+               }
+               value = apply_unary
+                       (func, opcode_map->cvt1, value, opcode_map->type1);
+               if(opcode_map->cvt2)
+               {
+                       value = apply_unary
+                               (func, opcode_map->cvt2, value, opcode_map->type2);
+               }
+               if(opcode_map->cvt3)
+               {
+                       value = apply_unary
+                               (func, opcode_map->cvt3, value, opcode_map->type3);
+               }
+       }
+       return value;
+}
+
+/*
+ * Convert the parameters for a function call into their final types.
+ */
+static int convert_call_parameters
+       (jit_function_t func, jit_type_t signature,
+        jit_value_t *args, unsigned int num_args,
+        jit_value_t *new_args)
+{
+       unsigned int param;
+       for(param = 0; param < num_args; ++param)
+       {
+               new_args[param] = jit_insn_convert
+                       (func, args[param],
+                        jit_type_get_param(signature, param), 0);
+       }
+       return 1;
+}
+
+/*
+ * Set up the exception frame information before a function call out.
+ */
+static int setup_eh_frame_for_call(jit_function_t func, int flags)
+{
+#if !defined(JIT_BACKEND_INTERP)
+       jit_type_t type;
+       jit_value_t eh_frame_info;
+       jit_block_t block;
+       jit_value_t args[2];
+       jit_insn_t insn;
+       jit_type_t params[2];
+       jit_value_t struct_return;
+
+       /* If the "nothrow" or "tail" flags are set, then we don't
+          need to worry about this */
+       if((flags & (JIT_CALL_NOTHROW | JIT_CALL_TAIL)) != 0)
+       {
+               return 1;
+       }
+
+       /* This function may throw an exception */
+       func->builder->may_throw = 1;
+
+       /* Get the value that holds the exception frame information */
+       if((eh_frame_info = func->builder->eh_frame_info) == 0)
+       {
+               type = jit_type_create_struct(0, 0, 0);
+               if(!type)
+               {
+                       return 0;
+               }
+               jit_type_set_size_and_alignment
+                       (type, sizeof(struct jit_backtrace), sizeof(void *));
+               eh_frame_info = jit_value_create(func, type);
+               jit_type_free(type);
+               if(!eh_frame_info)
+               {
+                       return 0;
+               }
+               func->builder->eh_frame_info = eh_frame_info;
+       }
+
+       /* Output an instruction to load the "pc" into a value */
+       args[1] = jit_value_create(func, jit_type_void_ptr);
+       if(!(args[1]))
+       {
+               return 0;
+       }
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, args[1]);
+       insn->opcode = JIT_OP_LOAD_PC;
+       insn->dest = args[1];
+
+       /* Load the address of "eh_frame_info" into another value */
+       args[0] = jit_insn_address_of(func, eh_frame_info);
+       if(!(args[0]))
+       {
+               return 0;
+       }
+
+       /* Create a signature for the prototype "void (void *, void *)" */
+       params[0] = jit_type_void_ptr;
+       params[1] = jit_type_void_ptr;
+       type = jit_type_create_signature
+               (jit_abi_cdecl, jit_type_void, params, 2, 1);
+       if(!type)
+       {
+               return 0;
+       }
+
+       /* Set up to call the "_jit_backtrace_push" intrinsic */
+       if(!_jit_create_call_setup_insns
+                       (func, type, args, 2, 0, 0, &struct_return))
+       {
+               jit_type_free(type);
+               return 0;
+       }
+
+       /* Terminate the current block and then call "_jit_backtrace_push" */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               jit_type_free(type);
+               return 0;
+       }
+       block->entered_via_top = 1;
+       func->builder->current_block = block;
+       insn = _jit_block_add_insn(block);
+       if(!insn)
+       {
+               jit_type_free(type);
+               return 0;
+       }
+       insn->opcode = JIT_OP_CALL_EXTERNAL;
+       insn->flags = JIT_INSN_DEST_IS_NATIVE | JIT_INSN_VALUE1_IS_NAME;
+       insn->dest = (jit_value_t)(void *)_jit_backtrace_push;
+       insn->value1 = (jit_value_t)"_jit_backtrace_push";
+
+       /* Clean up after the function call */
+       if(!_jit_create_call_return_insns(func, type, args, 2, 0, 0))
+       {
+               jit_type_free(type);
+               return 0;
+       }
+
+       /* We are now ready to make the actual function call */
+       jit_type_free(type);
+       return 1;
+#else /* JIT_BACKEND_INTERP */
+       /* The interpreter handles exception frames for us */
+       if((flags & (JIT_CALL_NOTHROW | JIT_CALL_TAIL)) == 0)
+       {
+               func->builder->may_throw = 1;
+       }
+       return 1;
+#endif
+}
+
+/*
+ * Restore the exception handling frame after a function call.
+ */
+static int restore_eh_frame_after_call(jit_function_t func, int flags)
+{
+#if !defined(JIT_BACKEND_INTERP)
+       jit_type_t type;
+       jit_value_t struct_return;
+       jit_block_t block;
+       jit_insn_t insn;
+
+       /* If the "nothrow", "noreturn", or "tail" flags are set, then we
+          don't need to worry about this */
+       if((flags & (JIT_CALL_NOTHROW | JIT_CALL_NORETURN | JIT_CALL_TAIL)) != 0)
+       {
+               return 1;
+       }
+
+       /* Create the signature prototype "void (void)" */
+       type = jit_type_create_signature
+               (jit_abi_cdecl, jit_type_void, 0, 0, 0);
+       if(!type)
+       {
+               return 0;
+       }
+
+       /* Set up to call the "_jit_backtrace_pop" intrinsic */
+       if(!_jit_create_call_setup_insns
+                       (func, type, 0, 0, 0, 0, &struct_return))
+       {
+               jit_type_free(type);
+               return 0;
+       }
+
+       /* Terminate the current block and then call "_jit_backtrace_pop" */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               jit_type_free(type);
+               return 0;
+       }
+       block->entered_via_top = 1;
+       func->builder->current_block = block;
+       insn = _jit_block_add_insn(block);
+       if(!insn)
+       {
+               jit_type_free(type);
+               return 0;
+       }
+       insn->opcode = JIT_OP_CALL_EXTERNAL;
+       insn->flags = JIT_INSN_DEST_IS_NATIVE | JIT_INSN_VALUE1_IS_NAME;
+       insn->dest = (jit_value_t)(void *)_jit_backtrace_pop;
+       insn->value1 = (jit_value_t)"_jit_backtrace_pop";
+
+       /* Clean up after the function call */
+       if(!_jit_create_call_return_insns(func, type, 0, 0, 0, 0))
+       {
+               jit_type_free(type);
+               return 0;
+       }
+
+       /* Everything is back to where it should be */
+       jit_type_free(type);
+       return 1;
+#else /* JIT_BACKEND_INTERP */
+       /* The interpreter handles exception frames for us */
+       return 1;
+#endif
+}
+
+/*@
+ * @deftypefun 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 @code{jit_func}, which may or may not be translated yet.
+ * The @code{name} is for diagnostic purposes only, and can be NULL.
+ *
+ * If @code{signature} is NULL, then the actual signature of @code{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 @code{flags} parameter specifies additional information about the
+ * type of call to perform:
+ *
+ * @table @code
+ * @vindex JIT_CALL_NOTHROW
+ * @item JIT_CALL_NOTHROW
+ * The function never throws exceptions.
+ *
+ * @vindex JIT_CALL_NORETURN
+ * @item 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.
+ *
+ * @vindex JIT_CALL_TAIL
+ * @item 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.
+ * @end table
+ *
+ * If @code{jit_func} has already been compiled, then @code{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.
+ * @end deftypefun
+@*/
+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)
+{
+       int is_nested;
+       int nesting_level;
+       jit_function_t temp_func;
+       jit_value_t *new_args;
+       jit_value_t return_value;
+       jit_block_t block;
+       jit_insn_t insn;
+
+       /* Bail out if there is something wrong with the parameters */
+       if(!func || !jit_func)
+       {
+               return 0;
+       }
+
+       /* Get the default signature from "jit_func" */
+       if(!signature)
+       {
+               signature = jit_func->signature;
+       }
+
+       /* Determine the nesting relationship with the current function */
+       if(jit_func->nested_parent)
+       {
+               is_nested = 1;
+               if(jit_func->nested_parent == func)
+               {
+                       /* We are calling one of our children */
+                       nesting_level = -1;
+               }
+               else if(jit_func->nested_parent == func->nested_parent)
+               {
+                       /* We are calling one of our direct siblings */
+                       nesting_level = 0;
+               }
+               else
+               {
+                       /* Search up to find the actual nesting level */
+                       temp_func = func->nested_parent;
+                       nesting_level = 1;
+                       while(temp_func != 0 && temp_func != jit_func)
+                       {
+                               ++nesting_level;
+                               temp_func = temp_func->nested_parent;
+                       }
+               }
+       }
+       else
+       {
+               is_nested = 0;
+               nesting_level = 0;
+       }
+
+       /* Convert the arguments to the actual parameter types */
+       if(num_args > 0)
+       {
+               new_args = (jit_value_t *)alloca(sizeof(jit_value_t) * num_args);
+               if(!convert_call_parameters(func, signature, args, num_args, new_args))
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               new_args = args;
+       }
+
+       /* Intuit additional flags from "jit_func" if it was already compiled */
+       if(func->no_throw)
+       {
+               flags |= JIT_CALL_NOTHROW;
+       }
+       if(func->no_return)
+       {
+               flags |= JIT_CALL_NORETURN;
+       }
+
+       /* Set up exception frame information for the call */
+       if(!setup_eh_frame_for_call(func, flags))
+       {
+               return 0;
+       }
+
+       /* Create the instructions to push the parameters onto the stack */
+       if(!_jit_create_call_setup_insns
+                       (func, signature, new_args, num_args,
+                        is_nested, nesting_level, &return_value))
+       {
+               return 0;
+       }
+
+       /* Functions that call out are not leaves */
+       func->builder->non_leaf = 1;
+
+       /* Start a new block and output the "call" instruction */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       block->entered_via_top = 1;
+       func->builder->current_block = block;
+       insn = _jit_block_add_insn(block);
+       if(!insn)
+       {
+               return 0;
+       }
+       insn->opcode = JIT_OP_CALL;
+       insn->flags = JIT_INSN_DEST_IS_FUNCTION | JIT_INSN_VALUE1_IS_NAME;
+       insn->dest = (jit_value_t)jit_func;
+       insn->value1 = (jit_value_t)name;
+
+       /* If the function does not return, then end the current block.
+          The next block does not have "entered_via_top" set so that
+          it will be eliminated during later code generation */
+       if((flags & JIT_CALL_NORETURN) != 0)
+       {
+               block = _jit_block_create(func, 0);
+               if(!block)
+               {
+                       return 0;
+               }
+               func->builder->current_block = block;
+       }
+
+       /* Create space for the return value, if we don't already have one */
+       if(!return_value)
+       {
+               return_value = jit_value_create(func, jit_type_get_return(signature));
+               if(!return_value)
+               {
+                       return 0;
+               }
+       }
+
+       /* Create the instructions necessary to move the return value into place */
+       if(!_jit_create_call_return_insns
+                       (func, signature, new_args, num_args, return_value, is_nested))
+       {
+               return 0;
+       }
+
+       /* Restore exception frame information after the call */
+       if(!restore_eh_frame_after_call(func, flags))
+       {
+               return 0;
+       }
+
+       /* Return the value containing the result to the caller */
+       return return_value;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+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)
+{
+       jit_value_t *new_args;
+       jit_value_t return_value;
+       jit_block_t block;
+       jit_insn_t insn;
+
+       /* Bail out if there is something wrong with the parameters */
+       if(!func || !value || !signature)
+       {
+               return 0;
+       }
+
+       /* Convert the arguments to the actual parameter types */
+       if(num_args > 0)
+       {
+               new_args = (jit_value_t *)alloca(sizeof(jit_value_t) * num_args);
+               if(!convert_call_parameters(func, signature, args, num_args, new_args))
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               new_args = args;
+       }
+
+       /* Set up exception frame information for the call */
+       if(!setup_eh_frame_for_call(func, flags))
+       {
+               return 0;
+       }
+
+       /* Create the instructions to push the parameters onto the stack */
+       if(!_jit_create_call_setup_insns
+                       (func, signature, new_args, num_args, 0, 0, &return_value))
+       {
+               return 0;
+       }
+
+       /* Move the indirect pointer value into an appropriate register */
+       if(!_jit_setup_indirect_pointer(func, value))
+       {
+               return 0;
+       }
+
+       /* Functions that call out are not leaves */
+       func->builder->non_leaf = 1;
+
+       /* Start a new block and output the "call_indirect" instruction */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       block->entered_via_top = 1;
+       func->builder->current_block = block;
+       insn = _jit_block_add_insn(block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, value);
+       insn->opcode = JIT_OP_CALL_INDIRECT;
+       insn->value1 = value;
+
+       /* If the function does not return, then end the current block.
+          The next block does not have "entered_via_top" set so that
+          it will be eliminated during later code generation */
+       if((flags & JIT_CALL_NORETURN) != 0)
+       {
+               block = _jit_block_create(func, 0);
+               if(!block)
+               {
+                       return 0;
+               }
+               func->builder->current_block = block;
+       }
+
+       /* Create space for the return value, if we don't already have one */
+       if(!return_value)
+       {
+               return_value = jit_value_create(func, jit_type_get_return(signature));
+               if(!return_value)
+               {
+                       return 0;
+               }
+       }
+
+       /* Create the instructions necessary to move the return value into place */
+       if(!_jit_create_call_return_insns
+                       (func, signature, new_args, num_args, return_value, 0))
+       {
+               return 0;
+       }
+
+       /* Restore exception frame information after the call */
+       if(!restore_eh_frame_after_call(func, flags))
+       {
+               return 0;
+       }
+
+       /* Return the value containing the result to the caller */
+       return return_value;
+}
+
+/*@
+ * @deftypefun 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
+ * @code{jit_insn_call_indirect} in that we assume that @code{value}
+ * contains a pointer that resulted from calling
+ * @code{jit_function_to_vtable_pointer}.  Indirect vtable pointer
+ * calls may be more efficient on some platforms than regular indirect calls.
+ * @end deftypefun
+@*/
+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)
+{
+       jit_value_t *new_args;
+       jit_value_t return_value;
+       jit_block_t block;
+       jit_insn_t insn;
+
+       /* Bail out if there is something wrong with the parameters */
+       if(!func || !value || !signature)
+       {
+               return 0;
+       }
+
+       /* Convert the arguments to the actual parameter types */
+       if(num_args > 0)
+       {
+               new_args = (jit_value_t *)alloca(sizeof(jit_value_t) * num_args);
+               if(!convert_call_parameters(func, signature, args, num_args, new_args))
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               new_args = args;
+       }
+
+       /* Set up exception frame information for the call */
+       if(!setup_eh_frame_for_call(func, flags))
+       {
+               return 0;
+       }
+
+       /* Create the instructions to push the parameters onto the stack */
+       if(!_jit_create_call_setup_insns
+                       (func, signature, new_args, num_args, 0, 0, &return_value))
+       {
+               return 0;
+       }
+
+       /* Move the indirect pointer value into an appropriate register */
+       if(!_jit_setup_indirect_pointer(func, value))
+       {
+               return 0;
+       }
+
+       /* Functions that call out are not leaves */
+       func->builder->non_leaf = 1;
+
+       /* Start a new block and output the "call_vtable_ptr" instruction */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       block->entered_via_top = 1;
+       func->builder->current_block = block;
+       insn = _jit_block_add_insn(block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, value);
+       insn->opcode = JIT_OP_CALL_VTABLE_PTR;
+       insn->value1 = value;
+
+       /* If the function does not return, then end the current block.
+          The next block does not have "entered_via_top" set so that
+          it will be eliminated during later code generation */
+       if((flags & JIT_CALL_NORETURN) != 0)
+       {
+               block = _jit_block_create(func, 0);
+               if(!block)
+               {
+                       return 0;
+               }
+               func->builder->current_block = block;
+       }
+
+       /* Create space for the return value, if we don't already have one */
+       if(!return_value)
+       {
+               return_value = jit_value_create(func, jit_type_get_return(signature));
+               if(!return_value)
+               {
+                       return 0;
+               }
+       }
+
+       /* Create the instructions necessary to move the return value into place */
+       if(!_jit_create_call_return_insns
+                       (func, signature, new_args, num_args, return_value, 0))
+       {
+               return 0;
+       }
+
+       /* Restore exception frame information after the call */
+       if(!restore_eh_frame_after_call(func, flags))
+       {
+               return 0;
+       }
+
+       /* Return the value containing the result to the caller */
+       return return_value;
+}
+
+/*@
+ * @deftypefun 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 @code{name} is for diagnostic purposes only, and can be NULL.
+ * @end deftypefun
+@*/
+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 flags)
+{
+       jit_value_t *new_args;
+       jit_value_t return_value;
+       jit_block_t block;
+       jit_insn_t insn;
+
+       /* Bail out if there is something wrong with the parameters */
+       if(!func || !native_func || !signature)
+       {
+               return 0;
+       }
+
+       /* Convert the arguments to the actual parameter types */
+       if(num_args > 0)
+       {
+               new_args = (jit_value_t *)alloca(sizeof(jit_value_t) * num_args);
+               if(!convert_call_parameters(func, signature, args, num_args, new_args))
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               new_args = args;
+       }
+
+       /* Set up exception frame information for the call */
+       if(!setup_eh_frame_for_call(func, flags))
+       {
+               return 0;
+       }
+
+       /* Create the instructions to push the parameters onto the stack */
+       if(!_jit_create_call_setup_insns
+                       (func, signature, new_args, num_args, 0, 0, &return_value))
+       {
+               return 0;
+       }
+
+       /* Functions that call out are not leaves */
+       func->builder->non_leaf = 1;
+
+       /* Start a new block and output the "call_external" instruction */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       block->entered_via_top = 1;
+       func->builder->current_block = block;
+       insn = _jit_block_add_insn(block);
+       if(!insn)
+       {
+               return 0;
+       }
+       insn->opcode = JIT_OP_CALL_EXTERNAL;
+       insn->flags = JIT_INSN_DEST_IS_NATIVE | JIT_INSN_VALUE1_IS_NAME;
+       insn->dest = (jit_value_t)native_func;
+       insn->value1 = (jit_value_t)name;
+
+       /* If the function does not return, then end the current block.
+          The next block does not have "entered_via_top" set so that
+          it will be eliminated during later code generation */
+       if((flags & JIT_CALL_NORETURN) != 0)
+       {
+               block = _jit_block_create(func, 0);
+               if(!block)
+               {
+                       return 0;
+               }
+               func->builder->current_block = block;
+       }
+
+       /* Create space for the return value, if we don't already have one */
+       if(!return_value)
+       {
+               return_value = jit_value_create(func, jit_type_get_return(signature));
+               if(!return_value)
+               {
+                       return 0;
+               }
+       }
+
+       /* Create the instructions necessary to move the return value into place */
+       if(!_jit_create_call_return_insns
+                       (func, signature, new_args, num_args, return_value, 0))
+       {
+               return 0;
+       }
+
+       /* Restore exception frame information after the call */
+       if(!restore_eh_frame_after_call(func, flags))
+       {
+               return 0;
+       }
+
+       /* Return the value containing the result to the caller */
+       return return_value;
+}
+
+/*@
+ * @deftypefun 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:
+ *
+ * @table @code
+ * @item return_type
+ * The type of value that is returned from the intrinsic.
+ *
+ * @item ptr_result_type
+ * This should be NULL for an ordinary intrinsic, or the result type
+ * if the intrinsic reports exceptions.
+ *
+ * @item arg1_type
+ * The type of the first argument.
+ *
+ * @item arg2_type
+ * The type of the second argument, or NULL for a unary intrinsic.
+ * @end table
+ *
+ * If all of the arguments are constant, then @code{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 @code{name} is for diagnostic purposes only, and can be NULL.
+ * @end deftypefun
+@*/
+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)
+{
+       jit_type_t signature;
+       jit_type_t param_types[3];
+       jit_value_t param_values[3];
+       unsigned int num_params;
+       jit_value_t return_value;
+       jit_value_t temp_value;
+       jit_value_t cond_value;
+       jit_label_t label;
+       jit_constant_t const1;
+       jit_constant_t const2;
+       jit_constant_t return_const;
+       jit_constant_t temp_const;
+       void *apply_args[3];
+
+       /* Ensure that we have a builder for this function */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* Coerce the arguments to the desired types */
+       arg1 = jit_insn_convert(func, arg1, descriptor->arg1_type, 0);
+       if(!arg1)
+       {
+               return 0;
+       }
+       if(arg2)
+       {
+               arg2 = jit_insn_convert(func, arg2, descriptor->arg2_type, 0);
+               if(!arg2)
+               {
+                       return 0;
+               }
+       }
+
+       /* Allocate space for a return value if the intrinsic reports exceptions */
+       if(descriptor->ptr_result_type)
+       {
+               return_value = jit_value_create(func, descriptor->ptr_result_type);
+               if(!return_value)
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               return_value = 0;
+       }
+
+       /* Construct the signature for the intrinsic */
+       num_params = 0;
+       if(return_value)
+       {
+               /* Pass a pointer to "return_value" as the first argument */
+               temp_value = jit_insn_address_of(func, return_value);
+               if(!temp_value)
+               {
+                       return 0;
+               }
+               param_types[num_params] = jit_value_get_type(temp_value);
+               param_values[num_params] = temp_value;
+               ++num_params;
+       }
+       param_types[num_params] = jit_value_get_type(arg1);
+       param_values[num_params] = arg1;
+       ++num_params;
+       if(arg2)
+       {
+               param_types[num_params] = jit_value_get_type(arg2);
+               param_values[num_params] = arg2;
+               ++num_params;
+       }
+       signature = jit_type_create_signature
+               (jit_abi_cdecl, descriptor->return_type, param_types, num_params, 1);
+       if(!signature)
+       {
+               return 0;
+       }
+
+       /* If the arguments are constant, then invoke the intrinsic now */
+       if(jit_value_is_constant(arg1) && (!arg2 || jit_value_is_constant(arg2)))
+       {
+               const1 = jit_value_get_constant(arg1);
+               const2 = jit_value_get_constant(arg2);
+               return_const.type = descriptor->ptr_result_type;
+               if(return_value)
+               {
+                       jit_int result;
+                       temp_const.un.ptr_value = &return_const.un;
+                       apply_args[0] = &temp_const.un;
+                       apply_args[1] = &const1.un;
+                       apply_args[2] = &const2.un;
+                       jit_apply(signature, intrinsic_func, apply_args,
+                                         num_params, &result);
+                       if(result >= 1)
+                       {
+                               /* No exception occurred, so return the constant value */
+                               jit_type_free(signature);
+                               return jit_value_create_constant(func, &return_const);
+                       }
+               }
+               else
+               {
+                       apply_args[0] = &const1.un;
+                       apply_args[1] = &const2.un;
+                       jit_apply(signature, intrinsic_func, apply_args,
+                                         num_params, &return_const.un);
+                       jit_type_free(signature);
+                       return jit_value_create_constant(func, &return_const);
+               }
+       }
+
+       /* Call the intrinsic as a native function */
+       temp_value = jit_insn_call_native
+               (func, name, intrinsic_func, signature, param_values,
+                num_params, JIT_CALL_NOTHROW);
+       if(!temp_value)
+       {
+               jit_type_free(signature);
+               return 0;
+       }
+       jit_type_free(signature);
+
+       /* If no exceptions to report, then return "temp_value" as the result */
+       if(!return_value)
+       {
+               return temp_value;
+       }
+
+       /* Determine if an exception was reported */
+       cond_value = jit_insn_ge(func, temp_value,
+               jit_value_create_nint_constant(func, jit_type_int, 1));
+       if(!cond_value)
+       {
+               return 0;
+       }
+       label = jit_label_undefined;
+       if(!jit_insn_branch_if(func, cond_value, &label))
+       {
+               return 0;
+       }
+
+       /* Call the "jit_exception_builtin" function to report the exception */
+       param_types[0] = jit_type_int;
+       signature = jit_type_create_signature
+               (jit_abi_cdecl, jit_type_void, param_types, 1, 1);
+       if(!signature)
+       {
+               return 0;
+       }
+       param_values[0] = temp_value;
+       jit_insn_call_native
+               (func, "jit_exception_builtin",
+                (void *)jit_exception_builtin, signature, param_values, 1,
+                JIT_CALL_NORETURN);
+       jit_type_free(signature);
+
+       /* The "jit_exception_builtin" function will never return */
+       func->builder->current_block->ends_in_dead = 1;
+
+       /* Execution continues here if there was no exception */
+       if(!jit_insn_label(func, &label))
+       {
+               return 0;
+       }
+
+       /* Return the temporary that contains the result value */
+       return return_value;
+}
+
+/*@
+ * @deftypefun int jit_insn_incoming_reg (jit_function_t func, jit_value_t value, int reg)
+ * Output an instruction that notes that the contents of @code{value}
+ * can be found in the register @code{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.
+ * @end deftypefun
+@*/
+int jit_insn_incoming_reg(jit_function_t func, jit_value_t value, int reg)
+{
+       return create_note(func, JIT_OP_INCOMING_REG, value,
+                                          jit_value_create_nint_constant
+                                                       (func, jit_type_int, (jit_nint)reg));
+}
+
+/*@
+ * @deftypefun 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 @code{value}
+ * can be found in the stack frame at @code{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.
+ * @end deftypefun
+@*/
+int jit_insn_incoming_frame_posn
+               (jit_function_t func, jit_value_t value, jit_nint frame_offset)
+{
+       return create_note(func, JIT_OP_INCOMING_FRAME_POSN, value,
+                                          jit_value_create_nint_constant
+                                                       (func, jit_type_int, frame_offset));
+}
+
+/*@
+ * @deftypefun int jit_insn_outgoing_reg (jit_function_t func, jit_value_t value, int reg)
+ * Output an instruction that copies the contents of @code{value}
+ * into the register @code{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.
+ * @end deftypefun
+@*/
+int jit_insn_outgoing_reg(jit_function_t func, jit_value_t value, int reg)
+{
+       return create_note(func, JIT_OP_OUTGOING_REG, value,
+                                          jit_value_create_nint_constant
+                                                       (func, jit_type_int, (jit_nint)reg));
+}
+
+/*@
+ * @deftypefun int jit_insn_return_reg (jit_function_t func, jit_value_t value, int reg)
+ * Output an instruction that notes that the contents of @code{value}
+ * can be found in the register @code{reg} at this point in the code.
+ * This is similar to @code{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.
+ * @end deftypefun
+@*/
+int jit_insn_return_reg(jit_function_t func, jit_value_t value, int reg)
+{
+       return create_note(func, JIT_OP_RETURN_REG, value,
+                                          jit_value_create_nint_constant
+                                                       (func, jit_type_int, (jit_nint)reg));
+}
+
+/*@
+ * @deftypefun 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 @code{nested_level} value will be -1 to call a child, zero to call a
+ * sibling of @code{func}, 1 to call a sibling of the parent, 2 to call
+ * a sibling of the grandparent, etc.  If @code{reg} is not -1, then
+ * it indicates the register to receive the parent frame information.
+ * If @code{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.
+ * @end deftypefun
+@*/
+int jit_insn_setup_for_nested(jit_function_t func, int nested_level, int reg)
+{
+       if(nested_level < 0)
+       {
+               return create_unary_note
+                       (func, JIT_OP_SETUP_FOR_NESTED,
+                        jit_value_create_nint_constant
+                                (func, jit_type_int, (jit_nint)reg));
+       }
+       else
+       {
+               return create_note
+                       (func, JIT_OP_SETUP_FOR_SIBLING,
+                        jit_value_create_nint_constant
+                                (func, jit_type_int, (jit_nint)nested_level),
+                        jit_value_create_nint_constant
+                                (func, jit_type_int, (jit_nint)reg));
+       }
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+int jit_insn_flush_struct(jit_function_t func, jit_value_t value)
+{
+       if(value)
+       {
+               jit_value_set_addressable(value);
+       }
+       return create_unary_note(func, JIT_OP_FLUSH_SMALL_STRUCT, value);
+}
+
+/*@
+ * @deftypefun jit_value_t jit_insn_import (jit_function_t func, jit_value_t value)
+ * Import @code{value} from an outer nested scope into @code{func}.  Returns
+ * the effective address of the value for local access via a pointer.
+ * If @code{value} is local to @code{func}, then it is returned as-is.
+ * Returns NULL if out of memory or the value is not accessible via a
+ * parent, grandparent, or other ancestor of @code{func}.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_import(jit_function_t func, jit_value_t value)
+{
+       jit_function_t value_func;
+       jit_function_t current_func;
+       int level;
+
+       /* Make sure that we have a builder before we start */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* If the value is already local, then there is nothing to do */
+       value_func = jit_value_get_function(value);
+       if(value_func == func)
+       {
+               return value;
+       }
+
+       /* Find the nesting level of the value, where 1 is our parent */
+       level = 1;
+       current_func = func->nested_parent;
+       while(current_func != 0 && current_func != value_func)
+       {
+               ++level;
+               current_func = current_func->nested_parent;
+       }
+       if(!current_func)
+       {
+               /* The value is not accessible from this scope */
+               return 0;
+       }
+
+       /* Output the relevant import instruction, which will also cause
+          it to be marked as a non-local addressable by "jit_value_ref" */
+       return apply_binary
+               (func, JIT_OP_IMPORT, value,
+                jit_value_create_nint_constant(func, jit_type_int, (jit_nint)value),
+                jit_type_void_ptr);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+int jit_insn_push(jit_function_t func, jit_value_t value)
+{
+       jit_type_t type;
+       if(!value)
+       {
+               return 0;
+       }
+       type = jit_type_promote_int(jit_type_normalize(jit_value_get_type(value)));
+       switch(type->kind)
+       {
+               case JIT_TYPE_SBYTE:
+               case JIT_TYPE_UBYTE:
+               case JIT_TYPE_SHORT:
+               case JIT_TYPE_USHORT:
+               case JIT_TYPE_INT:
+               case JIT_TYPE_UINT:
+               {
+                       return create_unary_note(func, JIT_OP_PUSH_INT, value);
+               }
+               /* Not reached */
+
+               case JIT_TYPE_LONG:
+               case JIT_TYPE_ULONG:
+               {
+                       return create_unary_note(func, JIT_OP_PUSH_LONG, value);
+               }
+               /* Not reached */
+
+               case JIT_TYPE_FLOAT32:
+               {
+                       return create_unary_note(func, JIT_OP_PUSH_FLOAT32, value);
+               }
+               /* Not reached */
+
+               case JIT_TYPE_FLOAT64:
+               {
+                       return create_unary_note(func, JIT_OP_PUSH_FLOAT64, value);
+               }
+               /* Not reached */
+
+               case JIT_TYPE_NFLOAT:
+               {
+                       return create_unary_note(func, JIT_OP_PUSH_NFLOAT, value);
+               }
+               /* Not reached */
+
+               case JIT_TYPE_STRUCT:
+               case JIT_TYPE_UNION:
+               {
+                       return create_unary_note(func, JIT_OP_PUSH_STRUCT, value);
+               }
+               /* Not reached */
+       }
+       return 1;
+}
+
+/*@
+ * @deftypefun int jit_insn_pop_stack (jit_function_t func, jit_nint num_items)
+ * Pop @code{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).
+ * @end deftypefun
+@*/
+int jit_insn_pop_stack(jit_function_t func, jit_nint num_items)
+{
+       return create_unary_note
+               (func, JIT_OP_POP_STACK,
+                jit_value_create_nint_constant(func, jit_type_nint, num_items));
+}
+
+/*@
+ * @deftypefun int jit_insn_return (jit_function_t func, jit_value_t value)
+ * Output an instruction to return @code{value} as the function's result.
+ * If @code{value} is NULL, then the function is assumed to return
+ * @code{void}.  If the function returns a structure, this will copy
+ * the value into the memory at the structure return address.
+ * @end deftypefun
+@*/
+int jit_insn_return(jit_function_t func, jit_value_t value)
+{
+       jit_type_t type;
+
+       /* Ensure that we have a builder for this function */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* This function has an ordinary return path */
+       func->builder->ordinary_return = 1;
+
+       /* Output an appropriate instruction to return to the caller */
+       type = jit_type_normalize(jit_type_get_return(func->signature));
+       type = jit_type_promote_int(type);
+       if(!value || type == jit_type_void)
+       {
+               /* Handle "finally" clauses if necessary */
+               if(!handle_finally(func, JIT_OP_PREPARE_FOR_RETURN))
+               {
+                       return 0;
+               }
+
+               /* This function returns "void" */
+               if(!create_noarg_note(func, JIT_OP_RETURN))
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               /* Convert the value into the desired return type */
+               value = jit_insn_convert(func, value, type, 0);
+               if(!value)
+               {
+                       return 0;
+               }
+
+               /* Handle "finally" clauses if necessary */
+               if(!handle_finally(func, JIT_OP_PREPARE_FOR_RETURN))
+               {
+                       return 0;
+               }
+
+               /* Create the "return" instruction */
+               switch(type->kind)
+               {
+                       case JIT_TYPE_SBYTE:
+                       case JIT_TYPE_UBYTE:
+                       case JIT_TYPE_SHORT:
+                       case JIT_TYPE_USHORT:
+                       case JIT_TYPE_INT:
+                       case JIT_TYPE_UINT:
+                       {
+                               if(!create_unary_note(func, JIT_OP_RETURN_INT, value))
+                               {
+                                       return 0;
+                               }
+                       }
+                       break;
+
+                       case JIT_TYPE_LONG:
+                       case JIT_TYPE_ULONG:
+                       {
+                               if(!create_unary_note(func, JIT_OP_RETURN_LONG, value))
+                               {
+                                       return 0;
+                               }
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT32:
+                       {
+                               if(!create_unary_note(func, JIT_OP_RETURN_FLOAT32, value))
+                               {
+                                       return 0;
+                               }
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT64:
+                       {
+                               if(!create_unary_note(func, JIT_OP_RETURN_FLOAT64, value))
+                               {
+                                       return 0;
+                               }
+                       }
+                       break;
+
+                       case JIT_TYPE_NFLOAT:
+                       {
+                               if(!create_unary_note(func, JIT_OP_RETURN_NFLOAT, value))
+                               {
+                                       return 0;
+                               }
+                       }
+                       break;
+
+                       case JIT_TYPE_STRUCT:
+                       case JIT_TYPE_UNION:
+                       {
+                               jit_value_t return_ptr = jit_value_get_struct_pointer(func);
+                               if(return_ptr)
+                               {
+                                       /* Return the structure via the supplied pointer */
+                                       /* TODO */
+                               }
+                               else
+                               {
+                                       /* Return the structure via registers */
+                                       if(!create_unary_note
+                                                       (func, JIT_OP_RETURN_SMALL_STRUCT, value))
+                                       {
+                                               break;
+                                       }
+                               }
+                       }
+                       break;
+               }
+       }
+
+       /* Mark the current block as "ends in dead" */
+       func->builder->current_block->ends_in_dead = 1;
+
+       /* Start a new block just after the "return" instruction */
+       return jit_insn_label(func, 0);
+}
+
+/*@
+ * @deftypefun 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
+ * @code{void}, then it indicates that a higher-level language error
+ * has occurred and the function should be abandoned.
+ * @end deftypefun
+@*/
+int jit_insn_default_return(jit_function_t func)
+{
+       jit_block_t current;
+       jit_insn_t last;
+
+       /* Ensure that we have a builder for this function */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* If the last block ends in an unconditional branch, or is dead,
+          then we don't need to add a default return */
+       current = func->builder->current_block;
+       if(current->ends_in_dead)
+       {
+               /* The block ends in dead */
+               return 2;
+       }
+       last = _jit_block_get_last(current);
+       if(last)
+       {
+               if(last->opcode == JIT_OP_BR)
+               {
+                       /* This block ends in an unconditional branch */
+                       return 2;
+               }
+       }
+       else if(!(current->entered_via_top) && !(current->entered_via_branch))
+       {
+               /* This block is never entered */
+               return 2;
+       }
+
+       /* Add a simple "void" return to terminate the function */
+       return jit_insn_return(func, 0);
+}
+
+/*@
+ * @deftypefun int jit_insn_throw (jit_function_t func, jit_value_t value)
+ * Throw a pointer @code{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.
+ * @end deftypefun
+@*/
+int jit_insn_throw(jit_function_t func, jit_value_t value)
+{
+       jit_block_t block;
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       func->builder->may_throw = 1;
+       func->builder->non_leaf = 1;    /* May have to call out to throw */
+       if(!create_unary_note(func, JIT_OP_THROW, value))
+       {
+               return 0;
+       }
+       func->builder->current_block->ends_in_dead = 1;
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       func->builder->current_block = block;
+       return 1;
+}
+
+/*@
+ * @deftypefun 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 @code{jit_exception_get_stack_trace},
+ * and is normally used just prior to @code{jit_insn_throw} to record
+ * the location of the exception that is being thrown.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_get_call_stack(jit_function_t func)
+{
+       jit_type_t type;
+       jit_value_t value;
+
+       /* Create a signature prototype for "void *()" */
+       type = jit_type_create_signature
+               (jit_abi_cdecl, jit_type_void_ptr, 0, 0, 1);
+       if(!type)
+       {
+               return 0;
+       }
+
+       /* Call "jit_exception_get_stack_trace" to obtain the stack trace */
+       value = jit_insn_call_native
+               (func, "jit_exception_get_stack_trace",
+                (void *)jit_exception_get_stack_trace, type, 0, 0, 0);
+
+       /* Clean up and exit */
+       jit_type_free(type);
+       return value;
+}
+
+/*@
+ * @deftypefun int jit_insn_start_try (jit_function_t func, {jit_label_t *} catch_label, {jit_label_t *} finally_label, int finally_on_fault)
+ * Start an exception-handling @code{try} block at the current position
+ * within @code{func}.
+ *
+ * Whenever an exception occurs in the block, execution will jump to
+ * @code{catch_label}.  When execution exits the @code{try} block's scope,
+ * @code{finally_label} will be called.  If @code{finally_on_fault} is
+ * non-zero, then @code{finally_label} will be called for exceptions,
+ * but not when control exits the @code{try} block normally.
+ *
+ * The @code{finally_label} parameter may be NULL if the @code{try} block
+ * does not have a @code{finally} clause associated with it.
+ *
+ * All of the blocks between @code{jit_insn_start_try} and
+ * @code{jit_insn_start_catch} are covered by the @code{catch}
+ * clause and the @code{finally} clause.  Blocks between
+ * @code{jit_insn_start_catch} and @code{jit_insn_end_try} are
+ * covered by the @code{finally} clause.
+ *
+ * Calls to @code{jit_insn_branch}, @code{jit_insn_return},
+ * @code{jit_insn_throw} and @code{jit_insn_rethrow} will cause
+ * additional code to be output to invoke the relevant @code{finally}
+ * clauses.
+ *
+ * The destinations for @code{jit_insn_branch_if} and
+ * @code{jit_insn_branch_if_not} must never be outside the current
+ * @code{finally} context.  You should always use @code{jit_insn_branch}
+ * to branch out of @code{finally} contexts.
+ *
+ * Note: you don't need to output calls to @code{finally} clauses
+ * yourself as @code{libjit} can detect when it is necessary on its own.
+ * @end deftypefun
+@*/
+int jit_insn_start_try
+       (jit_function_t func, jit_label_t *catch_label,
+        jit_label_t *finally_label, int finally_on_fault)
+{
+       jit_block_eh_t eh;
+       jit_block_t block;
+
+       /* Ensure that we have a function builder */
+       if(!_jit_function_ensure_builder(func) || !catch_label)
+       {
+               return 0;
+       }
+
+       /* Allocate the label numbers */
+       if(*catch_label == jit_label_undefined)
+       {
+               *catch_label = (func->builder->next_label)++;
+       }
+       if(finally_label && *finally_label == jit_label_undefined)
+       {
+               *finally_label = (func->builder->next_label)++;
+       }
+
+       /* This function has a "try" block.  This flag helps native
+          back ends know when they must be careful about global
+          register allocation */
+       func->builder->has_try = 1;
+
+       /* Anything with a finally handler makes the function not a leaf,
+          because we may need to do a native "call" to invoke the handler */
+       if(finally_label)
+       {
+               func->builder->non_leaf = 1;
+       }
+
+       /* Create a new exception handling context and populate it */
+       eh = jit_cnew(struct jit_block_eh);
+       if(!eh)
+       {
+               return 0;
+       }
+       eh->parent = func->builder->current_handler;
+       eh->next = func->builder->exception_handlers;
+       func->builder->exception_handlers = eh;
+       eh->catch_label = *catch_label;
+       eh->finally_label = (finally_label ? *finally_label : jit_label_undefined);
+       eh->finally_on_fault = finally_on_fault;
+       eh->in_try_body = 1;
+       func->builder->current_handler = eh;
+
+       /* Start a new block, for the body of the "try" */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       block->entered_via_top = 1;
+       return 1;
+}
+
+/*@
+ * @deftypefun jit_value_t jit_insn_start_catch (jit_function_t func, {jit_label_t *} catch_label)
+ * Start the @code{catch} clause for the currently active @code{try}
+ * block.  Returns a pointer @code{value} that indicates the exception
+ * that is thrown.
+ *
+ * There can be only one @code{catch} clause per @code{try} block.
+ * The front end is responsible for outputting instructions that
+ * inspect the exception object, determine if it is appropriate to
+ * the clause, and then either handle it or rethrow it.
+ *
+ * Every @code{try} block must have an associated @code{catch} clause,
+ * even if all it does is rethrow the exception immediately.  Without a
+ * @code{catch} clause, the correct @code{finally} logic will not be
+ * performed for thrown exceptions.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_start_catch
+       (jit_function_t func, jit_label_t *catch_label)
+{
+       jit_block_eh_t eh;
+       jit_block_eh_t new_eh;
+
+       /* Ensure that we have a function builder */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* Create a new exception handler to indicate that we are in a "catch" */
+       eh = func->builder->current_handler;
+       if(!eh)
+       {
+               return 0;
+       }
+       new_eh = jit_cnew(struct jit_block_eh);
+       if(!new_eh)
+       {
+               return 0;
+       }
+       new_eh->parent = eh->parent;
+       new_eh->next = func->builder->exception_handlers;
+       func->builder->exception_handlers = new_eh;
+       if(eh->finally_label != jit_label_undefined)
+       {
+               /* We will need a mini "catch" block to call the "finally"
+                  clause when an exception occurs within the "catch" */
+               new_eh->catch_label = (func->builder->next_label)++;
+       }
+       else
+       {
+               new_eh->catch_label = jit_label_undefined;
+       }
+       new_eh->finally_label = eh->finally_label;
+       new_eh->finally_on_fault = eh->finally_on_fault;
+       new_eh->in_try_body = 0;
+       func->builder->current_handler = new_eh;
+
+       /* Start a new block for the "catch" clause */
+       if(!jit_insn_label(func, catch_label))
+       {
+               return 0;
+       }
+
+       /* Output an instruction to notice the caught value */
+       return create_dest_note(func, JIT_OP_ENTER_CATCH, jit_type_void_ptr);
+}
+
+/*@
+ * @deftypefun int jit_insn_end_try (jit_function_t func)
+ * Mark the end of the @code{try} block and its associated @code{catch}
+ * clause.  This is normally followed by a call to
+ * @code{jit_insn_start_finally} to define the @code{finally} clause.
+ * @end deftypefun
+@*/
+int jit_insn_end_try(jit_function_t func)
+{
+       jit_block_eh_t eh;
+       jit_block_t block;
+       jit_value_t value;
+
+       /* Ensure that we have a function builder */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* Get the current exception handling context */
+       eh = func->builder->current_handler;
+       if(!eh)
+       {
+               return 0;
+       }
+
+       /* We may need another mini "catch" block to invoke the "finally"
+          clause for exceptions that happen during the "catch" */
+       if(eh->catch_label != jit_label_undefined)
+       {
+               /* TODO: not quite right */
+               if(!jit_insn_label(func, &(eh->catch_label)))
+               {
+                       return 0;
+               }
+               value = create_dest_note(func, JIT_OP_ENTER_CATCH, jit_type_void_ptr);
+               if(!value)
+               {
+                       return 0;
+               }
+               if(!jit_insn_throw(func, value))
+               {
+                       return 0;
+               }
+       }
+
+       /* Pop the current exception context */
+       func->builder->current_handler = eh->parent;
+
+       /* Start a new block, covered by the next outer "try" context */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       return 1;
+}
+
+/*@
+ * @deftypefun int jit_insn_start_finally (jit_function_t func, {jit_label_t *} finally_label)
+ * Start the @code{finally} clause for the preceding @code{try} block.
+ * @end deftypefun
+@*/
+int jit_insn_start_finally(jit_function_t func, jit_label_t *finally_label)
+{
+       if(!jit_insn_label(func, finally_label))
+       {
+               return 0;
+       }
+       return create_noarg_note(func, JIT_OP_ENTER_FINALLY);
+}
+
+/*@
+ * @deftypefun int jit_insn_return_from_finally (jit_function_t func)
+ * Return from the @code{finally} clause to where it was called from.
+ * This is usually the last instruction in a @code{finally} clause.
+ * @end deftypefun
+@*/
+int jit_insn_return_from_finally(jit_function_t func)
+{
+       jit_block_t block;
+
+       /* Mark the end of the "finally" clause */
+       if(!create_noarg_note(func, JIT_OP_LEAVE_FINALLY))
+       {
+               return 0;
+       }
+
+       /* The current block ends in a dead instruction */
+       func->builder->current_block->ends_in_dead = 1;
+
+       /* Create a new block for the following code */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       return 1;
+}
+
+/*@
+ * @deftypefun 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 @code{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 @code{type},
+ * indicating the parameter that is supplied to the filter.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_start_filter
+       (jit_function_t func, jit_label_t *label, jit_type_t type)
+{
+       /* Set a label at this point to start a new block */
+       if(!jit_insn_label(func, label))
+       {
+               return 0;
+       }
+
+       /* Create a note to load the filter's parameter at runtime */
+       return create_dest_note(func, JIT_OP_ENTER_FILTER, type);
+}
+
+/*@
+ * @deftypefun int jit_insn_return_from_filter (jit_function_t func, jit_value_t value)
+ * Return from a filter subroutine with the specified @code{value} as
+ * its result.
+ * @end deftypefun
+@*/
+int jit_insn_return_from_filter(jit_function_t func, jit_value_t value)
+{
+       jit_block_t block;
+
+       /* Mark the end of the "filter" clause */
+       if(!create_unary_note(func, JIT_OP_LEAVE_FILTER, value))
+       {
+               return 0;
+       }
+
+       /* The current block ends in a dead instruction */
+       func->builder->current_block->ends_in_dead = 1;
+
+       /* Create a new block for the following code */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       return 1;
+}
+
+/*@
+ * @deftypefun 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 @code{label}, passing it @code{value} as
+ * its argument.  This function returns a value of the specified
+ * @code{type}, indicating the filter's result.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_call_filter
+       (jit_function_t func, jit_label_t *label,
+        jit_value_t value, jit_type_t type)
+{
+       jit_block_t block;
+       jit_insn_t insn;
+
+       /* Ensure that we have a function builder */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* Allocate the label number if necessary */
+       if(*label == jit_label_undefined)
+       {
+               *label = (func->builder->next_label)++;
+       }
+
+       /* Calling a filter makes the function not a leaf because we may
+          need to do a native "call" to invoke the handler */
+       func->builder->non_leaf = 1;
+
+       /* Add a new branch instruction to branch to the filter */
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, value);
+       insn->opcode = (short)JIT_OP_CALL_FILTER;
+       insn->flags = JIT_INSN_DEST_IS_LABEL;
+       insn->dest = (jit_value_t)(*label);
+       insn->value1 = value;
+
+       /* Create a new block, and add the filter return logic to it */
+       block = _jit_block_create(func, 0);
+       if(!block)
+       {
+               return 0;
+       }
+       block->entered_via_top = 1;
+       return create_dest_note(func, JIT_OP_CALL_FILTER_RETURN, type);
+}
+
+/*@
+ * @deftypefun void jit_insn_iter_init ({jit_insn_iter_t *} iter, jit_block_t block)
+ * Initialize an iterator to point to the first instruction in @code{block}.
+ * @end deftypefun
+@*/
+void jit_insn_iter_init(jit_insn_iter_t *iter, jit_block_t block)
+{
+       iter->block = block;
+       iter->posn = block->first_insn;
+}
+
+/*@
+ * @deftypefun 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 @code{block}.
+ * @end deftypefun
+@*/
+void jit_insn_iter_init_last(jit_insn_iter_t *iter, jit_block_t block)
+{
+       iter->block = block;
+       iter->posn = block->last_insn + 1;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_insn_t jit_insn_iter_next(jit_insn_iter_t *iter)
+{
+       if(iter->posn <= iter->block->last_insn)
+       {
+               return iter->block->func->builder->insns[(iter->posn)++];
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_insn_t jit_insn_iter_previous(jit_insn_iter_t *iter)
+{
+       if(iter->posn > iter->block->first_insn)
+       {
+               return iter->block->func->builder->insns[--(iter->posn)];
+       }
+       else
+       {
+               return 0;
+       }
+}
diff --git a/jit/jit-internal.h b/jit/jit-internal.h
new file mode 100644 (file)
index 0000000..a81f8c7
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ * jit-internal.h - Internal definitions for the JIT.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_INTERNAL_H
+#define        _JIT_INTERNAL_H
+
+#include <jit/jit.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Determine what kind of Win32 system we are running on.
+ */
+#if defined(__CYGWIN__) || defined(__CYGWIN32__)
+#define        JIT_WIN32_CYGWIN        1
+#define        JIT_WIN32_PLATFORM      1
+#elif defined(_WIN32) || defined(WIN32)
+#define        JIT_WIN32_NATIVE        1
+#define        JIT_WIN32_PLATFORM      1
+#endif
+
+/*
+ * We need the apply rules for "jit_redirector_size".
+ */
+#include "jit-apply-func.h"
+
+/*
+ * Include the thread routines.
+ */
+#include "jit-thread.h"
+
+/*
+ * The following is some macro magic that attempts to detect
+ * the best alignment to use on the target platform.  The final
+ * value, "JIT_BEST_ALIGNMENT", will be a compile-time constant.
+ */
+
+#define        _JIT_ALIGN_CHECK_TYPE(type,name)        \
+       struct _JIT_align_##name { \
+               jit_sbyte pad; \
+               type field; \
+       }
+
+#define        _JIT_ALIGN_FOR_TYPE(name)       \
+       ((unsigned)(&(((struct _JIT_align_##name *)0)->field)))
+
+#define        _JIT_ALIGN_MAX(a,b)     \
+       ((a) > (b) ? (a) : (b))
+
+#define        _JIT_ALIGN_MAX3(a,b,c) \
+       (_JIT_ALIGN_MAX((a), _JIT_ALIGN_MAX((b), (c))))
+
+_JIT_ALIGN_CHECK_TYPE(jit_sbyte, sbyte);
+_JIT_ALIGN_CHECK_TYPE(jit_short, short);
+_JIT_ALIGN_CHECK_TYPE(jit_int, int);
+_JIT_ALIGN_CHECK_TYPE(jit_long, long);
+_JIT_ALIGN_CHECK_TYPE(jit_ptr, ptr);
+_JIT_ALIGN_CHECK_TYPE(jit_float32, float);
+_JIT_ALIGN_CHECK_TYPE(jit_float64, double);
+_JIT_ALIGN_CHECK_TYPE(jit_nfloat, nfloat);
+
+#if defined(JIT_X86)
+/* Sometimes the code below guesses wrong on Win32 platforms */
+#define        JIT_BEST_ALIGNMENT      4
+#else
+#define        JIT_BEST_ALIGNMENT      \
+       _JIT_ALIGN_MAX(_JIT_ALIGN_MAX3(_JIT_ALIGN_FOR_TYPE(int), \
+                                                                  _JIT_ALIGN_FOR_TYPE(long), \
+                                                                  _JIT_ALIGN_FOR_TYPE(ptr)), \
+                                  _JIT_ALIGN_MAX3(_JIT_ALIGN_FOR_TYPE(float), \
+                                                                  _JIT_ALIGN_FOR_TYPE(double), \
+                                                                  _JIT_ALIGN_FOR_TYPE(nfloat)))
+#endif
+
+/*
+ * Get the alignment values for various system types.
+ * These will also be compile-time constants.
+ */
+#define        JIT_ALIGN_SBYTE                 _JIT_ALIGN_FOR_TYPE(sbyte)
+#define        JIT_ALIGN_UBYTE                 _JIT_ALIGN_FOR_TYPE(sbyte)
+#define        JIT_ALIGN_SHORT                 _JIT_ALIGN_FOR_TYPE(short)
+#define        JIT_ALIGN_USHORT                _JIT_ALIGN_FOR_TYPE(short)
+#define        JIT_ALIGN_CHAR                  _JIT_ALIGN_FOR_TYPE(char)
+#define        JIT_ALIGN_INT                   _JIT_ALIGN_FOR_TYPE(int)
+#define        JIT_ALIGN_UINT                  _JIT_ALIGN_FOR_TYPE(int)
+#define        JIT_ALIGN_NINT                  _JIT_ALIGN_FOR_TYPE(ptr)
+#define        JIT_ALIGN_NUINT                 _JIT_ALIGN_FOR_TYPE(ptr)
+#define        JIT_ALIGN_LONG                  _JIT_ALIGN_FOR_TYPE(long)
+#define        JIT_ALIGN_ULONG                 _JIT_ALIGN_FOR_TYPE(long)
+#define        JIT_ALIGN_FLOAT32               _JIT_ALIGN_FOR_TYPE(float)
+#define        JIT_ALIGN_FLOAT64               _JIT_ALIGN_FOR_TYPE(double)
+#define        JIT_ALIGN_NFLOAT                _JIT_ALIGN_FOR_TYPE(nfloat)
+#define        JIT_ALIGN_PTR                   _JIT_ALIGN_FOR_TYPE(ptr)
+
+/*
+ * Structure of a memory pool.
+ */
+typedef struct jit_pool_block *jit_pool_block_t;
+struct jit_pool_block
+{
+       jit_pool_block_t        next;
+       char                            data[1];
+};
+typedef struct
+{
+       unsigned int            elem_size;
+       unsigned int            elems_per_block;
+       unsigned int            elems_in_last;
+       jit_pool_block_t        blocks;
+       void                       *free_list;
+
+} jit_memory_pool;
+
+/*
+ * Initialize a memory pool.
+ */
+void _jit_memory_pool_init(jit_memory_pool *pool, unsigned int elem_size);
+#define        jit_memory_pool_init(pool,type) \
+                       _jit_memory_pool_init((pool), sizeof(type))
+
+/*
+ * Free the contents of a memory pool.
+ */
+void _jit_memory_pool_free(jit_memory_pool *pool, jit_meta_free_func func);
+#define        jit_memory_pool_free(pool,func) _jit_memory_pool_free((pool), (func))
+
+/*
+ * Allocate an item from a memory pool.
+ */
+void *_jit_memory_pool_alloc(jit_memory_pool *pool);
+#define        jit_memory_pool_alloc(pool,type)        \
+                       ((type *)_jit_memory_pool_alloc((pool)))
+
+/*
+ * Deallocate an item back to a memory pool.
+ */
+void _jit_memory_pool_dealloc(jit_memory_pool *pool, void *item);
+#define        jit_memory_pool_dealloc(pool,item)      \
+                       (_jit_memory_pool_dealloc((pool), (item)))
+
+/*
+ * Storage for metadata.
+ */
+struct _jit_meta
+{
+       int                                     type;
+       void                       *data;
+       jit_meta_free_func      free_data;
+       jit_meta_t                      next;
+       jit_function_t          pool_owner;
+};
+
+/*
+ * Exception handling information that is attached to blocks.
+ */
+typedef struct jit_block_eh *jit_block_eh_t;
+struct jit_block_eh
+{
+       jit_block_eh_t          parent;
+       jit_block_eh_t          next;
+       jit_label_t                     catch_label;
+       jit_label_t                     finally_label;
+       int                                     finally_on_fault : 1;
+       int                                     in_try_body : 1;
+};
+
+/*
+ * Internal structure of a block.
+ */
+struct _jit_block
+{
+       jit_function_t          func;
+       jit_label_t                     label;
+       int                                     first_insn;
+       int                                     last_insn;
+       jit_block_t             next;
+       jit_block_t             prev;
+       jit_meta_t                      meta;
+       jit_block_eh_t          block_eh;
+       int                                     entered_via_top : 1;
+       int                                     entered_via_branch : 1;
+       int                                     ends_in_dead : 1;
+       void                       *address;
+       void                       *fixup_list;
+};
+
+/*
+ * Internal structure of a value.
+ */
+struct _jit_value
+{
+       jit_block_t                     block;
+       jit_type_t                      type;
+       short                           is_temporary : 1;
+       short                           is_local : 1;
+       short                           is_volatile : 1;
+       short                           is_addressable : 1;
+       short                           is_constant : 1;
+       short                           is_nint_constant : 1;
+       short                           has_address : 1;
+       short                           free_address : 1;
+       short                           in_register : 1;
+       short                           in_frame : 1;
+       short                           live : 1;
+       short                           next_use : 1;
+       short                           has_frame_offset : 1;
+       short                           reg;
+       jit_nint                        address;
+       jit_nint                        frame_offset;
+};
+#define        JIT_INVALID_FRAME_OFFSET        ((jit_nint)0x7FFFFFFF)
+
+/*
+ * Free the structures that are associated with a value.
+ */
+void _jit_value_free(void *value);
+
+/*
+ * Internal structure of an instruction.
+ */
+struct _jit_insn
+{
+       short                           opcode;
+       short                           flags;
+       jit_value_t                     dest;
+       jit_value_t                     value1;
+       jit_value_t                     value2;
+};
+
+/*
+ * Instruction flags.
+ */
+#define        JIT_INSN_DEST_LIVE                              0x0001
+#define        JIT_INSN_DEST_NEXT_USE                  0x0002
+#define        JIT_INSN_VALUE1_LIVE                    0x0004
+#define        JIT_INSN_VALUE1_NEXT_USE                0x0008
+#define        JIT_INSN_VALUE2_LIVE                    0x0010
+#define        JIT_INSN_VALUE2_NEXT_USE                0x0020
+#define        JIT_INSN_LIVENESS_FLAGS                 0x003F
+#define        JIT_INSN_DEST_IS_LABEL                  0x0040
+#define        JIT_INSN_DEST_IS_FUNCTION               0x0080
+#define        JIT_INSN_DEST_IS_NATIVE                 0x0100
+#define        JIT_INSN_DEST_OTHER_FLAGS               0x01C0
+#define        JIT_INSN_VALUE1_IS_NAME                 0x0200
+#define        JIT_INSN_VALUE1_OTHER_FLAGS             0x0200
+#define        JIT_INSN_VALUE2_IS_SIGNATURE    0x0400
+#define        JIT_INSN_VALUE2_OTHER_FLAGS             0x0400
+#define        JIT_INSN_DEST_IS_VALUE                  0x0800
+
+/*
+ * Information that is associated with a function for building
+ * the instructions and values.  This structure can be discarded
+ * once the function has been fully compiled.
+ */
+typedef struct _jit_builder *jit_builder_t;
+struct _jit_builder
+{
+       /* List of blocks within this function */
+       jit_block_t                     first_block;
+       jit_block_t                     last_block;
+
+       /* The next block label to be allocated */
+       jit_label_t                     next_label;
+
+       /* Mapping from label numbers to blocks */
+       jit_block_t                *label_blocks;
+       jit_label_t                     max_label_blocks;
+
+       /* Entry point for the function */
+       jit_block_t                     entry;
+
+       /* The current block that is being constructed */
+       jit_block_t                     current_block;
+
+       /* Exception handlers for the function */
+       jit_block_eh_t          exception_handlers;
+       jit_block_eh_t          current_handler;
+
+       /* Flag that is set to indicate that this function is not a leaf */
+       int                                     non_leaf : 1;
+
+       /* Flag that indicates if we've seen code that may throw an exception */
+       int                                     may_throw : 1;
+
+       /* Flag that indicates if the function has an ordinary return */
+       int                                     ordinary_return : 1;
+
+       /* Flag that indicates if we have "try" blocks */
+       int                                     has_try : 1;
+
+       /* List of all instructions in this function */
+       jit_insn_t                 *insns;
+       int                                     num_insns;
+       int                                     max_insns;
+
+       /* Memory pools that contain values, instructions, and metadata blocks */
+       jit_memory_pool         value_pool;
+       jit_memory_pool         insn_pool;
+       jit_memory_pool         meta_pool;
+
+       /* Common constants that have been cached */
+       jit_value_t                     null_constant;
+       jit_value_t                     zero_constant;
+
+       /* The values for the parameters, structure return, and parent frame */
+       jit_value_t                *param_values;
+       jit_value_t                     struct_return;
+       jit_value_t                     parent_frame;
+
+       /* The value that holds the exception frame information for a callout */
+       jit_value_t                     eh_frame_info;
+
+       /* Metadata that is stored only while the function is being built */
+       jit_meta_t                      meta;
+
+       /* Current size of the local variable frame (used by the back end) */
+       jit_nint                        frame_size;
+
+};
+
+/*
+ * Internal structure of a function.
+ */
+struct _jit_function
+{
+       /* The context that the function is associated with */
+       jit_context_t           context;
+       jit_function_t          next;
+       jit_function_t          prev;
+
+       /* Containing function in a nested context */
+       jit_function_t          nested_parent;
+
+       /* Metadata that survives once the builder is discarded */
+       jit_meta_t                      meta;
+
+       /* The signature for this function */
+       jit_type_t                      signature;
+
+       /* The builder information for this function */
+       jit_builder_t           builder;
+
+       /* Flag bits for this function */
+       int                                     is_recompilable : 1;
+       int                                     no_throw : 1;
+       int                                     no_return : 1;
+       int                                     optimization_level : 8;
+       int volatile            is_compiled;
+
+       /* The entry point for the function's compiled code */
+       void * volatile         entry_point;
+
+       /* The closure/vtable entry point for the function's compiled code */
+       void * volatile         closure_entry;
+
+       /* The function to call to perform on-demand compilation */
+       jit_on_demand_func      on_demand;
+
+#ifdef jit_redirector_size
+       /* Buffer that contains the redirector for this function.
+          Redirectors are used to support on-demand compilation */
+       unsigned char           redirector[jit_redirector_size];
+#endif
+};
+
+/*
+ * Ensure that there is a builder associated with a function.
+ */
+int _jit_function_ensure_builder(jit_function_t func);
+
+/*
+ * Free the builder associated with a function.
+ */
+void _jit_function_free_builder(jit_function_t func);
+
+/*
+ * Destroy all memory associated with a function.
+ */
+void _jit_function_destroy(jit_function_t func);
+
+/*
+ * Compute value liveness and "next use" information for a function.
+ */
+void _jit_function_compute_liveness(jit_function_t func);
+
+/*
+ * Compile a function on-demand.  Returns the entry point.
+ */
+void *_jit_function_compile_on_demand(jit_function_t func);
+
+/*
+ * Internal structure of a context.
+ */
+struct _jit_context
+{
+       /* Lock that controls access to the building process */
+       jit_mutex_t                     builder_lock;
+
+       /* Lock that controls access to the function code cache */
+       jit_mutex_t                     cache_lock;
+
+       /* List of functions that are currently registered with the context */
+       jit_function_t          functions;
+       jit_function_t          last_function;
+
+       /* Metadata that is associated with the context */
+       jit_meta_t                      meta;
+
+       /* The context's function code cache */
+       struct jit_cache   *cache;
+};
+
+/*
+ * Backtrace control structure, for managing stack traces.
+ * These structures must be allocated on the stack.
+ */
+typedef struct jit_backtrace *jit_backtrace_t;
+struct jit_backtrace
+{
+       jit_backtrace_t         parent;
+       void                       *pc;
+       void                       *catch_pc;
+       void                       *sp;
+       void                       *security_object;
+       jit_meta_free_func  free_security_object;
+};
+
+/*
+ * Push a new backtrace onto the stack.  The fields in "trace" are filled in.
+ */
+void _jit_backtrace_push
+       (jit_backtrace_t trace, void *pc, void *catch_pc, void *sp);
+
+/*
+ * Pop the top-most backtrace item.
+ */
+void _jit_backtrace_pop(void);
+
+/*
+ * Reset the backtrace stack to "trace".  Used in exception catch
+ * blocks to fix up the backtrace information.
+ */
+void _jit_backtrace_set(jit_backtrace_t trace);
+
+/*
+ * Control information that is associated with a thread.
+ */
+struct jit_thread_control
+{
+       void                       *last_exception;
+       jit_exception_func      exception_handler;
+       jit_backtrace_t         backtrace_head;
+};
+
+/*
+ * Get the function code cache for a context, creating it if necessary.
+ */
+struct jit_cache *_jit_context_get_cache(jit_context_t context);
+
+/*
+ * Initialize the block list for a function.
+ */
+int _jit_block_init(jit_function_t func);
+
+/*
+ * Free all blocks that are associated with a function.
+ */
+void _jit_block_free(jit_function_t func);
+
+/*
+ * Create a new block and associate it with a function.
+ */
+jit_block_t _jit_block_create(jit_function_t func, jit_label_t *label);
+
+/*
+ * Record the label mapping for a block.
+ */
+int _jit_block_record_label(jit_block_t block);
+
+/*
+ * Add an instruction to a block.
+ */
+jit_insn_t _jit_block_add_insn(jit_block_t block);
+
+/*
+ * Get the last instruction in a block.  NULL if the block is empty.
+ */
+jit_insn_t _jit_block_get_last(jit_block_t block);
+
+/*
+ * Free one element in a metadata list.
+ */
+void _jit_meta_free_one(void *meta);
+
+/*
+ * Determine if a NULL pointer check is redundant.  The specified
+ * iterator is assumed to be positioned one place beyond the
+ * "check_null" instruction that we are testing.
+ */
+int _jit_insn_check_is_redundant(const jit_insn_iter_t *iter);
+
+/*
+ * Get the correct opcode to use for a "load" instruction,
+ * starting at a particular opcode base.  We assume that the
+ * instructions are laid out as "sbyte", "ubyte", "short",
+ * "ushort", "int", "long", "float32", "float64", "nfloat",
+ * and "struct".
+ */
+int _jit_load_opcode(int base_opcode, jit_type_t type,
+                                        jit_value_t value, int no_temps);
+
+/*
+ * Get the correct opcode to use for a "store" instruction.
+ * We assume that the instructions are laid out as "byte",
+ * "short", "int", "long", "float32", "float64", "nfloat",
+ * and "struct".
+ */
+int _jit_store_opcode(int base_opcode, int small_base, jit_type_t type);
+
+/*
+ * Type descriptor kinds.
+ */
+#define        JIT_TYPE_VOID                           0
+#define        JIT_TYPE_SBYTE                          1
+#define        JIT_TYPE_UBYTE                          2
+#define        JIT_TYPE_SHORT                          3
+#define        JIT_TYPE_USHORT                         4
+#define        JIT_TYPE_INT                            5
+#define        JIT_TYPE_UINT                           6
+#define        JIT_TYPE_NINT                           7
+#define        JIT_TYPE_NUINT                          8
+#define        JIT_TYPE_LONG                           9
+#define        JIT_TYPE_ULONG                          10
+#define        JIT_TYPE_FLOAT32                        11
+#define        JIT_TYPE_FLOAT64                        12
+#define        JIT_TYPE_NFLOAT                         13
+#define        JIT_TYPE_MAX_PRIMITIVE          JIT_TYPE_NFLOAT
+#define        JIT_TYPE_STRUCT                         14
+#define        JIT_TYPE_UNION                          15
+#define        JIT_TYPE_SIGNATURE                      16
+#define        JIT_TYPE_PTR                            17
+#define        JIT_TYPE_FIRST_TAGGED           32
+
+/*
+ * Internal structure of a type descriptor.
+ */
+struct jit_component
+{
+       jit_type_t              type;
+       jit_nuint               offset;
+       char               *name;
+};
+struct _jit_type
+{
+       unsigned int    ref_count;
+       int                             kind : 19;
+       int                             abi : 8;
+       int                             is_fixed : 1;
+       int                             layout_flags : 4;
+       jit_nuint               size;
+       jit_nuint               alignment;
+       jit_type_t              sub_type;
+       unsigned int    num_components;
+       struct jit_component components[1];
+};
+struct jit_tagged_type
+{
+       struct _jit_type        type;
+       void                       *data;
+       jit_meta_free_func      free_func;
+
+};
+
+/*
+ * Pre-defined type descriptors.
+ */
+extern struct _jit_type const _jit_type_void_def;
+extern struct _jit_type const _jit_type_sbyte_def;
+extern struct _jit_type const _jit_type_ubyte_def;
+extern struct _jit_type const _jit_type_short_def;
+extern struct _jit_type const _jit_type_ushort_def;
+extern struct _jit_type const _jit_type_int_def;
+extern struct _jit_type const _jit_type_uint_def;
+extern struct _jit_type const _jit_type_nint_def;
+extern struct _jit_type const _jit_type_nuint_def;
+extern struct _jit_type const _jit_type_long_def;
+extern struct _jit_type const _jit_type_ulong_def;
+extern struct _jit_type const _jit_type_float32_def;
+extern struct _jit_type const _jit_type_float64_def;
+extern struct _jit_type const _jit_type_nfloat_def;
+extern struct _jit_type const _jit_type_void_ptr_def;
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_INTERNAL_H */
diff --git a/jit/jit-interp.cpp b/jit/jit-interp.cpp
new file mode 100644 (file)
index 0000000..fae091f
--- /dev/null
@@ -0,0 +1,4503 @@
+/*
+ * jit-interp.cpp - Fallback interpreter implementation.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+
+This file must be compiled with a C++ compiler, because it uses
+C++ exceptions to manage JIT exception throws.  It is otherwise
+straight vanilla ANSI C.
+
+*/
+
+#include "jit-interp.h"
+#include "jit-rules.h"
+#include "jit-memory.h"
+#include <config.h>
+#if HAVE_ALLOCA_H
+       #include <alloca.h>
+#endif
+#ifdef JIT_WIN32_PLATFORM
+       #include <malloc.h>
+       #ifndef alloca
+               #define alloca  _alloca
+       #endif
+#endif
+
+#if defined(JIT_BACKEND_INTERP)
+
+/*
+ * Macros that help with the definition of the interpreter switch loop.
+ */
+#define        VMSWITCH(pc)    \
+               for(;;) \
+               { \
+                       switch((int)*((jit_nint *)(pc)))
+#define        VMSWITCHEND             \
+               }
+#define        VMCASE(opcode)  \
+               case opcode
+#define        VMBREAK                 \
+               break
+
+/*
+ * Modify the program counter and stack pointer.
+ */
+#define        VM_MODIFY_PC_AND_STACK(pcmod,stkmod)    \
+               do { \
+                       pc += (jit_nint)(int)(pcmod); \
+                       stacktop += (jit_nint)(int)(stkmod); \
+               } while (0)
+#define        VM_MODIFY_STACK(stkmod) \
+               do { \
+                       stacktop += (jit_nint)(int)(stkmod); \
+               } while (0)
+
+/*
+ * Fetch arguments of various types from the instruction stream.
+ */
+#define        VM_NINT_ARG             (((jit_nint *)(pc))[1])
+#define        VM_NINT_ARG2    (((jit_nint *)(pc))[2])
+#define        VM_NINT_ARG3    (((jit_nint *)(pc))[3])
+#define        VM_BR_TARGET    (pc + VM_NINT_ARG)
+
+/*
+ * Fetch stack items from various positions.
+ */
+#define        VM_STK_INT0             (stacktop[0].int_value)
+#define        VM_STK_INT1             (stacktop[1].int_value)
+#define        VM_STK_INTP             (stacktop[-1].int_value)
+#define        VM_STK_UINT0    (stacktop[0].uint_value)
+#define        VM_STK_UINT1    (stacktop[1].uint_value)
+#define        VM_STK_UINTP    (stacktop[-1].uint_value)
+#define        VM_STK_LONG0    (stacktop[0].long_value)
+#define        VM_STK_LONG1    (stacktop[1].long_value)
+#define        VM_STK_LONGP    (stacktop[-1].long_value)
+#define        VM_STK_ULONG0   (stacktop[0].ulong_value)
+#define        VM_STK_ULONG1   (stacktop[1].ulong_value)
+#define        VM_STK_ULONGP   (stacktop[-1].ulong_value)
+#define        VM_STK_FLOAT320 (stacktop[0].float32_value)
+#define        VM_STK_FLOAT321 (stacktop[1].float32_value)
+#define        VM_STK_FLOAT32P (stacktop[-1].float32_value)
+#define        VM_STK_FLOAT640 (stacktop[0].float64_value)
+#define        VM_STK_FLOAT641 (stacktop[1].float64_value)
+#define        VM_STK_FLOAT64P (stacktop[-1].float64_value)
+#define        VM_STK_NFLOAT0  (stacktop[0].nfloat_value)
+#define        VM_STK_NFLOAT1  (stacktop[1].nfloat_value)
+#define        VM_STK_NFLOATP  (stacktop[-1].nfloat_value)
+#define        VM_STK_PTR0             (stacktop[0].ptr_value)
+#define        VM_STK_PTR1             (stacktop[1].ptr_value)
+#define        VM_STK_PTRP             (stacktop[-1].ptr_value)
+#define        VM_STK_PTRP2    (stacktop[-2].ptr_value)
+
+/*
+ * Apply a relative adjustment to a pointer and cast to a specific type.
+ */
+#define        VM_REL(type,ptr)        \
+                       ((type *)(((unsigned char *)(ptr)) + VM_NINT_ARG))
+
+/*
+ * Get the address of an argument or local variable at a particular offset.
+ */
+#define        VM_ARG(type)            \
+                       ((type *)(((jit_item *)args) + VM_NINT_ARG))
+#define        VM_LOC(type)            \
+                       ((type *)(((jit_item *)frame) + VM_NINT_ARG))
+
+/*
+ * Handle the return value from a function that reports a builtin exception.
+ */
+#define        VM_BUILTIN(value)       \
+                       do { \
+                               builtin_exception = (value); \
+                               if(builtin_exception < JIT_RESULT_OK) \
+                               { \
+                                       goto handle_builtin; \
+                               } \
+                       } while (0)
+
+/*
+ * Call "jit_apply" from the interpreter, to invoke a native function.
+ */
+static void apply_from_interpreter
+               (jit_type_t signature, void *func,
+                jit_item *args, unsigned int num_fixed_args,
+                void *return_area)
+{
+       unsigned int num_params;
+       unsigned int param;
+       jit_type_t type;
+       void **apply_args;
+
+       /* Allocate space for the apply arguments and initialize them */
+       num_params = jit_type_num_params(signature);
+       apply_args = (void **)alloca(sizeof(void *) * num_params);
+       for(param = 0; param < num_params; ++param)
+       {
+               type = jit_type_normalize(jit_type_get_param(signature, param));
+               switch(type->kind)
+               {
+                       case JIT_TYPE_SBYTE:
+                       case JIT_TYPE_UBYTE:
+                       {
+                               apply_args[param] =
+                                       ((unsigned char *)args) + _jit_int_lowest_byte();
+                               ++args;
+                       }
+                       break;
+
+                       case JIT_TYPE_SHORT:
+                       case JIT_TYPE_USHORT:
+                       {
+                               apply_args[param] =
+                                       ((unsigned char *)args) + _jit_int_lowest_short();
+                               ++args;
+                       }
+                       break;
+
+                       case JIT_TYPE_INT:
+                       case JIT_TYPE_UINT:
+                       case JIT_TYPE_LONG:
+                       case JIT_TYPE_ULONG:
+                       case JIT_TYPE_FLOAT32:
+                       case JIT_TYPE_FLOAT64:
+                       case JIT_TYPE_NFLOAT:
+                       {
+                               apply_args[param] = args;
+                               ++args;
+                       }
+                       break;
+
+                       case JIT_TYPE_STRUCT:
+                       case JIT_TYPE_UNION:
+                       {
+                               apply_args[param] = args;
+                               args += JIT_NUM_ITEMS_IN_STRUCT(jit_type_get_size(type));
+                       }
+                       break;
+
+                       default:
+                       {
+                               /* Shouldn't happen, but do something sane */
+                               apply_args[param] = args;
+                       }
+                       break;
+               }
+       }
+
+       /* Apply the function */
+       jit_apply(signature, func, apply_args, num_fixed_args, return_area);
+}
+
+void _jit_run_function(jit_function_interp *func, jit_item *args,
+                                          jit_item *return_area)
+{
+       jit_item *frame;
+       jit_item *stacktop;
+       void **pc;
+       jit_int builtin_exception;
+       jit_nint temparg;
+       void *tempptr;
+       void *tempptr2;
+       jit_function_t call_func;
+       struct jit_backtrace call_trace;
+       void *entry;
+       void *exception_object = 0;
+       void *handler;
+
+       /* Set up the stack frame for this function */
+       frame = (jit_item *)alloca(func->frame_size);
+       stacktop = frame + func->working_area;
+       frame = stacktop;
+
+       /* Get the initial program counter */
+       pc = jit_function_interp_entry_pc(func);
+
+       /* Enter the instruction dispatch loop */
+       VMSWITCH(pc)
+       {
+               /******************************************************************
+                * Simple opcodes.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_NOP):
+               {
+                       /* Nothing to do except move on to the next instruction */
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Conversion opcodes.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_TRUNC_SBYTE):
+               {
+                       /* Truncate an integer to a signed 8-bit value */
+                       VM_STK_INT0 = (jit_int)(jit_sbyte)VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_TRUNC_UBYTE):
+               {
+                       /* Truncate an integer to an unsigned 8-bit value */
+                       VM_STK_INT0 = (jit_int)(jit_ubyte)VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_TRUNC_SHORT):
+               {
+                       /* Truncate an integer to a signed 16-bit value */
+                       VM_STK_INT0 = (jit_int)(jit_short)VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_TRUNC_USHORT):
+               {
+                       /* Truncate an integer to an unsigned 16-bit value */
+                       VM_STK_INT0 = (jit_int)(jit_ushort)VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_TRUNC_INT):
+               {
+                       /* Truncate an integer to a signed 32-bit value */
+                       /* In the interpreter, this is a NOP */
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_TRUNC_UINT):
+               {
+                       /* Truncate an integer to an unsigned 32-bit value */
+                       /* In the interpreter, this is a NOP */
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_SBYTE):
+               {
+                       /* Truncate an integer to a signed 8-bit value, and check */
+                       VM_BUILTIN(jit_int_to_sbyte_ovf(&VM_STK_INT0, VM_STK_INT0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_UBYTE):
+               {
+                       /* Truncate an integer to an unsigned 8-bit value, and check */
+                       VM_BUILTIN(jit_int_to_ubyte_ovf(&VM_STK_INT0, VM_STK_INT0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_SHORT):
+               {
+                       /* Truncate an integer to a signed 16-bit value, and check */
+                       VM_BUILTIN(jit_int_to_short_ovf(&VM_STK_INT0, VM_STK_INT0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_USHORT):
+               {
+                       /* Truncate an integer to an unsigned 16-bit value, and check */
+                       VM_BUILTIN(jit_int_to_ushort_ovf(&VM_STK_INT0, VM_STK_INT0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_INT):
+               {
+                       /* Truncate an integer to a signed 32-bit value, and check */
+                       VM_BUILTIN(jit_uint_to_int_ovf(&VM_STK_INT0, VM_STK_UINT0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_UINT):
+               {
+                       /* Truncate an integer to an unsigned 32-bit value, and check */
+                       VM_BUILTIN(jit_int_to_uint_ovf(&VM_STK_UINT0, VM_STK_INT0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOW_WORD):
+               {
+                       /* Fetch the low word of a 64-bit value */
+                       VM_STK_UINT0 = (jit_uint)VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_EXPAND_INT):
+               {
+                       /* Expand a signed 32-bit value to a 64-bit value */
+                       VM_STK_LONG0 = (jit_long)VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_EXPAND_UINT):
+               {
+                       /* Expand an unsigned 32-bit value to a 64-bit value */
+                       VM_STK_ULONG0 = (jit_ulong)VM_STK_UINT0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_LOW_WORD):
+               {
+                       /* Fetch the low word of a 64-bit value, and check */
+                       VM_BUILTIN(jit_long_to_uint_ovf(&VM_STK_UINT0, VM_STK_LONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_SIGNED_LOW_WORD):
+               {
+                       /* Fetch the signed low word of a 64-bit value, and check */
+                       VM_BUILTIN(jit_long_to_int_ovf(&VM_STK_INT0, VM_STK_LONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_LONG):
+               {
+                       /* Convert unsigned 64-bit into signed, and check */
+                       VM_BUILTIN(jit_ulong_to_long_ovf(&VM_STK_LONG0, VM_STK_ULONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_ULONG):
+               {
+                       /* Convert signed 64-bit into unsigned, and check */
+                       VM_BUILTIN(jit_long_to_ulong_ovf(&VM_STK_ULONG0, VM_STK_LONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLOAT_TO_INT):
+               {
+                       /* Convert native float into 32-bit signed integer */
+                       VM_STK_INT0 = jit_nfloat_to_int(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLOAT_TO_UINT):
+               {
+                       /* Convert native float into 32-bit unsigned integer */
+                       VM_STK_UINT0 = jit_nfloat_to_uint(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLOAT_TO_LONG):
+               {
+                       /* Convert native float into 64-bit signed integer */
+                       VM_STK_LONG0 = jit_nfloat_to_long(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLOAT_TO_ULONG):
+               {
+                       /* Convert native float into 64-bit unsigned integer */
+                       VM_STK_ULONG0 = jit_nfloat_to_ulong(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_NFLOAT_TO_INT):
+               {
+                       /* Convert native float into 32-bit signed integer, and check */
+                       VM_BUILTIN(jit_nfloat_to_int_ovf(&VM_STK_INT0, VM_STK_NFLOAT0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_NFLOAT_TO_UINT):
+               {
+                       /* Convert native float into 32-bit unsigned integer, and check */
+                       VM_BUILTIN(jit_nfloat_to_uint_ovf(&VM_STK_UINT0, VM_STK_NFLOAT0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_NFLOAT_TO_LONG):
+               {
+                       /* Convert native float into 64-bit signed integer, and check */
+                       VM_BUILTIN(jit_nfloat_to_long_ovf(&VM_STK_LONG0, VM_STK_NFLOAT0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_NFLOAT_TO_ULONG):
+               {
+                       /* Convert native float into 64-bit unsigned integer, and check */
+                       VM_BUILTIN(jit_nfloat_to_ulong_ovf(&VM_STK_ULONG0, VM_STK_NFLOAT0));
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_INT_TO_NFLOAT):
+               {
+                       /* Convert 32-bit signed integer into native float */
+                       VM_STK_NFLOAT0 = jit_int_to_nfloat(VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_UINT_TO_NFLOAT):
+               {
+                       /* Convert 32-bit unsigned integer into native float */
+                       VM_STK_NFLOAT0 = jit_uint_to_nfloat(VM_STK_UINT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LONG_TO_NFLOAT):
+               {
+                       /* Convert 64-bit signed integer into native float */
+                       VM_STK_NFLOAT0 = jit_long_to_nfloat(VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ULONG_TO_NFLOAT):
+               {
+                       /* Convert 64-bit unsigned integer into native float */
+                       VM_STK_NFLOAT0 = jit_ulong_to_nfloat(VM_STK_ULONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLOAT_TO_FLOAT32):
+               {
+                       /* Convert native float into 32-bit float */
+                       VM_STK_FLOAT320 = jit_nfloat_to_float32(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLOAT_TO_FLOAT64):
+               {
+                       /* Convert native float into 64-bit float */
+                       VM_STK_FLOAT640 = jit_nfloat_to_float64(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FLOAT32_TO_NFLOAT):
+               {
+                       /* Convert 32-bit float into native float */
+                       VM_STK_NFLOAT0 = jit_float32_to_nfloat(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FLOAT64_TO_NFLOAT):
+               {
+                       /* Convert 64-bit float into native float */
+                       VM_STK_NFLOAT0 = jit_float64_to_nfloat(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Arithmetic opcodes.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_IADD):
+               {
+                       /* Add signed 32-bit integers */
+                       VM_STK_INT1 = VM_STK_INT1 + VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IADD_OVF):
+               {
+                       /* Add signed 32-bit integers, and check */
+                       VM_BUILTIN(jit_int_add_ovf
+                               (&VM_STK_INT1, VM_STK_INT1, VM_STK_INT0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IADD_OVF_UN):
+               {
+                       /* Add unsigned 32-bit integers, and check */
+                       VM_BUILTIN(jit_uint_add_ovf
+                               (&VM_STK_UINT1, VM_STK_UINT1, VM_STK_UINT0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ISUB):
+               {
+                       /* Subtract signed 32-bit integers */
+                       VM_STK_INT1 = VM_STK_INT1 - VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ISUB_OVF):
+               {
+                       /* Subtract signed 32-bit integers, and check */
+                       VM_BUILTIN(jit_int_sub_ovf
+                               (&VM_STK_INT1, VM_STK_INT1, VM_STK_INT0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ISUB_OVF_UN):
+               {
+                       /* Subtract unsigned 32-bit integers, and check */
+                       VM_BUILTIN(jit_uint_sub_ovf
+                               (&VM_STK_UINT1, VM_STK_UINT1, VM_STK_UINT0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IMUL):
+               {
+                       /* Multiply signed 32-bit integers */
+                       VM_STK_INT1 = VM_STK_INT1 * VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IMUL_OVF):
+               {
+                       /* Multiply signed 32-bit integers, and check */
+                       VM_BUILTIN(jit_int_mul_ovf
+                               (&VM_STK_INT1, VM_STK_INT1, VM_STK_INT0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IMUL_OVF_UN):
+               {
+                       /* Multiply unsigned 32-bit integers, and check */
+                       VM_BUILTIN(jit_uint_mul_ovf
+                               (&VM_STK_UINT1, VM_STK_UINT1, VM_STK_UINT0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IDIV):
+               {
+                       /* Divide signed 32-bit integers */
+                       VM_BUILTIN(jit_int_div
+                               (&VM_STK_INT1, VM_STK_INT1, VM_STK_INT0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IDIV_UN):
+               {
+                       /* Divide unsigned 32-bit integers */
+                       VM_BUILTIN(jit_uint_div
+                               (&VM_STK_UINT1, VM_STK_UINT1, VM_STK_UINT0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IREM):
+               {
+                       /* Remainder signed 32-bit integers */
+                       VM_BUILTIN(jit_int_rem
+                               (&VM_STK_INT1, VM_STK_INT1, VM_STK_INT0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IREM_UN):
+               {
+                       /* Remainder unsigned 32-bit integers */
+                       VM_BUILTIN(jit_uint_rem
+                               (&VM_STK_UINT1, VM_STK_UINT1, VM_STK_UINT0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_INEG):
+               {
+                       /* Negate signed 32-bit integer */
+                       VM_STK_INT0 = -VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LADD):
+               {
+                       /* Add signed 64-bit integers */
+                       VM_STK_LONG1 = VM_STK_LONG1 + VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LADD_OVF):
+               {
+                       /* Add signed 64-bit integers, and check */
+                       VM_BUILTIN(jit_long_add_ovf
+                               (&VM_STK_LONG1, VM_STK_LONG1, VM_STK_LONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LADD_OVF_UN):
+               {
+                       /* Add unsigned 64-bit integers, and check */
+                       VM_BUILTIN(jit_ulong_add_ovf
+                               (&VM_STK_ULONG1, VM_STK_ULONG1, VM_STK_ULONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LSUB):
+               {
+                       /* Subtract signed 64-bit integers */
+                       VM_STK_LONG1 = VM_STK_LONG1 - VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LSUB_OVF):
+               {
+                       /* Subtract signed 64-bit integers, and check */
+                       VM_BUILTIN(jit_long_sub_ovf
+                               (&VM_STK_LONG1, VM_STK_LONG1, VM_STK_LONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LSUB_OVF_UN):
+               {
+                       /* Subtract unsigned 64-bit integers, and check */
+                       VM_BUILTIN(jit_ulong_sub_ovf
+                               (&VM_STK_ULONG1, VM_STK_ULONG1, VM_STK_ULONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LMUL):
+               {
+                       /* Multiply signed 64-bit integers */
+                       VM_STK_LONG1 = VM_STK_LONG1 * VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LMUL_OVF):
+               {
+                       /* Multiply signed 64-bit integers, and check */
+                       VM_BUILTIN(jit_long_mul_ovf
+                               (&VM_STK_LONG1, VM_STK_LONG1, VM_STK_LONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LMUL_OVF_UN):
+               {
+                       /* Multiply unsigned 64-bit integers, and check */
+                       VM_BUILTIN(jit_ulong_mul_ovf
+                               (&VM_STK_ULONG1, VM_STK_ULONG1, VM_STK_ULONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDIV):
+               {
+                       /* Divide signed 64-bit integers */
+                       VM_BUILTIN(jit_long_div
+                               (&VM_STK_LONG1, VM_STK_LONG1, VM_STK_LONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDIV_UN):
+               {
+                       /* Divide unsigned 64-bit integers */
+                       VM_BUILTIN(jit_ulong_div
+                               (&VM_STK_ULONG1, VM_STK_ULONG1, VM_STK_ULONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LREM):
+               {
+                       /* Remainder signed 64-bit integers */
+                       VM_BUILTIN(jit_long_rem
+                               (&VM_STK_LONG1, VM_STK_LONG1, VM_STK_LONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LREM_UN):
+               {
+                       /* Remainder unsigned 64-bit integers */
+                       VM_BUILTIN(jit_ulong_rem
+                               (&VM_STK_ULONG1, VM_STK_ULONG1, VM_STK_ULONG0));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LNEG):
+               {
+                       /* Negate signed 64-bit integer */
+                       VM_STK_LONG0 = -VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FADD):
+               {
+                       /* Add 32-bit floats */
+                       VM_STK_FLOAT321 = VM_STK_FLOAT321 + VM_STK_FLOAT320;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FSUB):
+               {
+                       /* Subtract 32-bit floats */
+                       VM_STK_FLOAT321 = VM_STK_FLOAT321 - VM_STK_FLOAT320;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FMUL):
+               {
+                       /* Multiply 32-bit floats */
+                       VM_STK_FLOAT321 = VM_STK_FLOAT321 * VM_STK_FLOAT320;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FDIV):
+               {
+                       /* Divide 32-bit floats */
+                       VM_STK_FLOAT321 = VM_STK_FLOAT321 / VM_STK_FLOAT320;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FREM):
+               {
+                       /* Remainder 32-bit floats */
+                       VM_STK_FLOAT321 = jit_float32_rem
+                               (VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FREM_IEEE):
+               {
+                       /* Remainder 32-bit floats, with IEEE rules */
+                       VM_STK_FLOAT321 = jit_float32_ieee_rem
+                               (VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FNEG):
+               {
+                       /* Negate 32-bit float */
+                       VM_STK_FLOAT320 = -VM_STK_FLOAT320;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DADD):
+               {
+                       /* Add 64-bit floats */
+                       VM_STK_FLOAT641 = VM_STK_FLOAT641 + VM_STK_FLOAT640;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DSUB):
+               {
+                       /* Subtract 64-bit floats */
+                       VM_STK_FLOAT641 = VM_STK_FLOAT641 - VM_STK_FLOAT640;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DMUL):
+               {
+                       /* Multiply 64-bit floats */
+                       VM_STK_FLOAT641 = VM_STK_FLOAT641 * VM_STK_FLOAT640;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DDIV):
+               {
+                       /* Divide 64-bit floats */
+                       VM_STK_FLOAT641 = VM_STK_FLOAT641 / VM_STK_FLOAT640;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DREM):
+               {
+                       /* Remainder 64-bit floats */
+                       VM_STK_FLOAT641 = jit_float64_rem
+                               (VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DREM_IEEE):
+               {
+                       /* Remainder 64-bit floats, with IEEE rules */
+                       VM_STK_FLOAT641 = jit_float64_ieee_rem
+                               (VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DNEG):
+               {
+                       /* Negate 64-bit float */
+                       VM_STK_FLOAT640 = -VM_STK_FLOAT640;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFADD):
+               {
+                       /* Add native floats */
+                       VM_STK_NFLOAT1 = VM_STK_NFLOAT1 + VM_STK_NFLOAT0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFSUB):
+               {
+                       /* Subtract native floats */
+                       VM_STK_NFLOAT1 = VM_STK_NFLOAT1 - VM_STK_NFLOAT0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFMUL):
+               {
+                       /* Multiply native floats */
+                       VM_STK_NFLOAT1 = VM_STK_NFLOAT1 * VM_STK_NFLOAT0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFDIV):
+               {
+                       /* Divide native floats */
+                       VM_STK_NFLOAT1 = VM_STK_NFLOAT1 / VM_STK_NFLOAT0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFREM):
+               {
+                       /* Remainder native floats */
+                       VM_STK_NFLOAT1 = jit_nfloat_rem
+                               (VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFREM_IEEE):
+               {
+                       /* Remainder native floats, with IEEE rules */
+                       VM_STK_NFLOAT1 = jit_nfloat_ieee_rem
+                               (VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFNEG):
+               {
+                       /* Negate native float */
+                       VM_STK_NFLOAT0 = -VM_STK_NFLOAT0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Bitwise opcodes.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_IAND):
+               {
+                       /* Bitwise and signed 32-bit integers */
+                       VM_STK_INT1 = VM_STK_INT1 & VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IOR):
+               {
+                       /* Bitwise or signed 32-bit integers */
+                       VM_STK_INT1 = VM_STK_INT1 | VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IXOR):
+               {
+                       /* Bitwise xor signed 32-bit integers */
+                       VM_STK_INT1 = VM_STK_INT1 ^ VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_INOT):
+               {
+                       /* Bitwise not signed 32-bit integers */
+                       VM_STK_INT0 = ~VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ISHL):
+               {
+                       /* Shift left signed 32-bit integers */
+                       VM_STK_INT1 = VM_STK_INT1 << (VM_STK_UINT0 & 0x1F);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ISHR):
+               {
+                       /* Shift right signed 32-bit integers */
+                       VM_STK_INT1 = VM_STK_INT1 >> (VM_STK_UINT0 & 0x1F);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ISHR_UN):
+               {
+                       /* Shift right unsigned 32-bit integers */
+                       VM_STK_UINT1 = VM_STK_UINT1 >> (VM_STK_UINT0 & 0x1F);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LAND):
+               {
+                       /* Bitwise and signed 64-bit integers */
+                       VM_STK_LONG1 = VM_STK_LONG1 & VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOR):
+               {
+                       /* Bitwise or signed 64-bit integers */
+                       VM_STK_LONG1 = VM_STK_LONG1 | VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LXOR):
+               {
+                       /* Bitwise xor signed 64-bit integers */
+                       VM_STK_LONG1 = VM_STK_LONG1 ^ VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LNOT):
+               {
+                       /* Bitwise not signed 64-bit integers */
+                       VM_STK_LONG0 = ~VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LSHL):
+               {
+                       /* Shift left signed 64-bit integers */
+                       VM_STK_LONG1 = (VM_STK_LONG1 << (VM_STK_UINT0 & 0x3F));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LSHR):
+               {
+                       /* Shift right signed 64-bit integers */
+                       VM_STK_LONG1 = (VM_STK_LONG1 >> (VM_STK_UINT0 & 0x3F));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LSHR_UN):
+               {
+                       /* Shift right signed 64-bit integers */
+                       VM_STK_ULONG1 = (VM_STK_ULONG1 >> (VM_STK_UINT0 & 0x3F));
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Branch opcodes.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_BR):
+               {
+                       /* Unconditional branch */
+                       pc = VM_BR_TARGET;
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_IFALSE):
+               {
+                       /* Branch if signed 32-bit integer is false */
+                       if(VM_STK_INT0 == 0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(1);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 1);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_ITRUE):
+               {
+                       /* Branch if signed 32-bit integer is true */
+                       if(VM_STK_INT0 != 0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(1);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 1);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_IEQ):
+               {
+                       /* Branch if signed 32-bit integers are equal */
+                       if(VM_STK_INT1 == VM_STK_INT0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_INE):
+               {
+                       /* Branch if signed 32-bit integers are not equal */
+                       if(VM_STK_INT1 != VM_STK_INT0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_ILT):
+               {
+                       /* Branch if signed 32-bit integers are less than */
+                       if(VM_STK_INT1 < VM_STK_INT0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_ILT_UN):
+               {
+                       /* Branch if unsigned 32-bit integers are less than */
+                       if(VM_STK_UINT1 < VM_STK_UINT0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_ILE):
+               {
+                       /* Branch if signed 32-bit integers are less than or equal */
+                       if(VM_STK_INT1 <= VM_STK_INT0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_ILE_UN):
+               {
+                       /* Branch if unsigned 32-bit integers are less than or equal */
+                       if(VM_STK_UINT1 <= VM_STK_UINT0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_IGT):
+               {
+                       /* Branch if signed 32-bit integers are greater than */
+                       if(VM_STK_INT1 > VM_STK_INT0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_IGT_UN):
+               {
+                       /* Branch if unsigned 32-bit integers are greater than */
+                       if(VM_STK_UINT1 > VM_STK_UINT0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_IGE):
+               {
+                       /* Branch if signed 32-bit integers are greater than or equal */
+                       if(VM_STK_INT1 >= VM_STK_INT0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_IGE_UN):
+               {
+                       /* Branch if unsigned 32-bit integers are greater than or equal */
+                       if(VM_STK_UINT1 >= VM_STK_UINT0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LFALSE):
+               {
+                       /* Branch if signed 64-bit integer is false */
+                       if(VM_STK_LONG0 == 0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(1);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 1);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LTRUE):
+               {
+                       /* Branch if signed 64-bit integer is true */
+                       if(VM_STK_LONG0 != 0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(1);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 1);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LEQ):
+               {
+                       /* Branch if signed 64-bit integers are equal */
+                       if(VM_STK_LONG1 == VM_STK_LONG0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LNE):
+               {
+                       /* Branch if signed 64-bit integers are not equal */
+                       if(VM_STK_LONG1 != VM_STK_LONG0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LLT):
+               {
+                       /* Branch if signed 64-bit integers are less than */
+                       if(VM_STK_LONG1 < VM_STK_LONG0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LLT_UN):
+               {
+                       /* Branch if unsigned 64-bit integers are less than */
+                       if(VM_STK_ULONG1 < VM_STK_ULONG0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LLE):
+               {
+                       /* Branch if signed 64-bit integers are less than or equal */
+                       if(VM_STK_LONG1 <= VM_STK_LONG0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LLE_UN):
+               {
+                       /* Branch if unsigned 64-bit integers are less than or equal */
+                       if(VM_STK_ULONG1 <= VM_STK_ULONG0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LGT):
+               {
+                       /* Branch if signed 64-bit integers are greater than */
+                       if(VM_STK_LONG1 > VM_STK_LONG0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LGT_UN):
+               {
+                       /* Branch if unsigned 64-bit integers are greater than */
+                       if(VM_STK_ULONG1 > VM_STK_ULONG0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LGE):
+               {
+                       /* Branch if signed 64-bit integers are greater than or equal */
+                       if(VM_STK_LONG1 >= VM_STK_LONG0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_LGE_UN):
+               {
+                       /* Branch if unsigned 64-bit integers are greater than or equal */
+                       if(VM_STK_ULONG1 >= VM_STK_ULONG0)
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FEQ):
+               {
+                       /* Branch if 32-bit floats are equal */
+                       if(jit_float32_eq(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FNE):
+               {
+                       /* Branch if 32-bit floats are not equal */
+                       if(jit_float32_ne(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FLT):
+               {
+                       /* Branch if 32-bit floats are less than */
+                       if(jit_float32_lt(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FLE):
+               {
+                       /* Branch if 32-bit floats are less than or equal */
+                       if(jit_float32_le(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FGT):
+               {
+                       /* Branch if 32-bit floats are greater than */
+                       if(jit_float32_gt(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FGE):
+               {
+                       /* Branch if 32-bit floats are greater than or equal */
+                       if(jit_float32_ge(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FEQ_INV):
+               {
+                       /* Branch if 32-bit floats are equal; invert nan test */
+                       if(!jit_float32_ne(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FNE_INV):
+               {
+                       /* Branch if 32-bit floats are not equal; invert nan test */
+                       if(!jit_float32_eq(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FLT_INV):
+               {
+                       /* Branch if 32-bit floats are less than; invert nan test */
+                       if(!jit_float32_ge(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FLE_INV):
+               {
+                       /* Branch if 32-bit floats are less or equal; invert nan test */
+                       if(!jit_float32_gt(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FGT_INV):
+               {
+                       /* Branch if 32-bit floats are greater than; invert nan test */
+                       if(!jit_float32_le(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_FGE_INV):
+               {
+                       /* Branch if 32-bit floats are greater or equal; invert nan test */
+                       if(!jit_float32_lt(VM_STK_FLOAT321, VM_STK_FLOAT320))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DEQ):
+               {
+                       /* Branch if 64-bit floats are equal */
+                       if(jit_float64_eq(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DNE):
+               {
+                       /* Branch if 64-bit floats are not equal */
+                       if(jit_float64_ne(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DLT):
+               {
+                       /* Branch if 64-bit floats are less than */
+                       if(jit_float64_lt(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DLE):
+               {
+                       /* Branch if 64-bit floats are less than or equal */
+                       if(jit_float64_le(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DGT):
+               {
+                       /* Branch if 64-bit floats are greater than */
+                       if(jit_float64_gt(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DGE):
+               {
+                       /* Branch if 64-bit floats are greater than or equal */
+                       if(jit_float64_ge(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DEQ_INV):
+               {
+                       /* Branch if 64-bit floats are equal; invert nan test */
+                       if(!jit_float64_ne(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DNE_INV):
+               {
+                       /* Branch if 64-bit floats are not equal; invert nan test */
+                       if(!jit_float64_eq(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DLT_INV):
+               {
+                       /* Branch if 64-bit floats are less than; invert nan test */
+                       if(!jit_float64_ge(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DLE_INV):
+               {
+                       /* Branch if 64-bit floats are less or equal; invert nan test */
+                       if(!jit_float64_gt(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DGT_INV):
+               {
+                       /* Branch if 64-bit floats are greater than; invert nan test */
+                       if(!jit_float64_le(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_DGE_INV):
+               {
+                       /* Branch if 64-bit floats are greater or equal; invert nan test */
+                       if(!jit_float64_lt(VM_STK_FLOAT641, VM_STK_FLOAT640))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFEQ):
+               {
+                       /* Branch if native floats are equal */
+                       if(jit_nfloat_eq(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFNE):
+               {
+                       /* Branch if native floats are not equal */
+                       if(jit_nfloat_ne(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFLT):
+               {
+                       /* Branch if native floats are less than */
+                       if(jit_nfloat_lt(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFLE):
+               {
+                       /* Branch if native floats are less than or equal */
+                       if(jit_nfloat_le(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFGT):
+               {
+                       /* Branch if native floats are greater than */
+                       if(jit_nfloat_gt(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFGE):
+               {
+                       /* Branch if native floats are greater than or equal */
+                       if(jit_nfloat_ge(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFEQ_INV):
+               {
+                       /* Branch if native floats are equal; invert nan test */
+                       if(!jit_nfloat_ne(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFNE_INV):
+               {
+                       /* Branch if native floats are not equal; invert nan test */
+                       if(!jit_nfloat_eq(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFLT_INV):
+               {
+                       /* Branch if native floats are less than; invert nan test */
+                       if(!jit_nfloat_ge(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFLE_INV):
+               {
+                       /* Branch if native floats are less or equal; invert nan test */
+                       if(!jit_nfloat_gt(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFGT_INV):
+               {
+                       /* Branch if native floats are greater than; invert nan test */
+                       if(!jit_nfloat_le(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_BR_NFGE_INV):
+               {
+                       /* Branch if native floats are greater or equal; invert nan test */
+                       if(!jit_nfloat_lt(VM_STK_NFLOAT1, VM_STK_NFLOAT0))
+                       {
+                               pc = VM_BR_TARGET;
+                               VM_MODIFY_STACK(2);
+                       }
+                       else
+                       {
+                               VM_MODIFY_PC_AND_STACK(2, 2);
+                       }
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Comparison opcodes.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_ICMP):
+               {
+                       /* Compare signed 32-bit integers */
+                       VM_STK_INT1 = jit_int_cmp(VM_STK_INT1, VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ICMP_UN):
+               {
+                       /* Compare unsigned 32-bit integers */
+                       VM_STK_UINT1 = jit_uint_cmp(VM_STK_UINT1, VM_STK_UINT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LCMP):
+               {
+                       /* Compare signed 64-bit integers */
+                       VM_STK_INT1 = jit_long_cmp(VM_STK_LONG1, VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LCMP_UN):
+               {
+                       /* Compare unsigned 64-bit integers */
+                       VM_STK_INT1 = jit_long_cmp(VM_STK_ULONG1, VM_STK_ULONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FCMPL):
+               {
+                       /* Compare 32-bit floats, with less nan */
+                       VM_STK_INT1 = jit_float32_cmpl(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FCMPG):
+               {
+                       /* Compare 32-bit floats, with greater nan */
+                       VM_STK_INT1 = jit_float32_cmpg(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DCMPL):
+               {
+                       /* Compare 64-bit floats, with less nan */
+                       VM_STK_INT1 = jit_float64_cmpl(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DCMPG):
+               {
+                       /* Compare 64-bit floats, with greater nan */
+                       VM_STK_INT1 = jit_float64_cmpg(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFCMPL):
+               {
+                       /* Compare native floats, with less nan */
+                       VM_STK_INT1 = jit_float64_cmpl(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFCMPG):
+               {
+                       /* Compare native floats, with greater nan */
+                       VM_STK_INT1 = jit_float64_cmpg(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IEQ):
+               {
+                       /* Compare signed 32-bit integers for equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_INT1 == VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_INE):
+               {
+                       /* Compare signed 32-bit integers for not equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_INT1 != VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ILT):
+               {
+                       /* Compare signed 32-bit integers for less than */
+                       VM_STK_INT1 = (jit_int)(VM_STK_INT1 < VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ILT_UN):
+               {
+                       /* Compare unsigned 32-bit integers for less than */
+                       VM_STK_INT1 = (jit_int)(VM_STK_UINT1 < VM_STK_UINT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ILE):
+               {
+                       /* Compare signed 32-bit integers for less than or equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_INT1 <= VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ILE_UN):
+               {
+                       /* Compare unsigned 32-bit integers for less than or equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_UINT1 <= VM_STK_UINT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IGT):
+               {
+                       /* Compare signed 32-bit integers for greater than */
+                       VM_STK_INT1 = (jit_int)(VM_STK_INT1 > VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IGT_UN):
+               {
+                       /* Compare unsigned 32-bit integers for greater than */
+                       VM_STK_INT1 = (jit_int)(VM_STK_UINT1 > VM_STK_UINT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IGE):
+               {
+                       /* Compare signed 32-bit integers for greater than or equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_INT1 >= VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IGE_UN):
+               {
+                       /* Compare unsigned 32-bit integers for greater than or equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_UINT1 >= VM_STK_UINT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LEQ):
+               {
+                       /* Compare signed 64-bit integers for equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_LONG1 == VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LNE):
+               {
+                       /* Compare signed 64-bit integers for not equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_LONG1 != VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LLT):
+               {
+                       /* Compare signed 64-bit integers for less than */
+                       VM_STK_INT1 = (jit_int)(VM_STK_LONG1 < VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LLT_UN):
+               {
+                       /* Compare unsigned 64-bit integers for less than */
+                       VM_STK_INT1 = (jit_int)(VM_STK_ULONG1 < VM_STK_ULONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LLE):
+               {
+                       /* Compare signed 64-bit integers for less than or equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_LONG1 <= VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LLE_UN):
+               {
+                       /* Compare unsigned 64-bit integers for less than or equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_ULONG1 <= VM_STK_ULONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LGT):
+               {
+                       /* Compare signed 64-bit integers for greater than */
+                       VM_STK_INT1 = (jit_int)(VM_STK_LONG1 > VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LGT_UN):
+               {
+                       /* Compare unsigned 64-bit integers for greater than */
+                       VM_STK_INT1 = (jit_int)(VM_STK_ULONG1 > VM_STK_ULONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LGE):
+               {
+                       /* Compare signed 64-bit integers for greater than or equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_LONG1 >= VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LGE_UN):
+               {
+                       /* Compare unsigned 64-bit integers for greater than or equal */
+                       VM_STK_INT1 = (jit_int)(VM_STK_ULONG1 >= VM_STK_ULONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FEQ):
+               {
+                       /* Compare 32-bit floats for equal */
+                       VM_STK_INT1 = jit_float32_eq(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FNE):
+               {
+                       /* Compare 32-bit floats for not equal */
+                       VM_STK_INT1 = jit_float32_ne(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FLT):
+               {
+                       /* Compare 32-bit floats for less than */
+                       VM_STK_INT1 = jit_float32_lt(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FLE):
+               {
+                       /* Compare 32-bit floats for less than or equal */
+                       VM_STK_INT1 = jit_float32_le(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FGT):
+               {
+                       /* Compare 32-bit floats for greater than */
+                       VM_STK_INT1 = jit_float32_gt(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FGE):
+               {
+                       /* Compare 32-bit floats for greater than or equal */
+                       VM_STK_INT1 = jit_float32_ge(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FEQ_INV):
+               {
+                       /* Compare 32-bit floats for equal; invert nan test */
+                       VM_STK_INT1 = !jit_float32_ne(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FNE_INV):
+               {
+                       /* Compare 32-bit floats for not equal; invert nan test */
+                       VM_STK_INT1 = !jit_float32_eq(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FLT_INV):
+               {
+                       /* Compare 32-bit floats for less than; invert nan test */
+                       VM_STK_INT1 = !jit_float32_ge(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FLE_INV):
+               {
+                       /* Compare 32-bit floats for less than or equal; invert nan test */
+                       VM_STK_INT1 = !jit_float32_gt(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FGT_INV):
+               {
+                       /* Compare 32-bit floats for greater than; invert nan test */
+                       VM_STK_INT1 = !jit_float32_le(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FGE_INV):
+               {
+                       /* Compare 32-bit floats for greater or equal; invert nan test */
+                       VM_STK_INT1 = !jit_float32_lt(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DEQ):
+               {
+                       /* Compare 64-bit floats for equal */
+                       VM_STK_INT1 = jit_float64_eq(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DNE):
+               {
+                       /* Compare 64-bit floats for not equal */
+                       VM_STK_INT1 = jit_float64_ne(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DLT):
+               {
+                       /* Compare 64-bit floats for less than */
+                       VM_STK_INT1 = jit_float64_lt(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DLE):
+               {
+                       /* Compare 64-bit floats for less than or equal */
+                       VM_STK_INT1 = jit_float64_le(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DGT):
+               {
+                       /* Compare 64-bit floats for greater than */
+                       VM_STK_INT1 = jit_float64_gt(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DGE):
+               {
+                       /* Compare 64-bit floats for greater than or equal */
+                       VM_STK_INT1 = jit_float64_ge(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DEQ_INV):
+               {
+                       /* Compare 64-bit floats for equal; invert nan test */
+                       VM_STK_INT1 = !jit_float64_ne(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DNE_INV):
+               {
+                       /* Compare 64-bit floats for equal; invert nan test */
+                       VM_STK_INT1 = !jit_float64_eq(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DLT_INV):
+               {
+                       /* Compare 64-bit floats for equal; invert nan test */
+                       VM_STK_INT1 = !jit_float64_ge(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DLE_INV):
+               {
+                       /* Compare 64-bit floats for equal; invert nan test */
+                       VM_STK_INT1 = !jit_float64_gt(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DGT_INV):
+               {
+                       /* Compare 64-bit floats for equal; invert nan test */
+                       VM_STK_INT1 = !jit_float64_le(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DGE_INV):
+               {
+                       /* Compare 64-bit floats for equal; invert nan test */
+                       VM_STK_INT1 = !jit_float64_lt(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFEQ):
+               {
+                       /* Compare native floats for equal */
+                       VM_STK_INT1 = jit_nfloat_eq(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFNE):
+               {
+                       /* Compare native floats for not equal */
+                       VM_STK_INT1 = jit_nfloat_ne(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLT):
+               {
+                       /* Compare native floats for less than */
+                       VM_STK_INT1 = jit_nfloat_lt(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLE):
+               {
+                       /* Compare native floats for less than or equal */
+                       VM_STK_INT1 = jit_nfloat_le(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFGT):
+               {
+                       /* Compare native floats for greater than */
+                       VM_STK_INT1 = jit_nfloat_gt(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFGE):
+               {
+                       /* Compare native floats for greater than or equal */
+                       VM_STK_INT1 = jit_nfloat_ge(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFEQ_INV):
+               {
+                       /* Compare native floats for equal; invert nan test */
+                       VM_STK_INT1 = !jit_nfloat_ne(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFNE_INV):
+               {
+                       /* Compare native floats for not equal; invert nan test */
+                       VM_STK_INT1 = !jit_nfloat_eq(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLT_INV):
+               {
+                       /* Compare native floats for less than; invert nan test */
+                       VM_STK_INT1 = !jit_nfloat_ge(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLE_INV):
+               {
+                       /* Compare native floats for less than or equal; invert nan test */
+                       VM_STK_INT1 = !jit_nfloat_gt(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFGT_INV):
+               {
+                       /* Compare native floats for greater than; invert nan test */
+                       VM_STK_INT1 = !jit_nfloat_le(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFGE_INV):
+               {
+                       /* Compare native floats for greater or equal; invert nan test */
+                       VM_STK_INT1 = !jit_nfloat_lt(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IS_FNAN):
+               {
+                       /* Check a 32-bit float for "not a number" */
+                       VM_STK_INT0 = jit_float32_is_nan(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IS_FINF):
+               {
+                       /* Check a 32-bit float for "infinity" */
+                       VM_STK_INT0 = jit_float32_is_inf(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IS_FFINITE):
+               {
+                       /* Check a 32-bit float for "finite" */
+                       VM_STK_INT0 = jit_float32_is_finite(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IS_DNAN):
+               {
+                       /* Check a 64-bit float for "not a number" */
+                       VM_STK_INT0 = jit_float64_is_nan(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IS_DINF):
+               {
+                       /* Check a 64-bit float for "infinity" */
+                       VM_STK_INT0 = jit_float64_is_inf(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IS_DFINITE):
+               {
+                       /* Check a 64-bit float for "finite" */
+                       VM_STK_INT0 = jit_float64_is_finite(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IS_NFNAN):
+               {
+                       /* Check a native float for "not a number" */
+                       VM_STK_INT0 = jit_nfloat_is_nan(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IS_NFINF):
+               {
+                       /* Check a native float for "infinity" */
+                       VM_STK_INT0 = jit_nfloat_is_inf(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IS_NFFINITE):
+               {
+                       /* Check a native float for "finite" */
+                       VM_STK_INT0 = jit_nfloat_is_finite(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Mathematical functions.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_FACOS):
+               {
+                       /* Compute 32-bit float "acos" */
+                       VM_STK_FLOAT320 = jit_float32_acos(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FASIN):
+               {
+                       /* Compute 32-bit float "asin" */
+                       VM_STK_FLOAT320 = jit_float32_asin(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FATAN):
+               {
+                       /* Compute 32-bit float "atan" */
+                       VM_STK_FLOAT320 = jit_float32_atan(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FATAN2):
+               {
+                       /* Compute 32-bit float "atan2" */
+                       VM_STK_FLOAT321 = jit_float32_atan2
+                               (VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FCEIL):
+               {
+                       /* Compute 32-bit float "ceil" */
+                       VM_STK_FLOAT320 = jit_float32_ceil(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FCOS):
+               {
+                       /* Compute 32-bit float "cos" */
+                       VM_STK_FLOAT320 = jit_float32_cos(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FCOSH):
+               {
+                       /* Compute 32-bit float "cosh" */
+                       VM_STK_FLOAT320 = jit_float32_cosh(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FEXP):
+               {
+                       /* Compute 32-bit float "exp" */
+                       VM_STK_FLOAT320 = jit_float32_exp(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FFLOOR):
+               {
+                       /* Compute 32-bit float "floor" */
+                       VM_STK_FLOAT320 = jit_float32_floor(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FLOG):
+               {
+                       /* Compute 32-bit float "log" */
+                       VM_STK_FLOAT320 = jit_float32_log(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FLOG10):
+               {
+                       /* Compute 32-bit float "log10" */
+                       VM_STK_FLOAT320 = jit_float32_log10(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FPOW):
+               {
+                       /* Compute 32-bit float "pow" */
+                       VM_STK_FLOAT321 = jit_float32_pow
+                               (VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FRINT):
+               {
+                       /* Compute 32-bit float "rint" */
+                       VM_STK_FLOAT320 = jit_float32_rint(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FROUND):
+               {
+                       /* Compute 32-bit float "round" */
+                       VM_STK_FLOAT320 = jit_float32_round(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FSIN):
+               {
+                       /* Compute 32-bit float "sin" */
+                       VM_STK_FLOAT320 = jit_float32_sin(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FSINH):
+               {
+                       /* Compute 32-bit float "sinh" */
+                       VM_STK_FLOAT320 = jit_float32_sinh(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FSQRT):
+               {
+                       /* Compute 32-bit float "sqrt" */
+                       VM_STK_FLOAT320 = jit_float32_sqrt(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FTAN):
+               {
+                       /* Compute 32-bit float "tan" */
+                       VM_STK_FLOAT320 = jit_float32_tan(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FTANH):
+               {
+                       /* Compute 32-bit float "tanh" */
+                       VM_STK_FLOAT320 = jit_float32_tanh(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DACOS):
+               {
+                       /* Compute 64-bit float "acos" */
+                       VM_STK_FLOAT640 = jit_float64_acos(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DASIN):
+               {
+                       /* Compute 64-bit float "asin" */
+                       VM_STK_FLOAT640 = jit_float64_asin(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DATAN):
+               {
+                       /* Compute 64-bit float "atan" */
+                       VM_STK_FLOAT640 = jit_float64_atan(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DATAN2):
+               {
+                       /* Compute 64-bit float "atan2" */
+                       VM_STK_FLOAT641 = jit_float64_atan2
+                               (VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DCEIL):
+               {
+                       /* Compute 64-bit float "ceil" */
+                       VM_STK_FLOAT640 = jit_float64_ceil(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DCOS):
+               {
+                       /* Compute 64-bit float "cos" */
+                       VM_STK_FLOAT640 = jit_float64_cos(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DCOSH):
+               {
+                       /* Compute 64-bit float "cosh" */
+                       VM_STK_FLOAT640 = jit_float64_cosh(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DEXP):
+               {
+                       /* Compute 64-bit float "exp" */
+                       VM_STK_FLOAT640 = jit_float64_exp(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DFLOOR):
+               {
+                       /* Compute 64-bit float "floor" */
+                       VM_STK_FLOAT640 = jit_float64_floor(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DLOG):
+               {
+                       /* Compute 64-bit float "log" */
+                       VM_STK_FLOAT640 = jit_float64_log(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DLOG10):
+               {
+                       /* Compute 64-bit float "log10" */
+                       VM_STK_FLOAT640 = jit_float64_log10(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DPOW):
+               {
+                       /* Compute 64-bit float "pow" */
+                       VM_STK_FLOAT641 = jit_float64_pow
+                               (VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DRINT):
+               {
+                       /* Compute 64-bit float "rint" */
+                       VM_STK_FLOAT640 = jit_float64_rint(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DROUND):
+               {
+                       /* Compute 64-bit float "round" */
+                       VM_STK_FLOAT640 = jit_float64_round(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DSIN):
+               {
+                       /* Compute 64-bit float "sin" */
+                       VM_STK_FLOAT640 = jit_float64_sin(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DSINH):
+               {
+                       /* Compute 64-bit float "sinh" */
+                       VM_STK_FLOAT640 = jit_float64_sinh(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DSQRT):
+               {
+                       /* Compute 64-bit float "sqrt" */
+                       VM_STK_FLOAT640 = jit_float64_sqrt(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DTAN):
+               {
+                       /* Compute 64-bit float "tan" */
+                       VM_STK_FLOAT640 = jit_float64_tan(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DTANH):
+               {
+                       /* Compute 64-bit float "tanh" */
+                       VM_STK_FLOAT640 = jit_float64_tanh(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFACOS):
+               {
+                       /* Compute native float "acos" */
+                       VM_STK_NFLOAT0 = jit_nfloat_acos(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFASIN):
+               {
+                       /* Compute native float "asin" */
+                       VM_STK_NFLOAT0 = jit_nfloat_asin(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFATAN):
+               {
+                       /* Compute native float "atan" */
+                       VM_STK_NFLOAT0 = jit_nfloat_atan(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFATAN2):
+               {
+                       /* Compute native float "atan2" */
+                       VM_STK_NFLOAT1 = jit_nfloat_atan2
+                               (VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFCEIL):
+               {
+                       /* Compute native float "ceil" */
+                       VM_STK_NFLOAT0 = jit_nfloat_ceil(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFCOS):
+               {
+                       /* Compute native float "cos" */
+                       VM_STK_NFLOAT0 = jit_nfloat_cos(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFCOSH):
+               {
+                       /* Compute native float "cosh" */
+                       VM_STK_NFLOAT0 = jit_nfloat_cosh(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFEXP):
+               {
+                       /* Compute native float "exp" */
+                       VM_STK_NFLOAT0 = jit_nfloat_exp(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFFLOOR):
+               {
+                       /* Compute native float "floor" */
+                       VM_STK_NFLOAT0 = jit_nfloat_floor(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLOG):
+               {
+                       /* Compute native float "log" */
+                       VM_STK_NFLOAT0 = jit_nfloat_log(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFLOG10):
+               {
+                       /* Compute native float "log10" */
+                       VM_STK_NFLOAT0 = jit_nfloat_log10(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFPOW):
+               {
+                       /* Compute native float "pow" */
+                       VM_STK_NFLOAT1 = jit_nfloat_pow
+                               (VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFRINT):
+               {
+                       /* Compute native float "rint" */
+                       VM_STK_NFLOAT0 = jit_nfloat_rint(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFROUND):
+               {
+                       /* Compute native float "round" */
+                       VM_STK_NFLOAT0 = jit_nfloat_round(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFSIN):
+               {
+                       /* Compute native float "sin" */
+                       VM_STK_NFLOAT0 = jit_nfloat_sin(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFSINH):
+               {
+                       /* Compute native float "sinh" */
+                       VM_STK_NFLOAT0 = jit_nfloat_sinh(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFSQRT):
+               {
+                       /* Compute native float "sqrt" */
+                       VM_STK_NFLOAT0 = jit_nfloat_sqrt(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFTAN):
+               {
+                       /* Compute native float "tan" */
+                       VM_STK_NFLOAT0 = jit_nfloat_tan(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFTANH):
+               {
+                       /* Compute native float "tanh" */
+                       VM_STK_NFLOAT0 = jit_nfloat_tanh(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Absolute, minimum, maximum, and sign.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_IABS):
+               {
+                       /* Compute the absolute value of a signed 32-bit integer value */
+                       VM_STK_INT0 = jit_int_abs(VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LABS):
+               {
+                       /* Compute the absolute value of a signed 64-bit integer value */
+                       VM_STK_LONG0 = jit_long_abs(VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FABS):
+               {
+                       /* Compute the absolute value of a 32-bit float value */
+                       VM_STK_FLOAT320 = jit_float32_abs(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DABS):
+               {
+                       /* Compute the absolute value of a 64-bit float value */
+                       VM_STK_FLOAT640 = jit_float64_abs(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFABS):
+               {
+                       /* Compute the absolute value of a native float value */
+                       VM_STK_NFLOAT0 = jit_nfloat_abs(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IMIN):
+               {
+                       /* Compute the minimum of two signed 32-bit integer values */
+                       VM_STK_INT1 = jit_int_min(VM_STK_INT1, VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IMIN_UN):
+               {
+                       /* Compute the minimum of two unsigned 32-bit integer values */
+                       VM_STK_UINT1 = jit_uint_min(VM_STK_UINT1, VM_STK_UINT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LMIN):
+               {
+                       /* Compute the minimum of two signed 64-bit integer values */
+                       VM_STK_LONG1 = jit_long_min(VM_STK_LONG1, VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LMIN_UN):
+               {
+                       /* Compute the minimum of two unsigned 64-bit integer values */
+                       VM_STK_ULONG1 = jit_ulong_min(VM_STK_ULONG1, VM_STK_ULONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FMIN):
+               {
+                       /* Compute the minimum of two 32-bit float values */
+                       VM_STK_FLOAT321 = jit_float32_min(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DMIN):
+               {
+                       /* Compute the minimum of two 64-bit float values */
+                       VM_STK_FLOAT641 = jit_float64_min(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFMIN):
+               {
+                       /* Compute the minimum of two native float values */
+                       VM_STK_NFLOAT1 = jit_nfloat_min(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IMAX):
+               {
+                       /* Compute the maximum of two signed 32-bit integer values */
+                       VM_STK_INT1 = jit_int_max(VM_STK_INT1, VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_IMAX_UN):
+               {
+                       /* Compute the maximum of two unsigned 32-bit integer values */
+                       VM_STK_UINT1 = jit_uint_max(VM_STK_UINT1, VM_STK_UINT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LMAX):
+               {
+                       /* Compute the maximum of two signed 64-bit integer values */
+                       VM_STK_LONG1 = jit_long_max(VM_STK_LONG1, VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LMAX_UN):
+               {
+                       /* Compute the maximum of two unsigned 64-bit integer values */
+                       VM_STK_ULONG1 = jit_ulong_max(VM_STK_ULONG1, VM_STK_ULONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FMAX):
+               {
+                       /* Compute the maximum of two 32-bit float values */
+                       VM_STK_FLOAT321 = jit_float32_max(VM_STK_FLOAT321, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DMAX):
+               {
+                       /* Compute the maximum of two 64-bit float values */
+                       VM_STK_FLOAT641 = jit_float64_max(VM_STK_FLOAT641, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFMAX):
+               {
+                       /* Compute the maximum of two native float values */
+                       VM_STK_NFLOAT1 = jit_nfloat_max(VM_STK_NFLOAT1, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ISIGN):
+               {
+                       /* Compute the sign of a signed 32-bit integer value */
+                       VM_STK_INT0 = jit_int_sign(VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LSIGN):
+               {
+                       /* Compute the sign of a signed 64-bit integer value */
+                       VM_STK_INT0 = jit_long_sign(VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_FSIGN):
+               {
+                       /* Compute the sign of a 32-bit float value */
+                       VM_STK_INT0 = jit_float32_sign(VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_DSIGN):
+               {
+                       /* Compute the sign of a 64-bit float value */
+                       VM_STK_INT0 = jit_float64_sign(VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_NFSIGN):
+               {
+                       /* Compute the sign of a native float value */
+                       VM_STK_INT0 = jit_nfloat_sign(VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Pointer check opcodes.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_CHECK_NULL):
+               {
+                       /* Check the top of stack to see if it is null */
+                       if(!VM_STK_PTR0)
+                       {
+                               VM_BUILTIN(JIT_RESULT_NULL_REFERENCE);
+                       }
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CHECK_NULL_N):
+               {
+                       /* Check a pointer for null "n" items down the stack.
+                          This opcode is specific to the interpreter */
+                       if(!(stacktop[VM_NINT_ARG].ptr_value))
+                       {
+                               VM_BUILTIN(JIT_RESULT_NULL_REFERENCE);
+                       }
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Function calls.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_CALL):
+               {
+                       /* Call a function that is under the control of the JIT */
+                       call_func = (jit_function_t)VM_NINT_ARG;
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+                       entry = call_func->entry_point;
+                       _jit_backtrace_push(&call_trace, pc, 0, 0);
+                       try
+                       {
+                               if(!entry)
+                               {
+                                       entry = _jit_function_compile_on_demand(call_func);
+                               }
+                               _jit_run_function((jit_function_interp_t)entry, stacktop,
+                                                                 return_area);
+                               _jit_backtrace_pop();
+                       }
+                       catch(jit_exception *e)
+                       {
+                               _jit_backtrace_set(call_trace.parent);
+                               exception_object = e->object;
+                               delete e;
+                               goto handle_exception;
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CALL_INDIRECT):
+               {
+                       /* Call a native function via an indirect pointer */
+                       tempptr = (void *)VM_NINT_ARG;
+                       temparg = VM_NINT_ARG2;
+                       VM_MODIFY_PC_AND_STACK(3, 2);
+                       _jit_backtrace_push(&call_trace, pc, 0, 0);
+                       try
+                       {
+                               apply_from_interpreter((jit_type_t)tempptr,
+                                                                          (void *)VM_STK_PTRP2,
+                                                                          stacktop,
+                                                                          (unsigned int)temparg,
+                                                                          VM_STK_PTRP);
+                               _jit_backtrace_pop();
+                       }
+                       catch(jit_exception *e)
+                       {
+                               _jit_backtrace_set(call_trace.parent);
+                               exception_object = e->object;
+                               delete e;
+                               goto handle_exception;
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CALL_VTABLE_PTR):
+               {
+                       /* Call a JIT-managed function via an indirect vtable pointer */
+                       call_func = (jit_function_t)(VM_STK_PTR0);
+                       if(!call_func)
+                       {
+                               VM_BUILTIN(JIT_RESULT_NULL_FUNCTION);
+                       }
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+                       entry = call_func->entry_point;
+                       _jit_backtrace_push(&call_trace, pc, 0, 0);
+                       try
+                       {
+                               if(!entry)
+                               {
+                                       entry = _jit_function_compile_on_demand(call_func);
+                               }
+                               _jit_run_function((jit_function_interp_t)entry, stacktop,
+                                                                 return_area);
+                               _jit_backtrace_pop();
+                       }
+                       catch(jit_exception *e)
+                       {
+                               _jit_backtrace_set(call_trace.parent);
+                               exception_object = e->object;
+                               delete e;
+                               goto handle_exception;
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CALL_EXTERNAL):
+               {
+                       /* Call an external native function */
+                       tempptr = (void *)VM_NINT_ARG;
+                       tempptr2 = (void *)VM_NINT_ARG2;
+                       temparg = VM_NINT_ARG3;
+                       VM_MODIFY_PC_AND_STACK(4, 1);
+                       _jit_backtrace_push(&call_trace, pc, 0, 0);
+                       try
+                       {
+                               apply_from_interpreter((jit_type_t)tempptr,
+                                                                          (void *)tempptr2,
+                                                                          stacktop,
+                                                                          (unsigned int)temparg,
+                                                                          VM_STK_PTRP);
+                               _jit_backtrace_pop();
+                       }
+                       catch(jit_exception *e)
+                       {
+                               _jit_backtrace_set(call_trace.parent);
+                               exception_object = e->object;
+                               delete e;
+                               goto handle_exception;
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_RETURN):
+               {
+                       /* Return from the current function, with no result */
+                       return;
+               }
+               /* Not reached */
+
+               VMCASE(JIT_OP_RETURN_INT):
+               {
+                       /* Return from the current function, with an integer result */
+                       return_area->int_value = VM_STK_INT0;
+                       return;
+               }
+               /* Not reached */
+
+               VMCASE(JIT_OP_RETURN_LONG):
+               {
+                       /* Return from the current function, with a long result */
+                       return_area->long_value = VM_STK_LONG0;
+                       return;
+               }
+               /* Not reached */
+
+               VMCASE(JIT_OP_RETURN_FLOAT32):
+               {
+                       /* Return from the current function, with a 32-bit float result */
+                       return_area->float32_value = VM_STK_FLOAT320;
+                       return;
+               }
+               /* Not reached */
+
+               VMCASE(JIT_OP_RETURN_FLOAT64):
+               {
+                       /* Return from the current function, with a 64-bit float result */
+                       return_area->float64_value = VM_STK_FLOAT640;
+                       return;
+               }
+               /* Not reached */
+
+               VMCASE(JIT_OP_RETURN_NFLOAT):
+               {
+                       /* Return from the current function, with a native float result */
+                       return_area->nfloat_value = VM_STK_NFLOAT0;
+                       return;
+               }
+               /* Not reached */
+
+               VMCASE(JIT_OP_RETURN_SMALL_STRUCT):
+               {
+                       /* Return from the current function, with a small structure */
+               #if JIT_APPLY_MAX_STRUCT_IN_REG != 0
+                       jit_memcpy(return_area->struct_value, stacktop,
+                                          (unsigned int)VM_NINT_ARG);
+               #endif
+                       return;
+               }
+               /* Not reached */
+
+               VMCASE(JIT_OP_SETUP_FOR_NESTED):
+               {
+                       /* Set up to call a nested function who is our child */
+                       stacktop[-1].ptr_value = args;
+                       stacktop[-2].ptr_value = frame;
+                       VM_MODIFY_PC_AND_STACK(1, -2);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_SETUP_FOR_SIBLING):
+               {
+                       /* Set up to call a nested function who is our sibling, a sibling
+                          of one of our ancestors, or one of our ancestors directly */
+                       temparg = VM_NINT_ARG;
+                       tempptr = &(args[0]);
+                       while(temparg > 0)
+                       {
+                               tempptr = (((jit_item *)tempptr)[1]).ptr_value;
+                               --temparg;
+                       }
+                       stacktop[-1].ptr_value = (((jit_item *)tempptr)[1]).ptr_value;
+                       stacktop[-2].ptr_value = (((jit_item *)tempptr)[0]).ptr_value;
+                       VM_MODIFY_PC_AND_STACK(1, -2);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_PARENT_LOCALS):
+               {
+                       /* Push the pointer to the parent's local variables */
+                       VM_STK_PTRP = args[0].ptr_value;
+                       VM_MODIFY_PC_AND_STACK(1, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_PARENT_ARGS):
+               {
+                       /* Push the pointer to the parent's argument variables */
+                       VM_STK_PTRP = args[1].ptr_value;
+                       VM_MODIFY_PC_AND_STACK(1, -1);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Exception handling.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_THROW):
+               {
+                       /* Throw an exception, which may be handled in this function */
+                       exception_object = VM_STK_PTR0;
+               handle_exception:
+                       if(jit_function_from_pc(func->func->context, pc, &handler)
+                                       == func->func && handler != 0)
+                       {
+                               /* We have an appropriate "catch" handler in this function */
+                               pc = (void **)handler;
+                               stacktop = frame - 1;
+                               stacktop->ptr_value = exception_object;
+                       }
+                       else
+                       {
+                               /* Throw the exception up to the next level */
+                               throw new jit_exception(exception_object);
+                       }
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_PC):
+               {
+                       /* Load the current program counter onto the stack */
+                       VM_STK_PTRP = (void *)pc;
+                       VM_MODIFY_PC_AND_STACK(1, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LEAVE_FINALLY):
+               {
+                       /* Return from a "finally" handler */
+                       pc = (void **)VM_STK_PTR0;
+                       VM_MODIFY_STACK(1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LEAVE_FILTER):
+               {
+                       /* Return from a "filter" handler: pc and value on stack */
+                       pc = (void **)(stacktop[1].ptr_value);
+                       stacktop[1] = stacktop[0];
+                       VM_MODIFY_STACK(1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CALL_FILTER):
+               {
+                       /* Call a "filter" handler with pc and value on stack */
+                       stacktop[-1] = stacktop[0];
+                       stacktop[0].ptr_value = (void *)(pc + 2);
+                       VM_MODIFY_STACK(-1);
+                       pc = VM_BR_TARGET;
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_CALL_FINALLY):
+               {
+                       /* Call a "finally" handler */
+                       VM_STK_PTRP = (void *)(pc + 2);
+                       VM_MODIFY_STACK(-1);
+                       pc = VM_BR_TARGET;
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Pointer-relative loads and stores.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_LOAD_RELATIVE_SBYTE):
+               {
+                       /* Load a signed 8-bit integer from a relative pointer */
+                       VM_STK_INT0 = *VM_REL(jit_sbyte, VM_STK_PTR0);
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_RELATIVE_UBYTE):
+               {
+                       /* Load an unsigned 8-bit integer from a relative pointer */
+                       VM_STK_INT0 = *VM_REL(jit_ubyte, VM_STK_PTR0);
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_RELATIVE_SHORT):
+               {
+                       /* Load a signed 16-bit integer from a relative pointer */
+                       VM_STK_INT0 = *VM_REL(jit_short, VM_STK_PTR0);
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_RELATIVE_USHORT):
+               {
+                       /* Load an unsigned 16-bit integer from a relative pointer */
+                       VM_STK_INT0 = *VM_REL(jit_ushort, VM_STK_PTR0);
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_RELATIVE_INT):
+               {
+                       /* Load a 32-bit integer from a relative pointer */
+                       VM_STK_INT0 = *VM_REL(jit_int, VM_STK_PTR0);
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_RELATIVE_LONG):
+               {
+                       /* Load a 64-bit integer from a relative pointer */
+                       VM_STK_LONG0 = *VM_REL(jit_long, VM_STK_PTR0);
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_RELATIVE_FLOAT32):
+               {
+                       /* Load a 32-bit float from a relative pointer */
+                       VM_STK_FLOAT320 = *VM_REL(jit_float32, VM_STK_PTR0);
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_RELATIVE_FLOAT64):
+               {
+                       /* Load a 64-bit float from a relative pointer */
+                       VM_STK_FLOAT640 = *VM_REL(jit_float64, VM_STK_PTR0);
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_RELATIVE_NFLOAT):
+               {
+                       /* Load a native float from a relative pointer */
+                       VM_STK_NFLOAT0 = *VM_REL(jit_nfloat, VM_STK_PTR0);
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_RELATIVE_STRUCT):
+               {
+                       /* Load a structure from a relative pointer */
+                       tempptr = VM_REL(void, VM_STK_PTR0);
+                       temparg = VM_NINT_ARG2;
+                       stacktop -= (JIT_NUM_ITEMS_IN_STRUCT(temparg) - 1);
+                       jit_memcpy(stacktop, tempptr, temparg);
+                       VM_MODIFY_PC_AND_STACK(3, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_RELATIVE_BYTE):
+               {
+                       /* Store an 8-bit integer value to a relative pointer */
+                       *VM_REL(jit_sbyte, VM_STK_PTR1) = (jit_sbyte)VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(2, 2);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_RELATIVE_SHORT):
+               {
+                       /* Store a 16-bit integer value to a relative pointer */
+                       *VM_REL(jit_short, VM_STK_PTR1) = (jit_short)VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(2, 2);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_RELATIVE_INT):
+               {
+                       /* Store a 32-bit integer value to a relative pointer */
+                       *VM_REL(jit_int, VM_STK_PTR1) = VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(2, 2);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_RELATIVE_LONG):
+               {
+                       /* Store a 64-bit integer value to a relative pointer */
+                       *VM_REL(jit_long, VM_STK_PTR1) = VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(2, 2);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_RELATIVE_FLOAT32):
+               {
+                       /* Store a 32-bit float value to a relative pointer */
+                       *VM_REL(jit_float32, VM_STK_PTR1) = VM_STK_FLOAT320;
+                       VM_MODIFY_PC_AND_STACK(2, 2);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_RELATIVE_FLOAT64):
+               {
+                       /* Store a 64-bit float value to a relative pointer */
+                       *VM_REL(jit_float64, VM_STK_PTR1) = VM_STK_FLOAT640;
+                       VM_MODIFY_PC_AND_STACK(2, 2);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_RELATIVE_NFLOAT):
+               {
+                       /* Store a native float value to a relative pointer */
+                       *VM_REL(jit_nfloat, VM_STK_PTR1) = VM_STK_NFLOAT0;
+                       VM_MODIFY_PC_AND_STACK(2, 2);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_RELATIVE_STRUCT):
+               {
+                       /* Store a structure value to a relative pointer */
+                       temparg = VM_NINT_ARG2;
+                       tempptr = stacktop;
+                       stacktop += JIT_NUM_ITEMS_IN_STRUCT(temparg);
+                       jit_memcpy(VM_REL(void, VM_STK_PTR0), tempptr, temparg);
+                       VM_MODIFY_PC_AND_STACK(3, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_ADD_RELATIVE):
+               {
+                       /* Add a relative offset to a pointer */
+                       VM_STK_PTR0 = VM_REL(void, VM_STK_PTR0);
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Argument variable access opcodes.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_LDARG_SBYTE):
+               {
+                       /* Load a signed 8-bit integer argument onto the stack */
+                       VM_STK_INTP = *VM_ARG(jit_sbyte);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDARG_UBYTE):
+               {
+                       /* Load an unsigned 8-bit integer argument onto the stack */
+                       VM_STK_INTP = *VM_ARG(jit_ubyte);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDARG_SHORT):
+               {
+                       /* Load a signed 16-bit integer argument onto the stack */
+                       VM_STK_INTP = *VM_ARG(jit_short);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDARG_USHORT):
+               {
+                       /* Load an unsigned 16-bit integer argument onto the stack */
+                       VM_STK_INTP = *VM_ARG(jit_ushort);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDARG_INT):
+               {
+                       /* Load a 32-bit integer argument onto the stack */
+                       VM_STK_INTP = *VM_ARG(jit_int);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDARG_LONG):
+               {
+                       /* Load a 64-bit integer argument onto the stack */
+                       VM_STK_LONGP = *VM_ARG(jit_long);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDARG_FLOAT32):
+               {
+                       /* Load a 32-bit float argument onto the stack */
+                       VM_STK_FLOAT32P = *VM_ARG(jit_float32);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDARG_FLOAT64):
+               {
+                       /* Load a 64-bit float argument onto the stack */
+                       VM_STK_FLOAT64P = *VM_ARG(jit_float64);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDARG_NFLOAT):
+               {
+                       /* Load a native float argument onto the stack */
+                       VM_STK_NFLOATP = *VM_ARG(jit_float64);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDARG_STRUCT):
+               {
+                       /* Load a structure argument onto the stack */
+                       temparg = VM_NINT_ARG2;
+                       stacktop -= JIT_NUM_ITEMS_IN_STRUCT(temparg);
+                       jit_memcpy(stacktop, VM_ARG(void), temparg);
+                       VM_MODIFY_PC_AND_STACK(3, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDARGA):
+               {
+                       /* Load the address of an argument onto the stack */
+                       VM_STK_PTRP = VM_ARG(void);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STARG_BYTE):
+               {
+                       /* Store an 8-bit integer into a stack argument */
+                       *VM_ARG(jit_sbyte) = (jit_sbyte)VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STARG_SHORT):
+               {
+                       /* Store a 16-bit integer into a stack argument */
+                       *VM_ARG(jit_short) = (jit_short)VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STARG_INT):
+               {
+                       /* Store a 32-bit integer into a stack argument */
+                       *VM_ARG(jit_int) = VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STARG_LONG):
+               {
+                       /* Store a 64-bit integer into a stack argument */
+                       *VM_ARG(jit_long) = VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STARG_FLOAT32):
+               {
+                       /* Store a 32-bit float into a stack argument */
+                       *VM_ARG(jit_float32) = VM_STK_FLOAT320;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STARG_FLOAT64):
+               {
+                       /* Store a 64-bit float into a stack argument */
+                       *VM_ARG(jit_float64) = VM_STK_FLOAT640;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STARG_NFLOAT):
+               {
+                       /* Store a native float into a stack argument */
+                       *VM_ARG(jit_nfloat) = VM_STK_NFLOAT0;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STARG_STRUCT):
+               {
+                       /* Store a structure value into a stack argument */
+                       temparg = VM_NINT_ARG2;
+                       jit_memcpy(VM_ARG(void), stacktop, temparg);
+                       stacktop += JIT_NUM_ITEMS_IN_STRUCT(temparg);
+                       VM_MODIFY_PC_AND_STACK(3, 0);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Local variable frame access opcodes.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_LDLOC_SBYTE):
+               {
+                       /* Load a signed 8-bit integer local onto the stack */
+                       VM_STK_INTP = *VM_LOC(jit_sbyte);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDLOC_UBYTE):
+               {
+                       /* Load an unsigned 8-bit integer local onto the stack */
+                       VM_STK_INTP = *VM_LOC(jit_ubyte);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDLOC_SHORT):
+               {
+                       /* Load a signed 16-bit integer local onto the stack */
+                       VM_STK_INTP = *VM_LOC(jit_short);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDLOC_USHORT):
+               {
+                       /* Load an unsigned 16-bit integer local onto the stack */
+                       VM_STK_INTP = *VM_LOC(jit_ushort);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDLOC_INT):
+               {
+                       /* Load a 32-bit integer local onto the stack */
+                       VM_STK_INTP = *VM_LOC(jit_int);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDLOC_LONG):
+               {
+                       /* Load a 64-bit integer local onto the stack */
+                       VM_STK_LONGP = *VM_LOC(jit_long);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDLOC_FLOAT32):
+               {
+                       /* Load a 32-bit float local onto the stack */
+                       VM_STK_FLOAT32P = *VM_LOC(jit_float32);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDLOC_FLOAT64):
+               {
+                       /* Load a 64-bit float local onto the stack */
+                       VM_STK_FLOAT64P = *VM_LOC(jit_float64);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDLOC_NFLOAT):
+               {
+                       /* Load a native float local onto the stack */
+                       VM_STK_NFLOATP = *VM_LOC(jit_float64);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDLOC_STRUCT):
+               {
+                       /* Load a structure local onto the stack */
+                       temparg = VM_NINT_ARG2;
+                       stacktop -= JIT_NUM_ITEMS_IN_STRUCT(temparg);
+                       jit_memcpy(stacktop, VM_LOC(void), temparg);
+                       VM_MODIFY_PC_AND_STACK(3, 0);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LDLOCA):
+               {
+                       /* Load the address of an local onto the stack */
+                       VM_STK_PTRP = VM_LOC(void);
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STLOC_BYTE):
+               {
+                       /* Store an 8-bit integer into a stack local */
+                       *VM_LOC(jit_sbyte) = (jit_sbyte)VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STLOC_SHORT):
+               {
+                       /* Store a 16-bit integer into a stack local */
+                       *VM_LOC(jit_short) = (jit_short)VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STLOC_INT):
+               {
+                       /* Store a 32-bit integer into a stack local */
+                       *VM_LOC(jit_int) = VM_STK_INT0;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STLOC_LONG):
+               {
+                       /* Store a 64-bit integer into a stack local */
+                       *VM_LOC(jit_long) = VM_STK_LONG0;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STLOC_FLOAT32):
+               {
+                       /* Store a 32-bit float into a stack local */
+                       *VM_LOC(jit_float32) = VM_STK_FLOAT320;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STLOC_FLOAT64):
+               {
+                       /* Store a 64-bit float into a stack local */
+                       *VM_LOC(jit_float64) = VM_STK_FLOAT640;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STLOC_NFLOAT):
+               {
+                       /* Store a native float into a stack local */
+                       *VM_LOC(jit_nfloat) = VM_STK_NFLOAT0;
+                       VM_MODIFY_PC_AND_STACK(2, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STLOC_STRUCT):
+               {
+                       /* Store a structure value into a stack local */
+                       temparg = VM_NINT_ARG2;
+                       jit_memcpy(VM_LOC(void), stacktop, temparg);
+                       stacktop += JIT_NUM_ITEMS_IN_STRUCT(temparg);
+                       VM_MODIFY_PC_AND_STACK(3, 0);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Stack management
+                ******************************************************************/
+
+               VMCASE(JIT_OP_POP_STACK):
+               {
+                       /* Pop a specific number of items from the stack */
+                       temparg = VM_NINT_ARG;
+                       VM_MODIFY_PC_AND_STACK(2, temparg);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_POP):
+               {
+                       /* Pop a single item from the stack */
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_POP_2):
+               {
+                       /* Pop two items from the stack */
+                       VM_MODIFY_PC_AND_STACK(1, 2);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_POP_3):
+               {
+                       /* Pop three items from the stack */
+                       VM_MODIFY_PC_AND_STACK(1, 3);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_RETURN_INT):
+               {
+                       /* Push an integer return value back onto the stack */
+                       VM_STK_INTP = return_area->int_value;
+                       VM_MODIFY_PC_AND_STACK(1, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_RETURN_LONG):
+               {
+                       /* Push a long integer return value back onto the stack */
+                       VM_STK_LONGP = return_area->long_value;
+                       VM_MODIFY_PC_AND_STACK(1, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_RETURN_FLOAT32):
+               {
+                       /* Push a 32-bit float return value back onto the stack */
+                       VM_STK_FLOAT32P = return_area->float32_value;
+                       VM_MODIFY_PC_AND_STACK(1, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_RETURN_FLOAT64):
+               {
+                       /* Push a 64-bit float return value back onto the stack */
+                       VM_STK_FLOAT64P = return_area->float64_value;
+                       VM_MODIFY_PC_AND_STACK(1, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_RETURN_NFLOAT):
+               {
+                       /* Push a native float return value back onto the stack */
+                       VM_STK_NFLOATP = return_area->nfloat_value;
+                       VM_MODIFY_PC_AND_STACK(1, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_RETURN_SMALL_STRUCT):
+               {
+                       /* Push a small structure return value back onto the stack */
+                       temparg = VM_NINT_ARG;
+                       stacktop -= JIT_NUM_ITEMS_IN_STRUCT(temparg);
+               #if JIT_APPLY_MAX_STRUCT_IN_REG != 0
+                       jit_memcpy(stacktop, return_area->struct_value, temparg);
+               #endif
+                       VM_MODIFY_PC_AND_STACK(2, 0);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Stack management
+                ******************************************************************/
+
+               VMCASE(JIT_OP_PUSH_CONST_INT):
+               {
+                       /* Push an integer constant onto the stack */
+                       VM_STK_INTP = (jit_int)VM_NINT_ARG;
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_CONST_LONG):
+               {
+                       /* Push a long constant onto the stack */
+               #ifdef JIT_NATIVE_INT64
+                       VM_STK_LONGP = (jit_long)VM_NINT_ARG;
+                       VM_MODIFY_PC_AND_STACK(2, -1);
+               #else
+                       jit_memcpy(stacktop - 1, pc + 1, sizeof(jit_long));
+                       VM_MODIFY_PC_AND_STACK
+                               (1 + (sizeof(jit_long) / sizeof(void *)), -1);
+               #endif
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_CONST_FLOAT32):
+               {
+                       /* Push a 32-bit float constant onto the stack */
+                       jit_memcpy(stacktop - 1, pc + 1, sizeof(jit_float32));
+                       VM_MODIFY_PC_AND_STACK
+                               (1 + (sizeof(jit_float32) / sizeof(void *)), -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_CONST_FLOAT64):
+               {
+                       /* Push a 64-bit float constant onto the stack */
+                       jit_memcpy(stacktop - 1, pc + 1, sizeof(jit_float64));
+                       VM_MODIFY_PC_AND_STACK
+                               (1 + (sizeof(jit_float64) / sizeof(void *)), -1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_PUSH_CONST_NFLOAT):
+               {
+                       /* Push a native float constant onto the stack */
+                       jit_memcpy(stacktop - 1, pc + 1, sizeof(jit_nfloat));
+                       VM_MODIFY_PC_AND_STACK
+                               (1 + (sizeof(jit_nfloat) / sizeof(void *)), -1);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Opcodes that aren't used by the interpreter.  These are replaced
+                * by more specific instructions during function compilation.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_IMPORT):
+               VMCASE(JIT_OP_COPY_LOAD_SBYTE):
+               VMCASE(JIT_OP_COPY_LOAD_UBYTE):
+               VMCASE(JIT_OP_COPY_LOAD_SHORT):
+               VMCASE(JIT_OP_COPY_LOAD_USHORT):
+               VMCASE(JIT_OP_COPY_INT):
+               VMCASE(JIT_OP_COPY_LONG):
+               VMCASE(JIT_OP_COPY_FLOAT32):
+               VMCASE(JIT_OP_COPY_FLOAT64):
+               VMCASE(JIT_OP_COPY_NFLOAT):
+               VMCASE(JIT_OP_COPY_STRUCT):
+               VMCASE(JIT_OP_COPY_STORE_BYTE):
+               VMCASE(JIT_OP_COPY_STORE_SHORT):
+               VMCASE(JIT_OP_ADDRESS_OF):
+               VMCASE(JIT_OP_INCOMING_REG):
+               VMCASE(JIT_OP_INCOMING_FRAME_POSN):
+               VMCASE(JIT_OP_OUTGOING_REG):
+               VMCASE(JIT_OP_RETURN_REG):
+               VMCASE(JIT_OP_PUSH_INT):
+               VMCASE(JIT_OP_PUSH_LONG):
+               VMCASE(JIT_OP_PUSH_FLOAT32):
+               VMCASE(JIT_OP_PUSH_FLOAT64):
+               VMCASE(JIT_OP_PUSH_NFLOAT):
+               VMCASE(JIT_OP_PUSH_STRUCT):
+               VMCASE(JIT_OP_FLUSH_SMALL_STRUCT):
+               VMCASE(JIT_OP_END_MARKER):
+               VMCASE(JIT_OP_ENTER_CATCH):
+               VMCASE(JIT_OP_ENTER_FINALLY):
+               VMCASE(JIT_OP_ENTER_FILTER):
+               VMCASE(JIT_OP_CALL_FILTER_RETURN):
+               VMCASE(JIT_OP_PREPARE_FOR_LEAVE):
+               VMCASE(JIT_OP_PREPARE_FOR_RETURN):
+               {
+                       /* Shouldn't happen, but skip the instruction anyway */
+                       VM_MODIFY_PC_AND_STACK(1, 0);
+               }
+               VMBREAK;
+
+       }
+       VMSWITCHEND
+
+handle_builtin: ;
+       /* TODO */
+}
+
+/*
+ * Class that helps restore the backtrace when C++ exceptions
+ * travel up the stack.  Acts sort of like a "finally" clause.
+ */
+class jit_trace_restorer
+{
+public:
+       jit_backtrace_t previous;
+       jit_trace_restorer(jit_backtrace_t previous)
+               { this->previous = previous; }
+       ~jit_trace_restorer()
+               { _jit_backtrace_set(previous); }
+};
+
+extern "C" int jit_function_apply
+       (jit_function_t func, void **args, void *return_area)
+{
+       if(func)
+       {
+               return jit_function_apply_vararg
+                       (func, func->signature, args, return_area);
+       }
+       else
+       {
+               return jit_function_apply_vararg(func, 0, args, return_area);
+       }
+}
+
+/* Imported from "jit-rules-interp.c" */
+extern "C" unsigned int _jit_interp_calculate_arg_size
+               (jit_function_t func, jit_type_t signature);
+
+extern "C" int jit_function_apply_vararg
+       (jit_function_t func, jit_type_t signature, void **args, void *return_area)
+{
+       struct jit_backtrace call_trace;
+       jit_function_interp *entry;
+       jit_item interp_return_area;
+       jit_item *arg_buffer;
+       jit_item *temp_arg;
+       jit_type_t type;
+       unsigned int num_params;
+       unsigned int param;
+
+       _jit_backtrace_push(&call_trace, 0, 0, 0);
+       {
+               jit_trace_restorer restorer(call_trace.parent);
+               jit_exception_clear_last();
+               try
+               {
+                       /* Bail out if the function is NULL */
+                       if(!func)
+                       {
+                               jit_exception_builtin(JIT_RESULT_NULL_FUNCTION);
+                       }
+
+                       /* Make sure that the function is compiled */
+                       if(func->is_compiled)
+                       {
+                               entry = (jit_function_interp *)(func->entry_point);
+                       }
+                       else
+                       {
+                               entry = (jit_function_interp *)
+                                       _jit_function_compile_on_demand(func);
+                       }
+
+                       /* Populate the low-level argument buffer */
+                       if(!signature)
+                       {
+                               signature = func->signature;
+                               arg_buffer = (jit_item *)alloca(entry->args_size);
+                       }
+                       else if(signature == func->signature)
+                       {
+                               arg_buffer = (jit_item *)alloca(entry->args_size);
+                       }
+                       else
+                       {
+                               arg_buffer = (jit_item *)alloca
+                                       (_jit_interp_calculate_arg_size(func, signature));
+                       }
+                       temp_arg = arg_buffer;
+                       if(func->nested_parent)
+                       {
+                               jit_exception_builtin(JIT_RESULT_CALLED_NESTED);
+                       }
+                       type = jit_type_get_return(signature);
+                       if(jit_type_return_via_pointer(type))
+                       {
+                               if(!return_area)
+                               {
+                                       return_area = alloca(jit_type_get_size(type));
+                               }
+                               temp_arg->ptr_value = return_area;
+                               ++temp_arg;
+                       }
+                       num_params = jit_type_num_params(signature);
+                       for(param = 0; param < num_params; ++param)
+                       {
+                               type = jit_type_normalize
+                                       (jit_type_get_param(signature, param));
+                               if(!(args[param]))
+                               {
+                                       jit_exception_builtin(JIT_RESULT_NULL_REFERENCE);
+                               }
+                               switch(type->kind)
+                               {
+                                       case JIT_TYPE_SBYTE:
+                                       {
+                                               temp_arg->int_value = *((jit_sbyte *)(args[param]));
+                                               ++temp_arg;
+                                       }
+                                       break;
+
+                                       case JIT_TYPE_UBYTE:
+                                       {
+                                               temp_arg->int_value = *((jit_ubyte *)(args[param]));
+                                               ++temp_arg;
+                                       }
+                                       break;
+
+                                       case JIT_TYPE_SHORT:
+                                       {
+                                               temp_arg->int_value = *((jit_short *)(args[param]));
+                                               ++temp_arg;
+                                       }
+                                       break;
+
+                                       case JIT_TYPE_USHORT:
+                                       {
+                                               temp_arg->int_value = *((jit_ushort *)(args[param]));
+                                               ++temp_arg;
+                                       }
+                                       break;
+
+                                       case JIT_TYPE_INT:
+                                       case JIT_TYPE_UINT:
+                                       {
+                                               temp_arg->int_value = *((jit_int *)(args[param]));
+                                               ++temp_arg;
+                                       }
+                                       break;
+
+                                       case JIT_TYPE_LONG:
+                                       case JIT_TYPE_ULONG:
+                                       {
+                                               temp_arg->long_value = *((jit_long *)(args[param]));
+                                               ++temp_arg;
+                                       }
+                                       break;
+
+                                       case JIT_TYPE_FLOAT32:
+                                       {
+                                               temp_arg->float32_value =
+                                                       *((jit_float32 *)(args[param]));
+                                               ++temp_arg;
+                                       }
+                                       break;
+
+                                       case JIT_TYPE_FLOAT64:
+                                       {
+                                               temp_arg->float64_value =
+                                                       *((jit_float64 *)(args[param]));
+                                               ++temp_arg;
+                                       }
+                                       break;
+
+                                       case JIT_TYPE_NFLOAT:
+                                       {
+                                               temp_arg->nfloat_value =
+                                                       *((jit_nfloat *)(args[param]));
+                                               ++temp_arg;
+                                       }
+                                       break;
+
+                                       case JIT_TYPE_STRUCT:
+                                       case JIT_TYPE_UNION:
+                                       {
+                                               jit_memcpy(temp_arg, args[param],
+                                                                  jit_type_get_size(type));
+                                               temp_arg += JIT_NUM_ITEMS_IN_STRUCT
+                                                       (jit_type_get_size(type));
+                                       }
+                                       break;
+                               }
+                       }
+
+                       /* Run the function */
+                       _jit_run_function(entry, arg_buffer, &interp_return_area);
+
+                       /* Copy the return value into place, if it isn't already there */
+                       if(return_area)
+                       {
+                               type = jit_type_normalize(jit_type_get_return(signature));
+                               if(type && type != jit_type_void)
+                               {
+                                       switch(type->kind)
+                                       {
+                                               case JIT_TYPE_SBYTE:
+                                               case JIT_TYPE_UBYTE:
+                                               {
+                                                       *((jit_sbyte *)return_area) =
+                                                               (jit_sbyte)(interp_return_area.int_value);
+                                               }
+                                               break;
+
+                                               case JIT_TYPE_SHORT:
+                                               case JIT_TYPE_USHORT:
+                                               {
+                                                       *((jit_short *)return_area) =
+                                                               (jit_short)(interp_return_area.int_value);
+                                               }
+                                               break;
+
+                                               case JIT_TYPE_INT:
+                                               case JIT_TYPE_UINT:
+                                               {
+                                                       *((jit_int *)return_area) =
+                                                               interp_return_area.int_value;
+                                               }
+                                               break;
+
+                                               case JIT_TYPE_LONG:
+                                               case JIT_TYPE_ULONG:
+                                               {
+                                                       *((jit_long *)return_area) =
+                                                               interp_return_area.long_value;
+                                               }
+                                               break;
+
+                                               case JIT_TYPE_FLOAT32:
+                                               {
+                                                       *((jit_float32 *)return_area) =
+                                                               interp_return_area.float32_value;
+                                               }
+                                               break;
+
+                                               case JIT_TYPE_FLOAT64:
+                                               {
+                                                       *((jit_float64 *)return_area) =
+                                                               interp_return_area.float64_value;
+                                               }
+                                               break;
+
+                                               case JIT_TYPE_NFLOAT:
+                                               {
+                                                       *((jit_nfloat *)return_area) =
+                                                               interp_return_area.nfloat_value;
+                                               }
+                                               break;
+
+                                               case JIT_TYPE_STRUCT:
+                                               case JIT_TYPE_UNION:
+                                               {
+                                                       if(!jit_type_return_via_pointer(type))
+                                                       {
+                                                               jit_memcpy(return_area, &interp_return_area,
+                                                                                  jit_type_get_size(type));
+                                                       }
+                                               }
+                                               break;
+                                       }
+                               }
+                       }
+                       return 1;
+               }
+               catch(jit_exception *e)
+               {
+                       /* Record the exception, but don't throw it any further yet */
+                       jit_exception_set_last(e->object);
+                       delete e;
+                       return 0;
+               }
+       }
+}
+
+#endif /* JIT_BACKEND_INTERP */
diff --git a/jit/jit-interp.h b/jit/jit-interp.h
new file mode 100644 (file)
index 0000000..5b93dc1
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * jit-interp.h - Bytecode interpreter for platforms without native support.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_INTERP_H
+#define        _JIT_INTERP_H
+
+#include "jit-internal.h"
+#include "jit-apply-rules.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Structure of a stack item.
+ */
+typedef union
+{
+       jit_int         int_value;
+       jit_uint        uint_value;
+       jit_long        long_value;
+       jit_ulong       ulong_value;
+       jit_float32     float32_value;
+       jit_float64     float64_value;
+       jit_nfloat      nfloat_value;
+       void       *ptr_value;
+#if JIT_APPLY_MAX_STRUCT_IN_REG != 0
+       char            struct_value[JIT_APPLY_MAX_STRUCT_IN_REG];
+#endif
+
+} jit_item;
+
+/*
+ * Number of items that make up a struct or union value on the stack.
+ */
+#define        JIT_NUM_ITEMS_IN_STRUCT(size)           \
+       (((size) + (sizeof(jit_item) - 1)) / sizeof(jit_item))
+
+/*
+ * Information that is prefixed to a function that describes
+ * its interpretation context.  The code starts just after this.
+ */
+typedef struct jit_function_interp *jit_function_interp_t;
+struct jit_function_interp
+{
+       /* The function that this structure is associated with */
+       jit_function_t  func;
+
+       /* Size of the argument area to allocate, in bytes */
+       unsigned int    args_size;
+
+       /* Size of the local stack frame to allocate, in bytes */
+       unsigned int    frame_size;
+
+       /* Size of the working stack area of the frame, in items */
+       unsigned int    working_area;
+};
+
+/*
+ * Get the size of the "jit_function_interp" structure, rounded
+ * up to a multiple of "void *".
+ */
+#define        jit_function_interp_size        \
+                       ((sizeof(struct jit_function_interp) + sizeof(void *) - 1) & \
+                        ~(sizeof(void *) - 1))
+
+/*
+ * Get the entry point for a function, from its "jit_function_interp_t" block.
+ */
+#define        jit_function_interp_entry_pc(info)      \
+                       ((void **)(((unsigned char *)(info)) + jit_function_interp_size))
+
+#if defined(__cplusplus)
+
+/*
+ * The JIT exception class.  Instances of this object are thrown
+ * to simulate a JIT-level exception.
+ */
+class jit_exception
+{
+public:
+       jit_exception(void *object) { this->object = object; }
+
+       void *object;
+};
+
+#endif /* __cplusplus */
+
+/*
+ * Argument variable access opcodes.
+ */
+#define        JIT_OP_LDARG_SBYTE                                      (JIT_OP_NUM_OPCODES + 0x0000)
+#define        JIT_OP_LDARG_UBYTE                                      (JIT_OP_NUM_OPCODES + 0x0001)
+#define        JIT_OP_LDARG_SHORT                                      (JIT_OP_NUM_OPCODES + 0x0002)
+#define        JIT_OP_LDARG_USHORT                                     (JIT_OP_NUM_OPCODES + 0x0003)
+#define        JIT_OP_LDARG_INT                                        (JIT_OP_NUM_OPCODES + 0x0004)
+#define        JIT_OP_LDARG_LONG                                       (JIT_OP_NUM_OPCODES + 0x0005)
+#define        JIT_OP_LDARG_FLOAT32                            (JIT_OP_NUM_OPCODES + 0x0006)
+#define        JIT_OP_LDARG_FLOAT64                            (JIT_OP_NUM_OPCODES + 0x0007)
+#define        JIT_OP_LDARG_NFLOAT                                     (JIT_OP_NUM_OPCODES + 0x0008)
+#define        JIT_OP_LDARG_STRUCT                                     (JIT_OP_NUM_OPCODES + 0x0009)
+#define        JIT_OP_LDARGA                                           (JIT_OP_NUM_OPCODES + 0x000A)
+#define        JIT_OP_STARG_BYTE                                       (JIT_OP_NUM_OPCODES + 0x000B)
+#define        JIT_OP_STARG_SHORT                                      (JIT_OP_NUM_OPCODES + 0x000C)
+#define        JIT_OP_STARG_INT                                        (JIT_OP_NUM_OPCODES + 0x000D)
+#define        JIT_OP_STARG_LONG                                       (JIT_OP_NUM_OPCODES + 0x000E)
+#define        JIT_OP_STARG_FLOAT32                            (JIT_OP_NUM_OPCODES + 0x000F)
+#define        JIT_OP_STARG_FLOAT64                            (JIT_OP_NUM_OPCODES + 0x0010)
+#define        JIT_OP_STARG_NFLOAT                                     (JIT_OP_NUM_OPCODES + 0x0011)
+#define        JIT_OP_STARG_STRUCT                                     (JIT_OP_NUM_OPCODES + 0x0012)
+
+/*
+ * Local variable frame access opcodes.
+ */
+#define        JIT_OP_LDLOC_SBYTE                                      (JIT_OP_NUM_OPCODES + 0x0013)
+#define        JIT_OP_LDLOC_UBYTE                                      (JIT_OP_NUM_OPCODES + 0x0014)
+#define        JIT_OP_LDLOC_SHORT                                      (JIT_OP_NUM_OPCODES + 0x0015)
+#define        JIT_OP_LDLOC_USHORT                                     (JIT_OP_NUM_OPCODES + 0x0016)
+#define        JIT_OP_LDLOC_INT                                        (JIT_OP_NUM_OPCODES + 0x0017)
+#define        JIT_OP_LDLOC_LONG                                       (JIT_OP_NUM_OPCODES + 0x0018)
+#define        JIT_OP_LDLOC_FLOAT32                            (JIT_OP_NUM_OPCODES + 0x0019)
+#define        JIT_OP_LDLOC_FLOAT64                            (JIT_OP_NUM_OPCODES + 0x001A)
+#define        JIT_OP_LDLOC_NFLOAT                                     (JIT_OP_NUM_OPCODES + 0x001B)
+#define        JIT_OP_LDLOC_STRUCT                                     (JIT_OP_NUM_OPCODES + 0x001C)
+#define        JIT_OP_LDLOCA                                           (JIT_OP_NUM_OPCODES + 0x001D)
+#define        JIT_OP_STLOC_BYTE                                       (JIT_OP_NUM_OPCODES + 0x001E)
+#define        JIT_OP_STLOC_SHORT                                      (JIT_OP_NUM_OPCODES + 0x001F)
+#define        JIT_OP_STLOC_INT                                        (JIT_OP_NUM_OPCODES + 0x0020)
+#define        JIT_OP_STLOC_LONG                                       (JIT_OP_NUM_OPCODES + 0x0021)
+#define        JIT_OP_STLOC_FLOAT32                            (JIT_OP_NUM_OPCODES + 0x0022)
+#define        JIT_OP_STLOC_FLOAT64                            (JIT_OP_NUM_OPCODES + 0x0023)
+#define        JIT_OP_STLOC_NFLOAT                                     (JIT_OP_NUM_OPCODES + 0x0024)
+#define        JIT_OP_STLOC_STRUCT                                     (JIT_OP_NUM_OPCODES + 0x0025)
+
+/*
+ * Pointer check opcodes (interpreter only).
+ */
+#define        JIT_OP_CHECK_NULL_N                                     (JIT_OP_NUM_OPCODES + 0x0026)
+
+/*
+ * Stack management.
+ */
+#define        JIT_OP_POP                                                      (JIT_OP_NUM_OPCODES + 0x0027)
+#define        JIT_OP_POP_2                                            (JIT_OP_NUM_OPCODES + 0x0028)
+#define        JIT_OP_POP_3                                            (JIT_OP_NUM_OPCODES + 0x0029)
+#define        JIT_OP_PUSH_RETURN_INT                          (JIT_OP_NUM_OPCODES + 0x002A)
+#define        JIT_OP_PUSH_RETURN_LONG                         (JIT_OP_NUM_OPCODES + 0x002B)
+#define        JIT_OP_PUSH_RETURN_FLOAT32                      (JIT_OP_NUM_OPCODES + 0x002C)
+#define        JIT_OP_PUSH_RETURN_FLOAT64                      (JIT_OP_NUM_OPCODES + 0x002D)
+#define        JIT_OP_PUSH_RETURN_NFLOAT                       (JIT_OP_NUM_OPCODES + 0x002E)
+#define        JIT_OP_PUSH_RETURN_SMALL_STRUCT         (JIT_OP_NUM_OPCODES + 0x002F)
+
+/*
+ * Nested function call handling.
+ */
+#define        JIT_OP_PUSH_PARENT_LOCALS                       (JIT_OP_NUM_OPCODES + 0x0030)
+#define        JIT_OP_PUSH_PARENT_ARGS                         (JIT_OP_NUM_OPCODES + 0x0031)
+
+/*
+ * Push constant values onto the stack.
+ */
+#define        JIT_OP_PUSH_CONST_INT                           (JIT_OP_NUM_OPCODES + 0x0032)
+#define        JIT_OP_PUSH_CONST_LONG                          (JIT_OP_NUM_OPCODES + 0x0033)
+#define        JIT_OP_PUSH_CONST_FLOAT32                       (JIT_OP_NUM_OPCODES + 0x0034)
+#define        JIT_OP_PUSH_CONST_FLOAT64                       (JIT_OP_NUM_OPCODES + 0x0035)
+#define        JIT_OP_PUSH_CONST_NFLOAT                        (JIT_OP_NUM_OPCODES + 0x0036)
+
+/*
+ * Exception handling (interpreter-only).
+ */
+#define        JIT_OP_CALL_FINALLY                                     (JIT_OP_NUM_OPCODES + 0x0037)
+
+/*
+ * Marker opcode for the end of a function.
+ */
+#define        JIT_OP_END_MARKER                                       (JIT_OP_NUM_OPCODES + 0x0038)
+
+/*
+ * Number of interpreter-specific opcodes.
+ */
+#define        JIT_OP_NUM_INTERP_OPCODES       \
+               (JIT_OP_END_MARKER + 1 - JIT_OP_NUM_OPCODES)
+
+/*
+ * Opcode version.  Should be increased whenever new opcodes
+ * are added to this list or the public list in "jit-opcode.h".
+ * This value is written to ELF binaries, to ensure that code
+ * for one version of libjit is not inadvertantly used in another.
+ */
+#define        JIT_OPCODE_VERSION                                      0
+
+/*
+ * Additional opcode definition flags.
+ */
+#define        JIT_OPCODE_INTERP_ARGS_MASK                     0x7E000000
+#define        JIT_OPCODE_NINT_ARG                                     0x02000000
+#define        JIT_OPCODE_NINT_ARG_TWO                         0x04000000
+#define        JIT_OPCODE_CONST_LONG                           0x06000000
+#define        JIT_OPCODE_CONST_FLOAT32                        0x08000000
+#define        JIT_OPCODE_CONST_FLOAT64                        0x0A000000
+#define        JIT_OPCODE_CONST_NFLOAT                         0x0C000000
+#define        JIT_OPCODE_CALL_INDIRECT_ARGS           0x0E000000
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_INTERP_H */
diff --git a/jit/jit-intrinsic.c b/jit/jit-intrinsic.c
new file mode 100644 (file)
index 0000000..04919b4
--- /dev/null
@@ -0,0 +1,3482 @@
+/*
+ * jit-intrinsic.c - Support routines for JIT intrinsics.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include <config.h>
+#if defined(HAVE_TGMATH_H) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       #include <tgmath.h>
+#elif defined(HAVE_MATH_H)
+       #include <math.h>
+#endif
+#ifdef JIT_WIN32_NATIVE
+#include <float.h>
+#if !defined(isnan)
+#define isnan(value)   _isnan((value))
+#endif
+#if !defined(isfinite)
+#define isfinite(value)        _finite((value))
+#endif
+#ifndef HAVE_ISNAN
+#define HAVE_ISNAN 1
+#endif
+#undef HAVE_ISNANF
+#undef HAVE_ISNANL
+#else
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+#endif
+
+/*@
+
+@cindex jit-intrinsic.h
+
+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).  @xref{Exceptions}, for a list of built-in exception codes.
+
+The following functions are defined in @code{<jit/jit-intrinsic.h>}:
+
+@*/
+
+/*
+ * Special values that indicate "not a number" for floating-point types.
+ * Visual C++ won't let us compute NaN's at compile time, so we have to
+ * work around it with a run-time hack.
+ */
+#if defined(_MSC_VER) && defined(_M_IX86)
+static unsigned int const float32_nan = 0x7FC00000;
+static unsigned __int64 const float64_nan = 0x7FF8000000000000LL;
+#define        jit_float32_nan (*((jit_float32 *)&float32_nan))
+#define        jit_float64_nan (*((jit_float64 *)&float64_nan))
+#define        jit_nfloat_nan  ((jit_nfloat)(*((jit_float64 *)&float64_nan)))
+#else
+#define        jit_float32_nan ((jit_float32)(0.0 / 0.0))
+#define        jit_float64_nan ((jit_float64)(0.0 / 0.0))
+#define        jit_nfloat_nan  ((jit_nfloat)(0.0 / 0.0))
+#endif
+
+/*@
+ * @deftypefun jit_int jit_int_add (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_sub (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_mul (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_neg (jit_int value1)
+ * @deftypefunx jit_int jit_int_and (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_or (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_xor (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_not (jit_int value1)
+ * @deftypefunx jit_int jit_int_not (jit_int value1)
+ * @deftypefunx jit_int jit_int_shl (jit_int value1, jit_uint value2)
+ * @deftypefunx jit_int jit_int_shr (jit_int value1, jit_uint value2)
+ * Perform an arithmetic operation on signed 32-bit integers.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_int_add_ovf ({jit_int *} result, jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_sub_ovf ({jit_int *} result, jit_int value1, jit_int value2)
+ * @deftypefunx 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 @code{JIT_RESULT_OK}
+ * or @code{JIT_RESULT_OVERFLOW}.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_int_div_ovf ({jit_int *} result, jit_int value1, jit_int value2)
+ * @deftypefunx 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 @code{JIT_RESULT_OK}, @code{JIT_RESULT_DIVISION_BY_ZERO},
+ * or @code{JIT_RESULT_ARITHMETIC}.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_int_eq (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_ne (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_lt (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_le (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_gt (jit_int value1, jit_int value2)
+ * @deftypefunx 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.
+ * @end deftypefun
+ *
+ * @deftypefun 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.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_int_abs (jit_int value1)
+ * @deftypefunx jit_int jit_int_min (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_max (jit_int value1, jit_int value2)
+ * @deftypefunx jit_int jit_int_sign (jit_int value1)
+ * Calculate the absolute value, minimum, maximum, or sign for
+ * signed 32-bit integer values.
+ * @end deftypefun
+@*/
+jit_int jit_int_add(jit_int value1, jit_int value2)
+{
+       return value1 + value2;
+}
+
+jit_int jit_int_sub(jit_int value1, jit_int value2)
+{
+       return value1 - value2;
+}
+
+jit_int jit_int_mul(jit_int value1, jit_int value2)
+{
+       return value1 * value2;
+}
+
+jit_int jit_int_div(jit_int *result, jit_int value1, jit_int value2)
+{
+       if(value2 == 0)
+       {
+               *result = 0;
+               return JIT_RESULT_DIVISION_BY_ZERO;
+       }
+       else if(value2 == (jit_int)(-1) && value1 == jit_min_int)
+       {
+               *result = 0;
+               return JIT_RESULT_ARITHMETIC;
+       }
+       else
+       {
+               *result = value1 / value2;
+               return JIT_RESULT_OK;
+       }
+}
+
+jit_int jit_int_rem(jit_int *result, jit_int value1, jit_int value2)
+{
+       if(value2 == 0)
+       {
+               *result = 0;
+               return JIT_RESULT_DIVISION_BY_ZERO;
+       }
+       else if(value2 == (jit_int)(-1) && value1 == jit_min_int)
+       {
+               *result = 0;
+               return JIT_RESULT_ARITHMETIC;
+       }
+       else
+       {
+               *result = value1 % value2;
+               return JIT_RESULT_OK;
+       }
+}
+
+jit_int jit_int_add_ovf(jit_int *result, jit_int value1, jit_int value2)
+{
+       if(value1 >= 0 && value2 >= 0)
+       {
+               return ((*result = value1 + value2) >= value1);
+       }
+       else if(value1 < 0 && value2 < 0)
+       {
+               return ((*result = value1 + value2) < value1);
+       }
+       else
+       {
+               *result = value1 + value2;
+               return 1;
+       }
+}
+
+jit_int jit_int_sub_ovf(jit_int *result, jit_int value1, jit_int value2)
+{
+       if(value1 >= 0 && value2 >= 0)
+       {
+               *result = value1 - value2;
+               return 1;
+       }
+       else if(value1 < 0 && value2 < 0)
+       {
+               *result = value1 - value2;
+               return 1;
+       }
+       else if(value1 < 0)
+       {
+               return ((*result = value1 - value2) <= value1);
+       }
+       else
+       {
+               return ((*result = value1 - value2) >= value1);
+       }
+}
+
+jit_int jit_int_mul_ovf(jit_int *result, jit_int value1, jit_int value2)
+{
+       jit_long temp = ((jit_long)value1) * ((jit_long)value2);
+       *result = (jit_int)temp;
+       return (temp >= (jit_long)jit_min_int && temp <= (jit_long)jit_max_int);
+}
+
+jit_int jit_int_neg(jit_int value1)
+{
+       return -value1;
+}
+
+jit_int jit_int_and(jit_int value1, jit_int value2)
+{
+       return value1 & value2;
+}
+
+jit_int jit_int_or(jit_int value1, jit_int value2)
+{
+       return value1 | value2;
+}
+
+jit_int jit_int_xor(jit_int value1, jit_int value2)
+{
+       return value1 ^ value2;
+}
+
+jit_int jit_int_not(jit_int value1)
+{
+       return ~value1;
+}
+
+jit_int jit_int_shl(jit_int value1, jit_uint value2)
+{
+       return value1 << (value2 & 0x1F);
+}
+
+jit_int jit_int_shr(jit_int value1, jit_uint value2)
+{
+       return value1 >> (value2 & 0x1F);
+}
+
+jit_int jit_int_eq(jit_int value1, jit_int value2)
+{
+       return (value1 == value2);
+}
+
+jit_int jit_int_ne(jit_int value1, jit_int value2)
+{
+       return (value1 != value2);
+}
+
+jit_int jit_int_lt(jit_int value1, jit_int value2)
+{
+       return (value1 < value2);
+}
+
+jit_int jit_int_le(jit_int value1, jit_int value2)
+{
+       return (value1 <= value2);
+}
+
+jit_int jit_int_gt(jit_int value1, jit_int value2)
+{
+       return (value1 > value2);
+}
+
+jit_int jit_int_ge(jit_int value1, jit_int value2)
+{
+       return (value1 >= value2);
+}
+
+jit_int jit_int_cmp(jit_int value1, jit_int value2)
+{
+       if(value1 < value2)
+       {
+               return -1;
+       }
+       else if(value1 > value2)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_int jit_int_abs(jit_int value1)
+{
+       return ((value1 >= 0) ? value1 : -value1);
+}
+
+jit_int jit_int_min(jit_int value1, jit_int value2)
+{
+       return ((value1 <= value2) ? value1 : value2);
+}
+
+jit_int jit_int_max(jit_int value1, jit_int value2)
+{
+       return ((value1 >= value2) ? value1 : value2);
+}
+
+jit_int jit_int_sign(jit_int value1)
+{
+       if(value1 < 0)
+       {
+               return -1;
+       }
+       else if(value1 > 0)
+       {
+               return 0;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_uint jit_uint_add (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_uint jit_uint_sub (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_uint jit_uint_mul (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_uint jit_uint_neg (jit_uint value1)
+ * @deftypefunx jit_uint jit_uint_and (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_uint jit_uint_or (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_uint jit_uint_xor (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_uint jit_uint_not (jit_uint value1)
+ * @deftypefunx jit_uint jit_uint_not (jit_uint value1)
+ * @deftypefunx jit_uint jit_uint_shl (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_uint jit_uint_shr (jit_uint value1, jit_uint value2)
+ * Perform an arithmetic operation on unsigned 32-bit integers.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_uint_add_ovf ({jit_uint *} result, jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_int jit_uint_sub_ovf ({jit_uint *} result, jit_uint value1, jit_uint value2)
+ * @deftypefunx 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 @code{JIT_RESULT_OK}
+ * or @code{JIT_RESULT_OVERFLOW}.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_uint_div_ovf ({jit_uint *} result, jit_uint value1, jit_uint value2)
+ * @deftypefunx 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 @code{JIT_RESULT_OK} or @code{JIT_RESULT_DIVISION_BY_ZERO}
+ * (@code{JIT_RESULT_ARITHMETIC} is not possible with unsigned integers).
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_uint_eq (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_int jit_uint_ne (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_int jit_uint_lt (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_int jit_uint_le (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_int jit_uint_gt (jit_uint value1, jit_uint value2)
+ * @deftypefunx 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.
+ * @end deftypefun
+ *
+ * @deftypefun 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.
+ * @end deftypefun
+ *
+ * @deftypefun jit_uint jit_uint_min (jit_uint value1, jit_uint value2)
+ * @deftypefunx jit_uint jit_uint_max (jit_uint value1, jit_uint value2)
+ * Calculate the minimum or maximum for unsigned 32-bit integer values.
+ * @end deftypefun
+@*/
+jit_uint jit_uint_add(jit_uint value1, jit_uint value2)
+{
+       return value1 + value2;
+}
+
+jit_uint jit_uint_sub(jit_uint value1, jit_uint value2)
+{
+       return value1 - value2;
+}
+
+jit_uint jit_uint_mul(jit_uint value1, jit_uint value2)
+{
+       return value1 * value2;
+}
+
+jit_int jit_uint_div(jit_uint *result, jit_uint value1, jit_uint value2)
+{
+       if(value2 == 0)
+       {
+               *result = 0;
+               return JIT_RESULT_DIVISION_BY_ZERO;
+       }
+       else
+       {
+               *result = value1 / value2;
+               return JIT_RESULT_OK;
+       }
+}
+
+jit_int jit_uint_rem(jit_uint *result, jit_uint value1, jit_uint value2)
+{
+       if(value2 == 0)
+       {
+               *result = 0;
+               return JIT_RESULT_DIVISION_BY_ZERO;
+       }
+       else
+       {
+               *result = value1 % value2;
+               return JIT_RESULT_OK;
+       }
+}
+
+jit_int jit_uint_add_ovf(jit_uint *result, jit_uint value1, jit_uint value2)
+{
+       return ((*result = value1 + value2) >= value1);
+}
+
+jit_int jit_uint_sub_ovf(jit_uint *result, jit_uint value1, jit_uint value2)
+{
+       return ((*result = value1 - value2) <= value1);
+}
+
+jit_int jit_uint_mul_ovf(jit_uint *result, jit_uint value1, jit_uint value2)
+{
+       jit_ulong temp = ((jit_ulong)value1) * ((jit_ulong)value2);
+       *result = (jit_uint)temp;
+       return (temp <= (jit_ulong)jit_max_uint);
+}
+
+jit_uint jit_uint_neg(jit_uint value1)
+{
+       return (jit_uint)(-((jit_int)value1));
+}
+
+jit_uint jit_uint_and(jit_uint value1, jit_uint value2)
+{
+       return value1 & value2;
+}
+
+jit_uint jit_uint_or(jit_uint value1, jit_uint value2)
+{
+       return value1 | value2;
+}
+
+jit_uint jit_uint_xor(jit_uint value1, jit_uint value2)
+{
+       return value1 ^ value2;
+}
+
+jit_uint jit_uint_not(jit_uint value1)
+{
+       return ~value1;
+}
+
+jit_uint jit_uint_shl(jit_uint value1, jit_uint value2)
+{
+       return value1 << (value2 & 0x1F);
+}
+
+jit_uint jit_uint_shr(jit_uint value1, jit_uint value2)
+{
+       return value1 >> (value2 & 0x1F);
+}
+
+jit_int jit_uint_eq(jit_uint value1, jit_uint value2)
+{
+       return (value1 == value2);
+}
+
+jit_int jit_uint_ne(jit_uint value1, jit_uint value2)
+{
+       return (value1 != value2);
+}
+
+jit_int jit_uint_lt(jit_uint value1, jit_uint value2)
+{
+       return (value1 < value2);
+}
+
+jit_int jit_uint_le(jit_uint value1, jit_uint value2)
+{
+       return (value1 <= value2);
+}
+
+jit_int jit_uint_gt(jit_uint value1, jit_uint value2)
+{
+       return (value1 > value2);
+}
+
+jit_int jit_uint_ge(jit_uint value1, jit_uint value2)
+{
+       return (value1 >= value2);
+}
+
+jit_int jit_uint_cmp(jit_uint value1, jit_uint value2)
+{
+       if(value1 < value2)
+       {
+               return -1;
+       }
+       else if(value1 > value2)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_uint jit_uint_min(jit_uint value1, jit_uint value2)
+{
+       return ((value1 <= value2) ? value1 : value2);
+}
+
+jit_uint jit_uint_max(jit_uint value1, jit_uint value2)
+{
+       return ((value1 >= value2) ? value1 : value2);
+}
+
+/*@
+ * @deftypefun jit_long jit_long_add (jit_long value1, jit_long value2)
+ * @deftypefunx jit_long jit_long_sub (jit_long value1, jit_long value2)
+ * @deftypefunx jit_long jit_long_mul (jit_long value1, jit_long value2)
+ * @deftypefunx jit_long jit_long_neg (jit_long value1)
+ * @deftypefunx jit_long jit_long_and (jit_long value1, jit_long value2)
+ * @deftypefunx jit_long jit_long_or (jit_long value1, jit_long value2)
+ * @deftypefunx jit_long jit_long_xor (jit_long value1, jit_long value2)
+ * @deftypefunx jit_long jit_long_not (jit_long value1)
+ * @deftypefunx jit_long jit_long_not (jit_long value1)
+ * @deftypefunx jit_long jit_long_shl (jit_long value1, jit_uint value2)
+ * @deftypefunx jit_long jit_long_shr (jit_long value1, jit_uint value2)
+ * Perform an arithmetic operation on signed 64-bit integers.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_long_add_ovf ({jit_long *} result, jit_long value1, jit_long value2)
+ * @deftypefunx jit_int jit_long_sub_ovf ({jit_long *} result, jit_long value1, jit_long value2)
+ * @deftypefunx 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 @code{JIT_RESULT_OK}
+ * or @code{JIT_RESULT_OVERFLOW}.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_long_div_ovf ({jit_long *} result, jit_long value1, jit_long value2)
+ * @deftypefunx 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 @code{JIT_RESULT_OK}, @code{JIT_RESULT_DIVISION_BY_ZERO},
+ * or @code{JIT_RESULT_ARITHMETIC}.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_long_eq (jit_long value1, jit_long value2)
+ * @deftypefunx jit_int jit_long_ne (jit_long value1, jit_long value2)
+ * @deftypefunx jit_int jit_long_lt (jit_long value1, jit_long value2)
+ * @deftypefunx jit_int jit_long_le (jit_long value1, jit_long value2)
+ * @deftypefunx jit_int jit_long_gt (jit_long value1, jit_long value2)
+ * @deftypefunx 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.
+ * @end deftypefun
+ *
+ * @deftypefun 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.
+ * @end deftypefun
+ *
+ * @deftypefun jit_long jit_long_abs (jit_long value1)
+ * @deftypefunx jit_long jit_long_min (jit_long value1, jit_long value2)
+ * @deftypefunx jit_long jit_long_max (jit_long value1, jit_long value2)
+ * @deftypefunx jit_int jit_long_sign (jit_long value1)
+ * Calculate the absolute value, minimum, maximum, or sign for
+ * signed 64-bit integer values.
+ * @end deftypefun
+@*/
+jit_long jit_long_add(jit_long value1, jit_long value2)
+{
+       return value1 + value2;
+}
+
+jit_long jit_long_sub(jit_long value1, jit_long value2)
+{
+       return value1 - value2;
+}
+
+jit_long jit_long_mul(jit_long value1, jit_long value2)
+{
+       return value1 * value2;
+}
+
+jit_int jit_long_div(jit_long *result, jit_long value1, jit_long value2)
+{
+       if(value2 == 0)
+       {
+               *result = 0;
+               return JIT_RESULT_DIVISION_BY_ZERO;
+       }
+       else if(value2 == (jit_long)(-1) && value1 == jit_min_long)
+       {
+               *result = 0;
+               return JIT_RESULT_ARITHMETIC;
+       }
+       else
+       {
+               *result = value1 / value2;
+               return JIT_RESULT_OK;
+       }
+}
+
+jit_int jit_long_rem(jit_long *result, jit_long value1, jit_long value2)
+{
+       if(value2 == 0)
+       {
+               *result = 0;
+               return JIT_RESULT_DIVISION_BY_ZERO;
+       }
+       else if(value2 == (jit_long)(-1) && value1 == jit_min_long)
+       {
+               *result = 0;
+               return JIT_RESULT_ARITHMETIC;
+       }
+       else
+       {
+               *result = value1 % value2;
+               return JIT_RESULT_OK;
+       }
+}
+
+jit_int jit_long_add_ovf(jit_long *result, jit_long value1, jit_long value2)
+{
+       if(value1 >= 0 && value2 >= 0)
+       {
+               return ((*result = value1 + value2) >= value1);
+       }
+       else if(value1 < 0 && value2 < 0)
+       {
+               return ((*result = value1 + value2) < value1);
+       }
+       else
+       {
+               *result = value1 + value2;
+               return 1;
+       }
+}
+
+jit_int jit_long_sub_ovf(jit_long *result, jit_long value1, jit_long value2)
+{
+       if(value1 >= 0 && value2 >= 0)
+       {
+               *result = value1 - value2;
+               return 1;
+       }
+       else if(value1 < 0 && value2 < 0)
+       {
+               *result = value1 - value2;
+               return 1;
+       }
+       else if(value1 < 0)
+       {
+               return ((*result = value1 - value2) <= value1);
+       }
+       else
+       {
+               return ((*result = value1 - value2) >= value1);
+       }
+}
+
+jit_int jit_long_mul_ovf(jit_long *result, jit_long value1, jit_long value2)
+{
+       jit_ulong temp;
+       if(value1 >= 0 && value2 >= 0)
+       {
+               /* Both values are positive */
+               if(!jit_ulong_mul_ovf(&temp, (jit_ulong)value1, (jit_ulong)value2))
+               {
+                       *result = jit_max_long;
+                       return 0;
+               }
+               if(temp > ((jit_ulong)jit_max_long))
+               {
+                       *result = jit_max_long;
+                       return 0;
+               }
+               *result = (jit_long)temp;
+               return 1;
+       }
+       else if(value1 >= 0)
+       {
+               /* The first value is positive */
+               if(!jit_ulong_mul_ovf(&temp, (jit_ulong)value1, (jit_ulong)-value2))
+               {
+                       *result = jit_min_long;
+                       return 0;
+               }
+               if(temp > (((jit_ulong)jit_max_long) + 1))
+               {
+                       *result = jit_min_long;
+                       return 0;
+               }
+               *result = -((jit_long)temp);
+               return 1;
+       }
+       else if(value2 >= 0)
+       {
+               /* The second value is positive */
+               if(!jit_ulong_mul_ovf(&temp, (jit_ulong)-value1, (jit_ulong)value2))
+               {
+                       *result = jit_min_long;
+                       return 0;
+               }
+               if(temp > (((jit_ulong)jit_max_long) + 1))
+               {
+                       *result = jit_min_long;
+                       return 0;
+               }
+               *result = -((jit_long)temp);
+               return 1;
+       }
+       else
+       {
+               /* Both values are negative */
+               if(!jit_ulong_mul_ovf(&temp, (jit_ulong)-value1, (jit_ulong)-value2))
+               {
+                       *result = jit_max_long;
+                       return 0;
+               }
+               if(temp > ((jit_ulong)jit_max_long))
+               {
+                       *result = jit_max_long;
+                       return 0;
+               }
+               *result = (jit_long)temp;
+               return 1;
+       }
+}
+
+jit_long jit_long_neg(jit_long value1)
+{
+       return -value1;
+}
+
+jit_long jit_long_and(jit_long value1, jit_long value2)
+{
+       return value1 & value2;
+}
+
+jit_long jit_long_or(jit_long value1, jit_long value2)
+{
+       return value1 | value2;
+}
+
+jit_long jit_long_xor(jit_long value1, jit_long value2)
+{
+       return value1 ^ value2;
+}
+
+jit_long jit_long_not(jit_long value1)
+{
+       return ~value1;
+}
+
+jit_long jit_long_shl(jit_long value1, jit_uint value2)
+{
+       return value1 << (value2 & 0x3F);
+}
+
+jit_long jit_long_shr(jit_long value1, jit_uint value2)
+{
+       return value1 >> (value2 & 0x3F);
+}
+
+jit_int jit_long_eq(jit_long value1, jit_long value2)
+{
+       return (value1 == value2);
+}
+
+jit_int jit_long_ne(jit_long value1, jit_long value2)
+{
+       return (value1 != value2);
+}
+
+jit_int jit_long_lt(jit_long value1, jit_long value2)
+{
+       return (value1 < value2);
+}
+
+jit_int jit_long_le(jit_long value1, jit_long value2)
+{
+       return (value1 <= value2);
+}
+
+jit_int jit_long_gt(jit_long value1, jit_long value2)
+{
+       return (value1 > value2);
+}
+
+jit_int jit_long_ge(jit_long value1, jit_long value2)
+{
+       return (value1 >= value2);
+}
+
+jit_int jit_long_cmp(jit_long value1, jit_long value2)
+{
+       if(value1 < value2)
+       {
+               return -1;
+       }
+       else if(value1 > value2)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_long jit_long_abs(jit_long value1)
+{
+       return ((value1 >= 0) ? value1 : -value1);
+}
+
+jit_long jit_long_min(jit_long value1, jit_long value2)
+{
+       return ((value1 <= value2) ? value1 : value2);
+}
+
+jit_long jit_long_max(jit_long value1, jit_long value2)
+{
+       return ((value1 >= value2) ? value1 : value2);
+}
+
+jit_int jit_long_sign(jit_long value1)
+{
+       if(value1 < 0)
+       {
+               return -1;
+       }
+       else if(value1 > 0)
+       {
+               return 0;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_ulong jit_ulong_add (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_ulong jit_ulong_sub (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_ulong jit_ulong_mul (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_ulong jit_ulong_neg (jit_ulong value1)
+ * @deftypefunx jit_ulong jit_ulong_and (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_ulong jit_ulong_or (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_ulong jit_ulong_xor (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_ulong jit_ulong_not (jit_ulong value1)
+ * @deftypefunx jit_ulong jit_ulong_not (jit_ulong value1)
+ * @deftypefunx jit_ulong jit_ulong_shl (jit_ulong value1, jit_uint value2)
+ * @deftypefunx jit_ulong jit_ulong_shr (jit_ulong value1, jit_uint value2)
+ * Perform an arithmetic operation on unsigned 64-bit integers.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_ulong_add_ovf ({jit_ulong *} result, jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_int jit_ulong_sub_ovf ({jit_ulong *} result, jit_ulong value1, jit_ulong value2)
+ * @deftypefunx 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 @code{JIT_RESULT_OK}
+ * or @code{JIT_RESULT_OVERFLOW}.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_ulong_div_ovf ({jit_ulong *} result, jit_ulong value1, jit_ulong value2)
+ * @deftypefunx 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 @code{JIT_RESULT_OK} or @code{JIT_RESULT_DIVISION_BY_ZERO}
+ * (@code{JIT_RESULT_ARITHMETIC} is not possible with unsigned integers).
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_ulong_eq (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_int jit_ulong_ne (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_int jit_ulong_lt (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_int jit_ulong_le (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_int jit_ulong_gt (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx 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.
+ * @end deftypefun
+ *
+ * @deftypefun 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.
+ * @end deftypefun
+ *
+ * @deftypefun jit_ulong jit_ulong_min (jit_ulong value1, jit_ulong value2)
+ * @deftypefunx jit_ulong jit_ulong_max (jit_ulong value1, jit_ulong value2)
+ * Calculate the minimum or maximum for unsigned 64-bit integer values.
+ * @end deftypefun
+@*/
+jit_ulong jit_ulong_add(jit_ulong value1, jit_ulong value2)
+{
+       return value1 + value2;
+}
+
+jit_ulong jit_ulong_sub(jit_ulong value1, jit_ulong value2)
+{
+       return value1 - value2;
+}
+
+jit_ulong jit_ulong_mul(jit_ulong value1, jit_ulong value2)
+{
+       return value1 - value2;
+}
+
+jit_int jit_ulong_div(jit_ulong *result, jit_ulong value1, jit_ulong value2)
+{
+       if(value2 == 0)
+       {
+               *result = 0;
+               return JIT_RESULT_DIVISION_BY_ZERO;
+       }
+       else
+       {
+               *result = value1 / value2;
+               return JIT_RESULT_OK;
+       }
+}
+
+jit_int jit_ulong_rem(jit_ulong *result, jit_ulong value1, jit_ulong value2)
+{
+       if(value2 == 0)
+       {
+               *result = 0;
+               return JIT_RESULT_DIVISION_BY_ZERO;
+       }
+       else
+       {
+               *result = value1 % value2;
+               return JIT_RESULT_OK;
+       }
+}
+
+jit_int jit_ulong_add_ovf(jit_ulong *result, jit_ulong value1, jit_ulong value2)
+{
+       return ((*result = value1 + value2) >= value1);
+}
+
+jit_int jit_ulong_sub_ovf(jit_ulong *result, jit_ulong value1, jit_ulong value2)
+{
+       return ((*result = value1 - value2) <= value1);
+}
+
+jit_int jit_ulong_mul_ovf(jit_ulong *result, jit_ulong value1, jit_ulong value2)
+{
+       jit_uint high1, low1, high2, low2, orig;
+       jit_ulong temp;
+       jit_uint result1, result2, result3, result4;
+       high1 = (jit_uint)(value1 >> 32);
+       low1  = (jit_uint)value1;
+       high2 = (jit_uint)(value2 >> 32);
+       low2  = (jit_uint)value2;
+       temp = ((jit_ulong)low1) * ((jit_ulong)low2);
+       result1 = (jit_uint)temp;
+       result2 = (jit_uint)(temp >> 32);
+       temp = ((jit_ulong)low1) * ((jit_ulong)high2);
+       orig = result2;
+       result2 += (jit_uint)temp;
+       if(result2 < orig)
+               result3 = (((jit_uint)(temp >> 32)) + 1);
+       else
+               result3 = ((jit_uint)(temp >> 32));
+       temp = ((jit_ulong)high1) * ((jit_ulong)low2);
+       orig = result2;
+       result2 += (jit_uint)temp;
+       if(result2 < orig)
+       {
+               orig = result3;
+               result3 += (((jit_uint)(temp >> 32)) + 1);
+               if(result3 < orig)
+                       result4 = 1;
+               else
+                       result4 = 0;
+       }
+       else
+       {
+               orig = result3;
+               result3 += ((jit_uint)(temp >> 32));
+               if(result3 < orig)
+                       result4 = 1;
+               else
+                       result4 = 0;
+       }
+       temp = ((jit_ulong)high1) * ((jit_ulong)high2);
+       orig = result3;
+       result3 += (jit_uint)temp;
+       if(result3 < orig)
+               result4 += ((jit_uint)(temp >> 32)) + 1;
+       else
+               result4 += ((jit_uint)(temp >> 32));
+       if(result3 != 0 || result4 != 0)
+       {
+               *result = jit_max_ulong;
+               return 0;
+       }
+       *result = (((jit_ulong)result2) << 32) | ((jit_ulong)result1);
+       return 1;
+}
+
+jit_ulong jit_ulong_neg(jit_ulong value1)
+{
+       return (jit_ulong)(-((jit_long)value1));
+}
+
+jit_ulong jit_ulong_and(jit_ulong value1, jit_ulong value2)
+{
+       return value1 & value2;
+}
+
+jit_ulong jit_ulong_or(jit_ulong value1, jit_ulong value2)
+{
+       return value1 | value2;
+}
+
+jit_ulong jit_ulong_xor(jit_ulong value1, jit_ulong value2)
+{
+       return value1 ^ value2;
+}
+
+jit_ulong jit_ulong_not(jit_ulong value1)
+{
+       return ~value1;
+}
+
+jit_ulong jit_ulong_shl(jit_ulong value1, jit_uint value2)
+{
+       return value1 << (value2 & 0x3F);
+}
+
+jit_ulong jit_ulong_shr(jit_ulong value1, jit_uint value2)
+{
+       return value1 >> (value2 & 0x3F);
+}
+
+jit_int jit_ulong_eq(jit_ulong value1, jit_ulong value2)
+{
+       return (value1 == value2);
+}
+
+jit_int jit_ulong_ne(jit_ulong value1, jit_ulong value2)
+{
+       return (value1 != value2);
+}
+
+jit_int jit_ulong_lt(jit_ulong value1, jit_ulong value2)
+{
+       return (value1 < value2);
+}
+
+jit_int jit_ulong_le(jit_ulong value1, jit_ulong value2)
+{
+       return (value1 <= value2);
+}
+
+jit_int jit_ulong_gt(jit_ulong value1, jit_ulong value2)
+{
+       return (value1 > value2);
+}
+
+jit_int jit_ulong_ge(jit_ulong value1, jit_ulong value2)
+{
+       return (value1 >= value2);
+}
+
+jit_int jit_ulong_cmp(jit_ulong value1, jit_ulong value2)
+{
+       if(value1 < value2)
+       {
+               return -1;
+       }
+       else if(value1 > value2)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_ulong jit_ulong_min(jit_ulong value1, jit_ulong value2)
+{
+       return ((value1 <= value2) ? value1 : value2);
+}
+
+jit_ulong jit_ulong_max(jit_ulong value1, jit_ulong value2)
+{
+       return ((value1 >= value2) ? value1 : value2);
+}
+
+/*@
+ * @deftypefun jit_float32 jit_float32_add (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_float32 jit_float32_sub (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_float32 jit_float32_mul (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_float32 jit_float32_div (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_float32 jit_float32_rem (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_float32 jit_float32_ieee_rem (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_float32 jit_float32_neg (jit_float32 value1)
+ * Perform an arithmetic operation on 32-bit floating-point values.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_float32_eq (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_int jit_float32_ne (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_int jit_float32_lt (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_int jit_float32_le (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_int jit_float32_gt (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx 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.
+ * @end deftypefun
+ *
+ * @deftypefun 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.
+ * @end deftypefun
+ *
+ * @deftypefun 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.
+ * @end deftypefun
+ *
+ * @deftypefun jit_float32 jit_float32_abs (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_min (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_float32 jit_float32_max (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_int jit_float32_sign (jit_float32 value1)
+ * Calculate the absolute value, minimum, maximum, or sign for
+ * 32-bit floating point values.
+ * @end deftypefun
+@*/
+jit_float32 jit_float32_add(jit_float32 value1, jit_float32 value2)
+{
+       return value1 + value2;
+}
+
+jit_float32 jit_float32_sub(jit_float32 value1, jit_float32 value2)
+{
+       return value1 - value2;
+}
+
+jit_float32 jit_float32_mul(jit_float32 value1, jit_float32 value2)
+{
+       return value1 * value2;
+}
+
+jit_float32 jit_float32_div(jit_float32 value1, jit_float32 value2)
+{
+       return value1 / value2;
+}
+
+jit_float32 jit_float32_rem(jit_float32 value1, jit_float32 value2)
+{
+#if defined(HAVE_FMODF)
+       return fmod(value1, value2);
+#elif defined(HAVE_FMOD)
+       return fmod(value1, value2);
+#elif defined(HAVE_CEILF) && defined(HAVE_FLOORF)
+       jit_float32 temp = value1 / value2;
+       if(jit_float32_is_nan(temp))
+       {
+               return temp;
+       }
+       if(temp < (jit_float32)0.0)
+       {
+               temp = ceilf(temp);
+       }
+       else
+       {
+               temp = floorf(temp);
+       }
+       return value1 - temp * value2;
+#elif defined(HAVE_CEIL) && defined(HAVE_FLOOR)
+       jit_float32 temp = value1 / value2;
+       if(jit_float32_is_nan(temp))
+       {
+               return temp;
+       }
+       if(temp < (jit_float32)0.0)
+       {
+               temp = ceil(temp);
+       }
+       else
+       {
+               temp = floor(temp);
+       }
+       return value1 - temp * value2;
+#else
+       /* Don't know how to compute remainders on this platform */
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_ieee_rem(jit_float32 value1, jit_float32 value2)
+{
+#if defined(HAVE_REMAINDERF)
+       return remainderf(value1, value2);
+#elif defined(HAVE_REMAINDER)
+       return remainder(value1, value2);
+#elif defined(HAVE_DREMF)
+       return dremf(value1, value2);
+#elif defined(HAVE_DREM)
+       return drem(value1, value2);
+#elif defined(HAVE_CEILF) && defined(HAVE_FLOORF)
+       jit_float32 temp = value1 / value2;
+       jit_float32 ceil_value, floor_value;
+       if(jit_float32_is_nan(temp))
+       {
+               return temp;
+       }
+       ceil_value = ceilf(temp);
+       floor_value = floorf(temp);
+       if((temp - floor_value) < (jit_float32)0.5)
+       {
+               temp = floor_value;
+       }
+       else if((temp - floor_value) > (jit_float32)0.5)
+       {
+               temp = ceil_value;
+       }
+       else if((floor(ceil_value / (jit_float32)2.0) * (jit_float32)2.0)
+                               == ceil_value)
+       {
+               temp = ceil_value;
+       }
+       else
+       {
+               temp = floor_value;
+       }
+       return value1 - temp * value2;
+#elif defined(HAVE_CEIL) && defined(HAVE_FLOOR)
+       jit_float32 temp = value1 / value2;
+       jit_float32 ceil_value, floor_value;
+       if(jit_float32_is_nan(temp))
+       {
+               return temp;
+       }
+       ceil_value = ceil(temp);
+       floor_value = floor(temp);
+       if((temp - floor_value) < (jit_float32)0.5)
+       {
+               temp = floor_value;
+       }
+       else if((temp - floor_value) > (jit_float32)0.5)
+       {
+               temp = ceil_value;
+       }
+       else if((floor(ceil_value / (jit_float32)2.0) * (jit_float32)2.0)
+                               == ceil_value)
+       {
+               temp = ceil_value;
+       }
+       else
+       {
+               temp = floor_value;
+       }
+       return value1 - temp * value2;
+#else
+       /* Don't know how to compute remainders on this platform */
+       return (jit_float32)(0.0 / 0.0);
+#endif
+}
+
+jit_float32 jit_float32_neg(jit_float32 value1)
+{
+       return -value1;
+}
+
+jit_int jit_float32_eq(jit_float32 value1, jit_float32 value2)
+{
+       return (value1 == value2);
+}
+
+jit_int jit_float32_ne(jit_float32 value1, jit_float32 value2)
+{
+       return (value1 != value2);
+}
+
+jit_int jit_float32_lt(jit_float32 value1, jit_float32 value2)
+{
+       return (value1 < value2);
+}
+
+jit_int jit_float32_le(jit_float32 value1, jit_float32 value2)
+{
+       return (value1 <= value2);
+}
+
+jit_int jit_float32_gt(jit_float32 value1, jit_float32 value2)
+{
+       return (value1 > value2);
+}
+
+jit_int jit_float32_ge(jit_float32 value1, jit_float32 value2)
+{
+       return (value1 >= value2);
+}
+
+jit_int jit_float32_cmpl(jit_float32 value1, jit_float32 value2)
+{
+       if(jit_float32_is_nan(value1) || jit_float32_is_nan(value2))
+       {
+               return -1;
+       }
+       else if(value1 < value2)
+       {
+               return -1;
+       }
+       else if(value1 > value2)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_int jit_float32_cmpg(jit_float32 value1, jit_float32 value2)
+{
+       if(jit_float32_is_nan(value1) || jit_float32_is_nan(value2))
+       {
+               return 1;
+       }
+       else if(value1 < value2)
+       {
+               return -1;
+       }
+       else if(value1 > value2)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_float32 jit_float32_abs(jit_float32 value1)
+{
+       if(jit_float32_is_nan(value1))
+       {
+               return jit_float32_nan;
+       }
+       return ((value1 >= 0) ? value1 : -value1);
+}
+
+jit_float32 jit_float32_min(jit_float32 value1, jit_float32 value2)
+{
+       if(jit_float32_is_nan(value1) || jit_float32_is_nan(value2))
+       {
+               return jit_float32_nan;
+       }
+       return ((value1 <= value2) ? value1 : value2);
+}
+
+jit_float32 jit_float32_max(jit_float32 value1, jit_float32 value2)
+{
+       if(jit_float32_is_nan(value1) || jit_float32_is_nan(value2))
+       {
+               return jit_float32_nan;
+       }
+       return ((value1 >= value2) ? value1 : value2);
+}
+
+jit_int jit_float32_sign(jit_float32 value1)
+{
+       if(jit_float32_is_nan(value1))
+       {
+               return 0;
+       }
+       else if(value1 < 0)
+       {
+               return -1;
+       }
+       else if(value1 > 0)
+       {
+               return 0;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_float32 jit_float32_acos (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_asin (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_atan (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_atan2 (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_float32 jit_float32_ceil (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_cos (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_cosh (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_exp (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_floor (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_log (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_log10 (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_pow (jit_float32 value1, jit_float32 value2)
+ * @deftypefunx jit_float32 jit_float32_sin (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_sinh (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_sqrt (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_tan (jit_float32 value1)
+ * @deftypefunx jit_float32 jit_float32_tanh (jit_float32 value1)
+ * Apply a mathematical function to one or two 32-bit floating-point values.
+ * @end deftypefun
+@*/
+jit_float32 jit_float32_acos(jit_float32 value1)
+{
+#if defined(HAVE_ACOSF)
+       return (jit_float32)(acosf(value1));
+#elif defined(HAVE_ACOS)
+       return (jit_float32)(acos(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_asin(jit_float32 value1)
+{
+#if defined(HAVE_ASINF)
+       return (jit_float32)(asinf(value1));
+#elif defined(HAVE_ASIN)
+       return (jit_float32)(asin(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_atan(jit_float32 value1)
+{
+#if defined(HAVE_ATANF)
+       return (jit_float32)(atanf(value1));
+#elif defined(HAVE_ATAN)
+       return (jit_float32)(atan(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_atan2(jit_float32 value1, jit_float32 value2)
+{
+#if defined(HAVE_ATAN2F)
+       return (jit_float32)(atan2f(value1, value2));
+#elif defined(HAVE_ATAN2)
+       return (jit_float32)(atan2(value1, value2));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_ceil(jit_float32 value1)
+{
+#if defined(HAVE_CEILF)
+       return (jit_float32)(ceilf(value1));
+#elif defined(HAVE_CEIL)
+       return (jit_float32)(ceil(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_cos(jit_float32 value1)
+{
+#if defined(HAVE_COSF)
+       return (jit_float32)(cosf(value1));
+#elif defined(HAVE_COS)
+       return (jit_float32)(cos(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_cosh(jit_float32 value1)
+{
+#if defined(HAVE_COSHF)
+       return (jit_float32)(coshf(value1));
+#elif defined(HAVE_COSH)
+       return (jit_float32)(cosh(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_exp(jit_float32 value1)
+{
+#if defined(HAVE_EXPF)
+       return (jit_float32)(expf(value1));
+#elif defined(HAVE_EXP)
+       return (jit_float32)(exp(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_floor(jit_float32 value1)
+{
+#if defined(HAVE_FLOORF)
+       return (jit_float32)(floorf(value1));
+#elif defined(HAVE_FLOOR)
+       return (jit_float32)(floor(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_log(jit_float32 value1)
+{
+#if defined(HAVE_LOGF)
+       return (jit_float32)(logf(value1));
+#elif defined(HAVE_LOG)
+       return (jit_float32)(log(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_log10(jit_float32 value1)
+{
+#if defined(HAVE_LOG10F)
+       return (jit_float32)(log10f(value1));
+#elif defined(HAVE_LOG10)
+       return (jit_float32)(log10(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_pow(jit_float32 value1, jit_float32 value2)
+{
+#if defined(HAVE_POWF)
+       return (jit_float32)(powf(value1, value2));
+#elif defined(HAVE_POW)
+       return (jit_float32)(pow(value1, value2));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+/*@
+ * @deftypefun jit_float32 jit_float32_rint (jit_float32 value1)
+ * Round @code{value1} to the nearest integer.  Half-way cases
+ * are rounded to an even number.
+ * @end deftypefun
+@*/
+jit_float32 jit_float32_rint(jit_float32 value1)
+{
+       jit_float32 above, below;
+       if(!jit_float32_is_finite(value1))
+       {
+               return value1;
+       }
+       above = jit_float32_ceil(value1);
+       below = jit_float32_floor(value1);
+       if((above - value1) < (jit_float32)0.5)
+       {
+               return above;
+       }
+       else if((value1 - below) < (jit_float32)0.5)
+       {
+               return below;
+       }
+       else if(jit_float32_ieee_rem(above, (jit_float32)2.0) == (jit_float32)0.0)
+       {
+               return above;
+       }
+       else
+       {
+               return below;
+       }
+}
+
+/*@
+ * @deftypefun jit_float32 jit_float32_round (jit_float32 value1)
+ * Round @code{value1} to the nearest integer.  Half-way cases
+ * are rounded away from zero.
+ * @end deftypefun
+@*/
+jit_float32 jit_float32_round(jit_float32 value1)
+{
+       jit_float32 above, below;
+       if(!jit_float32_is_finite(value1))
+       {
+               return value1;
+       }
+       above = jit_float32_ceil(value1);
+       below = jit_float32_floor(value1);
+       if((above - value1) < (jit_float32)0.5)
+       {
+               return above;
+       }
+       else if((value1 - below) < (jit_float32)0.5)
+       {
+               return below;
+       }
+       else if(above >= (jit_float32)0.0)
+       {
+               return above;
+       }
+       else
+       {
+               return below;
+       }
+}
+
+jit_float32 jit_float32_sin(jit_float32 value1)
+{
+#if defined(HAVE_SINF)
+       return (jit_float32)(sinf(value1));
+#elif defined(HAVE_SIN)
+       return (jit_float32)(sin(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_sinh(jit_float32 value1)
+{
+#if defined(HAVE_SINHF)
+       return (jit_float32)(sinhf(value1));
+#elif defined(HAVE_SINH)
+       return (jit_float32)(sinh(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_sqrt(jit_float32 value1)
+{
+#if defined(HAVE_SQRTF)
+       return (jit_float32)(sqrtf(value1));
+#elif defined(HAVE_SQRT)
+       return (jit_float32)(sqrt(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_tan(jit_float32 value1)
+{
+#if defined(HAVE_TANF)
+       return (jit_float32)(tanf(value1));
+#elif defined(HAVE_TAN)
+       return (jit_float32)(tan(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+jit_float32 jit_float32_tanh(jit_float32 value1)
+{
+#if defined(HAVE_TANHF)
+       return (jit_float32)(tanhf(value1));
+#elif defined(HAVE_TANH)
+       return (jit_float32)(tanh(value1));
+#else
+       return jit_float32_nan;
+#endif
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_int jit_float32_is_finite(jit_float32 value)
+{
+#if defined(hpux) || defined(JIT_WIN32_NATIVE)
+       return isfinite(value);
+#else /* !hpux */
+#if defined(HAVE_FINITEF)
+       return finitef(value);
+#elif defined(HAVE_FINITE)
+       return finite(value);
+#else /* !HAVE_FINITE */
+#if defined(HAVE_ISNANF) && defined(HAVE_ISINFF)
+       return (!isnanf(value) && isinff(value) == 0);
+#elif defined(HAVE_ISNAN) && defined(HAVE_ISINF)
+       return (!isnan(value) && isinf(value) == 0);
+#else
+       #error "Don't know how to determine if floating point numbers are finite"
+       return 1;
+#endif
+#endif /* !HAVE_FINITE */
+#endif /* !hpux */
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_int jit_float32_is_nan(jit_float32 value)
+{
+#if defined(HAVE_ISNANF)
+       return isnanf(value);
+#elif defined(HAVE_ISNAN)
+       return isnan(value);
+#else
+       return (value != value);
+#endif
+}
+
+/*@
+ * @deftypefun 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 @code{isinf} intrinsic
+ * because some systems have a broken @code{isinf} function that returns
+ * 1 for both positive and negative infinity.
+ * @end deftypefun
+@*/
+jit_int jit_float32_is_inf(jit_float32 value)
+{
+       /* The code below works around broken "isinf" implementations */
+#if defined(HAVE_ISINFF)
+       if(isinff(value) == 0)
+       {
+               return 0;
+       }
+#elif defined(HAVE_ISINF)
+       if(isinf(value) == 0)
+       {
+               return 0;
+       }
+#else
+       if(jit_float32_is_nan(value) || jit_float32_is_finite(value))
+       {
+               return 0;
+       }
+#endif
+       if(value < (jit_float32)0.0)
+       {
+               return -1;
+       }
+       else
+       {
+               return 1;
+       }
+}
+
+/*@
+ * @deftypefun jit_float64 jit_float64_add (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_float64 jit_float64_sub (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_float64 jit_float64_mul (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_float64 jit_float64_div (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_float64 jit_float64_rem (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_float64 jit_float64_ieee_rem (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_float64 jit_float64_neg (jit_float64 value1)
+ * Perform an arithmetic operation on 64-bit floating-point values.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_float64_eq (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_int jit_float64_ne (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_int jit_float64_lt (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_int jit_float64_le (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_int jit_float64_gt (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx 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.
+ * @end deftypefun
+ *
+ * @deftypefun 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.
+ * @end deftypefun
+ *
+ * @deftypefun 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.
+ * @end deftypefun
+ *
+ * @deftypefun jit_float64 jit_float64_abs (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_min (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_float64 jit_float64_max (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_int jit_float64_sign (jit_float64 value1)
+ * Calculate the absolute value, minimum, maximum, or sign for
+ * 64-bit floating point values.
+ * @end deftypefun
+@*/
+jit_float64 jit_float64_add(jit_float64 value1, jit_float64 value2)
+{
+       return value1 + value2;
+}
+
+jit_float64 jit_float64_sub(jit_float64 value1, jit_float64 value2)
+{
+       return value1 - value2;
+}
+
+jit_float64 jit_float64_mul(jit_float64 value1, jit_float64 value2)
+{
+       return value1 * value2;
+}
+
+jit_float64 jit_float64_div(jit_float64 value1, jit_float64 value2)
+{
+       return value1 / value2;
+}
+
+jit_float64 jit_float64_rem(jit_float64 value1, jit_float64 value2)
+{
+#if defined(HAVE_FMOD)
+       return fmod(value1, value2);
+#elif defined(HAVE_CEIL) && defined(HAVE_FLOOR)
+       jit_float64 temp = value1 / value2;
+       if(jit_float64_is_nan(temp))
+       {
+               return temp;
+       }
+       if(temp < (jit_float64)0.0)
+       {
+               temp = ceil(temp);
+       }
+       else
+       {
+               temp = floor(temp);
+       }
+       return value1 - temp * value2;
+#else
+       /* Don't know how to compute remainders on this platform */
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_ieee_rem(jit_float64 value1, jit_float64 value2)
+{
+#if defined(HAVE_REMAINDER)
+       return remainder(value1, value2);
+#elif defined(HAVE_DREM)
+       return drem(value1, value2);
+#elif defined(HAVE_CEIL) && defined(HAVE_FLOOR)
+       jit_float64 temp = value1 / value2;
+       jit_float64 ceil_value, floor_value;
+       if(jit_float64_is_nan(temp))
+       {
+               return temp;
+       }
+       ceil_value = ceil(temp);
+       floor_value = floor(temp);
+       if((temp - floor_value) < (jit_float64)0.5)
+       {
+               temp = floor_value;
+       }
+       else if((temp - floor_value) > (jit_float64)0.5)
+       {
+               temp = ceil_value;
+       }
+       else if((floor(ceil_value / (jit_float64)2.0) * (jit_float64)2.0)
+                               == ceil_value)
+       {
+               temp = ceil_value;
+       }
+       else
+       {
+               temp = floor_value;
+       }
+       return value1 - temp * value2;
+#else
+       /* Don't know how to compute remainders on this platform */
+       return (jit_float64)(0.0 / 0.0);
+#endif
+}
+
+jit_float64 jit_float64_neg(jit_float64 value1)
+{
+       return -value1;
+}
+
+jit_int jit_float64_eq(jit_float64 value1, jit_float64 value2)
+{
+       return (value1 == value2);
+}
+
+jit_int jit_float64_ne(jit_float64 value1, jit_float64 value2)
+{
+       return (value1 != value2);
+}
+
+jit_int jit_float64_lt(jit_float64 value1, jit_float64 value2)
+{
+       return (value1 < value2);
+}
+
+jit_int jit_float64_le(jit_float64 value1, jit_float64 value2)
+{
+       return (value1 <= value2);
+}
+
+jit_int jit_float64_gt(jit_float64 value1, jit_float64 value2)
+{
+       return (value1 > value2);
+}
+
+jit_int jit_float64_ge(jit_float64 value1, jit_float64 value2)
+{
+       return (value1 >= value2);
+}
+
+jit_int jit_float64_cmpl(jit_float64 value1, jit_float64 value2)
+{
+       if(jit_float64_is_nan(value1) || jit_float64_is_nan(value2))
+       {
+               return -1;
+       }
+       else if(value1 < value2)
+       {
+               return -1;
+       }
+       else if(value1 > value2)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_int jit_float64_cmpg(jit_float64 value1, jit_float64 value2)
+{
+       if(jit_float64_is_nan(value1) || jit_float64_is_nan(value2))
+       {
+               return 1;
+       }
+       else if(value1 < value2)
+       {
+               return -1;
+       }
+       else if(value1 > value2)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_float64 jit_float64_abs(jit_float64 value1)
+{
+       if(jit_float64_is_nan(value1))
+       {
+               return jit_float64_nan;
+       }
+       return ((value1 >= 0) ? value1 : -value1);
+}
+
+jit_float64 jit_float64_min(jit_float64 value1, jit_float64 value2)
+{
+       if(jit_float64_is_nan(value1) || jit_float64_is_nan(value2))
+       {
+               return jit_float64_nan;
+       }
+       return ((value1 <= value2) ? value1 : value2);
+}
+
+jit_float64 jit_float64_max(jit_float64 value1, jit_float64 value2)
+{
+       if(jit_float64_is_nan(value1) || jit_float64_is_nan(value2))
+       {
+               return jit_float64_nan;
+       }
+       return ((value1 >= value2) ? value1 : value2);
+}
+
+jit_int jit_float64_sign(jit_float64 value1)
+{
+       if(jit_float64_is_nan(value1))
+       {
+               return 0;
+       }
+       else if(value1 < 0)
+       {
+               return -1;
+       }
+       else if(value1 > 0)
+       {
+               return 0;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_float64 jit_float64_acos (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_asin (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_atan (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_atan2 (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_float64 jit_float64_ceil (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_cos (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_cosh (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_exp (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_floor (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_log (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_log10 (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_pow (jit_float64 value1, jit_float64 value2)
+ * @deftypefunx jit_float64 jit_float64_sin (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_sinh (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_sqrt (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_tan (jit_float64 value1)
+ * @deftypefunx jit_float64 jit_float64_tanh (jit_float64 value1)
+ * Apply a mathematical function to one or two 64-bit floating-point values.
+ * @end deftypefun
+@*/
+jit_float64 jit_float64_acos(jit_float64 value1)
+{
+#if defined(HAVE_ACOS)
+       return (jit_float64)(acos(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_asin(jit_float64 value1)
+{
+#if defined(HAVE_ASIN)
+       return (jit_float64)(asin(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_atan(jit_float64 value1)
+{
+#if defined(HAVE_ATAN)
+       return (jit_float64)(atan(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_atan2(jit_float64 value1, jit_float64 value2)
+{
+#if defined(HAVE_ATAN2)
+       return (jit_float64)(atan2(value1, value2));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_ceil(jit_float64 value1)
+{
+#if defined(HAVE_CEIL)
+       return (jit_float64)(ceil(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_cos(jit_float64 value1)
+{
+#if defined(HAVE_COS)
+       return (jit_float64)(cos(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_cosh(jit_float64 value1)
+{
+#if defined(HAVE_COSH)
+       return (jit_float64)(cosh(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_exp(jit_float64 value1)
+{
+#if defined(HAVE_EXP)
+       return (jit_float64)(exp(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_floor(jit_float64 value1)
+{
+#if defined(HAVE_FLOOR)
+       return (jit_float64)(floor(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_log(jit_float64 value1)
+{
+#if defined(HAVE_LOG)
+       return (jit_float64)(log(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_log10(jit_float64 value1)
+{
+#if defined(HAVE_LOG10)
+       return (jit_float64)(log10(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_pow(jit_float64 value1, jit_float64 value2)
+{
+#if defined(HAVE_POW)
+       return (jit_float64)(pow(value1, value2));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+/*@
+ * @deftypefun jit_float64 jit_float64_rint (jit_float64 value1)
+ * Round @code{value1} to the nearest integer.  Half-way cases
+ * are rounded to an even number.
+ * @end deftypefun
+@*/
+jit_float64 jit_float64_rint(jit_float64 value1)
+{
+       jit_float64 above, below;
+       if(!jit_float64_is_finite(value1))
+       {
+               return value1;
+       }
+       above = jit_float64_ceil(value1);
+       below = jit_float64_floor(value1);
+       if((above - value1) < (jit_float64)0.5)
+       {
+               return above;
+       }
+       else if((value1 - below) < (jit_float64)0.5)
+       {
+               return below;
+       }
+       else if(jit_float64_ieee_rem(above, (jit_float64)2.0) == (jit_float64)0.0)
+       {
+               return above;
+       }
+       else
+       {
+               return below;
+       }
+}
+
+/*@
+ * @deftypefun jit_float64 jit_float64_round (jit_float64 value1)
+ * Round @code{value1} to the nearest integer.  Half-way cases
+ * are rounded away from zero.
+ * @end deftypefun
+@*/
+jit_float64 jit_float64_round(jit_float64 value1)
+{
+       jit_float64 above, below;
+       if(!jit_float64_is_finite(value1))
+       {
+               return value1;
+       }
+       above = jit_float64_ceil(value1);
+       below = jit_float64_floor(value1);
+       if((above - value1) < (jit_float64)0.5)
+       {
+               return above;
+       }
+       else if((value1 - below) < (jit_float64)0.5)
+       {
+               return below;
+       }
+       else if(above >= (jit_float64)0.0)
+       {
+               return above;
+       }
+       else
+       {
+               return below;
+       }
+}
+
+jit_float64 jit_float64_sin(jit_float64 value1)
+{
+#if defined(HAVE_SIN)
+       return (jit_float64)(sin(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_sinh(jit_float64 value1)
+{
+#if defined(HAVE_SINH)
+       return (jit_float64)(sinh(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_sqrt(jit_float64 value1)
+{
+#if defined(HAVE_SQRT)
+       return (jit_float64)(sqrt(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_tan(jit_float64 value1)
+{
+#if defined(HAVE_TAN)
+       return (jit_float64)(tan(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+jit_float64 jit_float64_tanh(jit_float64 value1)
+{
+#if defined(HAVE_TANH)
+       return (jit_float64)(tanh(value1));
+#else
+       return jit_float64_nan;
+#endif
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_int jit_float64_is_finite(jit_float64 value)
+{
+#if defined(hpux) || defined(JIT_WIN32_NATIVE)
+       return isfinite(value);
+#else /* !hpux */
+#if defined(HAVE_FINITE)
+       return finite(value);
+#else /* !HAVE_FINITE */
+#if defined(HAVE_ISNAN) && defined(HAVE_ISINF)
+       return (!isnan(value) && isinf(value) == 0);
+#else
+       #error "Don't know how to determine if floating point numbers are finite"
+       return 1;
+#endif
+#endif /* !HAVE_FINITE */
+#endif /* !hpux */
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_int jit_float64_is_nan(jit_float64 value)
+{
+#if defined(HAVE_ISNAN)
+       return isnan(value);
+#else
+       return (value != value);
+#endif
+}
+
+/*@
+ * @deftypefun 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 @code{isinf} intrinsic
+ * because some systems have a broken @code{isinf} function that returns
+ * 1 for both positive and negative infinity.
+ * @end deftypefun
+@*/
+jit_int jit_float64_is_inf(jit_float64 value)
+{
+       /* The code below works around broken "isinf" implementations */
+#if defined(HAVE_ISINF)
+       if(isinf(value) == 0)
+       {
+               return 0;
+       }
+#else
+       if(jit_float64_is_nan(value) || jit_float64_is_finite(value))
+       {
+               return 0;
+       }
+#endif
+       if(value < (jit_float64)0.0)
+       {
+               return -1;
+       }
+       else
+       {
+               return 1;
+       }
+}
+
+/*@
+ * @deftypefun jit_nfloat jit_nfloat_add (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_nfloat jit_nfloat_sub (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_nfloat jit_nfloat_mul (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_nfloat jit_nfloat_div (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_nfloat jit_nfloat_rem (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_nfloat jit_nfloat_ieee_rem (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_nfloat jit_nfloat_neg (jit_nfloat value1)
+ * Perform an arithmetic operation on native floating-point values.
+ * @end deftypefun
+ *
+ * @deftypefun jit_int jit_nfloat_eq (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_int jit_nfloat_ne (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_int jit_nfloat_lt (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_int jit_nfloat_le (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_int jit_nfloat_gt (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx 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.
+ * @end deftypefun
+ *
+ * @deftypefun 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.
+ * @end deftypefun
+ *
+ * @deftypefun 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.
+ * @end deftypefun
+ *
+ * @deftypefun jit_nfloat jit_nfloat_abs (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_min (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_nfloat jit_nfloat_max (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_int jit_nfloat_sign (jit_nfloat value1)
+ * Calculate the absolute value, minimum, maximum, or sign for
+ * native floating point values.
+ * @end deftypefun
+@*/
+jit_nfloat jit_nfloat_add(jit_nfloat value1, jit_nfloat value2)
+{
+       return value1 + value2;
+}
+
+jit_nfloat jit_nfloat_sub(jit_nfloat value1, jit_nfloat value2)
+{
+       return value1 - value2;
+}
+
+jit_nfloat jit_nfloat_mul(jit_nfloat value1, jit_nfloat value2)
+{
+       return value1 * value2;
+}
+
+jit_nfloat jit_nfloat_div(jit_nfloat value1, jit_nfloat value2)
+{
+       return value1 / value2;
+}
+
+jit_nfloat jit_nfloat_rem(jit_nfloat value1, jit_nfloat value2)
+{
+#if defined(HAVE_FMODL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return fmodl(value1, value2);
+#elif defined(HAVE_FMOD)
+       return fmod(value1, value2);
+#elif defined(HAVE_CEILL) && defined(HAVE_FLOORL) && \
+               !defined(JIT_NFLOAT_IS_DOUBLE)
+       jit_nfloat temp = value1 / value2;
+       if(jit_nfloat_is_nan(temp))
+       {
+               return temp;
+       }
+       if(temp < (jit_nfloat)0.0)
+       {
+               temp = ceill(temp);
+       }
+       else
+       {
+               temp = floorl(temp);
+       }
+       return value1 - temp * value2;
+#elif defined(HAVE_CEIL) && defined(HAVE_FLOOR)
+       jit_nfloat temp = value1 / value2;
+       if(jit_nfloat_is_nan(temp))
+       {
+               return temp;
+       }
+       if(temp < (jit_nfloat)0.0)
+       {
+               temp = ceil(temp);
+       }
+       else
+       {
+               temp = floor(temp);
+       }
+       return value1 - temp * value2;
+#else
+       /* Don't know how to compute remainders on this platform */
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_ieee_rem(jit_nfloat value1, jit_nfloat value2)
+{
+#if defined(HAVE_REMAINDERL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return remainderl(value1, value2);
+#elif defined(HAVE_REMAINDER)
+       return remainder(value1, value2);
+#elif defined(HAVE_DREML) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return dreml(value1, value2);
+#elif defined(HAVE_DREM)
+       return drem(value1, value2);
+#elif defined(HAVE_CEILL) && defined(HAVE_FLOORL) && \
+               !defined(JIT_NFLOAT_IS_DOUBLE)
+       jit_nfloat temp = value1 / value2;
+       jit_nfloat ceil_value, floor_value;
+       if(jit_nfloat_is_nan(temp))
+       {
+               return temp;
+       }
+       ceil_value = ceill(temp);
+       floor_value = floorl(temp);
+       if((temp - floor_value) < (jit_nfloat)0.5)
+       {
+               temp = floor_value;
+       }
+       else if((temp - floor_value) > (jit_nfloat)0.5)
+       {
+               temp = ceil_value;
+       }
+       else if((floor(ceil_value / (jit_nfloat)2.0) * (jit_nfloat)2.0)
+                               == ceil_value)
+       {
+               temp = ceil_value;
+       }
+       else
+       {
+               temp = floor_value;
+       }
+       return value1 - temp * value2;
+#elif defined(HAVE_CEIL) && defined(HAVE_FLOOR)
+       jit_nfloat temp = value1 / value2;
+       jit_nfloat ceil_value, floor_value;
+       if(jit_nfloat_is_nan(temp))
+       {
+               return temp;
+       }
+       ceil_value = ceil(temp);
+       floor_value = floor(temp);
+       if((temp - floor_value) < (jit_nfloat)0.5)
+       {
+               temp = floor_value;
+       }
+       else if((temp - floor_value) > (jit_nfloat)0.5)
+       {
+               temp = ceil_value;
+       }
+       else if((floor(ceil_value / (jit_nfloat)2.0) * (jit_nfloat)2.0)
+                               == ceil_value)
+       {
+               temp = ceil_value;
+       }
+       else
+       {
+               temp = floor_value;
+       }
+       return value1 - temp * value2;
+#else
+       /* Don't know how to compute remainders on this platform */
+       return (jit_nfloat)(0.0 / 0.0);
+#endif
+}
+
+jit_nfloat jit_nfloat_neg(jit_nfloat value1)
+{
+       return -value1;
+}
+
+jit_int jit_nfloat_eq(jit_nfloat value1, jit_nfloat value2)
+{
+       return (value1 == value2);
+}
+
+jit_int jit_nfloat_ne(jit_nfloat value1, jit_nfloat value2)
+{
+       return (value1 != value2);
+}
+
+jit_int jit_nfloat_lt(jit_nfloat value1, jit_nfloat value2)
+{
+       return (value1 < value2);
+}
+
+jit_int jit_nfloat_le(jit_nfloat value1, jit_nfloat value2)
+{
+       return (value1 <= value2);
+}
+
+jit_int jit_nfloat_gt(jit_nfloat value1, jit_nfloat value2)
+{
+       return (value1 > value2);
+}
+
+jit_int jit_nfloat_ge(jit_nfloat value1, jit_nfloat value2)
+{
+       return (value1 >= value2);
+}
+
+jit_int jit_nfloat_cmpl(jit_nfloat value1, jit_nfloat value2)
+{
+       if(jit_nfloat_is_nan(value1) || jit_nfloat_is_nan(value2))
+       {
+               return -1;
+       }
+       else if(value1 < value2)
+       {
+               return -1;
+       }
+       else if(value1 > value2)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_int jit_nfloat_cmpg(jit_nfloat value1, jit_nfloat value2)
+{
+       if(jit_nfloat_is_nan(value1) || jit_nfloat_is_nan(value2))
+       {
+               return 1;
+       }
+       else if(value1 < value2)
+       {
+               return -1;
+       }
+       else if(value1 > value2)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+jit_nfloat jit_nfloat_abs(jit_nfloat value1)
+{
+       if(jit_nfloat_is_nan(value1))
+       {
+               return jit_nfloat_nan;
+       }
+       return ((value1 >= 0) ? value1 : -value1);
+}
+
+jit_nfloat jit_nfloat_min(jit_nfloat value1, jit_nfloat value2)
+{
+       if(jit_nfloat_is_nan(value1) || jit_nfloat_is_nan(value2))
+       {
+               return jit_nfloat_nan;
+       }
+       return ((value1 <= value2) ? value1 : value2);
+}
+
+jit_nfloat jit_nfloat_max(jit_nfloat value1, jit_nfloat value2)
+{
+       if(jit_nfloat_is_nan(value1) || jit_nfloat_is_nan(value2))
+       {
+               return jit_nfloat_nan;
+       }
+       return ((value1 >= value2) ? value1 : value2);
+}
+
+jit_int jit_nfloat_sign(jit_nfloat value1)
+{
+       if(jit_nfloat_is_nan(value1))
+       {
+               return 0;
+       }
+       else if(value1 < 0)
+       {
+               return -1;
+       }
+       else if(value1 > 0)
+       {
+               return 0;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_nfloat jit_nfloat_acos (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_asin (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_atan (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_atan2 (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_nfloat jit_nfloat_ceil (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_cos (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_cosh (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_exp (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_floor (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_log (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_log10 (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_pow (jit_nfloat value1, jit_nfloat value2)
+ * @deftypefunx jit_nfloat jit_nfloat_sin (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_sinh (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_sqrt (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_tan (jit_nfloat value1)
+ * @deftypefunx jit_nfloat jit_nfloat_tanh (jit_nfloat value1)
+ * Apply a mathematical function to one or two native floating-point values.
+ * @end deftypefun
+@*/
+jit_nfloat jit_nfloat_acos(jit_nfloat value1)
+{
+#if defined(HAVE_ACOSL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(acosl(value1));
+#elif defined(HAVE_ACOS)
+       return (jit_nfloat)(acos(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_asin(jit_nfloat value1)
+{
+#if defined(HAVE_ASINL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(asinl(value1));
+#elif defined(HAVE_ASIN)
+       return (jit_nfloat)(asin(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_atan(jit_nfloat value1)
+{
+#if defined(HAVE_ATANL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(atanl(value1));
+#elif defined(HAVE_ATAN)
+       return (jit_nfloat)(atan(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_atan2(jit_nfloat value1, jit_nfloat value2)
+{
+#if defined(HAVE_ATAN2L) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(atan2l(value1, value2));
+#elif defined(HAVE_ATAN2)
+       return (jit_nfloat)(atan2(value1, value2));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_ceil(jit_nfloat value1)
+{
+#if defined(HAVE_CEILL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(ceill(value1));
+#elif defined(HAVE_CEIL)
+       return (jit_nfloat)(ceil(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_cos(jit_nfloat value1)
+{
+#if defined(HAVE_COSL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(cosl(value1));
+#elif defined(HAVE_COS)
+       return (jit_nfloat)(cos(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_cosh(jit_nfloat value1)
+{
+#if defined(HAVE_COSHL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(coshl(value1));
+#elif defined(HAVE_COSH)
+       return (jit_nfloat)(cosh(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_exp(jit_nfloat value1)
+{
+#if defined(HAVE_EXPL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(expl(value1));
+#elif defined(HAVE_EXP)
+       return (jit_nfloat)(exp(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_floor(jit_nfloat value1)
+{
+#if defined(HAVE_FLOORL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(floorl(value1));
+#elif defined(HAVE_FLOOR)
+       return (jit_nfloat)(floor(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_log(jit_nfloat value1)
+{
+#if defined(HAVE_LOGL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(logl(value1));
+#elif defined(HAVE_LOG)
+       return (jit_nfloat)(log(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_log10(jit_nfloat value1)
+{
+#if defined(HAVE_LOG10L) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(log10l(value1));
+#elif defined(HAVE_LOG10)
+       return (jit_nfloat)(log10(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_pow(jit_nfloat value1, jit_nfloat value2)
+{
+#if defined(HAVE_POWL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(powl(value1, value2));
+#elif defined(HAVE_POW)
+       return (jit_nfloat)(pow(value1, value2));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+/*@
+ * @deftypefun jit_nfloat jit_nfloat_rint (jit_nfloat value1)
+ * Round @code{value1} to the nearest integer.  Half-way cases
+ * are rounded to an even number.
+ * @end deftypefun
+@*/
+jit_nfloat jit_nfloat_rint(jit_nfloat value1)
+{
+       jit_nfloat above, below;
+       if(!jit_nfloat_is_finite(value1))
+       {
+               return value1;
+       }
+       above = jit_nfloat_ceil(value1);
+       below = jit_nfloat_floor(value1);
+       if((above - value1) < (jit_nfloat)0.5)
+       {
+               return above;
+       }
+       else if((value1 - below) < (jit_nfloat)0.5)
+       {
+               return below;
+       }
+       else if(jit_nfloat_ieee_rem(above, (jit_nfloat)2.0) == (jit_nfloat)0.0)
+       {
+               return above;
+       }
+       else
+       {
+               return below;
+       }
+}
+
+/*@
+ * @deftypefun jit_nfloat jit_nfloat_round (jit_nfloat value1)
+ * Round @code{value1} to the nearest integer.  Half-way cases
+ * are rounded away from zero.
+ * @end deftypefun
+@*/
+jit_nfloat jit_nfloat_round(jit_nfloat value1)
+{
+       jit_nfloat above, below;
+       if(!jit_nfloat_is_finite(value1))
+       {
+               return value1;
+       }
+       above = jit_nfloat_ceil(value1);
+       below = jit_nfloat_floor(value1);
+       if((above - value1) < (jit_nfloat)0.5)
+       {
+               return above;
+       }
+       else if((value1 - below) < (jit_nfloat)0.5)
+       {
+               return below;
+       }
+       else if(above >= (jit_nfloat)0.0)
+       {
+               return above;
+       }
+       else
+       {
+               return below;
+       }
+}
+
+jit_nfloat jit_nfloat_sin(jit_nfloat value1)
+{
+#if defined(HAVE_SINL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(sinl(value1));
+#elif defined(HAVE_SIN)
+       return (jit_nfloat)(sin(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_sinh(jit_nfloat value1)
+{
+#if defined(HAVE_SINHL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(sinhl(value1));
+#elif defined(HAVE_SINH)
+       return (jit_nfloat)(sinh(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_sqrt(jit_nfloat value1)
+{
+#if defined(HAVE_SQRTL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(sqrtl(value1));
+#elif defined(HAVE_SQRT)
+       return (jit_nfloat)(sqrt(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_tan(jit_nfloat value1)
+{
+#if defined(HAVE_TANL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(tanl(value1));
+#elif defined(HAVE_TAN)
+       return (jit_nfloat)(tan(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+jit_nfloat jit_nfloat_tanh(jit_nfloat value1)
+{
+#if defined(HAVE_TANHL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (jit_nfloat)(tanhl(value1));
+#elif defined(HAVE_TANH)
+       return (jit_nfloat)(tanh(value1));
+#else
+       return jit_nfloat_nan;
+#endif
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_int jit_nfloat_is_finite(jit_nfloat value)
+{
+#if defined(hpux) || defined(JIT_WIN32_NATIVE)
+       return isfinite(value);
+#else /* !hpux */
+#if defined(HAVE_FINITEL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return finitel(value);
+#elif defined(HAVE_FINITE)
+       return finite(value);
+#else /* !HAVE_FINITE */
+#if defined(HAVE_ISNANL) && defined(HAVE_ISINFL) && \
+               !defined(JIT_NFLOAT_IS_DOUBLE)
+       return (!isnanl(value) && isinfl(value) == 0);
+#elif defined(HAVE_ISNAN) && defined(HAVE_ISINF)
+       return (!isnan(value) && isinf(value) == 0);
+#else
+       #error "Don't know how to determine if floating point numbers are finite"
+       return 1;
+#endif
+#endif /* !HAVE_FINITE */
+#endif /* !hpux */
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_int jit_nfloat_is_nan(jit_nfloat value)
+{
+#if defined(HAVE_ISNANL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       return isnanl(value);
+#elif defined(HAVE_ISNAN)
+       return isnan(value);
+#else
+       return (value != value);
+#endif
+}
+
+/*@
+ * @deftypefun 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 @code{isinf} intrinsic
+ * because some systems have a broken @code{isinf} function that returns
+ * 1 for both positive and negative infinity.
+ * @end deftypefun
+@*/
+jit_int jit_nfloat_is_inf(jit_nfloat value)
+{
+       /* The code below works around broken "isinf" implementations */
+#if defined(HAVE_ISINFL) && !defined(JIT_NFLOAT_IS_DOUBLE)
+       if(isinfl(value) == 0)
+       {
+               return 0;
+       }
+#elif defined(HAVE_ISINF)
+       if(isinf(value) == 0)
+       {
+               return 0;
+       }
+#else
+       if(jit_nfloat_is_nan(value) || jit_nfloat_is_finite(value))
+       {
+               return 0;
+       }
+#endif
+       if(value < (jit_nfloat)0.0)
+       {
+               return -1;
+       }
+       else
+       {
+               return 1;
+       }
+}
+
+/*@
+ * @deftypefun jit_int jit_int_to_sbyte (jit_int value)
+ * @deftypefunx jit_int jit_int_to_ubyte (jit_int value)
+ * @deftypefunx jit_int jit_int_to_short (jit_int value)
+ * @deftypefunx jit_int jit_int_to_ushort (jit_int value)
+ * @deftypefunx jit_int jit_int_to_int (jit_int value)
+ * @deftypefunx jit_uint jit_int_to_uint (jit_int value)
+ * @deftypefunx jit_long jit_int_to_long (jit_int value)
+ * @deftypefunx jit_ulong jit_int_to_ulong (jit_int value)
+ * @deftypefunx jit_int jit_uint_to_int (jit_uint value)
+ * @deftypefunx jit_uint jit_uint_to_uint (jit_uint value)
+ * @deftypefunx jit_long jit_uint_to_long (jit_uint value)
+ * @deftypefunx jit_ulong jit_uint_to_ulong (jit_uint value)
+ * @deftypefunx jit_int jit_long_to_int (jit_long value)
+ * @deftypefunx jit_uint jit_long_to_uint (jit_long value)
+ * @deftypefunx jit_long jit_long_to_long (jit_long value)
+ * @deftypefunx jit_ulong jit_long_to_ulong (jit_long value)
+ * @deftypefunx jit_int jit_ulong_to_int (jit_ulong value)
+ * @deftypefunx jit_uint jit_ulong_to_uint (jit_ulong value)
+ * @deftypefunx jit_long jit_ulong_to_long (jit_ulong value)
+ * @deftypefunx jit_ulong jit_ulong_to_ulong (jit_ulong value)
+ * Convert between integer types.
+ * @end deftypefun
+@*/
+jit_int jit_int_to_sbyte(jit_int value)
+{
+       return (jit_int)(jit_sbyte)value;
+}
+
+jit_int jit_int_to_ubyte(jit_int value)
+{
+       return (jit_int)(jit_ubyte)value;
+}
+
+jit_int jit_int_to_short(jit_int value)
+{
+       return (jit_int)(jit_short)value;
+}
+
+jit_int jit_int_to_ushort(jit_int value)
+{
+       return (jit_int)(jit_ushort)value;
+}
+
+jit_int jit_int_to_int(jit_int value)
+{
+       return value;
+}
+
+jit_uint jit_int_to_uint(jit_int value)
+{
+       return (jit_uint)value;
+}
+
+jit_long jit_int_to_long(jit_int value)
+{
+       return (jit_long)value;
+}
+
+jit_ulong jit_int_to_ulong(jit_int value)
+{
+       return (jit_ulong)(jit_long)value;
+}
+
+jit_int jit_uint_to_int(jit_uint value)
+{
+       return (jit_int)value;
+}
+
+jit_uint jit_uint_to_uint(jit_uint value)
+{
+       return value;
+}
+
+jit_long jit_uint_to_long(jit_uint value)
+{
+       return (jit_long)value;
+}
+
+jit_ulong jit_uint_to_ulong(jit_uint value)
+{
+       return (jit_long)value;
+}
+
+jit_int jit_long_to_int(jit_long value)
+{
+       return (jit_int)value;
+}
+
+jit_uint jit_long_to_uint(jit_long value)
+{
+       return (jit_uint)value;
+}
+
+jit_long jit_long_to_long(jit_long value)
+{
+       return value;
+}
+
+jit_ulong jit_long_to_ulong(jit_long value)
+{
+       return (jit_ulong)value;
+}
+
+jit_int jit_ulong_to_int(jit_ulong value)
+{
+       return (jit_int)value;
+}
+
+jit_uint jit_ulong_to_uint(jit_ulong value)
+{
+       return (jit_uint)value;
+}
+
+jit_long jit_ulong_to_long(jit_ulong value)
+{
+       return (jit_long)value;
+}
+
+jit_ulong jit_ulong_to_ulong(jit_ulong value)
+{
+       return value;
+}
+
+/*@
+ * @deftypefun jit_int jit_int_to_sbyte_ovf ({jit_int *result}, jit_int value)
+ * @deftypefunx jit_int jit_int_to_ubyte_ovf ({jit_int *result}, jit_int value)
+ * @deftypefunx jit_int jit_int_to_short_ovf ({jit_int *result}, jit_int value)
+ * @deftypefunx jit_int jit_int_to_ushort_ovf ({jit_int *result}, jit_int value)
+ * @deftypefunx jit_int jit_int_to_int_ovf ({jit_int *result}, jit_int value)
+ * @deftypefunx jit_int jit_int_to_uint_ovf ({jit_uint *result}, jit_int value)
+ * @deftypefunx jit_int jit_int_to_long_ovf ({jit_long *result}, jit_int value)
+ * @deftypefunx jit_int jit_int_to_ulong_ovf ({jit_ulong *result}, jit_int value)
+ * @deftypefunx jit_int jit_uint_to_int_ovf ({jit_int *result}, jit_uint value)
+ * @deftypefunx jit_int jit_uint_to_uint_ovf ({jit_uint *result}, jit_uint value)
+ * @deftypefunx jit_int jit_uint_to_long_ovf ({jit_long *result}, jit_uint value)
+ * @deftypefunx jit_int jit_uint_to_ulong_ovf ({jit_ulong *result}, jit_uint value)
+ * @deftypefunx jit_int jit_long_to_int_ovf ({jit_int *result}, jit_long value)
+ * @deftypefunx jit_int jit_long_to_uint_ovf ({jit_uint *result}, jit_long value)
+ * @deftypefunx jit_int jit_long_to_long_ovf ({jit_long *result}, jit_long value)
+ * @deftypefunx jit_int jit_long_to_ulong_ovf ({jit_ulong *result}, jit_long value)
+ * @deftypefunx jit_int jit_ulong_to_int_ovf ({jit_int *result}, jit_ulong value)
+ * @deftypefunx jit_int jit_ulong_to_uint_ovf ({jit_uint *result}, jit_ulong value)
+ * @deftypefunx jit_int jit_ulong_to_long_ovf ({jit_long *result}, jit_ulong value)
+ * @deftypefunx jit_int jit_ulong_to_ulong_ovf ({jit_ulong *result}, jit_ulong value)
+ * Convert between integer types with overflow detection.
+ * @end deftypefun
+@*/
+jit_int jit_int_to_sbyte_ovf(jit_int *result, jit_int value)
+{
+       return ((*result = (jit_int)(jit_sbyte)value) == value);
+}
+
+jit_int jit_int_to_ubyte_ovf(jit_int *result, jit_int value)
+{
+       return ((*result = (jit_int)(jit_ubyte)value) == value);
+}
+
+jit_int jit_int_to_short_ovf(jit_int *result, jit_int value)
+{
+       return ((*result = (jit_int)(jit_short)value) == value);
+}
+
+jit_int jit_int_to_ushort_ovf(jit_int *result, jit_int value)
+{
+       return ((*result = (jit_int)(jit_ushort)value) == value);
+}
+
+jit_int jit_int_to_int_ovf(jit_int *result, jit_int value)
+{
+       *result = value;
+       return 1;
+}
+
+jit_int jit_int_to_uint_ovf(jit_uint *result, jit_int value)
+{
+       *result = (jit_uint)value;
+       return (value >= 0);
+}
+
+jit_int jit_int_to_long_ovf(jit_long *result, jit_int value)
+{
+       *result = (jit_long)value;
+       return 1;
+}
+
+jit_int jit_int_to_ulong_ovf(jit_ulong *result, jit_int value)
+{
+       *result = (jit_ulong)(jit_long)value;
+       return (value >= 0);
+}
+
+jit_int jit_uint_to_int_ovf(jit_int *result, jit_uint value)
+{
+       *result = (jit_int)value;
+       return (*result >= 0);
+}
+
+jit_int jit_uint_to_uint_ovf(jit_uint *result, jit_uint value)
+{
+       *result = value;
+       return 1;
+}
+
+jit_int jit_uint_to_long_ovf(jit_long *result, jit_uint value)
+{
+       *result = (jit_long)value;
+       return 1;
+}
+
+jit_int jit_uint_to_ulong_ovf(jit_ulong *result, jit_uint value)
+{
+       *result = (jit_ulong)value;
+       return 1;
+}
+
+jit_int jit_long_to_int_ovf(jit_int *result, jit_long value)
+{
+       *result = (jit_int)value;
+       return (((jit_long)(*result)) == value);
+}
+
+jit_int jit_long_to_uint_ovf(jit_uint *result, jit_long value)
+{
+       *result = (jit_uint)value;
+       return (((jit_long)(*result)) == value);
+}
+
+jit_int jit_long_to_long_ovf(jit_long *result, jit_long value)
+{
+       *result = value;
+       return 1;
+}
+
+jit_int jit_long_to_ulong_ovf(jit_ulong *result, jit_long value)
+{
+       *result = (jit_ulong)value;
+       return (value >= 0);
+}
+
+jit_int jit_ulong_to_int_ovf(jit_int *result, jit_ulong value)
+{
+       *result = (jit_int)value;
+       return (value <= (jit_ulong)(jit_long)jit_max_int);
+}
+
+jit_int jit_ulong_to_uint_ovf(jit_uint *result, jit_ulong value)
+{
+       *result = (jit_uint)value;
+       return (value <= (jit_ulong)jit_max_uint);
+}
+
+jit_int jit_ulong_to_long_ovf(jit_long *result, jit_ulong value)
+{
+       *result = (jit_long)value;
+       return (*result >= 0);
+}
+
+jit_int jit_ulong_to_ulong_ovf(jit_ulong *result, jit_ulong value)
+{
+       *result = value;
+       return 1;
+}
+
+/*@
+ * @deftypefun jit_int jit_nfloat_to_int (jit_nfloat value)
+ * @deftypefunx jit_uint jit_nfloat_to_uint (jit_nfloat value)
+ * @deftypefunx jit_long jit_nfloat_to_long (jit_nfloat value)
+ * @deftypefunx jit_ulong jit_nfloat_to_ulong (jit_nfloat value)
+ * Convert a native floating-point value into an integer.
+ * @end deftypefun
+@*/
+jit_int jit_nfloat_to_int(jit_nfloat value)
+{
+       return (jit_int)value;
+}
+
+jit_uint jit_nfloat_to_uint(jit_nfloat value)
+{
+       return (jit_uint)value;
+}
+
+jit_long jit_nfloat_to_long(jit_nfloat value)
+{
+       return (jit_long)value;
+}
+
+jit_ulong jit_nfloat_to_ulong(jit_nfloat value)
+{
+       /* Some platforms cannot perform the conversion directly,
+          so we need to do it in stages */
+       if(jit_nfloat_is_finite(value))
+       {
+               if(value >= (jit_nfloat)0.0)
+               {
+                       if(value < (jit_nfloat)9223372036854775808.0)
+                       {
+                               return (jit_ulong)(jit_long)value;
+                       }
+                       else if(value < (jit_nfloat)18446744073709551616.0)
+                       {
+                               jit_long temp = (jit_long)(value - 9223372036854775808.0);
+                               return (jit_ulong)(temp - jit_min_long);
+                       }
+                       else
+                       {
+                               return jit_max_ulong;
+                       }
+               }
+               else
+               {
+                       return 0;
+               }
+       }
+       else if(jit_nfloat_is_nan(value))
+       {
+               return 0;
+       }
+       else if(value < (jit_nfloat)0.0)
+       {
+               return 0;
+       }
+       else
+       {
+               return jit_max_ulong;
+       }
+}
+
+/*@
+ * @deftypefun jit_int jit_nfloat_to_int_ovf ({jit_int *} result, jit_nfloat value)
+ * @deftypefunx jit_uint jit_nfloat_to_uint_ovf ({jit_uint *} result, jit_nfloat value)
+ * @deftypefunx jit_long jit_nfloat_to_long_ovf ({jit_long *} result, jit_nfloat value)
+ * @deftypefunx 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 @code{JIT_RESULT_OK} if the conversion
+ * was successful or @code{JIT_RESULT_OVERFLOW} if an overflow occurred.
+ * @end deftypefun
+@*/
+jit_int jit_nfloat_to_int_ovf(jit_int *result, jit_nfloat value)
+{
+       if(jit_nfloat_is_finite(value))
+       {
+               if(value > (jit_nfloat)(-2147483649.0) &&
+                  value < (jit_nfloat)2147483648.0)
+               {
+                       *result = jit_nfloat_to_int(value);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+jit_int jit_nfloat_to_uint_ovf(jit_uint *result, jit_nfloat value)
+{
+       if(jit_nfloat_is_finite(value))
+       {
+               if(value >= (jit_nfloat)0.0 &&
+                  value < (jit_nfloat)4294967296.0)
+               {
+                       *result = jit_nfloat_to_uint(value);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+jit_int jit_nfloat_to_long_ovf(jit_long *result, jit_nfloat value)
+{
+       if(jit_nfloat_is_finite(value))
+       {
+               if(value >= (jit_nfloat)-9223372036854775808.0 &&
+                  value < (jit_nfloat)9223372036854775808.0)
+               {
+                       *result = jit_nfloat_to_long(value);
+                       return 1;
+               }
+               else if(value < (jit_nfloat)0.0)
+               {
+                       /* Account for the range -9223372036854775809.0 to
+                          -9223372036854775808.0, which may get rounded
+                          off if we aren't careful */
+                       value += (jit_nfloat)9223372036854775808.0;
+                       if(value > (jit_nfloat)(-1.0))
+                       {
+                               *result = jit_min_long;
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
+jit_int jit_nfloat_to_ulong_ovf(jit_ulong *result, jit_nfloat value)
+{
+       if(jit_nfloat_is_finite(value))
+       {
+               if(value >= (jit_nfloat)0.0)
+               {
+                       if(value < (jit_nfloat)18446744073709551616.0)
+                       {
+                               *result = jit_nfloat_to_ulong(value);
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun jit_nfloat jit_int_to_nfloat (jit_int value)
+ * @deftypefunx jit_nfloat jit_uint_to_nfloat (jit_uint value)
+ * @deftypefunx jit_nfloat jit_long_to_nfloat (jit_long value)
+ * @deftypefunx jit_nfloat jit_ulong_to_nfloat (jit_ulong value)
+ * Convert an integer into native floating-point value.
+ * @end deftypefun
+@*/
+jit_nfloat jit_int_to_nfloat(jit_int value)
+{
+       return (jit_nfloat)value;
+}
+
+jit_nfloat jit_uint_to_nfloat(jit_uint value)
+{
+       return (jit_nfloat)value;
+}
+
+jit_nfloat jit_long_to_nfloat(jit_long value)
+{
+       return (jit_nfloat)value;
+}
+
+jit_nfloat jit_ulong_to_nfloat(jit_ulong value)
+{
+       /* Some platforms cannot perform the conversion directly,
+          so we need to do it in stages */
+       if(value < (((jit_ulong)1) << 63))
+       {
+               return (jit_nfloat)(jit_long)value;
+       }
+       else
+       {
+               return ((jit_nfloat)(((jit_long)value) + jit_min_long)) +
+                                       (jit_nfloat)9223372036854775808.0;
+       }
+}
+
+/*@
+ * @deftypefun jit_nfloat jit_float32_to_nfloat (jit_float32 value)
+ * @deftypefunx jit_nfloat jit_float64_to_nfloat (jit_float64 value)
+ * @deftypefunx jit_float32 jit_nfloat_to_float32 (jit_nfloat value)
+ * @deftypefunx jit_float64 jit_nfloat_to_float64 (jit_nfloat value)
+ * Convert between floating-point types.
+ * @end deftypefun
+@*/
+jit_nfloat jit_float32_to_nfloat(jit_float32 value)
+{
+       return (jit_nfloat)value;
+}
+
+jit_nfloat jit_float64_to_nfloat(jit_float64 value)
+{
+       return (jit_nfloat)value;
+}
+
+jit_float32 jit_nfloat_to_float32(jit_nfloat value)
+{
+       return (jit_float32)value;
+}
+
+jit_float64 jit_nfloat_to_float64(jit_nfloat value)
+{
+       return (jit_float64)value;
+}
diff --git a/jit/jit-live.c b/jit/jit-live.c
new file mode 100644 (file)
index 0000000..882a54b
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * jit-live.c - Liveness analysis for function bodies.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+
+/*
+ * Compute liveness information for a basic block.
+ */
+static void compute_liveness_for_block(jit_block_t block)
+{
+       jit_insn_iter_t iter;
+       jit_insn_t insn;
+       jit_value_t dest;
+       jit_value_t value1;
+       jit_value_t value2;
+       int flags;
+
+       /* Scan backwards to compute the liveness flags */
+       jit_insn_iter_init_last(&iter, block);
+       while((insn = jit_insn_iter_previous(&iter)) != 0)
+       {
+               /* Skip NOP instructions, which may have arguments left
+                  over from when the instruction was replaced, but which
+                  are not relevant to our liveness analysis */
+               if(insn->opcode == JIT_OP_NOP)
+               {
+                       continue;
+               }
+
+               /* Fetch the value parameters to this instruction */
+               flags = insn->flags;
+               if((flags & JIT_INSN_DEST_OTHER_FLAGS) == 0)
+               {
+                       dest = insn->dest;
+                       if(dest && dest->is_constant)
+                       {
+                               dest = 0;
+                       }
+               }
+               else
+               {
+                       dest = 0;
+               }
+               if((flags & JIT_INSN_VALUE1_OTHER_FLAGS) == 0)
+               {
+                       value1 = insn->value1;
+                       if(value1 && value1->is_constant)
+                       {
+                               value1 = 0;
+                       }
+               }
+               else
+               {
+                       value1 = 0;
+               }
+               if((flags & JIT_INSN_VALUE2_OTHER_FLAGS) == 0)
+               {
+                       value2 = insn->value2;
+                       if(value2 && value2->is_constant)
+                       {
+                               value2 = 0;
+                       }
+               }
+               else
+               {
+                       value2 = 0;
+               }
+
+               /* Record the liveness information in the instruction flags */
+               flags &= ~JIT_INSN_LIVENESS_FLAGS;
+               if(dest)
+               {
+                       if(dest->live)
+                       {
+                               flags |= JIT_INSN_DEST_LIVE;
+                       }
+                       if(dest->next_use)
+                       {
+                               flags |= JIT_INSN_DEST_NEXT_USE;
+                       }
+               }
+               if(value1)
+               {
+                       if(value1->live)
+                       {
+                               flags |= JIT_INSN_VALUE1_LIVE;
+                       }
+                       if(value1->next_use)
+                       {
+                               flags |= JIT_INSN_VALUE1_NEXT_USE;
+                       }
+               }
+               if(value2)
+               {
+                       if(value2->live)
+                       {
+                               flags |= JIT_INSN_VALUE2_LIVE;
+                       }
+                       if(value2->next_use)
+                       {
+                               flags |= JIT_INSN_VALUE2_NEXT_USE;
+                       }
+               }
+               insn->flags = (short)flags;
+
+               /* Set the destination to "not live, no next use" */
+               if(dest)
+               {
+                       if((flags & JIT_INSN_DEST_IS_VALUE) == 0)
+                       {
+                               if(!(dest->next_use) && !(dest->live))
+                               {
+                                       /* There is no next use of this value and it is not
+                                          live on exit from the block.  So we can discard
+                                          the entire instruction as it will have no effect */
+                                       insn->opcode = (short)JIT_OP_NOP;
+                                       continue;
+                               }
+                               dest->live = 0;
+                               dest->next_use = 0;
+                       }
+                       else
+                       {
+                               /* The destination is actually a source value for this
+                                  instruction (e.g. JIT_OP_STORE_RELATIVE_*) */
+                               dest->live = 1;
+                               dest->next_use = 1;
+                       }
+               }
+
+               /* Set value1 and value2 to "live, next use" */
+               if(value1)
+               {
+                       value1->live = 1;
+                       value1->next_use = 1;
+               }
+               if(value2)
+               {
+                       value2->live = 1;
+                       value2->next_use = 1;
+               }
+       }
+
+       /* Re-scan the block to reset the liveness flags on all non-temporaries
+          because we need them in the original state for the next block */
+       jit_insn_iter_init_last(&iter, block);
+       while((insn = jit_insn_iter_previous(&iter)) != 0)
+       {
+               flags = insn->flags;
+               if((flags & JIT_INSN_DEST_OTHER_FLAGS) == 0)
+               {
+                       dest = insn->dest;
+                       if(dest && !(dest->is_constant) && !(dest->is_temporary))
+                       {
+                               dest->live = 1;
+                               dest->next_use = 0;
+                       }
+               }
+               if((flags & JIT_INSN_VALUE1_OTHER_FLAGS) == 0)
+               {
+                       value1 = insn->value1;
+                       if(value1 && !(value1->is_constant) && !(value1->is_temporary))
+                       {
+                               value1->live = 1;
+                               value1->next_use = 0;
+                       }
+               }
+               if((flags & JIT_INSN_VALUE2_OTHER_FLAGS) == 0)
+               {
+                       value2 = insn->value2;
+                       if(value2 && !(value2->is_constant) && !(value2->is_temporary))
+                       {
+                               value2->live = 1;
+                               value2->next_use = 0;
+                       }
+               }
+       }
+}
+
+void _jit_function_compute_liveness(jit_function_t func)
+{
+       jit_block_t block = func->builder->first_block;
+       while(block != 0)
+       {
+               compute_liveness_for_block(block);
+               block = block->next;
+       }
+}
diff --git a/jit/jit-memory.c b/jit/jit-memory.c
new file mode 100644 (file)
index 0000000..06056ab
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * jit-memory.c - Memory copy/set/compare routines.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-memory.h"
+
+/*
+ * Undefine the macros in "jit-memory.h" so that we
+ * can define the real function forms.
+ */
+#undef jit_memset
+#undef jit_memcpy
+#undef jit_memmove
+#undef jit_memcmp
+#undef jit_memchr
+
+/*@
+ * @section Memory set, copy, compare, etc
+ * @cindex Memory operations
+ *
+ * The following functions are provided to set, copy, compare, and search
+ * memory blocks.
+@*/
+
+/*@
+ * @deftypefun {void *} jit_memset ({void *} dest, int ch, {unsigned int} len)
+ * Set the @code{len} bytes at @code{dest} to the value @code{ch}.
+ * Returns @code{dest}.
+ * @end deftypefun
+@*/
+void *jit_memset(void *dest, int ch, unsigned int len)
+{
+#ifdef HAVE_MEMSET
+       return memset(dest, ch, len);
+#else
+       unsigned char *d = (unsigned char *)dest;
+       while(len > 0)
+       {
+               *d++ = (unsigned char)ch;
+               --len;
+       }
+       return dest;
+#endif
+}
+
+/*@
+ * @deftypefun {void *} jit_memcpy ({void *} dest, {const void *} src, {unsigned int} len)
+ * Copy the @code{len} bytes at @code{src} to @code{dest}.  Returns
+ * @code{dest}.  The behavior is undefined if the blocks overlap
+ * (use @code{jit_memmove} instead for that case).
+ * @end deftypefun
+@*/
+void *jit_memcpy(void *dest, const void *src, unsigned int len)
+{
+#if defined(HAVE_MEMCPY)
+       return memcpy(dest, src, len);
+#elif defined(HAVE_BCOPY)
+       bcopy(src, dest, len);
+       return dest;
+#else
+       unsigned char *d = (unsigned char *)dest;
+       const unsigned char *s = (const unsigned char *)src;
+       while(len > 0)
+       {
+               *d++ = *s++;
+               --len;
+       }
+       return dest;
+#endif
+}
+
+/*@
+ * @deftypefun {void *} jit_memmove ({void *} dest, {const void *} src, {unsigned int} len)
+ * Copy the @code{len} bytes at @code{src} to @code{dest} and handle
+ * overlapping blocks correctly.  Returns @code{dest}.
+ * @end deftypefun
+@*/
+void *jit_memmove(void *dest, const void *src, unsigned int len)
+{
+#ifdef HAVE_MEMMOVE
+       return memmove(dest, src, len);
+#else
+       unsigned char *d = (unsigned char *)dest;
+       const unsigned char *s = (const unsigned char *)src;
+       if(((const unsigned char *)d) < s)
+       {
+               while(len > 0)
+               {
+                       *d++ = *s++;
+                       --len;
+               }
+       }
+       else
+       {
+               d += len;
+               s += len;
+               while(len > 0)
+               {
+                       *(--d) = *(--s);
+                       --len;
+               }
+       }
+       return dest;
+#endif
+}
+
+/*@
+ * @deftypefun int jit_memcmp ({const void *} s1, {const void *} s2, {unsigned int} len)
+ * Compare @code{len} bytes at @code{s1} and @code{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.
+ * @end deftypefun
+@*/
+int jit_memcmp(const void *s1, const void *s2, unsigned int len)
+{
+#if defined(HAVE_MEMCMP)
+       return memcmp(s1, s2, len);
+#elif defined(HAVE_BCMP)
+       return bcmp(s1, s2, len);
+#else
+       const unsigned char *str1 = (const unsigned char *)s1;
+       const unsigned char *str2 = (const unsigned char *)s2;
+       while(len > 0)
+       {
+               if(*str1 < *str2)
+                       return -1;
+               else if(*str1 > *str2)
+                       return 1;
+               ++str1;
+               ++str2;
+               --len;
+       }
+       return 0;
+#endif
+}
+
+/*@
+ * @deftypefun {void *} jit_memchr ({void *} str, int ch, {unsigned int} len)
+ * Search the @code{len} bytes at @code{str} for the first instance of
+ * the value @code{ch}.  Returns the location of @code{ch} if it was found,
+ * or NULL if it was not found.
+ * @end deftypefun
+@*/
+void *jit_memchr(const void *str, int ch, unsigned int len)
+{
+#ifdef HAVE_MEMCHR
+       return memchr(str, ch, len);
+#else
+       const unsigned char *s = (const unsigned char *)str;
+       while(len > 0)
+       {
+               if(*s == (unsigned char)ch)
+               {
+                       return (void *)s;
+               }
+               ++s;
+               --len;
+       }
+       return (void *)0;
+#endif
+}
diff --git a/jit/jit-memory.h b/jit/jit-memory.h
new file mode 100644 (file)
index 0000000..6a1800c
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * jit-memory.h - Memory copy/set/compare routines.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_MEMORY_H
+#define        _JIT_MEMORY_H
+
+#include <config.h>
+#ifdef HAVE_STRING_H
+       #include <string.h>
+#else
+       #ifdef HAVE_STRINGS_H
+               #include <strings.h>
+       #endif
+#endif
+#ifdef HAVE_MEMORY_H
+       #include <memory.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Macros that replace the routines in <jit/jit-util.h>
+ * with direct calls on the underlying library functions.
+ */
+#ifdef HAVE_MEMSET
+       #define jit_memset(dest,ch,len) (memset((dest), (ch), (len)))
+       #define jit_memzero(dest,len)   (memset((dest), 0, (len)))
+#else
+       #ifdef HAVE_BZERO
+               #define jit_memzero(dest,len)   (bzero((char *)(dest), (len)))
+       #else
+               #define jit_memzero(dest,len)   (jit_memset((char *)(dest), 0, (len)))
+       #endif
+#endif
+#ifdef HAVE_MEMCPY
+       #define jit_memcpy(dest,src,len)        (memcpy((dest), (src), (len)))
+#endif
+#ifdef HAVE_MEMMOVE
+       #define jit_memmove(dest,src,len)       (memmove((dest), (src), (len)))
+#endif
+#ifdef HAVE_MEMCMP
+       #define jit_memcmp(s1,s2,len)           (memcmp((s1), (s2), (len)))
+#else
+       #ifdef HAVE_BCMP
+               #define jit_memcmp(s1,s2,len)   \
+                                       (bcmp((char *)(s1), (char *)(s2), (len)))
+       #endif
+#endif
+#ifdef HAVE_MEMCHR
+       #define jit_memchr(str,ch,len)  (memchr((str), (ch), (len)))
+#endif
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_MEMORY_H */
diff --git a/jit/jit-meta.c b/jit/jit-meta.c
new file mode 100644 (file)
index 0000000..f8d856b
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * jit-meta.c - Functions for manipulating metadata lists.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+
+/*@
+
+@section Metadata handling
+@cindex Metadata handling
+@cindex jit-meta.h
+
+Many of the structures in the @code{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. @code{jit_function_set_meta}, @code{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:
+
+@*/
+
+/*@
+ * @deftypefun 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 @code{type} is already present
+ * in the list, then its previous value will be freed.  The @code{free_func}
+ * is called when the metadata value is freed with @code{jit_meta_free}
+ * or @code{jit_meta_destroy}.  Returns zero if out of memory.
+ *
+ * If @code{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.
+ * @end deftypefun
+@*/
+int jit_meta_set(jit_meta_t *list, int type, void *data,
+                                jit_meta_free_func free_data, jit_function_t pool_owner)
+{
+       jit_meta_t current;
+
+       /* See if we already have this type in the list */
+       current = *list;
+       while(current != 0)
+       {
+               if(current->type == type)
+               {
+                       if(data == current->data)
+                       {
+                               /* The value is unchanged, so don't free the previous value */
+                               return 1;
+                       }
+                       if(current->free_data)
+                       {
+                               (*(current->free_data))(current->data);
+                       }
+                       current->data = data;
+                       current->free_data = free_data;
+                       return 1;
+               }
+               current = current->next;
+       }
+
+       /* Create a new metadata block and add it to the list */
+       if(pool_owner)
+       {
+               if((current = jit_memory_pool_alloc
+                               (&(pool_owner->builder->meta_pool), struct _jit_meta)) == 0)
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               if((current = jit_new(struct _jit_meta)) == 0)
+               {
+                       return 0;
+               }
+       }
+       current->type = type;
+       current->data = data;
+       current->free_data = free_data;
+       current->next = *list;
+       current->pool_owner = pool_owner;
+       *list = current;
+       return 1;
+}
+
+/*@
+ * @deftypefun {void *} jit_meta_get (jit_meta_t list, int type)
+ * Get the value associated with @code{type} in the specified @code{list}.
+ * Returns NULL if @code{type} is not present.
+ * @end deftypefun
+@*/
+void *jit_meta_get(jit_meta_t list, int type)
+{
+       while(list != 0)
+       {
+               if(list->type == type)
+               {
+                       return list->data;
+               }
+               list = list->next;
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun void jit_meta_free ({jit_meta_t *} list, int type)
+ * Free the metadata value in the @code{list} that has the
+ * specified @code{type}.  Does nothing if the @code{type}
+ * is not present.
+ * @end deftypefun
+@*/
+void jit_meta_free(jit_meta_t *list, int type)
+{
+       jit_meta_t current = *list;
+       jit_meta_t prev = 0;
+       while(current != 0)
+       {
+               if(current->type == type)
+               {
+                       if(current->free_data)
+                       {
+                               (*(current->free_data))(current->data);
+                               current->free_data = 0;
+                       }
+                       if(prev)
+                       {
+                               prev->next = current->next;
+                       }
+                       else
+                       {
+                               *list = current->next;
+                       }
+                       if(current->pool_owner)
+                       {
+                               jit_memory_pool_dealloc
+                                       (&(current->pool_owner->builder->meta_pool), current);
+                       }
+                       else
+                       {
+                               jit_free(current);
+                       }
+                       return;
+               }
+               else
+               {
+                       prev = current;
+                       current = current->next;
+               }
+       }
+}
+
+/*@
+ * @deftypefun void jit_meta_destroy ({jit_meta_t *}list)
+ * Destroy all of the metadata values in the specified @code{list}.
+ * @end deftypefun
+@*/
+void jit_meta_destroy(jit_meta_t *list)
+{
+       jit_meta_t current = *list;
+       jit_meta_t next;
+       while(current != 0)
+       {
+               next = current->next;
+               if(current->free_data)
+               {
+                       (*(current->free_data))(current->data);
+                       current->free_data = 0;
+               }
+               if(current->pool_owner)
+               {
+                       jit_memory_pool_dealloc
+                               (&(current->pool_owner->builder->meta_pool), current);
+               }
+               else
+               {
+                       jit_free(current);
+               }
+               current = next;
+       }
+}
+
+void _jit_meta_free_one(void *meta)
+{
+       jit_meta_t current = (jit_meta_t)meta;
+       if(current->free_data)
+       {
+               (*(current->free_data))(current->data);
+       }
+}
diff --git a/jit/jit-opcode.c b/jit/jit-opcode.c
new file mode 100644 (file)
index 0000000..ce86446
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * jit-opcode.c - Information about all of the JIT opcodes.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-rules.h"
+
+#define        F_(dest,src1,src2)      \
+       (JIT_OPCODE_DEST_##dest | JIT_OPCODE_SRC1_##src1 | JIT_OPCODE_SRC2_##src2)
+#define        O_(dest,src1,src2,oper) \
+       (JIT_OPCODE_DEST_##dest | JIT_OPCODE_SRC1_##src1 | \
+        JIT_OPCODE_SRC2_##src2 | JIT_OPCODE_OPER_##oper)
+#define        B_(src1,src2)   \
+       (JIT_OPCODE_IS_BRANCH | JIT_OPCODE_SRC1_##src1 | JIT_OPCODE_SRC2_##src2)
+#define        A_(src1,src2,oper)      \
+       (JIT_OPCODE_IS_BRANCH | JIT_OPCODE_SRC1_##src1 | \
+        JIT_OPCODE_SRC2_##src2 | JIT_OPCODE_OPER_##oper)
+#if defined(JIT_BACKEND_INTERP)
+       #define NINT_ARG                        JIT_OPCODE_NINT_ARG
+       #define NINT_ARG_TWO            JIT_OPCODE_NINT_ARG_TWO
+       #define INDIRECT_ARGS           JIT_OPCODE_CALL_INDIRECT_ARGS
+#else
+       #define NINT_ARG                        0
+       #define NINT_ARG_TWO            0
+       #define INDIRECT_ARGS           0
+#endif
+
+jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = {
+
+       /*
+        * Simple opcodes.
+        */
+       {"nop",                                                 F_(EMPTY, EMPTY, EMPTY)},
+
+       /*
+        * Conversion opcodes.
+        */
+       {"trunc_sbyte",                                 F_(INT, INT, EMPTY)},
+       {"trunc_ubyte",                                 F_(INT, INT, EMPTY)},
+       {"trunc_short",                                 F_(INT, INT, EMPTY)},
+       {"trunc_ushort",                                F_(INT, INT, EMPTY)},
+       {"trunc_int",                                   F_(INT, INT, EMPTY)},
+       {"trunc_uint",                                  F_(INT, INT, EMPTY)},
+       {"check_sbyte",                                 F_(INT, INT, EMPTY)},
+       {"check_ubyte",                                 F_(INT, INT, EMPTY)},
+       {"check_short",                                 F_(INT, INT, EMPTY)},
+       {"check_ushort",                                F_(INT, INT, EMPTY)},
+       {"check_int",                                   F_(INT, INT, EMPTY)},
+       {"check_uint",                                  F_(INT, INT, EMPTY)},
+       {"low_word",                                    F_(INT, LONG, EMPTY)},
+       {"expand_int",                                  F_(LONG, INT, EMPTY)},
+       {"expand_uint",                                 F_(LONG, INT, EMPTY)},
+       {"check_low_word",                              F_(INT, LONG, EMPTY)},
+       {"check_signed_low_word",               F_(INT, LONG, EMPTY)},
+       {"check_long",                                  F_(LONG, LONG, EMPTY)},
+       {"check_ulong",                                 F_(LONG, LONG, EMPTY)},
+       {"nfloat_to_int",                               F_(INT, NFLOAT, EMPTY)},
+       {"nfloat_to_uint",                              F_(INT, NFLOAT, EMPTY)},
+       {"nfloat_to_long",                              F_(LONG, NFLOAT, EMPTY)},
+       {"nfloat_to_ulong",                             F_(LONG, NFLOAT, EMPTY)},
+       {"check_nfloat_to_int",                 F_(INT, NFLOAT, EMPTY)},
+       {"check_nfloat_to_uint",                F_(INT, NFLOAT, EMPTY)},
+       {"check_nfloat_to_long",                F_(LONG, NFLOAT, EMPTY)},
+       {"check_nfloat_to_ulong",               F_(LONG, NFLOAT, EMPTY)},
+       {"int_to_nfloat",                               F_(NFLOAT, INT, EMPTY)},
+       {"uint_to_nfloat",                              F_(NFLOAT, INT, EMPTY)},
+       {"long_to_nfloat",                              F_(NFLOAT, LONG, EMPTY)},
+       {"ulong_to_nfloat",                             F_(NFLOAT, LONG, EMPTY)},
+       {"nfloat_to_float32",                   F_(FLOAT32, NFLOAT, EMPTY)},
+       {"nfloat_to_float64",                   F_(FLOAT64, NFLOAT, EMPTY)},
+       {"float32_to_nfloat",                   F_(NFLOAT, FLOAT32, EMPTY)},
+       {"float64_to_nfloat",                   F_(NFLOAT, FLOAT64, EMPTY)},
+
+       /*
+        * Arithmetic opcodes.
+        */
+       {"iadd",                                                O_(INT, INT, INT, ADD)},
+       {"iadd_ovf",                                    F_(INT, INT, INT)},
+       {"iadd_ovf_un",                                 F_(INT, INT, INT)},
+       {"isub",                                                O_(INT, INT, INT, SUB)},
+       {"isub_ovf",                                    F_(INT, INT, INT)},
+       {"isub_ovf_un",                                 F_(INT, INT, INT)},
+       {"imul",                                                O_(INT, INT, INT, MUL)},
+       {"imul_ovf",                                    F_(INT, INT, INT)},
+       {"imul_ovf_un",                                 F_(INT, INT, INT)},
+       {"idiv",                                                O_(INT, INT, INT, DIV)},
+       {"idiv_un",                                             F_(INT, INT, INT)},
+       {"irem",                                                O_(INT, INT, INT, REM)},
+       {"irem_un",                                             F_(INT, INT, INT)},
+       {"ineg",                                                O_(INT, INT, EMPTY, NEG)},
+       {"ladd",                                                O_(LONG, LONG, LONG, ADD)},
+       {"ladd_ovf",                                    F_(LONG, LONG, LONG)},
+       {"ladd_ovf_un",                                 F_(LONG, LONG, LONG)},
+       {"lsub",                                                O_(LONG, LONG, LONG, SUB)},
+       {"lsub_ovf",                                    F_(LONG, LONG, LONG)},
+       {"lsub_ovf_un",                                 F_(LONG, LONG, LONG)},
+       {"lmul",                                                O_(LONG, LONG, LONG, MUL)},
+       {"lmul_ovf",                                    F_(LONG, LONG, LONG)},
+       {"lmul_ovf_un",                                 F_(LONG, LONG, LONG)},
+       {"ldiv",                                                O_(LONG, LONG, LONG, DIV)},
+       {"ldiv_un",                                             F_(LONG, LONG, LONG)},
+       {"lrem",                                                O_(LONG, LONG, LONG, REM)},
+       {"lrem_un",                                             F_(LONG, LONG, LONG)},
+       {"lneg",                                                O_(LONG, LONG, EMPTY, NEG)},
+       {"fadd",                                                O_(FLOAT32, FLOAT32, FLOAT32, ADD)},
+       {"fsub",                                                O_(FLOAT32, FLOAT32, FLOAT32, SUB)},
+       {"fmul",                                                O_(FLOAT32, FLOAT32, FLOAT32, MUL)},
+       {"fdiv",                                                O_(FLOAT32, FLOAT32, FLOAT32, DIV)},
+       {"frem",                                                O_(FLOAT32, FLOAT32, FLOAT32, REM)},
+       {"frem_ieee",                                   F_(FLOAT32, FLOAT32, FLOAT32)},
+       {"fneg",                                                O_(FLOAT32, FLOAT32, EMPTY, NEG)},
+       {"dadd",                                                O_(FLOAT64, FLOAT64, FLOAT64, ADD)},
+       {"dsub",                                                O_(FLOAT64, FLOAT64, FLOAT64, SUB)},
+       {"dmul",                                                O_(FLOAT64, FLOAT64, FLOAT64, MUL)},
+       {"ddiv",                                                O_(FLOAT64, FLOAT64, FLOAT64, DIV)},
+       {"drem",                                                O_(FLOAT64, FLOAT64, FLOAT64, REM)},
+       {"drem_ieee",                                   F_(FLOAT64, FLOAT64, FLOAT64)},
+       {"dneg",                                                O_(FLOAT64, FLOAT64, EMPTY, NEG)},
+       {"nfadd",                                               O_(NFLOAT, NFLOAT, NFLOAT, ADD)},
+       {"nfsub",                                               O_(NFLOAT, NFLOAT, NFLOAT, SUB)},
+       {"nfmul",                                               O_(NFLOAT, NFLOAT, NFLOAT, MUL)},
+       {"nfdiv",                                               O_(NFLOAT, NFLOAT, NFLOAT, DIV)},
+       {"nfrem",                                               O_(NFLOAT, NFLOAT, NFLOAT, REM)},
+       {"nfrem_ieee",                                  F_(NFLOAT, NFLOAT, NFLOAT)},
+       {"nfneg",                                               O_(NFLOAT, NFLOAT, EMPTY, NEG)},
+
+       /*
+        * Bitwise opcodes.
+        */
+       {"iand",                                                O_(INT, INT, INT, AND)},
+       {"ior",                                                 O_(INT, INT, INT, OR)},
+       {"ixor",                                                O_(INT, INT, INT, XOR)},
+       {"inot",                                                O_(INT, INT, EMPTY, NOT)},
+       {"ishl",                                                O_(INT, INT, INT, SHL)},
+       {"ishr",                                                O_(INT, INT, INT, SHR)},
+       {"ishr_un",                                             O_(INT, INT, INT, SHR_UN)},
+       {"land",                                                O_(LONG, LONG, LONG, AND)},
+       {"lor",                                                 O_(LONG, LONG, LONG, OR)},
+       {"lxor",                                                O_(LONG, LONG, LONG, XOR)},
+       {"lnot",                                                O_(LONG, LONG, EMPTY, NOT)},
+       {"lshl",                                                O_(LONG, LONG, INT, SHL)},
+       {"lshr",                                                O_(LONG, LONG, INT, SHR)},
+       {"lshr_un",                                             O_(LONG, LONG, INT, SHR_UN)},
+
+       /*
+        * Branch opcodes.
+        */
+       {"br",                                                  B_(EMPTY, EMPTY)},
+       {"br_ifalse",                                   B_(INT, EMPTY)},
+       {"br_itrue",                                    B_(INT, EMPTY)},
+       {"br_ieq",                                              A_(INT, INT, EQ)},
+       {"br_ine",                                              A_(INT, INT, NE)},
+       {"br_ilt",                                              A_(INT, INT, LT)},
+       {"br_ilt_un",                                   B_(INT, INT)},
+       {"br_ile",                                              A_(INT, INT, LE)},
+       {"br_ile_un",                                   B_(INT, INT)},
+       {"br_igt",                                              A_(INT, INT, GT)},
+       {"br_igt_un",                                   B_(INT, INT)},
+       {"br_ige",                                              A_(INT, INT, GE)},
+       {"br_ige_un",                                   B_(INT, INT)},
+       {"br_lfalse",                                   B_(LONG, EMPTY)},
+       {"br_ltrue",                                    B_(LONG, EMPTY)},
+       {"br_leq",                                              A_(LONG, LONG, EQ)},
+       {"br_lne",                                              A_(LONG, LONG, NE)},
+       {"br_llt",                                              A_(LONG, LONG, LT)},
+       {"br_llt_un",                                   B_(LONG, LONG)},
+       {"br_lle",                                              A_(LONG, LONG, LE)},
+       {"br_lle_un",                                   B_(LONG, LONG)},
+       {"br_lgt",                                              A_(LONG, LONG, GT)},
+       {"br_lgt_un",                                   B_(LONG, LONG)},
+       {"br_lge",                                              A_(LONG, LONG, GE)},
+       {"br_lge_un",                                   B_(LONG, LONG)},
+       {"br_feq",                                              A_(FLOAT32, FLOAT32, EQ)},
+       {"br_fne",                                              A_(FLOAT32, FLOAT32, NE)},
+       {"br_flt",                                              A_(FLOAT32, FLOAT32, LT)},
+       {"br_fle",                                              A_(FLOAT32, FLOAT32, LE)},
+       {"br_fgt",                                              A_(FLOAT32, FLOAT32, GT)},
+       {"br_fge",                                              A_(FLOAT32, FLOAT32, GE)},
+       {"br_feq_inv",                                  B_(FLOAT32, FLOAT32)},
+       {"br_fne_inv",                                  B_(FLOAT32, FLOAT32)},
+       {"br_flt_inv",                                  B_(FLOAT32, FLOAT32)},
+       {"br_fle_inv",                                  B_(FLOAT32, FLOAT32)},
+       {"br_fgt_inv",                                  B_(FLOAT32, FLOAT32)},
+       {"br_fge_inv",                                  B_(FLOAT32, FLOAT32)},
+       {"br_deq",                                              A_(FLOAT64, FLOAT64, EQ)},
+       {"br_dne",                                              A_(FLOAT64, FLOAT64, NE)},
+       {"br_dlt",                                              A_(FLOAT64, FLOAT64, LT)},
+       {"br_dle",                                              A_(FLOAT64, FLOAT64, LE)},
+       {"br_dgt",                                              A_(FLOAT64, FLOAT64, GT)},
+       {"br_dge",                                              A_(FLOAT64, FLOAT64, GE)},
+       {"br_deq_inv",                                  B_(FLOAT64, FLOAT64)},
+       {"br_dne_inv",                                  B_(FLOAT64, FLOAT64)},
+       {"br_dlt_inv",                                  B_(FLOAT64, FLOAT64)},
+       {"br_dle_inv",                                  B_(FLOAT64, FLOAT64)},
+       {"br_dgt_inv",                                  B_(FLOAT64, FLOAT64)},
+       {"br_dge_inv",                                  B_(FLOAT64, FLOAT64)},
+       {"br_nfeq",                                             A_(NFLOAT, NFLOAT, EQ)},
+       {"br_nfne",                                             A_(NFLOAT, NFLOAT, NE)},
+       {"br_nflt",                                             A_(NFLOAT, NFLOAT, LT)},
+       {"br_nfle",                                             A_(NFLOAT, NFLOAT, LE)},
+       {"br_nfgt",                                             A_(NFLOAT, NFLOAT, GT)},
+       {"br_nfge",                                             A_(NFLOAT, NFLOAT, GE)},
+       {"br_nfeq_inv",                                 B_(NFLOAT, NFLOAT)},
+       {"br_nfne_inv",                                 B_(NFLOAT, NFLOAT)},
+       {"br_nflt_inv",                                 B_(NFLOAT, NFLOAT)},
+       {"br_nfle_inv",                                 B_(NFLOAT, NFLOAT)},
+       {"br_nfgt_inv",                                 B_(NFLOAT, NFLOAT)},
+       {"br_nfge_inv",                                 B_(NFLOAT, NFLOAT)},
+
+       /*
+        * Comparison opcodes.
+        */
+       {"icmp",                                                F_(INT, INT, INT)},
+       {"icmp_un",                                             F_(INT, INT, INT)},
+       {"lcmp",                                                F_(INT, LONG, LONG)},
+       {"lcmp_un",                                             F_(INT, LONG, LONG)},
+       {"fcmpl",                                               F_(INT, FLOAT32, FLOAT32)},
+       {"fcmpg",                                               F_(INT, FLOAT32, FLOAT32)},
+       {"dcmpl",                                               F_(INT, FLOAT64, FLOAT64)},
+       {"dcmpg",                                               F_(INT, FLOAT64, FLOAT64)},
+       {"nfcmpl",                                              F_(INT, NFLOAT, NFLOAT)},
+       {"nfcmpg",                                              F_(INT, NFLOAT, NFLOAT)},
+       {"ieq",                                                 O_(INT, INT, INT, EQ)},
+       {"ine",                                                 O_(INT, INT, INT, NE)},
+       {"ilt",                                                 O_(INT, INT, INT, LT)},
+       {"ilt_un",                                              F_(INT, INT, INT)},
+       {"ile",                                                 O_(INT, INT, INT, LE)},
+       {"ile_un",                                              F_(INT, INT, INT)},
+       {"igt",                                                 O_(INT, INT, INT, GT)},
+       {"igt_un",                                              F_(INT, INT, INT)},
+       {"ige",                                                 O_(INT, INT, INT, GE)},
+       {"ige_un",                                              F_(INT, INT, INT)},
+       {"leq",                                                 O_(INT, LONG, LONG, EQ)},
+       {"lne",                                                 O_(INT, LONG, LONG, NE)},
+       {"llt",                                                 O_(INT, LONG, LONG, LT)},
+       {"llt_un",                                              F_(INT, LONG, LONG)},
+       {"lle",                                                 O_(INT, LONG, LONG, LE)},
+       {"lle_un",                                              F_(INT, LONG, LONG)},
+       {"lgt",                                                 O_(INT, LONG, LONG, GT)},
+       {"lgt_un",                                              F_(INT, LONG, LONG)},
+       {"lge",                                                 O_(INT, LONG, LONG, GE)},
+       {"lge_un",                                              F_(INT, LONG, LONG)},
+       {"feq",                                                 O_(INT, FLOAT32, FLOAT32, EQ)},
+       {"fne",                                                 O_(INT, FLOAT32, FLOAT32, NE)},
+       {"flt",                                                 O_(INT, FLOAT32, FLOAT32, LT)},
+       {"fle",                                                 O_(INT, FLOAT32, FLOAT32, LE)},
+       {"fgt",                                                 O_(INT, FLOAT32, FLOAT32, GT)},
+       {"fge",                                                 O_(INT, FLOAT32, FLOAT32, GE)},
+       {"feq_inv",                                             F_(INT, FLOAT32, FLOAT32)},
+       {"fne_inv",                                             F_(INT, FLOAT32, FLOAT32)},
+       {"flt_inv",                                             F_(INT, FLOAT32, FLOAT32)},
+       {"fle_inv",                                             F_(INT, FLOAT32, FLOAT32)},
+       {"fgt_inv",                                             F_(INT, FLOAT32, FLOAT32)},
+       {"fge_inv",                                             F_(INT, FLOAT32, FLOAT32)},
+       {"deq",                                                 O_(INT, FLOAT64, FLOAT64, EQ)},
+       {"dne",                                                 O_(INT, FLOAT64, FLOAT64, NE)},
+       {"dlt",                                                 O_(INT, FLOAT64, FLOAT64, LT)},
+       {"dle",                                                 O_(INT, FLOAT64, FLOAT64, LE)},
+       {"dgt",                                                 O_(INT, FLOAT64, FLOAT64, GT)},
+       {"dge",                                                 O_(INT, FLOAT64, FLOAT64, GE)},
+       {"deq_inv",                                             F_(INT, FLOAT64, FLOAT64)},
+       {"dne_inv",                                             F_(INT, FLOAT64, FLOAT64)},
+       {"dlt_inv",                                             F_(INT, FLOAT64, FLOAT64)},
+       {"dle_inv",                                             F_(INT, FLOAT64, FLOAT64)},
+       {"dgt_inv",                                             F_(INT, FLOAT64, FLOAT64)},
+       {"dge_inv",                                             F_(INT, FLOAT64, FLOAT64)},
+       {"nfeq",                                                O_(INT, NFLOAT, NFLOAT, EQ)},
+       {"nfne",                                                O_(INT, NFLOAT, NFLOAT, NE)},
+       {"nflt",                                                O_(INT, NFLOAT, NFLOAT, LT)},
+       {"nfle",                                                O_(INT, NFLOAT, NFLOAT, LE)},
+       {"nfgt",                                                O_(INT, NFLOAT, NFLOAT, GT)},
+       {"nfge",                                                O_(INT, NFLOAT, NFLOAT, GE)},
+       {"nfeq_inv",                                    F_(INT, NFLOAT, NFLOAT)},
+       {"nfne_inv",                                    F_(INT, NFLOAT, NFLOAT)},
+       {"nflt_inv",                                    F_(INT, NFLOAT, NFLOAT)},
+       {"nfle_inv",                                    F_(INT, NFLOAT, NFLOAT)},
+       {"nfgt_inv",                                    F_(INT, NFLOAT, NFLOAT)},
+       {"nfge_inv",                                    F_(INT, NFLOAT, NFLOAT)},
+       {"is_fnan",                                             F_(INT, FLOAT32, EMPTY)},
+       {"is_finf",                                             F_(INT, FLOAT32, EMPTY)},
+       {"is_ffinite",                                  F_(INT, FLOAT32, EMPTY)},
+       {"is_dnan",                                             F_(INT, FLOAT64, EMPTY)},
+       {"is_dinf",                                             F_(INT, FLOAT64, EMPTY)},
+       {"is_dfinite",                                  F_(INT, FLOAT64, EMPTY)},
+       {"is_nfnan",                                    F_(INT, NFLOAT, EMPTY)},
+       {"is_nfinf",                                    F_(INT, NFLOAT, EMPTY)},
+       {"is_nffinite",                                 F_(INT, NFLOAT, EMPTY)},
+
+       /*
+        * Mathematical functions.
+        */
+       {"facos",                                               F_(FLOAT32, FLOAT32, EMPTY)},
+       {"fasin",                                               F_(FLOAT32, FLOAT32, EMPTY)},
+       {"fatan",                                               F_(FLOAT32, FLOAT32, EMPTY)},
+       {"fatan2",                                              F_(FLOAT32, FLOAT32, FLOAT32)},
+       {"fceil",                                               F_(FLOAT32, FLOAT32, EMPTY)},
+       {"fcos",                                                F_(FLOAT32, FLOAT32, EMPTY)},
+       {"fcosh",                                               F_(FLOAT32, FLOAT32, EMPTY)},
+       {"fexp",                                                F_(FLOAT32, FLOAT32, EMPTY)},
+       {"ffloor",                                              F_(FLOAT32, FLOAT32, EMPTY)},
+       {"flog",                                                F_(FLOAT32, FLOAT32, EMPTY)},
+       {"flog10",                                              F_(FLOAT32, FLOAT32, EMPTY)},
+       {"fpow",                                                F_(FLOAT32, FLOAT32, FLOAT32)},
+       {"frint",                                               F_(FLOAT32, FLOAT32, EMPTY)},
+       {"fround",                                              F_(FLOAT32, FLOAT32, EMPTY)},
+       {"fsin",                                                F_(FLOAT32, FLOAT32, EMPTY)},
+       {"fsinh",                                               F_(FLOAT32, FLOAT32, EMPTY)},
+       {"fsqrt",                                               F_(FLOAT32, FLOAT32, EMPTY)},
+       {"ftan",                                                F_(FLOAT32, FLOAT32, EMPTY)},
+       {"ftanh",                                               F_(FLOAT32, FLOAT32, EMPTY)},
+       {"dacos",                                               F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dasin",                                               F_(FLOAT64, FLOAT64, EMPTY)},
+       {"datan",                                               F_(FLOAT64, FLOAT64, EMPTY)},
+       {"datan2",                                              F_(FLOAT64, FLOAT64, FLOAT64)},
+       {"dceil",                                               F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dcos",                                                F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dcosh",                                               F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dexp",                                                F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dfloor",                                              F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dlog",                                                F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dlog10",                                              F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dpow",                                                F_(FLOAT64, FLOAT64, FLOAT64)},
+       {"drint",                                               F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dround",                                              F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dsin",                                                F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dsinh",                                               F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dsqrt",                                               F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dtan",                                                F_(FLOAT64, FLOAT64, EMPTY)},
+       {"dtanh",                                               F_(FLOAT64, FLOAT64, EMPTY)},
+       {"nfacos",                                              F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nfasin",                                              F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nfatan",                                              F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nfatan2",                                             F_(NFLOAT, NFLOAT, NFLOAT)},
+       {"nfceil",                                              F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nfcos",                                               F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nfcosh",                                              F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nfexp",                                               F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nffloor",                                             F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nflog",                                               F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nflog10",                                             F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nfpow",                                               F_(NFLOAT, NFLOAT, NFLOAT)},
+       {"nfrint",                                              F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nfround",                                             F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nfsin",                                               F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nfsinh",                                              F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nfsqrt",                                              F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nftan",                                               F_(NFLOAT, NFLOAT, EMPTY)},
+       {"nftanh",                                              F_(NFLOAT, NFLOAT, EMPTY)},
+
+       /*
+        * Absolute, minimum, maximum, and sign.
+        */
+       {"iabs",                                                F_(INT, INT, EMPTY)},
+       {"labs",                                                F_(LONG, LONG, EMPTY)},
+       {"fabs",                                                F_(FLOAT32, FLOAT32, EMPTY)},
+       {"dabs",                                                F_(FLOAT64, FLOAT64, EMPTY)},
+       {"nfabs",                                               F_(NFLOAT, NFLOAT, EMPTY)},
+       {"imin",                                                F_(INT, INT, INT)},
+       {"imin_un",                                             F_(INT, INT, INT)},
+       {"lmin",                                                F_(LONG, LONG, LONG)},
+       {"lmin_un",                                             F_(LONG, LONG, LONG)},
+       {"fmin",                                                F_(FLOAT32, FLOAT32, FLOAT32)},
+       {"dmin",                                                F_(FLOAT64, FLOAT64, FLOAT64)},
+       {"nfmin",                                               F_(NFLOAT, NFLOAT, NFLOAT)},
+       {"imax",                                                F_(INT, INT, INT)},
+       {"imax_un",                                             F_(INT, INT, INT)},
+       {"lmax",                                                F_(LONG, LONG, LONG)},
+       {"lmax_un",                                             F_(LONG, LONG, LONG)},
+       {"fmax",                                                F_(FLOAT32, FLOAT32, FLOAT32)},
+       {"dmax",                                                F_(FLOAT64, FLOAT64, FLOAT64)},
+       {"nfmax",                                               F_(NFLOAT, NFLOAT, NFLOAT)},
+       {"isign",                                               F_(INT, INT, EMPTY)},
+       {"lsign",                                               F_(INT, LONG, EMPTY)},
+       {"fsign",                                               F_(INT, FLOAT32, EMPTY)},
+       {"dsign",                                               F_(INT, FLOAT64, EMPTY)},
+       {"nfsign",                                              F_(INT, NFLOAT, EMPTY)},
+
+       /*
+        * Pointer check opcodes.
+        */
+       {"check_null",                                  F_(EMPTY, PTR, EMPTY)},
+
+       /*
+        * Function calls.
+        */
+       {"call",                                                JIT_OPCODE_IS_CALL},
+       {"call_tail",                                   JIT_OPCODE_IS_CALL},
+       {"call_indirect",                               F_(EMPTY, PTR, EMPTY) | INDIRECT_ARGS},
+       {"call_vtable_ptr",                             F_(EMPTY, PTR, EMPTY) | INDIRECT_ARGS},
+       {"call_external",                               JIT_OPCODE_IS_CALL_EXTERNAL},
+       {"return",                                              F_(EMPTY, EMPTY, EMPTY)},
+       {"return_int",                                  F_(EMPTY, INT, EMPTY)},
+       {"return_long",                                 F_(EMPTY, LONG, EMPTY)},
+       {"return_float32",                              F_(EMPTY, FLOAT32, EMPTY)},
+       {"return_float64",                              F_(EMPTY, FLOAT64, EMPTY)},
+       {"return_nfloat",                               F_(EMPTY, NFLOAT, EMPTY)},
+       {"return_small_struct",                 F_(EMPTY, PTR, EMPTY) | NINT_ARG},
+       {"setup_for_nested",                    F_(EMPTY, INT, EMPTY)},
+       {"setup_for_sibling",                   F_(EMPTY, INT, INT) | NINT_ARG},
+       {"import",                                              F_(PTR, ANY, INT)},
+
+       /*
+        * Exception handling.
+        */
+       {"throw",                                               F_(EMPTY, PTR, EMPTY)},
+       {"load_pc",                                             F_(PTR, EMPTY, EMPTY)},
+       {"enter_catch",                                 F_(PTR, EMPTY, EMPTY)},
+       {"enter_finally",                               F_(EMPTY, EMPTY, EMPTY)},
+       {"leave_finally",                               F_(EMPTY, EMPTY, EMPTY)},
+       {"enter_filter",                                F_(ANY, EMPTY, EMPTY)},
+       {"leave_filter",                                F_(EMPTY, ANY, EMPTY)},
+       {"call_filter",                                 B_(ANY, EMPTY)},
+       {"call_filter_return",                  F_(ANY, EMPTY, EMPTY)},
+       {"prepare_for_leave",                   F_(EMPTY, EMPTY, EMPTY)},
+       {"prepare_for_return",                  F_(EMPTY, EMPTY, EMPTY)},
+
+       /*
+        * Data manipulation.
+        */
+       {"copy_load_sbyte",                             F_(INT, INT, EMPTY)},
+       {"copy_load_ubyte",                             F_(INT, INT, EMPTY)},
+       {"copy_load_short",                             F_(INT, INT, EMPTY)},
+       {"copy_load_ushort",                    F_(INT, INT, EMPTY)},
+       {"copy_int",                                    O_(INT, INT, EMPTY, COPY)},
+       {"copy_long",                                   O_(LONG, LONG, EMPTY, COPY)},
+       {"copy_float32",                                O_(FLOAT32, FLOAT32, EMPTY, COPY)},
+       {"copy_float64",                                O_(FLOAT64, FLOAT64, EMPTY, COPY)},
+       {"copy_nfloat",                                 O_(NFLOAT, NFLOAT, EMPTY, COPY)},
+       {"copy_struct",                                 O_(PTR, PTR, EMPTY, COPY)},
+       {"copy_store_byte",                             F_(INT, INT, EMPTY)},
+       {"copy_store_short",                    F_(INT, INT, EMPTY)},
+       {"address_of",                                  O_(PTR, ANY, EMPTY, ADDRESS_OF)},
+
+       /*
+        * Incoming registers, outgoing registers, and stack pushes.
+        */
+       {"incoming_reg",                                JIT_OPCODE_IS_REG},
+       {"incoming_frame_posn",                 F_(EMPTY, ANY, INT)},
+       {"outgoing_reg",                                JIT_OPCODE_IS_REG},
+       {"return_reg",                                  JIT_OPCODE_IS_REG},
+       {"push_int",                                    F_(EMPTY, INT, EMPTY)},
+       {"push_long",                                   F_(EMPTY, LONG, EMPTY)},
+       {"push_float32",                                F_(EMPTY, FLOAT32, EMPTY)},
+       {"push_float64",                                F_(EMPTY, FLOAT64, EMPTY)},
+       {"push_nfloat",                                 F_(EMPTY, NFLOAT, EMPTY)},
+       {"push_struct",                                 F_(EMPTY, ANY, EMPTY)},
+       {"pop_stack",                                   F_(EMPTY, INT, EMPTY) | NINT_ARG},
+       {"flush_small_struct",                  F_(EMPTY, ANY, EMPTY)},
+
+       /*
+        * Pointer-relative loads and stores.
+        */
+       {"load_relative_sbyte",                 F_(INT, PTR, INT) | NINT_ARG},
+       {"load_relative_ubyte",                 F_(INT, PTR, INT) | NINT_ARG},
+       {"load_relative_short",                 F_(INT, PTR, INT) | NINT_ARG},
+       {"load_relative_ushort",                F_(INT, PTR, INT) | NINT_ARG},
+       {"load_relative_int",                   F_(INT, PTR, INT) | NINT_ARG},
+       {"load_relative_long",                  F_(LONG, PTR, INT) | NINT_ARG},
+       {"load_relative_float32",               F_(FLOAT32, PTR, INT) | NINT_ARG},
+       {"load_relative_float64",               F_(FLOAT64, PTR, INT) | NINT_ARG},
+       {"load_relative_nfloat",                F_(NFLOAT, PTR, INT) | NINT_ARG},
+       {"load_relative_struct",                F_(ANY, PTR, INT) | NINT_ARG_TWO},
+       {"store_relative_byte",                 F_(PTR, INT, INT) | NINT_ARG},
+       {"store_relative_short",                F_(PTR, INT, INT) | NINT_ARG},
+       {"store_relative_int",                  F_(PTR, INT, INT) | NINT_ARG},
+       {"store_relative_long",                 F_(PTR, LONG, INT) | NINT_ARG},
+       {"store_relative_float32",              F_(PTR, FLOAT32, INT) | NINT_ARG},
+       {"store_relative_float64",              F_(PTR, FLOAT64, INT) | NINT_ARG},
+       {"store_relative_nfloat",               F_(PTR, NFLOAT, INT) | NINT_ARG},
+       {"store_relative_struct",               F_(PTR, ANY, INT) | NINT_ARG_TWO},
+       {"add_relative",                                F_(PTR, PTR, INT) | NINT_ARG},
+};
+
+#if defined(JIT_BACKEND_INTERP)
+
+jit_opcode_info_t const _jit_interp_opcodes[JIT_OP_NUM_INTERP_OPCODES] = {
+
+       /*
+        * Argument variable access opcodes.
+        */
+       {"ldarg_sbyte",                                 JIT_OPCODE_NINT_ARG},
+       {"ldarg_ubyte",                                 JIT_OPCODE_NINT_ARG},
+       {"ldarg_short",                                 JIT_OPCODE_NINT_ARG},
+       {"ldarg_ushort",                                JIT_OPCODE_NINT_ARG},
+       {"ldarg_int",                                   JIT_OPCODE_NINT_ARG},
+       {"ldarg_long",                                  JIT_OPCODE_NINT_ARG},
+       {"ldarg_float32",                               JIT_OPCODE_NINT_ARG},
+       {"ldarg_float64",                               JIT_OPCODE_NINT_ARG},
+       {"ldarg_nfloat",                                JIT_OPCODE_NINT_ARG},
+       {"ldarg_struct",                                JIT_OPCODE_NINT_ARG_TWO},
+       {"ldarga",                                              JIT_OPCODE_NINT_ARG},
+       {"starg_byte",                                  JIT_OPCODE_NINT_ARG},
+       {"starg_short",                                 JIT_OPCODE_NINT_ARG},
+       {"starg_int",                                   JIT_OPCODE_NINT_ARG},
+       {"starg_long",                                  JIT_OPCODE_NINT_ARG},
+       {"starg_float32",                               JIT_OPCODE_NINT_ARG},
+       {"starg_float64",                               JIT_OPCODE_NINT_ARG},
+       {"starg_nfloat",                                JIT_OPCODE_NINT_ARG},
+       {"starg_struct",                                JIT_OPCODE_NINT_ARG_TWO},
+
+       /*
+        * Local variable frame access opcodes.
+        */
+       {"ldloc_sbyte",                                 JIT_OPCODE_NINT_ARG},
+       {"ldloc_ubyte",                                 JIT_OPCODE_NINT_ARG},
+       {"ldloc_short",                                 JIT_OPCODE_NINT_ARG},
+       {"ldloc_ushort",                                JIT_OPCODE_NINT_ARG},
+       {"ldloc_int",                                   JIT_OPCODE_NINT_ARG},
+       {"ldloc_long",                                  JIT_OPCODE_NINT_ARG},
+       {"ldloc_float32",                               JIT_OPCODE_NINT_ARG},
+       {"ldloc_float64",                               JIT_OPCODE_NINT_ARG},
+       {"ldloc_nfloat",                                JIT_OPCODE_NINT_ARG},
+       {"ldloc_struct",                                JIT_OPCODE_NINT_ARG_TWO},
+       {"ldloca",                                              JIT_OPCODE_NINT_ARG},
+       {"stloc_byte",                                  JIT_OPCODE_NINT_ARG},
+       {"stloc_short",                                 JIT_OPCODE_NINT_ARG},
+       {"stloc_int",                                   JIT_OPCODE_NINT_ARG},
+       {"stloc_long",                                  JIT_OPCODE_NINT_ARG},
+       {"stloc_float32",                               JIT_OPCODE_NINT_ARG},
+       {"stloc_float64",                               JIT_OPCODE_NINT_ARG},
+       {"stloc_nfloat",                                JIT_OPCODE_NINT_ARG},
+       {"stloc_struct",                                JIT_OPCODE_NINT_ARG_TWO},
+
+       /*
+        * Pointer check opcodes (interpreter only).
+        */
+       {"check_null_n",                                JIT_OPCODE_NINT_ARG},
+
+       /*
+        * Stack management.
+        */
+       {"pop",                                                 0},
+       {"pop_2",                                               0},
+       {"pop_3",                                               0},
+       {"push_return_int",                             0},
+       {"push_return_long",                    0},
+       {"push_return_float32",                 0},
+       {"push_return_float64",                 0},
+       {"push_return_nfloat",                  0},
+       {"push_return_small_struct",    JIT_OPCODE_NINT_ARG},
+
+       /*
+        * Nested function call handling.
+        */
+       {"push_parent_locals",                  0},
+       {"push_parent_args",                    0},
+
+       /*
+        * Push constant values onto the stack.
+        */
+       {"push_const_int",                              JIT_OPCODE_NINT_ARG},
+       {"push_const_long",                             JIT_OPCODE_CONST_LONG},
+       {"push_const_float32",                  JIT_OPCODE_CONST_FLOAT32},
+       {"push_const_float64",                  JIT_OPCODE_CONST_FLOAT64},
+       {"push_const_nfloat",                   JIT_OPCODE_CONST_NFLOAT},
+
+       /*
+        * Exception handling (interpreter only).
+        */
+       {"call_finally",                                B_(EMPTY, EMPTY)},
+
+       /*
+        * Marker opcode for the end of a function.
+        */
+       {"end_marker",                                  0},
+};
+
+#endif /* JIT_BACKEND_INTERP */
diff --git a/jit/jit-pool.c b/jit/jit-pool.c
new file mode 100644 (file)
index 0000000..959b6be
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * jit-pool.c - Functions for managing memory pools.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-memory.h"
+
+void _jit_memory_pool_init(jit_memory_pool *pool, unsigned int elem_size)
+{
+       pool->elem_size = elem_size;
+       pool->elems_per_block = 4000 / elem_size;
+       pool->elems_in_last = pool->elems_per_block;
+       pool->blocks = 0;
+       pool->free_list = 0;
+}
+
+void _jit_memory_pool_free(jit_memory_pool *pool, jit_meta_free_func func)
+{
+       jit_pool_block_t block;
+       while(pool->blocks != 0)
+       {
+               block = pool->blocks;
+               pool->blocks = block->next;
+               if(func)
+               {
+                       while(pool->elems_in_last > 0)
+                       {
+                               --(pool->elems_in_last);
+                               (*func)(block->data + pool->elems_in_last * pool->elem_size);
+                       }
+               }
+               jit_free(block);
+               pool->elems_in_last = pool->elems_per_block;
+       }
+       pool->free_list = 0;
+}
+
+void *_jit_memory_pool_alloc(jit_memory_pool *pool)
+{
+       void *data;
+       if(pool->free_list)
+       {
+               /* Reclaim an item that was previously deallocated */
+               data = pool->free_list;
+               pool->free_list = *((void **)data);
+               jit_memzero(data, pool->elem_size);
+               return data;
+       }
+       if(pool->elems_in_last >= pool->elems_per_block)
+       {
+               data = (void *)jit_calloc(1, sizeof(struct jit_pool_block) +
+                                                                 pool->elem_size * pool->elems_per_block - 1);
+               if(!data)
+               {
+                       return 0;
+               }
+               ((jit_pool_block_t)data)->next = pool->blocks;
+               pool->blocks = (jit_pool_block_t)data;
+               pool->elems_in_last = 0;
+       }
+       data = (void *)(pool->blocks->data +
+                                       pool->elems_in_last * pool->elem_size);
+       ++(pool->elems_in_last);
+       return data;
+}
+
+void _jit_memory_pool_dealloc(jit_memory_pool *pool, void *item)
+{
+       *((void **)item) = pool->free_list;
+       pool->free_list = item;
+}
diff --git a/jit/jit-reg-alloc.c b/jit/jit-reg-alloc.c
new file mode 100644 (file)
index 0000000..be3312f
--- /dev/null
@@ -0,0 +1,1191 @@
+/*
+ * jit-reg-alloc.c - Register allocation routines for the JIT.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-reg-alloc.h"
+#include <jit/jit-dump.h>
+#include <stdio.h>
+
+/*@
+
+The @code{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:
+
+@*/
+
+/*@
+ * @deftypefun void _jit_regs_init_for_block (jit_gencode_t gen)
+ * Initialize the register allocation state for a new block.
+ * @end deftypefun
+@*/
+void _jit_regs_init_for_block(jit_gencode_t gen)
+{
+       int reg;
+       gen->current_age = 1;
+       for(reg = 0; reg < JIT_NUM_REGS; ++reg)
+       {
+               /* Clear everything except permanent and fixed registers */
+               if(!jit_reg_is_used(gen->permanent, reg) &&
+                  (_jit_reg_info[reg].flags & JIT_REG_FIXED) == 0)
+               {
+                       gen->contents[reg].num_values = 0;
+                       gen->contents[reg].is_long_start = 0;
+                       gen->contents[reg].is_long_end = 0;
+                       gen->contents[reg].age = 0;
+                       gen->contents[reg].remap = -1;
+                       gen->contents[reg].used_for_temp = 0;
+               }
+               gen->stack_map[reg] = -1;
+       }
+}
+
+/*@
+ * @deftypefun int _jit_regs_needs_long_pair (jit_type_t type)
+ * Determine if a type requires a long register pair.
+ * @end deftypefun
+@*/
+int _jit_regs_needs_long_pair(jit_type_t type)
+{
+#if defined(JIT_NATIVE_INT32) && !defined(JIT_BACKEND_INTERP)
+       type = jit_type_normalize(type);
+       if(type)
+       {
+               if(type->kind == JIT_TYPE_LONG || type->kind == JIT_TYPE_ULONG)
+               {
+                       return 1;
+               }
+       }
+       return 0;
+#else
+       /* We don't register pairs on 64-bit platforms or the interpreter */
+       return 0;
+#endif
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+int _jit_regs_get_cpu(jit_gencode_t gen, int reg, int *other_reg)
+{
+       int cpu_reg, other;
+       cpu_reg = gen->contents[reg].remap;
+       if(cpu_reg == -1)
+       {
+               cpu_reg = _jit_reg_info[reg].cpu_reg;
+       }
+       else
+       {
+               cpu_reg = _jit_reg_info[cpu_reg].cpu_reg;
+       }
+       if(gen->contents[reg].is_long_start)
+       {
+               other = _jit_reg_info[reg].other_reg;
+               if(gen->contents[other].remap == -1)
+               {
+                       other = _jit_reg_info[other].cpu_reg;
+               }
+               else
+               {
+                       other = _jit_reg_info[gen->contents[other].remap].cpu_reg;
+               }
+       }
+       else
+       {
+               other = -1;
+       }
+       if(other_reg)
+       {
+               *other_reg = other;
+       }
+       return cpu_reg;
+}
+
+/*
+ * Dump debug information about the register allocation state.
+ */
+/*#define      JIT_REG_DEBUG   1*/
+#ifdef JIT_REG_DEBUG
+static void dump_regs(jit_gencode_t gen, const char *name)
+{
+       int reg;
+       unsigned int index;
+       printf("%s:\n", name);
+       for(reg = 0; reg < JIT_NUM_REGS; ++reg)
+       {
+               if(gen->contents[reg].num_values == 0 &&
+                  !(gen->contents[reg].used_for_temp) &&
+                  gen->contents[reg].remap == -1)
+               {
+                       continue;
+               }
+               printf("\t%s: ", _jit_reg_info[reg].name);
+               if(gen->contents[reg].num_values > 0)
+               {
+                       for(index = 0; index < gen->contents[reg].num_values; ++index)
+                       {
+                               if(index)
+                                       fputs(", ", stdout);
+                               jit_dump_value(stdout, jit_value_get_function
+                                                                               (gen->contents[reg].values[index]),
+                                                          gen->contents[reg].values[index], 0);
+                       }
+                       if(gen->contents[reg].used_for_temp)
+                       {
+                               printf(", used_for_temp");
+                       }
+               }
+               else if(gen->contents[reg].used_for_temp)
+               {
+                       printf("used_for_temp");
+               }
+               else
+               {
+                       printf("free");
+               }
+               if(gen->contents[reg].remap != -1)
+               {
+                       printf(", remap=%d", (int)(gen->contents[reg].remap));
+               }
+               for(index = 0; index < JIT_NUM_REGS; ++index)
+               {
+                       if(gen->stack_map[index] == reg)
+                       {
+                               printf(", reverse_remap=%d", (int)index);
+                       }
+               }
+               putc('\n', stdout);
+       }
+}
+#endif
+
+/*
+ * Spill all registers between two end points.
+ */
+static void spill_all_between(jit_gencode_t gen, int first, int last)
+{
+       int reg, posn, other_reg, real_reg;
+       int first_stack_reg = 0;
+       jit_value_t value;
+       int value_used;
+
+#ifdef JIT_REG_DEBUG
+       dump_regs(gen, "enter spill_all_between");
+#endif
+
+       /* Handle the non-stack registers first, as they are easy to spill */
+       for(reg = first; reg <= last; ++reg)
+       {
+               /* Skip this register if it is permanent or fixed */
+               if(jit_reg_is_used(gen->permanent, reg) ||
+                  (_jit_reg_info[reg].flags & JIT_REG_FIXED) != 0)
+               {
+                       continue;
+               }
+
+               /* Remember this register if it is the start of a stack */
+               if((_jit_reg_info[reg].flags & JIT_REG_START_STACK) != 0)
+               {
+                       first_stack_reg = reg;
+               }
+
+               /* Skip this register if there is nothing in it */
+               if(gen->contents[reg].num_values == 0 &&
+                  !(gen->contents[reg].used_for_temp))
+               {
+                       continue;
+               }
+
+               /* If this is a stack register, then we need to find the
+                  register that contains the top-most stack position,
+                  because we must spill stack registers from top down.
+                  As we spill each one, something else will become the top */
+               if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0)
+               {
+                       real_reg = gen->stack_map[first_stack_reg];
+               }
+               else
+               {
+                       real_reg = reg;
+               }
+
+               /* Get the other register in a long pair, if there is one */
+               if(gen->contents[real_reg].is_long_start)
+               {
+                       other_reg = _jit_reg_info[real_reg].other_reg;
+               }
+               else
+               {
+                       other_reg = -1;
+               }
+
+               /* Spill all values that are associated with the register */
+               value_used = 0;
+               if(gen->contents[real_reg].num_values > 0)
+               {
+                       for(posn = gen->contents[real_reg].num_values - 1;
+                               posn >= 0; --posn)
+                       {
+                               value = gen->contents[real_reg].values[posn];
+                               if(!(value->in_frame))
+                               {
+                                       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
+                                       {
+                                               _jit_gen_spill_reg(gen, real_reg, other_reg, value);
+                                       }
+                                       else
+                                       {
+                                               /* The back end needs to think that we are spilling
+                                                  the first register in the stack, regardless of
+                                                  what "real_reg" might happen to be */
+                                               _jit_gen_spill_reg(gen, first_stack_reg, -1, value);
+                                       }
+                                       value->in_frame = 1;
+                                       value_used = 1;
+                               }
+                               value->in_register = 0;
+                               value->reg = -1;
+                       }
+               }
+
+               /* Free the register */
+               _jit_regs_free_reg(gen, real_reg, value_used);
+       }
+
+#ifdef JIT_REG_DEBUG
+       dump_regs(gen, "leave spill_all_between");
+#endif
+}
+
+/*
+ * Spill a specific register.  If it is in a stack, then all registers
+ * above the specific register must also be spilled.
+ */
+static void spill_register(jit_gencode_t gen, int reg)
+{
+       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
+       {
+               return spill_all_between(gen, reg, reg);
+       }
+       else
+       {
+               int first_reg;
+               reg = gen->contents[reg].remap;
+               first_reg = reg;
+               while((_jit_reg_info[first_reg].flags & JIT_REG_START_STACK) == 0)
+               {
+                       --first_reg;
+               }
+               spill_all_between(gen, first_reg, reg);
+       }
+}
+
+/*
+ * Spill all stack registers of a specific type.
+ */
+static void spill_all_stack(jit_gencode_t gen, int reg)
+{
+       int first_reg;
+       while((_jit_reg_info[reg].flags & JIT_REG_START_STACK) == 0)
+       {
+               --reg;
+       }
+       first_reg = reg;
+       while((_jit_reg_info[reg].flags & JIT_REG_END_STACK) == 0)
+       {
+               ++reg;
+       }
+       spill_all_between(gen, first_reg, reg);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+void _jit_regs_spill_all(jit_gencode_t gen)
+{
+       spill_all_between(gen, 0, JIT_NUM_REGS - 1);
+}
+
+/*
+ * Free a register within a stack, and renumber the other stack registers
+ * to compensate for the change.
+ */
+static void free_stack_reg(jit_gencode_t gen, int reg)
+{
+       int remap;
+
+#ifdef JIT_REG_DEBUG
+       dump_regs(gen, "enter free_stack_reg");
+#endif
+
+       /* Shift everything after this register up by one position */
+       remap = gen->contents[reg].remap;
+       if((_jit_reg_info[remap].flags & JIT_REG_END_STACK) == 0)
+       {
+               ++remap;
+               for(;;)
+               {
+                       if(gen->stack_map[remap] == -1)
+                       {
+                               /* There are no more active values in this stack */
+                               gen->stack_map[remap - 1] = -1;
+                               break;
+                       }
+                       else if((_jit_reg_info[remap].flags & JIT_REG_END_STACK) != 0)
+                       {
+                               /* This is the last register in the stack */
+                               --(gen->contents[gen->stack_map[remap]].remap);
+                               gen->stack_map[remap - 1] = gen->stack_map[remap];
+                               gen->stack_map[remap] = -1;
+                               break;
+                       }
+                       else
+                       {
+                               /* Shift this stack entry up by one */
+                               --(gen->contents[gen->stack_map[remap]].remap);
+                               gen->stack_map[remap - 1] = gen->stack_map[remap];
+                               ++remap;
+                       }
+               }
+       }
+
+       /* Clear the remapping for the register */
+       gen->contents[reg].remap = -1;
+
+#ifdef JIT_REG_DEBUG
+       dump_regs(gen, "leave free_stack_reg");
+#endif
+}
+
+/*
+ * Make space for a new stack register in a particular stack.
+ * Returns the pseudo register number of the newly allocated register.
+ */
+static int create_stack_reg(jit_gencode_t gen, int reg, int roll_down)
+{
+       int first_stack_reg;
+       int temp_reg, remap;
+
+#ifdef JIT_REG_DEBUG
+       dump_regs(gen, "enter create_stack_reg");
+#endif
+
+       /* Find the first pseudo register in the stack */
+       while((_jit_reg_info[reg].flags & JIT_REG_START_STACK) == 0)
+       {
+               --reg;
+       }
+       first_stack_reg = reg;
+
+       /* Find a free pseudo register in the stack */
+       for(;;)
+       {
+               if(gen->contents[reg].num_values == 0 &&
+                  !(gen->contents[reg].used_for_temp))
+               {
+                       break;
+               }
+               if((_jit_reg_info[reg].flags & JIT_REG_END_STACK) != 0)
+               {
+                       /* None of the registers are free, so we have to spill them all */
+                       spill_all_between(gen, first_stack_reg, reg);
+                       reg = first_stack_reg;
+                       break;
+               }
+               ++reg;
+       }
+
+       /* Roll the stack remappings down to make room at the top */
+       if(roll_down)
+       {
+               temp_reg = first_stack_reg - 1;
+               do
+               {
+                       ++temp_reg;
+                       remap = gen->contents[temp_reg].remap;
+                       if(remap != -1)
+                       {
+                               /* Change the register's position in the stack */
+                               gen->contents[temp_reg].remap = remap + 1;
+                               gen->stack_map[remap + 1] = temp_reg;
+
+                               /* Mark the rolled-down register position as touched */
+                               jit_reg_set_used(gen->touched, remap + 1);
+                       }
+               }
+               while((_jit_reg_info[temp_reg].flags & JIT_REG_END_STACK) == 0);
+               gen->contents[reg].remap = first_stack_reg;
+               gen->stack_map[first_stack_reg] = reg;
+       }
+
+       /* Mark the register as touched, in case it needs to be saved */
+       jit_reg_set_used(gen->touched, reg);
+
+#ifdef JIT_REG_DEBUG
+       dump_regs(gen, "leave create_stack_reg");
+#endif
+
+       /* Return the free register to the caller */
+       return reg;
+}
+
+/*
+ * Free a register, and optionally spill its value.
+ */
+static void free_reg_and_spill
+       (jit_gencode_t gen, int reg, int value_used, int spill)
+{
+       int other_reg, posn;
+       jit_value_t value;
+
+#ifdef JIT_REG_DEBUG
+       dump_regs(gen, "enter free_reg_and_spill");
+#endif
+
+       /* Find the other register in a long pair */
+       if(gen->contents[reg].is_long_start)
+       {
+               other_reg = _jit_reg_info[reg].other_reg;
+               gen->contents[reg].is_long_start = 0;
+               gen->contents[other_reg].is_long_end = 0;
+       }
+       else if(gen->contents[reg].is_long_end)
+       {
+               gen->contents[reg].is_long_end = 0;
+               other_reg = reg;
+               for(reg = 0; reg < JIT_NUM_REGS; ++reg)
+               {
+                       if(other_reg == _jit_reg_info[reg].other_reg)
+                       {
+                               gen->contents[reg].is_long_start = 0;
+                               break;
+                       }
+               }
+       }
+       else
+       {
+               other_reg = -1;
+       }
+
+       /* Spill the register's contents to the local variable frame */
+       if(spill && gen->contents[reg].num_values > 0)
+       {
+               for(posn = gen->contents[reg].num_values - 1; posn >= 0; --posn)
+               {
+                       value = gen->contents[reg].values[posn];
+                       if(!(value->in_frame))
+                       {
+                               if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
+                               {
+                                       _jit_gen_spill_reg(gen, reg, other_reg, value);
+                               }
+                               else
+                               {
+                                       _jit_gen_spill_reg
+                                               (gen, gen->contents[reg].remap, -1, value);
+                               }
+                               value->in_frame = 1;
+                               value_used = 1;
+                       }
+                       value->in_register = 0;
+                       value->reg = -1;
+               }
+       }
+
+       /* The registers do not contain values any more */
+       gen->contents[reg].num_values = 0;
+       gen->contents[reg].used_for_temp = 0;
+       if(other_reg != -1)
+       {
+               gen->contents[other_reg].num_values = 0;
+               gen->contents[other_reg].used_for_temp = 0;
+       }
+
+       /* If the registers are members of a stack, then readjust the
+          stack mappings to compensate for the change */
+       if(gen->contents[reg].remap != -1)
+       {
+               free_stack_reg(gen, reg);
+       }
+       if(other_reg != -1 && gen->contents[other_reg].remap != -1)
+       {
+               free_stack_reg(gen, other_reg);
+       }
+
+#ifdef JIT_REG_DEBUG
+       dump_regs(gen, "leave free_reg_and_spill");
+#endif
+
+       /* Free the register using CPU-specific code */
+       _jit_gen_free_reg(gen, reg, other_reg, value_used);
+}
+
+/*@
+ * @deftypefun void _jit_regs_want_reg (jit_gencode_t gen, int reg)
+ * Tell the register allocator that we want a particular register
+ * for a specific purpose.  The current contents of the register
+ * are spilled.  If @code{reg} is part of a register pair, then the
+ * other register in the pair will also be spilled.  If @code{reg}
+ * is a stack register, then it should be the first one.
+ *
+ * This is typically used for x86 instructions that require operands
+ * to be in certain registers (especially multiplication and division),
+ * and we want to make sure that the register is free before we clobber it.
+ * It is also used to make space in the x86 FPU for floating-point returns.
+ *
+ * This may return a different pseudo register number if @code{reg}
+ * was a member of a stack and some other register was made free.
+ * @end deftypefun
+@*/
+int _jit_regs_want_reg(jit_gencode_t gen, int reg, int for_long)
+{
+       int other_reg;
+       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
+       {
+               /* Spill an ordinary register and its pair register */
+               free_reg_and_spill(gen, reg, 0, 1);
+               if(for_long)
+               {
+                       other_reg = _jit_reg_info[reg].other_reg;
+                       if(other_reg != -1)
+                       {
+                               free_reg_and_spill(gen, other_reg, 0, 1);
+                       }
+               }
+               else
+               {
+                       other_reg = -1;
+               }
+
+               /* Mark the register as touched and return it */
+               jit_reg_set_used(gen->touched, reg);
+               if(other_reg != -1)
+               {
+                       jit_reg_set_used(gen->touched, other_reg);
+               }
+               return reg;
+       }
+       else
+       {
+               /* If we want a stack register, all we have to do is roll
+                  everything down to make room for the new value.  If the
+                  stack is full, then we spill the entire stack */
+               return create_stack_reg(gen, reg, 0);
+       }
+}
+
+/*@
+ * @deftypefun void _jit_regs_free_reg (jit_gencode_t gen, int reg, int value_used)
+ * Free the contents of a pseudo register, without spilling.  Used when
+ * the contents of a register becomes invalid.  If @code{value_used}
+ * is non-zero, then it indicates that the value has already been
+ * used.  On some systems, an explicit instruction is needed to free
+ * a register whose value hasn't been used yet (e.g. x86 floating point
+ * stack registers).
+ * @end deftypefun
+@*/
+void _jit_regs_free_reg(jit_gencode_t gen, int reg, int value_used)
+{
+       free_reg_and_spill(gen, reg, value_used, 0);
+}
+
+/*@
+ * @deftypefun void _jit_regs_set_value (jit_gencode_t gen, int reg, jit_value_t value, int still_in_frame)
+ * Set pseudo register @code{reg} to record that it currently holds the
+ * contents of @code{value}.  The value is assumed to already be in
+ * the register and no spill occurs.  If @code{still_in_frame} is
+ * non-zero, then the value is still in the stack frame; otherwise the
+ * value is exclusively in the register.
+ * @end deftypefun
+@*/
+void _jit_regs_set_value
+       (jit_gencode_t gen, int reg, jit_value_t value, int still_in_frame)
+{
+       int other_reg;
+       int first_stack_reg;
+
+#ifdef JIT_REG_DEBUG
+       dump_regs(gen, "enter set_value");
+#endif
+
+       /* Get the other register in a pair */
+       if(_jit_regs_needs_long_pair(value->type))
+       {
+               other_reg = _jit_reg_info[reg].other_reg;
+       }
+       else
+       {
+               other_reg = -1;
+       }
+
+       /* Mark the register as touched */
+       jit_reg_set_used(gen->touched, reg);
+       if(other_reg != -1)
+       {
+               jit_reg_set_used(gen->touched, other_reg);
+       }
+
+       /* Adjust the allocation state to reflect that "reg" contains "value" */
+       gen->contents[reg].values[0] = value;
+       gen->contents[reg].num_values = 1;
+       gen->contents[reg].age = gen->current_age;
+       if(other_reg == -1)
+       {
+               gen->contents[reg].is_long_start = 0;
+               gen->contents[reg].is_long_end = 0;
+               gen->contents[reg].used_for_temp = 0;
+       }
+       else
+       {
+               gen->contents[reg].is_long_start = 1;
+               gen->contents[reg].is_long_end = 0;
+               gen->contents[reg].used_for_temp = 0;
+               gen->contents[other_reg].num_values = 0;
+               gen->contents[other_reg].is_long_start = 0;
+               gen->contents[other_reg].is_long_end = 1;
+               gen->contents[other_reg].age = gen->current_age;
+               gen->contents[other_reg].used_for_temp = 0;
+       }
+       (gen->current_age)++;
+
+       /* Set the stack mappings for this register */
+       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0)
+       {
+               first_stack_reg = reg;
+               while((_jit_reg_info[first_stack_reg].flags & JIT_REG_START_STACK) == 0)
+               {
+                       --first_stack_reg;
+               }
+               gen->contents[reg].remap = first_stack_reg;
+               gen->stack_map[first_stack_reg] = reg;
+       }
+
+#ifdef JIT_REG_DEBUG
+       dump_regs(gen, "leave set_value");
+#endif
+
+       /* Adjust the value to reflect that it is in "reg", and maybe the frame */
+       value->in_register = 1;
+       value->in_frame = still_in_frame;
+       value->reg = (short)reg;
+}
+
+/*@
+ * @deftypefun void _jit_regs_set_incoming (jit_gencode_t gen, int reg, jit_value_t value)
+ * Set pseudo register @code{reg} to record that it currently holds the
+ * contents of @code{value}.  If the register was previously in use,
+ * then spill its value first.
+ * @end deftypefun
+@*/
+void _jit_regs_set_incoming(jit_gencode_t gen, int reg, jit_value_t value)
+{
+       /* Eject any values that are currently in the register */
+       reg = _jit_regs_want_reg(gen, reg, _jit_regs_needs_long_pair(value->type));
+
+       /* Record that the value is in "reg", but not in the frame */
+       _jit_regs_set_value(gen, reg, value, 0);
+}
+
+/*@
+ * @deftypefun void _jit_regs_set_outgoing (jit_gencode_t gen, int reg, jit_value_t value)
+ * Load the contents of @code{value} into pseudo register @code{reg},
+ * spilling out the current contents.  This is used to set up outgoing
+ * parameters for a function call.
+ * @end deftypefun
+@*/
+void _jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value)
+{
+       /* TODO */
+}
+
+/*@
+ * @deftypefun int _jit_regs_is_top (jit_gencode_t gen, jit_value_t value)
+ * Determine if @code{value} is currently the in top-most position
+ * in the appropriate register stack.  Always returns non-zero if
+ * @code{value} is in a register, but that register is not part of a
+ * register stack.  This is used to check if an operand value is
+ * already in the right position for a unary operation.
+ * @end deftypefun
+@*/
+int _jit_regs_is_top(jit_gencode_t gen, jit_value_t value)
+{
+       int reg, remap;
+       if(!(value->in_register))
+       {
+               return 0;
+       }
+       reg = value->reg;
+       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
+       {
+               return 1;
+       }
+       remap = gen->contents[reg].remap;
+       if(remap != -1 && (_jit_reg_info[remap].flags & JIT_REG_START_STACK) != 0)
+       {
+               return 1;
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun int _jit_regs_is_top_two (jit_gencode_t gen, jit_value_t value1, jit_value_t value2)
+ * Determine if @code{value1} and @code{value2} are in the top two positions
+ * in the appropriate register stack, and @code{value2} is above
+ * @code{value1}.  Always returns non-zero if @code{value} and
+ * @code{value2} are in registers, but those registers are not part
+ * of a register stack.  This is used to check if the operand values
+ * for a binary operation are already in the right positions.
+ * @end deftypefun
+@*/
+int _jit_regs_is_top_two
+       (jit_gencode_t gen, jit_value_t value1, jit_value_t value2)
+{
+       int reg, remap;
+       if(!(value1->in_register) || !(value2->in_register))
+       {
+               return 0;
+       }
+       reg = value2->reg;
+       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
+       {
+               reg = value1->reg;
+               return ((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0);
+       }
+       remap = gen->contents[reg].remap;
+       if(remap == -1 || (_jit_reg_info[remap].flags & JIT_REG_START_STACK) == 0)
+       {
+               return 0;
+       }
+       reg = value1->reg;
+       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
+       {
+               return 1;
+       }
+       return (gen->contents[reg].remap == (remap + 1));
+}
+
+/*
+ * Load a value into a register.
+ */
+static void load_value(jit_gencode_t gen, int reg, int other_reg,
+                                          jit_value_t value, int destroy)
+{
+       _jit_gen_load_value(gen, reg, other_reg, value);
+       if(destroy || value->is_constant)
+       {
+               /* Mark the register as containing a temporary value */
+               gen->contents[reg].used_for_temp = 1;
+               jit_reg_set_used(gen->touched, reg);
+               if(other_reg != -1)
+               {
+                       gen->contents[reg].is_long_start = 1;
+                       gen->contents[other_reg].is_long_end = 1;
+                       gen->contents[other_reg].used_for_temp = 1;
+                       jit_reg_set_used(gen->touched, other_reg);
+               }
+       }
+       else
+       {
+               /* Mark the register as containing the value we have loaded */
+               _jit_regs_set_value(gen, reg, value, value->in_frame);
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{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
+ * @code{value} or any of the other values currently in that register.
+ *
+ * If @code{used_again} is non-zero, then it indicates that the value is
+ * used again further down the block.
+ * @end deftypefun
+@*/
+int _jit_regs_load_value
+       (jit_gencode_t gen, jit_value_t value, int destroy, int used_again)
+{
+       int reg, other_reg, type;
+       int suitable_reg, need_pair;
+       int suitable_age;
+
+       /* Determine if we need a long pair for this value */
+       need_pair = _jit_regs_needs_long_pair(value->type);
+
+       /* If the value is already in a register, then try to use that register */
+       if(value->in_register)
+       {
+               reg = value->reg;
+               if(destroy)
+               {
+                       if(gen->contents[reg].num_values == 1 &&
+                          (value->in_frame || !used_again))
+                       {
+                               /* We are the only value in this register, and the
+                                  value is duplicated in the frame, or will never
+                                  be used again in this block.  In this case,
+                                  we can disassociate the register from the value
+                                  and just return the register as-is */
+                               value->in_register = 0;
+                               gen->contents[reg].num_values = 0;
+                               gen->contents[reg].used_for_temp = 1;
+                               gen->contents[reg].age = gen->current_age;
+                               if(need_pair)
+                               {
+                                       other_reg = _jit_reg_info[reg].other_reg;
+                                       gen->contents[other_reg].used_for_temp = 1;
+                                       gen->contents[other_reg].age = gen->current_age;
+                               }
+                               ++(gen->current_age);
+                               return reg;
+                       }
+                       else
+                       {
+                               /* We need to spill the register and then reload it */
+                               spill_register(gen, reg);
+                       }
+               }
+               else
+               {
+                       gen->contents[reg].age = gen->current_age;
+                       if(need_pair)
+                       {
+                               other_reg = _jit_reg_info[reg].other_reg;
+                               gen->contents[other_reg].age = gen->current_age;
+                       }
+                       ++(gen->current_age);
+                       return reg;
+               }
+       }
+
+       /* Determine the type of register that we need */
+       switch(jit_type_normalize(value->type)->kind)
+       {
+               case JIT_TYPE_SBYTE:
+               case JIT_TYPE_UBYTE:
+               case JIT_TYPE_SHORT:
+               case JIT_TYPE_USHORT:
+               case JIT_TYPE_INT:
+               case JIT_TYPE_UINT:
+               case JIT_TYPE_NINT:
+               case JIT_TYPE_NUINT:
+               case JIT_TYPE_SIGNATURE:
+               case JIT_TYPE_PTR:
+               {
+                       type = JIT_REG_WORD;
+               }
+               break;
+
+               case JIT_TYPE_LONG:
+               case JIT_TYPE_ULONG:
+               {
+                       if(need_pair)
+                               type = JIT_REG_LONG;
+                       else
+                               type = JIT_REG_WORD;
+               }
+               break;
+
+               case JIT_TYPE_FLOAT32:
+               case JIT_TYPE_FLOAT64:
+               case JIT_TYPE_NFLOAT:
+               {
+                       type = JIT_REG_FLOAT;
+               }
+               break;
+
+               default: return -1;
+       }
+
+       /* Search for a free register, ignoring permanent global allocations.
+          We also keep track of the oldest suitable register that is not free */
+       suitable_reg = -1;
+       suitable_age = -1;
+       for(reg = 0; reg < JIT_NUM_REGS; ++reg)
+       {
+               if((_jit_reg_info[reg].flags & type) != 0 &&
+                  !jit_reg_is_used(gen->permanent, reg))
+               {
+                       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0)
+                       {
+                               /* We always load stack values to the top of the stack */
+                               reg = create_stack_reg(gen, reg, 1);
+                               load_value(gen, reg, -1, value, destroy);
+                               return reg;
+                       }
+                       else if(!need_pair)
+                       {
+                               if(gen->contents[reg].num_values == 0 &&
+                                  !(gen->contents[reg].used_for_temp))
+                               {
+                                       load_value(gen, reg, -1, value, destroy);
+                                       return reg;
+                               }
+                       }
+                       else
+                       {
+                               other_reg = _jit_reg_info[reg].other_reg;
+                               if(gen->contents[reg].num_values == 0 &&
+                                  !(gen->contents[reg].used_for_temp) &&
+                                  gen->contents[other_reg].num_values == 0 &&
+                                  !(gen->contents[other_reg].used_for_temp))
+                               {
+                                       load_value(gen, reg, other_reg, value, destroy);
+                                       return reg;
+                               }
+                       }
+                       if(suitable_reg == -1 || gen->contents[reg].age < suitable_age)
+                       {
+                               /* This is the oldest suitable register of this type */
+                               suitable_reg = reg;
+                               suitable_age = gen->contents[reg].age;
+                       }
+               }
+       }
+
+       /* If there were no suitable registers at all, then fail */
+       if(suitable_reg == -1)
+       {
+               return -1;
+       }
+
+       /* Eject the current contents of the register */
+       reg = _jit_regs_want_reg(gen, reg, need_pair);
+
+       /* Load the value into the register */
+       if(!need_pair)
+       {
+               load_value(gen, reg, -1, value, destroy);
+       }
+       else
+       {
+               load_value(gen, reg, _jit_reg_info[reg].other_reg, value, destroy);
+       }
+       return reg;
+}
+
+/*
+ * Determine if "num" stack registers are free in a specific stack.
+ */
+static int stack_regs_free(jit_gencode_t gen, int reg, int num)
+{
+       int first_reg;
+
+       /* Find the extents of the stack */
+       while((_jit_reg_info[reg].flags & JIT_REG_START_STACK) == 0)
+       {
+               --reg;
+       }
+       first_reg = reg;
+       while((_jit_reg_info[reg].flags & JIT_REG_END_STACK) == 0)
+       {
+               ++reg;
+       }
+
+       /* Search for free registers */
+       while(reg >= first_reg)
+       {
+               if(gen->contents[reg].num_values == 0 &&
+                  !(gen->contents[reg].used_for_temp))
+               {
+                       --num;
+                       if(num <= 0)
+                       {
+                               return 1;
+                       }
+               }
+               --reg;
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun int _jit_regs_load_to_top (jit_gencode_t gen, jit_value_t value, int used_again, int type_reg)
+ * Load the contents of @code{value} into a register that is guaranteed to
+ * be at the top of its stack.  This is the preferred way to set up for a
+ * unary operation on a stack-based architecture.  Returns the pseudo
+ * register that contains the value.
+ *
+ * When @code{value} is loaded, the "destroy" flag is set so that the
+ * unary operation will not affect the original contents of @code{value}.
+ * The @code{used_again} flag indicates if @code{value} is used again
+ * in the current basic block.
+ *
+ * The @code{type_reg} parameter should be set to the pseudo register
+ * number of a suitable register.  This is used to determine which
+ * register stack to use for the allocation.
+ * @end deftypefun
+@*/
+int _jit_regs_load_to_top(jit_gencode_t gen, jit_value_t value, int used_again, int type_reg)
+{
+       int reg;
+
+       /* Determine if the value is already in the top-most register */
+       if(value->in_register)
+       {
+               reg = value->reg;
+               if((_jit_reg_info[gen->contents[reg].remap].flags
+                               & JIT_REG_START_STACK) != 0)
+               {
+                       if(value->in_frame || !used_again)
+                       {
+                               /* Disassociate the value from the register and return */
+                               value->in_register = 0;
+                               gen->contents[reg].num_values = 0;
+                               gen->contents[reg].used_for_temp = 1;
+                               gen->contents[reg].age = gen->current_age;
+                               ++(gen->current_age);
+                               return reg;
+                       }
+               }
+               spill_all_stack(gen, type_reg);
+       }
+
+       /* If there are free registers of this type, then load the value now */
+       if(stack_regs_free(gen, type_reg, 1))
+       {
+               return _jit_regs_load_value(gen, value, 1, used_again);
+       }
+
+       /* Spill the entire stack contents, to get things into a known state */
+       spill_all_stack(gen, type_reg);
+
+       /* Reload the value and return */
+       return _jit_regs_load_value(gen, value, 1, used_again);
+}
+
+/*@
+ * @deftypefun int _jit_regs_load_to_top_two (jit_gencode_t gen, jit_value_t value, jit_value_t value2, int used_again1, int used_again2, int type_reg)
+ * Load the contents of @code{value} and @code{value2} into registers that
+ * are guaranteed to be at the top of the relevant register stack.
+ * This is the preferred way to set up for a binary operation on a
+ * stack-based architecture.
+ *
+ * Returns the pseudo register that contains @code{value}.  The pseudo
+ * register that contains @code{value2} is marked as free, because it is
+ * assumed that the binary operation will immediately consume its value.
+ *
+ * When @code{value} are @code{value2} are loaded, the "destroy" flag is
+ * set so that the binary operation will not affect their original contents.
+ * The @code{used_again1} and @code{used_again2} flags indicate if
+ * @code{value} and @code{value2} are used again in the current basic block.
+ *
+ * The @code{type_reg} parameter should be set to the pseudo register
+ * number of a suitable register.  This is used to determine which
+ * register stack to use for the allocation.
+ * @end deftypefun
+@*/
+int _jit_regs_load_to_top_two
+       (jit_gencode_t gen, jit_value_t value, jit_value_t value2,
+        int used_again1, int used_again2, int type_reg)
+{
+       int reg, reg2;
+
+       /* Determine if the values are already in the top two registers */
+       if(value->in_register && value2->in_register)
+       {
+               reg = value->reg;
+               reg2 = value->reg;
+               if((_jit_reg_info[gen->contents[reg2].remap].flags
+                               & JIT_REG_START_STACK) != 0 &&
+                  gen->contents[reg].remap == (gen->contents[reg2].remap + 1))
+               {
+                       if((value->in_frame || !used_again1) &&
+                          (value2->in_frame || !used_again2))
+                       {
+                               /* Disassociate the values from the registers and return */
+                               free_stack_reg(gen, reg2);
+                               value->in_register = 0;
+                               value2->in_register = 0;
+                               gen->contents[reg].num_values = 0;
+                               gen->contents[reg].used_for_temp = 1;
+                               gen->contents[reg].age = gen->current_age;
+                               gen->contents[reg2].num_values = 0;
+                               gen->contents[reg2].used_for_temp = 0;
+                               gen->contents[reg2].age = gen->current_age;
+                               ++(gen->current_age);
+                               return reg;
+                       }
+               }
+               spill_all_stack(gen, type_reg);
+       }
+
+       /* If there are free registers of this type, then load the values now */
+       if(stack_regs_free(gen, type_reg, 2))
+       {
+               reg = _jit_regs_load_value(gen, value, 1, used_again1);
+               reg2 = _jit_regs_load_value(gen, value2, 1, used_again2);
+               free_stack_reg(gen, reg2);
+               gen->contents[reg2].used_for_temp = 0;
+               return reg;
+       }
+
+       /* Spill the entire stack contents, to get things into a known state */
+       spill_all_stack(gen, type_reg);
+
+       /* Reload the values and return */
+       reg = _jit_regs_load_value(gen, value, 1, used_again1);
+       reg2 = _jit_regs_load_value(gen, value2, 1, used_again2);
+       free_stack_reg(gen, reg2);
+       gen->contents[reg2].used_for_temp = 0;
+       return reg;
+}
+
+/*@
+ * @deftypefun int _jit_regs_num_used (jit_gencode_t gen, int type_reg)
+ * Get the number of stack registers in use within the register stack
+ * indicated by @code{type_reg}.
+ * @end deftypefun
+@*/
+int _jit_regs_num_used(jit_gencode_t gen, int type_reg)
+{
+       int count;
+       while((_jit_reg_info[type_reg].flags & JIT_REG_START_STACK) == 0)
+       {
+               --type_reg;
+       }
+       count = 0;
+       for(;;)
+       {
+               if(gen->contents[type_reg].num_values > 0 ||
+                  gen->contents[type_reg].used_for_temp)
+               {
+                       ++count;
+               }
+               if((_jit_reg_info[type_reg].flags & JIT_REG_END_STACK) == 0)
+               {
+                       break;
+               }
+               ++type_reg;
+       }
+       return count;
+}
diff --git a/jit/jit-reg-alloc.h b/jit/jit-reg-alloc.h
new file mode 100644 (file)
index 0000000..f516e96
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * jit-reg-alloc.h - Register allocation routines for the JIT.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_REG_ALLOC_H
+#define        _JIT_REG_ALLOC_H
+
+#include "jit-rules.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void _jit_regs_init_for_block(jit_gencode_t gen);
+int _jit_regs_needs_long_pair(jit_type_t type);
+int _jit_regs_get_cpu(jit_gencode_t gen, int reg, int *other_reg);
+void _jit_regs_spill_all(jit_gencode_t gen);
+int _jit_regs_want_reg(jit_gencode_t gen, int reg, int for_long);
+void _jit_regs_free_reg(jit_gencode_t gen, int reg, int value_used);
+void _jit_regs_set_value
+       (jit_gencode_t gen, int reg, jit_value_t value, int still_in_frame);
+void _jit_regs_set_incoming(jit_gencode_t gen, int reg, jit_value_t value);
+void _jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value);
+int _jit_regs_is_top(jit_gencode_t gen, jit_value_t value);
+int _jit_regs_is_top_two
+       (jit_gencode_t gen, jit_value_t value1, jit_value_t value2);
+int _jit_regs_load_value
+       (jit_gencode_t gen, jit_value_t value, int destroy, int used_again);
+int _jit_regs_load_to_top
+       (jit_gencode_t gen, jit_value_t value, int used_again, int type_reg);
+int _jit_regs_load_to_top_two
+       (jit_gencode_t gen, jit_value_t value, jit_value_t value2,
+        int used_again1, int used_again2, int type_reg);
+int _jit_regs_num_used(jit_gencode_t gen, int type_reg);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_REG_ALLOC_H */
diff --git a/jit/jit-rules-arm.c b/jit/jit-rules-arm.c
new file mode 100644 (file)
index 0000000..e85101f
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ * jit-rules-arm.c - Rules that define the characteristics of the ARM.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-rules.h"
+#include "jit-apply-rules.h"
+
+#if defined(JIT_BACKEND_ARM)
+
+#include "jit-gen-arm.h"
+
+/*
+ * Determine if we actually have floating-point registers.
+ */
+#if JIT_APPLY_NUM_FLOAT_REGS != 0 || JIT_APPLY_RETURN_FLOATS_AFTER != 0
+       #define JIT_ARM_HAS_FLOAT_REGS  1
+#endif
+
+/*
+ * Round a size up to a multiple of the stack word size.
+ */
+#define        ROUND_STACK(size)       \
+               (((size) + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1))
+
+void _jit_init_backend(void)
+{
+#ifndef JIT_ARM_HAS_FLOAT_REGS
+       /* Turn off floating-point registers, as this ARM core doesn't have them */
+       int reg;
+       for(reg = 16; reg < JIT_NUM_REGS; ++reg)
+       {
+               _jit_reg_info[reg].flags = JIT_REG_FIXED;
+       }
+#endif
+}
+
+void _jit_gen_get_elf_info(jit_elf_info_t *info)
+{
+       info->machine = 40;             /* EM_ARM */
+       info->abi = 0;                  /* ELFOSABI_SYSV */
+       info->abi_version = 0;
+}
+
+/*
+ * Force values out of parameter registers that cannot be easily
+ * accessed in register form (i.e. long, float, and struct values).
+ */
+static int force_out_of_regs(jit_function_t func, jit_value_t param,
+                                                        int next_reg, unsigned int size)
+{
+       jit_value_t address;
+       jit_value_t temp;
+       jit_nint offset = 0;
+       jit_nint frame_offset = sizeof(void *);
+
+       /* Get the address of the parameter, to force it into the frame,
+          and to set up for the later "jit_insn_store_relative" calls */
+       address = jit_insn_address_of(func, param);
+       if(!address)
+       {
+               return 0;
+       }
+
+       /* Force the values out of the registers */
+       while(next_reg < ARM_NUM_PARAM_REGS && size > 0)
+       {
+               temp = jit_value_create(func, jit_type_void_ptr);
+               if(!temp)
+               {
+                       return 0;
+               }
+               if(!jit_insn_incoming_reg(func, temp, next_reg))
+               {
+                       return 0;
+               }
+               if(!jit_insn_store_relative(func, address, offset, temp))
+               {
+                       return 0;
+               }
+               offset += sizeof(void *);
+               size -= sizeof(void *);
+               ++next_reg;
+       }
+
+
+       /* Force the rest of the value out of the incoming stack frame */
+       while(size > 0)
+       {
+               temp = jit_value_create(func, jit_type_void_ptr);
+               if(!temp)
+               {
+                       return 0;
+               }
+               if(!jit_insn_incoming_frame_posn(func, temp, frame_offset))
+               {
+                       return 0;
+               }
+               if(!jit_insn_store_relative(func, address, offset, temp))
+               {
+                       return 0;
+               }
+               offset += sizeof(void *);
+               frame_offset += sizeof(void *);
+               size -= sizeof(void *);
+       }
+       return 1;
+}
+
+int _jit_create_entry_insns(jit_function_t func)
+{
+       jit_type_t signature = func->signature;
+       jit_type_t type;
+       int next_reg;
+       jit_nint offset;
+       jit_value_t value;
+       unsigned int num_params;
+       unsigned int param;
+       unsigned int size;
+
+       /* Reset the frame size for this function.  We start by assuming
+          that lr, sp, fp, r8, r7, r6, r5, and r4 need to be saved in
+          the local frame, as that is the worst-case scenario */
+       func->builder->frame_size = 8 * sizeof(void *);
+
+       /* The next register to be allocated to parameters is r0 */
+       next_reg = 0;
+
+       /* The starting parameter offset (saved pc on stack) */
+       offset = sizeof(void *);
+
+       /* If the function is nested, then we need an extra parameter
+          to pass the pointer to the parent's local variable frame */
+       if(func->nested_parent)
+       {
+               ++next_reg;
+       }
+
+       /* Allocate the structure return pointer */
+       value = jit_value_get_struct_pointer(func);
+       if(value)
+       {
+               if(!jit_insn_incoming_reg(func, value, next_reg))
+               {
+                       return 0;
+               }
+               ++next_reg;
+       }
+
+       /* Allocate the parameter registers and offsets */
+       num_params = jit_type_num_params(signature);
+       for(param = 0; param < num_params; ++param)
+       {
+               value = jit_value_get_param(func, param);
+               if(!value)
+               {
+                       continue;
+               }
+               type = jit_type_normalize(jit_value_get_type(value));
+               switch(type->kind)
+               {
+                       case JIT_TYPE_SBYTE:
+                       case JIT_TYPE_UBYTE:
+                       case JIT_TYPE_SHORT:
+                       case JIT_TYPE_USHORT:
+                       case JIT_TYPE_INT:
+                       case JIT_TYPE_UINT:
+                       case JIT_TYPE_NINT:
+                       case JIT_TYPE_NUINT:
+                       case JIT_TYPE_SIGNATURE:
+                       case JIT_TYPE_PTR:
+                       {
+                               if(next_reg < ARM_NUM_PARAM_REGS)
+                               {
+                                       if(!jit_insn_incoming_reg(func, value, next_reg))
+                                       {
+                                               return 0;
+                                       }
+                                       ++next_reg;
+                               }
+                               else
+                               {
+                                       if(!jit_insn_incoming_frame_posn(func, value, offset))
+                                       {
+                                               return 0;
+                                       }
+                                       offset += sizeof(void *);
+                               }
+                       }
+                       break;
+
+                       case JIT_TYPE_LONG:
+                       case JIT_TYPE_ULONG:
+                       case JIT_TYPE_FLOAT32:
+                       case JIT_TYPE_FLOAT64:
+                       case JIT_TYPE_NFLOAT:
+                       case JIT_TYPE_STRUCT:
+                       case JIT_TYPE_UNION:
+                       {
+                               /* Force these kinds of values out of the word registers.
+                                  While technically we could keep long and float values
+                                  in word registers on ARM, it simplifies the register
+                                  allocator if we force them out first */
+                               size = ROUND_STACK(jit_type_get_size(type));
+                               if(next_reg < ARM_NUM_PARAM_REGS)
+                               {
+                                       if(!force_out_of_regs(func, value, next_reg, size))
+                                       {
+                                               return 0;
+                                       }
+                                       while(size > 0 && next_reg < ARM_NUM_PARAM_REGS)
+                                       {
+                                               ++next_reg;
+                                               size -= sizeof(void *);
+                                       }
+                                       offset += size;
+                               }
+                               else
+                               {
+                                       /* The value is completely on the stack */
+                                       if(!jit_insn_incoming_frame_posn(func, value, offset))
+                                       {
+                                               return 0;
+                                       }
+                                       offset += size;
+                               }
+                       }
+                       break;
+               }
+       }
+       return 1;
+}
+
+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 nesting_level, jit_value_t *struct_return)
+{
+       jit_type_t type = jit_type_get_return(signature);
+       jit_value_t value;
+       unsigned int size;
+       unsigned int index;
+       unsigned int num_stack_args;
+       unsigned int word_regs;
+       jit_value_t partial;
+
+       /* Determine which values are going to end up in registers */
+       word_regs = 0;
+       if(func->nested_parent)
+       {
+               ++word_regs;
+       }
+       if(jit_type_return_via_pointer(type))
+       {
+               ++word_regs;
+       }
+       index = 0;
+       partial = 0;
+       while(index < num_args && word_regs < ARM_NUM_PARAM_REGS)
+       {
+               size = jit_type_get_size(jit_value_get_type(args[index]));
+               size = ROUND_STACK(size) / sizeof(void *);
+               if(size <= (ARM_NUM_PARAM_REGS - word_regs))
+               {
+                       /* This argument will fit entirely in registers */
+                       word_regs += size;
+                       ++index;
+               }
+               else
+               {
+                       /* Partly in registers and partly on the stack.
+                          We first copy it into a buffer that we can address */
+                       partial = jit_value_create
+                               (func, jit_value_get_type(args[index]));
+                       if(!partial)
+                       {
+                               return 0;
+                       }
+                       jit_value_set_addressable(partial);
+                       if(!jit_insn_store(func, partial, args[index]))
+                       {
+                               return 0;
+                       }
+                       ++index;
+                       break;
+               }
+       }
+       num_stack_args = num_args - index;
+
+       /* Push all of the stacked arguments in reverse order */
+       while(num_stack_args > 0)
+       {
+               --num_stack_args;
+               --num_args;
+               if(!jit_insn_push(func, args[num_args]))
+               {
+                       return 0;
+               }
+       }
+
+       /* Handle a value that is partly on the stack and partly in registers */
+       if(partial)
+       {
+               --num_args;
+               index = (ARM_NUM_PARAM_REGS - word_regs) * sizeof(void *);
+               size = ROUND_STACK(jit_type_get_size(jit_value_get_type(partial)));
+               while(size > index)
+               {
+                       size -= sizeof(void *);
+                       value = jit_value_create(func, jit_type_void_ptr);
+                       if(!value)
+                       {
+                               return 0;
+                       }
+                       value = jit_insn_load_relative
+                               (func, value, (jit_nint)size, jit_type_void_ptr);
+                       if(!value)
+                       {
+                               return 0;
+                       }
+                       if(!jit_insn_push(func, value))
+                       {
+                               return 0;
+                       }
+               }
+               while(size > 0)
+               {
+                       size -= sizeof(void *);
+                       value = jit_value_create(func, jit_type_void_ptr);
+                       if(!value)
+                       {
+                               return 0;
+                       }
+                       value = jit_insn_load_relative
+                               (func, value, (jit_nint)size, jit_type_void_ptr);
+                       if(!value)
+                       {
+                               return 0;
+                       }
+                       --word_regs;
+                       if(!jit_insn_outgoing_reg(func, value, (int)word_regs))
+                       {
+                               return 0;
+                       }
+               }
+       }
+
+       /* Push arguments that will end up entirely in registers */
+       while(num_args > 0)
+       {
+               --num_args;
+               size = jit_type_get_size(jit_value_get_type(args[num_args]));
+               size = ROUND_STACK(size) / sizeof(void *);
+               word_regs -= size;
+               if(!jit_insn_outgoing_reg(func, args[num_args], (int)size))
+               {
+                       return 0;
+               }
+       }
+
+       /* Do we need to add a structure return pointer argument? */
+       if(jit_type_return_via_pointer(type))
+       {
+               value = jit_value_create(func, type);
+               if(!value)
+               {
+                       return 0;
+               }
+               *struct_return = value;
+               value = jit_insn_address_of(func, value);
+               if(!value)
+               {
+                       return 0;
+               }
+               --word_regs;
+               if(!jit_insn_outgoing_reg(func, value, (int)word_regs))
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               *struct_return = 0;
+       }
+
+       /* Do we need to add nested function scope information? */
+       if(is_nested)
+       {
+               --word_regs;
+               if(!jit_insn_setup_for_nested(func, nesting_level, (int)word_regs))
+               {
+                       return 0;
+               }
+       }
+
+       /* The call is ready to proceed */
+       return 1;
+}
+
+int _jit_setup_indirect_pointer(jit_function_t func, jit_value_t value)
+{
+       return jit_insn_outgoing_reg(func, value, ARM_WORK);
+}
+
+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)
+{
+       jit_nint pop_bytes;
+       unsigned int size;
+       jit_type_t return_type;
+       int ptr_return;
+
+       /* Calculate the number of bytes that we need to pop */
+       return_type = jit_type_normalize(jit_type_get_return(signature));
+       ptr_return = jit_type_return_via_pointer(return_type);
+       pop_bytes = 0;
+       while(num_args > 0)
+       {
+               --num_args;
+               size = jit_type_get_size(jit_value_get_type(args[num_args]));
+               pop_bytes += ROUND_STACK(size);
+       }
+       if(ptr_return)
+       {
+               pop_bytes += sizeof(void *);
+       }
+       if(is_nested)
+       {
+               pop_bytes += sizeof(void *);
+       }
+       if(pop_bytes > (ARM_NUM_PARAM_REGS * sizeof(void *)))
+       {
+               pop_bytes -= (ARM_NUM_PARAM_REGS * sizeof(void *));
+       }
+       else
+       {
+               pop_bytes = 0;
+       }
+
+       /* Pop the bytes from the system stack */
+       if(pop_bytes > 0)
+       {
+               if(!jit_insn_pop_stack(func, pop_bytes))
+               {
+                       return 0;
+               }
+       }
+
+       /* Bail out now if we don't need to worry about return values */
+       if(!return_value || ptr_return)
+       {
+               return 0;
+       }
+
+       /* Structure values must be flushed into the frame, and
+          everything else ends up in a register */
+       if(jit_type_is_struct(return_type) || jit_type_is_union(return_type))
+       {
+               if(!jit_insn_flush_struct(func, return_value))
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               if(!jit_insn_return_reg(func, return_value, ARM_R0))
+               {
+                       return 0;
+               }
+       }
+
+       /* Everything is back where it needs to be */
+       return 1;
+}
+
+void *_jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf)
+{
+       unsigned int prolog[JIT_PROLOG_SIZE / sizeof(int)];
+       arm_inst_ptr inst = prolog;
+       int reg, regset;
+       unsigned int saved;
+       unsigned int frame_size;
+
+       /* Determine which registers need to be preserved */
+       regset = 0;
+       saved = 0;
+       for(reg = 0; reg <= 15; ++reg)
+       {
+               if(jit_reg_is_used(gen->touched, reg) &&
+                  (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
+               {
+                       regset |= (1 << reg);
+                       saved += sizeof(void *);
+               }
+       }
+
+       /* Setup the frame, pushing all the callee-save registers */
+       arm_setup_frame(inst, regset);
+
+       /* Allocate space for the local variable frame.  Subtract off
+          the space for the registers that we just saved.  The pc, lr,
+          and fp registers are always saved, so account for them too */
+       frame_size = func->builder->frame_size - (saved + 3);
+       if(frame_size > 0)
+       {
+               arm_alu_reg_imm(inst, ARM_SUB, ARM_SP, ARM_SP, frame_size);
+       }
+
+       /* Copy the prolog into place and return the adjusted entry position */
+       reg = (int)((inst - prolog) * sizeof(unsigned int));
+       jit_memcpy(((unsigned char *)buf) + JIT_PROLOG_SIZE - reg, prolog, reg);
+       return (void *)(((unsigned char *)buf) + JIT_PROLOG_SIZE - reg);
+}
+
+void _jit_gen_epilog(jit_gencode_t gen, jit_function_t func)
+{
+       int reg, regset;
+       arm_inst_ptr inst;
+
+       /* Bail out if there is insufficient space for the epilog */
+       if(!jit_cache_check_for_n(&(gen->posn), 4))
+       {
+               jit_cache_mark_full(&(gen->posn));
+               return;
+       }
+
+       /* Determine which registers need to be restored when we return */
+       regset = 0;
+       for(reg = 0; reg <= 15; ++reg)
+       {
+               if(jit_reg_is_used(gen->touched, reg) &&
+                  (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
+               {
+                       regset |= (1 << reg);
+               }
+       }
+
+       /* Pop the local stack frame and return */
+       inst = (arm_inst_ptr)(gen->posn.ptr);
+       arm_pop_frame(inst, regset);
+       gen->posn.ptr = (unsigned char *)inst;
+}
+
+void *_jit_gen_redirector(jit_gencode_t gen, jit_function_t func)
+{
+       void *ptr, *entry;
+       arm_inst_ptr inst;
+       if(!jit_cache_check_for_n(&(gen->posn), 12))
+       {
+               jit_cache_mark_full(&(gen->posn));
+               return 0;
+       }
+       ptr = (void *)&(func->entry_point);
+       entry = gen->posn.ptr;
+       inst = (arm_inst_ptr)(gen->posn.ptr);
+       arm_load_membase(inst, ARM_WORK, ARM_PC, 0);
+       arm_load_membase(inst, ARM_PC, ARM_WORK, 0);
+       *inst++ = (unsigned int)ptr;
+       gen->posn.ptr = (unsigned char *)inst;
+       return entry;
+}
+
+/*
+ * Setup or teardown the ARM code output process.
+ */
+#define        jit_cache_setup_output(needed)  \
+       arm_inst_ptr inst = (arm_inst_ptr)(gen->posn.ptr); \
+       if(!jit_cache_check_for_n(&(gen->posn), (needed))) \
+       { \
+               jit_cache_mark_full(&(gen->posn)); \
+               return; \
+       }
+#define        jit_cache_end_output()  \
+       gen->posn.ptr = (unsigned char *)inst
+
+void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
+                                               int other_reg, jit_value_t value)
+{
+       int offset;
+
+       /* Make sure that we have sufficient space */
+       jit_cache_setup_output(20);
+
+       /* Fix the value in place within the local variable frame */
+       _jit_gen_fix_value(value);
+
+       /* Output an appropriate instruction to spill the value */
+       offset = (int)(value->frame_offset);
+       arm_store_membase(inst, ARM_FP, offset, reg);
+       if(other_reg != -1)
+       {
+               /* Spill the other word register in a pair */
+               offset += sizeof(void *);
+               arm_store_membase(inst, ARM_FP, offset, reg);
+       }
+
+       /* End the code output process */
+       jit_cache_end_output();
+}
+
+void _jit_gen_free_reg(jit_gencode_t gen, int reg,
+                                          int other_reg, int value_used)
+{
+       /* We don't have to do anything to free ARM registers */
+}
+
+void _jit_gen_load_value
+       (jit_gencode_t gen, int reg, int other_reg, jit_value_t value)
+{
+       /* TODO */
+}
+
+void _jit_gen_fix_value(jit_value_t value)
+{
+       if(!(value->has_frame_offset) && !(value->is_constant))
+       {
+               jit_nint size = (jit_nint)(ROUND_STACK(jit_type_get_size(value->type)));
+               value->block->func->builder->frame_size += size;
+               value->frame_offset = -(value->block->func->builder->frame_size);
+               value->has_frame_offset = 1;
+       }
+}
+
+void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
+                                  jit_block_t block, jit_insn_t insn)
+{
+       /* TODO */
+}
+
+void _jit_gen_start_block(jit_gencode_t gen, jit_block_t block)
+{
+       /* TODO: label fixups */
+}
+
+void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
+{
+       /* Nothing to do here for ARM */
+}
+
+void _jit_gen_call_finally
+       (jit_gencode_t gen, jit_function_t func, jit_label_t label)
+{
+       /* TODO */
+}
+
+void _jit_gen_unwind_stack(void *stacktop, void *catch_pc, void *object)
+{
+       /* TODO */
+}
+
+#endif /* JIT_BACKEND_ARM */
diff --git a/jit/jit-rules-arm.h b/jit/jit-rules-arm.h
new file mode 100644 (file)
index 0000000..4ec5f60
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * jit-rules-arm.h - Rules that define the characteristics of the ARM.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_RULES_ARM_H
+#define        _JIT_RULES_ARM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Information about all of the registers, in allocation order.
+ * We use r0-r5 for general-purpose values and r6-r8 for globals.
+ *
+ * Of the floating-point registers, we only use f0-f3 at present,
+ * so that we don't have to worry about saving the values of f4-f7.
+ * The floating-point registers are only present on some ARM cores.
+ * "_jit_init_backend" will disable the FP registers if they don't exist.
+ */
+#define        JIT_REG_INFO    \
+       {"r0",   0,  1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
+       {"r1",   1, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
+       {"r2",   2,  3, JIT_REG_WORD | JIT_REG_CALL_USED}, \
+       {"r3",   3, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
+       {"r4",   4, -1, JIT_REG_WORD}, \
+       {"r5",   5, -1, JIT_REG_WORD}, \
+       {"r6",   6, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
+       {"r7",   7, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
+       {"r8",   8, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
+       {"r9",   9, -1, JIT_REG_FIXED},                         /* pic reg */ \
+       {"r10", 10, -1, JIT_REG_FIXED},                                         /* stack limit */ \
+       {"fp",  11, -1, JIT_REG_FIXED | JIT_REG_FRAME}, \
+       {"r12", 12, -1, JIT_REG_FIXED | JIT_REG_CALL_USED}, /* work reg */ \
+       {"sp",  13, -1, JIT_REG_FIXED | JIT_REG_STACK_PTR}, \
+       {"lr",  14, -1, JIT_REG_FIXED}, \
+       {"pc",  15, -1, JIT_REG_FIXED}, \
+       {"f0",   0, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED}, \
+       {"f1",   1, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED}, \
+       {"f2",   2, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED}, \
+       {"f3",   3, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED},
+#define        JIT_NUM_REGS    20
+
+/*
+ * Define to 1 if we should always load values into registers
+ * before operating on them.  i.e. the CPU does not have reg-mem
+ * and mem-reg addressing modes.
+ */
+#define        JIT_ALWAYS_REG_REG              1
+
+/*
+ * The maximum number of bytes to allocate for the prolog.
+ * This may be shortened once we know the true prolog size.
+ */
+#define        JIT_PROLOG_SIZE                 48
+
+/*
+ * Preferred alignment for the start of functions.
+ */
+#define        JIT_FUNCTION_ALIGNMENT  4
+
+/*
+ * 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.
+ */
+#define        JIT_ALIGN_OVERRIDES             0
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_RULES_ARM_H */
diff --git a/jit/jit-rules-interp.c b/jit/jit-rules-interp.c
new file mode 100644 (file)
index 0000000..3ac69b1
--- /dev/null
@@ -0,0 +1,1351 @@
+/*
+ * jit-rules-interp.c - Rules that define the interpreter characteristics.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-rules.h"
+#include "jit-reg-alloc.h"
+
+#if defined(JIT_BACKEND_INTERP)
+
+#include "jit-interp.h"
+
+/*@
+
+The architecture definition rules for a CPU are placed into the files
+@code{jit-rules-ARCH.h} and @code{jit-rules-ARCH.c}.  You should add
+both of these files to @code{Makefile.am} in @code{libjit/jit}.
+
+You will also need to edit @code{jit-rules.h} in two places.  First,
+place detection logic at the top of the file to detect your platform
+and define @code{JIT_BACKEND_ARCH} to 1.  Further down the file,
+you should add the following two lines to the include file logic:
+
+@example
+#elif defined(JIT_BACKEND_ARCH)
+#include "jit-rules-ARCH.h"
+@end example
+
+@subsection Defining the registers
+
+Every rule header file needs to define the macro @code{JIT_REG_INFO} to
+an array of values that represents the properties of the CPU's
+registers.  The @code{_jit_reg_info} array is populated with
+these values.  @code{JIT_NUM_REGS} defines the number of
+elements in the array.  Each element in the array has the
+following members:
+
+@table @code
+@item name
+The name of the register.  This is used for debugging purposes.
+
+@item cpu_reg
+The raw CPU register number.  Registers in @code{libjit} are
+referred to by their pseudo register numbers, corresponding to
+their index within @code{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.
+
+@item 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.
+
+@item flags
+Flag bits that describe the pseudo register's properties.
+@end table
+
+@noindent
+The following flags may be present:
+
+@table @code
+@item JIT_REG_WORD
+This register can hold an integer word value.
+
+@item JIT_REG_LONG
+This register can hold a 64-bit long value without needing a
+second register.  Normally only used on 64-bit platforms.
+
+@item JIT_REG_FLOAT
+This register can hold a native floating-point value.
+
+@item JIT_REG_FRAME
+This register holds the frame pointer.  You will almost always supply
+@code{JIT_REG_FIXED} for this register.
+
+@item JIT_REG_STACK_PTR
+This register holds the stack pointer.  You will almost always supply
+@code{JIT_REG_FIXED} for this register.
+
+@item JIT_REG_FIXED
+This register has a fixed meaning and cannot be used for general allocation.
+
+@item JIT_REG_CALL_USED
+This register will be destroyed by a function call.
+
+@item JIT_REG_START_STACK
+This register is the start of a range of registers that are used in a
+stack-like arrangement.  Operations can typically only occur at the
+top of the stack, and may automatically pop values as a side-effect
+of the operation.  The stack continues until the next register that is
+marked with @code{JIT_REG_END_STACK}.  The starting register must
+also have the @code{JIT_REG_IN_STACK} flag set.
+
+@item JIT_REG_END_STACK
+This register is the end of a range of registers that are used in a
+stack-like arrangement.  The ending register must also have the
+@code{JIT_REG_IN_STACK} flag set.
+
+@item JIT_REG_IN_STACK
+This register is in a stack-like arrangement.  If neither
+@code{JIT_REG_START_STACK} or @code{JIT_REG_END_STACK} is present,
+then the register is in the "middle" of the stack.
+
+@item JIT_REG_GLOBAL
+This register is a candidate for global register allocation.
+@end table
+
+@subsection Other architecture macros
+
+@noindent
+The rule file may also have definitions of the following macros:
+
+@table @code
+@item 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.
+
+@item JIT_PROLOG_SIZE
+If defined, this indicates the maximum size of the function prolog.
+
+@item 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.
+
+@item 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.
+
+@item jit_extra_gen_state
+@itemx jit_extra_gen_init
+@itemx jit_extra_gen_cleanup
+The @code{jit_extra_gen_state} macro can be supplied to add extra fields
+to the @code{struct jit_gencode} type in @code{jit-rules.h}, for
+extra CPU-specific code generation state information.
+
+The @code{jit_extra_gen_init} macro initializes this extra information,
+and the @code{jit_extra_gen_cleanup} macro cleans it up when code
+generation is complete.
+@end table
+
+@subsection Architecture-dependent functions
+
+@*/
+
+/*
+ * Write an interpreter opcode to the cache.
+ */
+#define        jit_cache_opcode(posn,opcode)   \
+                       jit_cache_native((posn), (jit_nint)(opcode))
+
+/*
+ * Write "n" bytes to the cache, rounded up to a multiple of "void *".
+ */
+#define        jit_cache_add_n(posn,buf,size)  \
+               do { \
+                       unsigned int __size = \
+                               ((size) + sizeof(void *) - 1) & ~(sizeof(void *) - 1); \
+                       if(jit_cache_check_for_n((posn), __size)) \
+                       { \
+                               jit_memcpy((posn)->ptr, (buf), (size)); \
+                               (posn)->ptr += __size; \
+                       } \
+                       else \
+                       { \
+                               jit_cache_mark_full((posn)); \
+                       } \
+               } while (0)
+
+/*
+ * Adjust the height of the working area.
+ */
+#define        adjust_working(gen,adjust)      \
+               do { \
+                       (gen)->working_area += (adjust); \
+                       if((gen)->working_area > (gen)->max_working_area) \
+                       { \
+                               (gen)->max_working_area = (gen)->working_area; \
+                       } \
+               } while (0)
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+void _jit_init_backend(void)
+{
+       /* Nothing to do here for the interpreter */
+}
+
+/*@
+ * @deftypefun void _jit_gen_get_elf_info ({jit_elf_info_t *} info)
+ * Get the ELF machine and ABI type information for this platform.
+ * The @code{machine} field should be set to one of the @code{EM_*}
+ * values in @code{jit-elf-defs.h}.  The @code{abi} field should
+ * be set to one of the @code{ELFOSABI_*} values in @code{jit-elf-defs.h}
+ * (@code{ELFOSABI_SYSV} will normally suffice if you are unsure).
+ * The @code{abi_version} field should be set to the ABI version,
+ * which is usually zero.
+ * @end deftypefun
+@*/
+void _jit_gen_get_elf_info(jit_elf_info_t *info)
+{
+       /* The interpreter's ELF machine type is defined to be "Lj",
+          which hopefully won't clash with any standard types */
+       info->machine = 0x4C6A;
+       info->abi = 0;
+       info->abi_version = JIT_OPCODE_VERSION;
+}
+
+/*@
+ * @deftypefun 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
+ * @code{jit_insn_incoming_reg} or @code{jit_insn_incoming_frame_posn}
+ * to notify @code{libjit} of the location.
+ * @end deftypefun
+@*/
+int _jit_create_entry_insns(jit_function_t func)
+{
+       jit_type_t signature = func->signature;
+       jit_type_t type;
+       jit_nint offset;
+       jit_value_t value;
+       unsigned int num_params;
+       unsigned int param;
+
+       /* Reset the frame size for this function */
+       func->builder->frame_size = 0;
+
+       /* The starting parameter offset.  We use negative offsets to indicate
+          an offset into the "args" block, and positive offsets to indicate
+          an offset into the "frame" block.  The negative values will be
+          flipped when we output the argument opcodes for interpretation */
+       offset = -1;
+
+       /* If the function is nested, then we need two extra parameters
+          to pass the pointer to the parent's local variables and arguments */
+       if(func->nested_parent)
+       {
+               offset -= 2;
+       }
+
+       /* Allocate the structure return pointer */
+       value = jit_value_get_struct_pointer(func);
+       if(value)
+       {
+               if(!jit_insn_incoming_frame_posn(func, value, offset))
+               {
+                       return 0;
+               }
+               --offset;
+       }
+
+       /* Allocate the parameter offsets */
+       num_params = jit_type_num_params(signature);
+       for(param = 0; param < num_params; ++param)
+       {
+               value = jit_value_get_param(func, param);
+               if(!value)
+               {
+                       continue;
+               }
+               type = jit_type_normalize(jit_value_get_type(value));
+               switch(type->kind)
+               {
+                       case JIT_TYPE_SBYTE:
+                       case JIT_TYPE_UBYTE:
+                       {
+                               if(!jit_insn_incoming_frame_posn
+                                               (func, value, offset - _jit_int_lowest_byte()))
+                               {
+                                       return 0;
+                               }
+                               --offset;
+                       }
+                       break;
+
+                       case JIT_TYPE_SHORT:
+                       case JIT_TYPE_USHORT:
+                       {
+                               if(!jit_insn_incoming_frame_posn
+                                               (func, value, offset - _jit_int_lowest_short()))
+                               {
+                                       return 0;
+                               }
+                               --offset;
+                       }
+                       break;
+
+                       case JIT_TYPE_INT:
+                       case JIT_TYPE_UINT:
+                       case JIT_TYPE_NINT:
+                       case JIT_TYPE_NUINT:
+                       case JIT_TYPE_SIGNATURE:
+                       case JIT_TYPE_PTR:
+                       case JIT_TYPE_LONG:
+                       case JIT_TYPE_ULONG:
+                       case JIT_TYPE_FLOAT32:
+                       case JIT_TYPE_FLOAT64:
+                       case JIT_TYPE_NFLOAT:
+                       {
+                               if(!jit_insn_incoming_frame_posn(func, value, offset))
+                               {
+                                       return 0;
+                               }
+                               --offset;
+                       }
+                       break;
+
+                       case JIT_TYPE_STRUCT:
+                       case JIT_TYPE_UNION:
+                       {
+                               if(!jit_insn_incoming_frame_posn(func, value, offset))
+                               {
+                                       return 0;
+                               }
+                               offset -= JIT_NUM_ITEMS_IN_STRUCT(jit_type_get_size(type));
+                       }
+                       break;
+               }
+       }
+       return 1;
+}
+
+/*@
+ * @deftypefun 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)
+ * Create instructions within @code{func} necessary to set up for a
+ * function call to a function with the specified @code{signature}.
+ * Use @code{jit_insn_push} to push values onto the system stack,
+ * or @code{jit_insn_outgoing_reg} to copy values into call registers.
+ *
+ * If @code{is_nested} is non-zero, then it indicates that we are calling a
+ * nested function within the current function's nested relationship tree.
+ * The @code{nested_level} value will be -1 to call a child, zero to call a
+ * sibling of @code{func}, 1 to call a sibling of the parent, 2 to call
+ * a sibling of the grandparent, etc.  The @code{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 @code{struct_return}
+ * must be set to a new local variable that will contain the returned
+ * structure.  Otherwise it should be set to NULL.
+ * @end deftypefun
+@*/
+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)
+{
+       jit_type_t type;
+       jit_value_t value;
+
+       /* Push all of the arguments in reverse order */
+       while(num_args > 0)
+       {
+               --num_args;
+               if(!jit_insn_push(func, args[num_args]))
+               {
+                       return 0;
+               }
+       }
+
+       /* Do we need to add a structure return pointer argument? */
+       type = jit_type_get_return(signature);
+       if(jit_type_return_via_pointer(type))
+       {
+               value = jit_value_create(func, type);
+               if(!value)
+               {
+                       return 0;
+               }
+               *struct_return = value;
+               value = jit_insn_address_of(func, value);
+               if(!value)
+               {
+                       return 0;
+               }
+               if(!jit_insn_push(func, value))
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               *struct_return = 0;
+       }
+
+       /* Do we need to add nested function scope information? */
+       if(is_nested)
+       {
+               if(!jit_insn_setup_for_nested(func, nested_level, -1))
+               {
+                       return 0;
+               }
+       }
+
+       /* The call is ready to proceed */
+       return 1;
+}
+
+/*@
+ * @deftypefun int _jit_setup_indirect_pointer (jit_function_t func, jit_value_t value)
+ * Place the indirect function pointer @code{value} into a suitable register
+ * or stack location for a subsequent indirect call.
+ * @end deftypefun
+@*/
+int _jit_setup_indirect_pointer(jit_function_t func, jit_value_t value)
+{
+       return jit_insn_push(func, value);
+}
+
+/*@
+ * @deftypefun 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 @code{func} to clean up after a function call
+ * and to place the function's result into @code{return_value}.
+ * This should use @code{jit_insn_pop_stack} to pop values off the system
+ * stack and @code{jit_insn_return_reg} to tell @code{libjit} which
+ * register contains the return value.  In the case of a @code{void}
+ * function, @code{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 @code{signature}
+ * alone; especially if the called function is vararg.
+ * @end deftypefun
+@*/
+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)
+{
+       jit_nint pop_items;
+       unsigned int size;
+       jit_type_t return_type;
+       int ptr_return;
+
+       /* Calculate the number of items that we need to pop */
+       pop_items = 0;
+       while(num_args > 0)
+       {
+               --num_args;
+               size = jit_type_get_size(jit_value_get_type(args[num_args]));
+               pop_items += JIT_NUM_ITEMS_IN_STRUCT(size);
+       }
+       return_type = jit_type_normalize(jit_type_get_return(signature));
+       ptr_return = jit_type_return_via_pointer(return_type);
+       if(ptr_return)
+       {
+               ++pop_items;
+       }
+       if(is_nested)
+       {
+               /* The interpreter needs two arguments for the parent frame info */
+               pop_items += 2;
+       }
+
+       /* Pop the items from the system stack */
+       if(pop_items > 0)
+       {
+               if(!jit_insn_pop_stack(func, pop_items))
+               {
+                       return 0;
+               }
+       }
+
+       /* Bail out now if we don't need to worry about return values */
+       if(!return_value || ptr_return)
+       {
+               return 0;
+       }
+
+       /* Structure values must be flushed into the frame, and
+          everything else ends up in the top-most stack register */
+       if(jit_type_is_struct(return_type) || jit_type_is_union(return_type))
+       {
+               if(!jit_insn_flush_struct(func, return_value))
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               if(!jit_insn_return_reg(func, return_value, 0))
+               {
+                       return 0;
+               }
+       }
+
+       /* Everything is back where it needs to be */
+       return 1;
+}
+
+/*@
+ * @deftypefun 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 @code{jit-insn.c} will output a
+ * call to an intrinsic function that is equivalent to the desired opcode.
+ * This is how you tell @code{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.
+ * @end deftypefun
+@*/
+int _jit_opcode_is_supported(int opcode)
+{
+       /* We support all opcodes in the interpreter */
+       return 1;
+}
+
+/*
+ * Calculate the size of the argument area for an interpreted function.
+ */
+unsigned int _jit_interp_calculate_arg_size
+               (jit_function_t func, jit_type_t signature)
+{
+       unsigned int size = 0;
+       jit_type_t type;
+       unsigned int num_params;
+       unsigned int param;
+
+       /* Determine if we need nested parameter information */
+       if(func->nested_parent)
+       {
+               size += 2 * sizeof(jit_item);
+       }
+
+       /* Determine if we need a structure pointer argument */
+       type = jit_type_get_return(signature);
+       if(jit_type_return_via_pointer(type))
+       {
+               size += sizeof(jit_item);
+       }
+
+       /* Calculate the total size of the regular arguments */
+       num_params = jit_type_num_params(signature);
+       for(param = 0; param < num_params; ++param)
+       {
+               type = jit_type_normalize(jit_type_get_param(signature, param));
+               if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
+               {
+                       size += JIT_NUM_ITEMS_IN_STRUCT(jit_type_get_size(type)) *
+                                       sizeof(jit_item);
+               }
+               else
+               {
+                       size += sizeof(jit_item);
+               }
+       }
+
+       /* Return the final size to the caller */
+       return size;
+}
+
+/*@
+ * @deftypefun {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 @code{JIT_PROLOG_SIZE} bytes in size.  Returns
+ * the start of the prolog, which may be different than @code{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.
+ * @end deftypefun
+@*/
+void *_jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf)
+{
+       /* Output the jit_function_interp structure at the beginning */
+       jit_function_interp_t interp = (jit_function_interp_t)buf;
+       interp->func = func;
+       interp->args_size = _jit_interp_calculate_arg_size(func, func->signature);
+       interp->frame_size =
+               (func->builder->frame_size + gen->max_working_area) * sizeof(jit_item);
+       interp->working_area = gen->max_working_area;
+       return buf;
+}
+
+/*@
+ * @deftypefun 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
+ * @code{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.
+ * @end deftypefun
+@*/
+void _jit_gen_epilog(jit_gencode_t gen, jit_function_t func)
+{
+       jit_cache_opcode(&(gen->posn), JIT_OP_END_MARKER);
+}
+
+/*@
+ * @deftypefun {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 @code{func->entry_point}.  Redirectors
+ * are used on recompilable functions in place of the regular
+ * entry point.  This allows @code{libjit} to redirect existing
+ * calls to the new version after recompilation.
+ * @end deftypefun
+@*/
+void *_jit_gen_redirector(jit_gencode_t gen, jit_function_t func)
+{
+       /* The interpreter doesn't need redirectors */
+       return 0;
+}
+
+/*@
+ * @deftypefun 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 @code{other_reg} is not -1, then it indicates
+ * the second register in a 64-bit register pair.
+ *
+ * This function will typically call @code{_jit_gen_fix_value} to
+ * fix the value's frame position, and will then generate the
+ * appropriate spill instructions.
+ * @end deftypefun
+@*/
+void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
+                                               int other_reg, jit_value_t value)
+{
+       int opcode;
+       jit_nint offset;
+
+       /* Fix the value in place within the local variable frame */
+       _jit_gen_fix_value(value);
+
+       /* Output an appropriate instruction to spill the value */
+       offset = value->frame_offset;
+       if(offset >= 0)
+       {
+               opcode = _jit_store_opcode(JIT_OP_STLOC_BYTE, 0, value->type);
+       }
+       else
+       {
+               opcode = _jit_store_opcode(JIT_OP_STARG_BYTE, 0, value->type);
+               offset = -(offset + 1);
+       }
+       jit_cache_opcode(&(gen->posn), opcode);
+       jit_cache_native(&(gen->posn), offset);
+
+       /* Adjust the working area to account for the popped value */
+       adjust_working(gen, -1);
+}
+
+/*@
+ * @deftypefun 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 @code{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.
+ * @end deftypefun
+@*/
+void _jit_gen_free_reg(jit_gencode_t gen, int reg,
+                                          int other_reg, int value_used)
+{
+       /* If the value wasn't used, then pop it from the stack.
+          Registers are always freed from the top down */
+       if(!value_used)
+       {
+               jit_cache_opcode(&(gen->posn), JIT_OP_POP);
+               adjust_working(gen, -1);
+       }
+}
+
+/*@
+ * @deftypefun 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 @code{_jit_gen_fix_value}.
+ * @end deftypefun
+@*/
+void _jit_gen_load_value
+       (jit_gencode_t gen, int reg, int other_reg, jit_value_t value)
+{
+       int opcode;
+       if(value->is_constant)
+       {
+               /* Determine the type of constant to be loaded */
+               switch(jit_type_normalize(value->type)->kind)
+               {
+                       case JIT_TYPE_SBYTE:
+                       case JIT_TYPE_UBYTE:
+                       case JIT_TYPE_SHORT:
+                       case JIT_TYPE_USHORT:
+                       case JIT_TYPE_INT:
+                       case JIT_TYPE_UINT:
+                       {
+                               jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_CONST_INT);
+                               jit_cache_native(&(gen->posn), (jit_nint)(value->address));
+                       }
+                       break;
+
+                       case JIT_TYPE_LONG:
+                       case JIT_TYPE_ULONG:
+                       {
+                               jit_long long_value;
+                               long_value = jit_value_get_long_constant(value);
+                               jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_CONST_LONG);
+                       #ifdef JIT_NATIVE_INT64
+                               jit_cache_native(&(gen->posn), long_value);
+                       #else
+                               jit_cache_add_n(&(gen->posn), &long_value, sizeof(long_value));
+                       #endif
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT32:
+                       {
+                               jit_float32 float32_value;
+                               float32_value = jit_value_get_float32_constant(value);
+                               jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_CONST_FLOAT32);
+                               jit_cache_add_n
+                                       (&(gen->posn), &float32_value, sizeof(float32_value));
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT64:
+                       {
+                               jit_float64 float64_value;
+                               float64_value = jit_value_get_float64_constant(value);
+                               jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_CONST_FLOAT64);
+                               jit_cache_add_n
+                                       (&(gen->posn), &float64_value, sizeof(float64_value));
+                       }
+                       break;
+
+                       case JIT_TYPE_NFLOAT:
+                       {
+                               jit_nfloat nfloat_value;
+                               nfloat_value = jit_value_get_nfloat_constant(value);
+                               jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_CONST_NFLOAT);
+                               jit_cache_add_n
+                                       (&(gen->posn), &nfloat_value, sizeof(nfloat_value));
+                       }
+                       break;
+               }
+       }
+       else
+       {
+               /* Fix the position of the value in the stack frame */
+               _jit_gen_fix_value(value);
+
+               /* Generate a local or argument access opcode, as appropriate */
+               if(value->frame_offset >= 0)
+               {
+                       /* Load a local variable value onto the stack */
+                       opcode = _jit_load_opcode
+                               (JIT_OP_LDLOC_SBYTE, value->type, value, 0);
+                       jit_cache_opcode(&(gen->posn), opcode);
+                       jit_cache_native(&(gen->posn), value->frame_offset);
+               }
+               else
+               {
+                       /* Load an argument value onto the stack */
+                       opcode = _jit_load_opcode
+                               (JIT_OP_LDARG_SBYTE, value->type, value, 0);
+                       jit_cache_opcode(&(gen->posn), opcode);
+                       jit_cache_native(&(gen->posn), -(value->frame_offset + 1));
+               }
+       }
+
+       /* We have one more value on the stack */
+       adjust_working(gen, 1);
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+void _jit_gen_fix_value(jit_value_t value)
+{
+       if(!(value->has_frame_offset) && !(value->is_constant))
+       {
+               jit_nint size = (jit_nint)
+                       (JIT_NUM_ITEMS_IN_STRUCT(jit_type_get_size(value->type)));
+               value->frame_offset = value->block->func->builder->frame_size;
+               value->block->func->builder->frame_size += size;
+               value->has_frame_offset = 1;
+       }
+}
+
+/*
+ * Get the destination of a branch instruction, and thread through
+ * unconditional branches that this one points to.  Returns
+ * "jit_label_undefined" if we are branching to the next block
+ * (i.e. the branch instruction can be quietly eliminated).
+ */
+static jit_label_t get_branch_dest(jit_block_t block, jit_insn_t insn)
+{
+       jit_label_t label;
+       jit_block_t new_block;
+       int max_thread;
+       jit_insn_iter_t iter;
+
+       /* Get the starting label */
+       label = (jit_label_t)(insn->dest);
+
+       /* Bail out now if we are within an exception block, because we
+          don't want to thread to jumps outside the "finally" context */
+       if(block->block_eh && insn->opcode == JIT_OP_BR)
+       {
+               return label;
+       }
+
+       /* Thread unconditional jumps at the destination */
+       max_thread = 20;
+       while(max_thread > 0 &&
+             (new_block = jit_block_from_label(block->func, label)) != 0)
+       {
+               jit_insn_iter_init(&iter, new_block);
+               insn = jit_insn_iter_next(&iter);
+               if(!insn || insn->opcode != JIT_OP_BR)
+               {
+                       break;
+               }
+               label = (jit_label_t)(insn->dest);
+               --max_thread;
+       }
+
+       /* Determine if we are branching to the next block */
+       if(block->next && block->next->label == label)
+       {
+               return jit_label_undefined;
+       }
+
+       /* Return the destination label to the caller */
+       return label;
+}
+
+/*@
+ * @deftypefun 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 @code{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.
+ * @end deftypefun
+@*/
+void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
+                                  jit_block_t block, jit_insn_t insn)
+{
+       int reg;
+       jit_label_t label;
+       void **pc;
+
+       switch(insn->opcode)
+       {
+               /* TODO */
+
+               case JIT_OP_BR:
+               {
+                       /* Unconditional branch */
+                       _jit_regs_spill_all(gen);
+                       label = get_branch_dest(block, insn);
+                       if(label != jit_label_undefined)
+                       {
+                       branch:
+                               pc = (void **)(gen->posn.ptr);
+                               jit_cache_opcode(&(gen->posn), insn->opcode);
+                               block = jit_block_from_label(func, label);
+                               if(!block)
+                               {
+                                       break;
+                               }
+                               if(block->address)
+                               {
+                                       /* We already know the address of the block */
+                                       jit_cache_native
+                                               (&(gen->posn), ((void **)(block->address)) - pc);
+                               }
+                               else
+                               {
+                                       /* Record this position on the block's fixup list */
+                                       jit_cache_native(&(gen->posn), block->fixup_list);
+                                       block->fixup_list = (void *)pc;
+                               }
+                       }
+               }
+               break;
+
+               case JIT_OP_BR_IFALSE:
+               case JIT_OP_BR_ITRUE:
+               case JIT_OP_BR_LFALSE:
+               case JIT_OP_BR_LTRUE:
+               {
+                       /* Unary branch */
+                       label = get_branch_dest(block, insn);
+                       if(label == jit_label_undefined)
+                       {
+                               /* We are falling through, no matter what the test
+                                  says, so optimize the entire instruction away */
+                               _jit_regs_spill_all(gen);
+                               break;
+                       }
+                       if(!_jit_regs_is_top(gen, insn->value1) ||
+                          _jit_regs_num_used(gen, 0) != 1)
+                       {
+                               _jit_regs_spill_all(gen);
+                       }
+                       reg = _jit_regs_load_to_top
+                               (gen, insn->value1, (insn->flags & JIT_INSN_VALUE1_LIVE), 0);
+                       _jit_regs_free_reg(gen, reg, 1);
+                       goto branch;
+               }
+               /* Not reached */
+
+               case JIT_OP_BR_IEQ:
+               case JIT_OP_BR_INE:
+               case JIT_OP_BR_ILT:
+               case JIT_OP_BR_ILT_UN:
+               case JIT_OP_BR_ILE:
+               case JIT_OP_BR_ILE_UN:
+               case JIT_OP_BR_IGT:
+               case JIT_OP_BR_IGT_UN:
+               case JIT_OP_BR_IGE:
+               case JIT_OP_BR_IGE_UN:
+               case JIT_OP_BR_LEQ:
+               case JIT_OP_BR_LNE:
+               case JIT_OP_BR_LLT:
+               case JIT_OP_BR_LLT_UN:
+               case JIT_OP_BR_LLE:
+               case JIT_OP_BR_LLE_UN:
+               case JIT_OP_BR_LGT:
+               case JIT_OP_BR_LGT_UN:
+               case JIT_OP_BR_LGE:
+               case JIT_OP_BR_LGE_UN:
+               case JIT_OP_BR_FEQ:
+               case JIT_OP_BR_FNE:
+               case JIT_OP_BR_FLT:
+               case JIT_OP_BR_FLE:
+               case JIT_OP_BR_FGT:
+               case JIT_OP_BR_FGE:
+               case JIT_OP_BR_FEQ_INV:
+               case JIT_OP_BR_FNE_INV:
+               case JIT_OP_BR_FLT_INV:
+               case JIT_OP_BR_FLE_INV:
+               case JIT_OP_BR_FGT_INV:
+               case JIT_OP_BR_FGE_INV:
+               case JIT_OP_BR_DEQ:
+               case JIT_OP_BR_DNE:
+               case JIT_OP_BR_DLT:
+               case JIT_OP_BR_DLE:
+               case JIT_OP_BR_DGT:
+               case JIT_OP_BR_DGE:
+               case JIT_OP_BR_DEQ_INV:
+               case JIT_OP_BR_DNE_INV:
+               case JIT_OP_BR_DLT_INV:
+               case JIT_OP_BR_DLE_INV:
+               case JIT_OP_BR_DGT_INV:
+               case JIT_OP_BR_DGE_INV:
+               case JIT_OP_BR_NFEQ:
+               case JIT_OP_BR_NFNE:
+               case JIT_OP_BR_NFLT:
+               case JIT_OP_BR_NFLE:
+               case JIT_OP_BR_NFGT:
+               case JIT_OP_BR_NFGE:
+               case JIT_OP_BR_NFEQ_INV:
+               case JIT_OP_BR_NFNE_INV:
+               case JIT_OP_BR_NFLT_INV:
+               case JIT_OP_BR_NFLE_INV:
+               case JIT_OP_BR_NFGT_INV:
+               case JIT_OP_BR_NFGE_INV:
+               {
+                       /* Binary branch */
+                       label = get_branch_dest(block, insn);
+                       if(label == jit_label_undefined)
+                       {
+                               /* We are falling through, no matter what the test
+                                  says, so optimize the entire instruction away */
+                               _jit_regs_spill_all(gen);
+                               break;
+                       }
+                       if(!_jit_regs_is_top_two(gen, insn->value1, insn->value2) ||
+                          _jit_regs_num_used(gen, 0) != 2)
+                       {
+                               _jit_regs_spill_all(gen);
+                       }
+                       reg = _jit_regs_load_to_top_two
+                               (gen, insn->value1, insn->value2,
+                                (insn->flags & JIT_INSN_VALUE1_LIVE),
+                                (insn->flags & JIT_INSN_VALUE2_LIVE), 0);
+                       _jit_regs_free_reg(gen, reg, 1);
+                       goto branch;
+               }
+               /* Not reached */
+
+               case JIT_OP_CALL:
+               case JIT_OP_CALL_EXTERNAL:
+               {
+                       /* Call a function, whose pointer is supplied explicitly */
+                       jit_cache_opcode(&(gen->posn), insn->opcode);
+                       jit_cache_native(&(gen->posn), (jit_nint)(insn->dest));
+               }
+               break;
+
+               case JIT_OP_CALL_INDIRECT:
+               case JIT_OP_CALL_VTABLE_PTR:
+               {
+                       /* Call a function, whose pointer is supplied on the stack */
+                       _jit_regs_load_to_top(gen, insn->value1, 0, 0);
+                       jit_cache_opcode(&(gen->posn), insn->opcode);
+                       adjust_working(gen, -1);
+               }
+               break;
+
+               case JIT_OP_RETURN:
+               {
+                       /* Return from the current function with no result */
+                       _jit_regs_spill_all(gen);
+                       jit_cache_opcode(&(gen->posn), JIT_OP_RETURN);
+               }
+               break;
+
+               case JIT_OP_RETURN_INT:
+               case JIT_OP_RETURN_LONG:
+               case JIT_OP_RETURN_FLOAT32:
+               case JIT_OP_RETURN_FLOAT64:
+               case JIT_OP_RETURN_NFLOAT:
+               {
+                       /* Return from the current function with a specific result */
+                       if(!_jit_regs_is_top(gen, insn->value1) ||
+                          _jit_regs_num_used(gen, 0) != 1)
+                       {
+                               _jit_regs_spill_all(gen);
+                       }
+                       reg = _jit_regs_load_to_top(gen, insn->value1, 0, 0);
+                       jit_cache_opcode(&(gen->posn), insn->opcode);
+                       _jit_regs_free_reg(gen, reg, 1);
+               }
+               break;
+
+               case JIT_OP_RETURN_REG:
+               {
+                       /* Push a function return value back onto the stack */
+                       switch(jit_type_normalize(insn->value1->type)->kind)
+                       {
+                               case JIT_TYPE_SBYTE:
+                               case JIT_TYPE_UBYTE:
+                               case JIT_TYPE_SHORT:
+                               case JIT_TYPE_USHORT:
+                               case JIT_TYPE_INT:
+                               case JIT_TYPE_UINT:
+                               {
+                                       jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_RETURN_INT);
+                                       adjust_working(gen, 1);
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               case JIT_TYPE_ULONG:
+                               {
+                                       jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_RETURN_LONG);
+                                       adjust_working(gen, 1);
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_RETURN_FLOAT32);
+                                       adjust_working(gen, 1);
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_RETURN_FLOAT64);
+                                       adjust_working(gen, 1);
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_RETURN_NFLOAT);
+                                       adjust_working(gen, 1);
+                               }
+                               break;
+                       }
+               }
+               break;
+
+               case JIT_OP_PUSH_INT:
+               case JIT_OP_PUSH_LONG:
+               case JIT_OP_PUSH_FLOAT32:
+               case JIT_OP_PUSH_FLOAT64:
+               case JIT_OP_PUSH_NFLOAT:
+               {
+                       /* Push an item onto the stack, ready for a function call */
+                       if(!_jit_regs_is_top(gen, insn->value1) ||
+                          _jit_regs_num_used(gen, 0) != 1)
+                       {
+                               _jit_regs_spill_all(gen);
+                       }
+                       reg = _jit_regs_load_to_top
+                               (gen, insn->value1,
+                                (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
+                                                                JIT_INSN_VALUE1_LIVE)), 0);
+                       _jit_regs_free_reg(gen, reg, 1);
+               }
+               break;
+
+               case JIT_OP_PUSH_STRUCT:
+               {
+                       /* TODO */
+               }
+               break;
+
+               case JIT_OP_POP_STACK:
+               {
+                       /* Pop parameter values from the stack after a function returns */
+                       jit_nint size = jit_value_get_nint_constant(insn->value1);
+                       if(size == 1)
+                       {
+                               jit_cache_opcode(&(gen->posn), JIT_OP_POP);
+                       }
+                       else if(size == 2)
+                       {
+                               jit_cache_opcode(&(gen->posn), JIT_OP_POP_2);
+                       }
+                       else if(size == 3)
+                       {
+                               jit_cache_opcode(&(gen->posn), JIT_OP_POP_3);
+                       }
+                       else if(size != 0)
+                       {
+                               jit_cache_opcode(&(gen->posn), JIT_OP_POP_STACK);
+                               jit_cache_native(&(gen->posn), size);
+                       }
+               }
+               break;
+
+               case JIT_OP_FLUSH_SMALL_STRUCT:
+               {
+                       /* Flush a small structure return value back into the frame */
+                       _jit_gen_fix_value(insn->value1);
+                       if(insn->value1->frame_offset >= 0)
+                       {
+                               jit_cache_opcode(&(gen->posn), JIT_OP_LDLOCA);
+                               jit_cache_native(&(gen->posn), insn->value1->frame_offset);
+                       }
+                       else
+                       {
+                               jit_cache_opcode(&(gen->posn), JIT_OP_LDARGA);
+                               jit_cache_native
+                                       (&(gen->posn), -(insn->value1->frame_offset + 1));
+                       }
+                       jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_RETURN_SMALL_STRUCT);
+                       jit_cache_native
+                               (&(gen->posn), jit_type_get_size(insn->value1->type));
+                       adjust_working(gen, 2);
+                       jit_cache_opcode(&(gen->posn), JIT_OP_STORE_RELATIVE_STRUCT);
+                       jit_cache_native(&(gen->posn), 0);
+                       jit_cache_native
+                               (&(gen->posn), jit_type_get_size(insn->value1->type));
+                       adjust_working(gen, -2);
+               }
+               break;
+
+               default:
+               {
+                       /* Whatever opcodes are left are binary or unary operators,
+                          and the interpreter's opcode is identical to the JIT's */
+                       if(insn->value2)
+                       {
+                               /* Generate code for a binary operator */
+                               reg = _jit_regs_load_to_top_two
+                                       (gen, insn->value1, insn->value2,
+                                        (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
+                                                                        JIT_INSN_VALUE1_LIVE)),
+                                        (insn->flags & (JIT_INSN_VALUE2_NEXT_USE |
+                                                                        JIT_INSN_VALUE2_LIVE)), 0);
+                               jit_cache_opcode(&(gen->posn), insn->opcode);
+                               adjust_working(gen, -1);
+                               if(insn->dest)
+                               {
+                                       if((insn->flags & JIT_INSN_DEST_NEXT_USE) != 0)
+                                       {
+                                               /* Record that the destination is in "reg" */
+                                               _jit_regs_set_value(gen, reg, insn->dest, 0);
+                                       }
+                                       else
+                                       {
+                                               /* No next use, so store to the destination */
+                                               _jit_gen_spill_reg(gen, reg, -1, insn->dest);
+                                               insn->dest->in_frame = 1;
+                                               _jit_regs_free_reg(gen, reg, 1);
+                                       }
+                               }
+                               else
+                               {
+                                       /* This is a note, with the result left on the stack */
+                                       _jit_regs_free_reg(gen, reg, 1);
+                               }
+                       }
+                       else
+                       {
+                               /* Generate code for a unary operator */
+                               reg = _jit_regs_load_to_top
+                                       (gen, insn->value1,
+                                        (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
+                                                                        JIT_INSN_VALUE1_LIVE)), 0);
+                               jit_cache_opcode(&(gen->posn), insn->opcode);
+                               if(insn->dest)
+                               {
+                                       if((insn->flags & JIT_INSN_DEST_NEXT_USE) != 0)
+                                       {
+                                               /* Record that the destination is in "reg" */
+                                               _jit_regs_set_value(gen, reg, insn->dest, 0);
+                                       }
+                                       else
+                                       {
+                                               /* No next use, so store to the destination */
+                                               _jit_gen_spill_reg(gen, reg, -1, insn->dest);
+                                               insn->dest->in_frame = 1;
+                                               _jit_regs_free_reg(gen, reg, 1);
+                                       }
+                               }
+                               else
+                               {
+                                       /* This is a note, with the result left on the stack */
+                                       _jit_regs_free_reg(gen, reg, 1);
+                               }
+                       }
+               }
+               break;
+       }
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+void _jit_gen_start_block(jit_gencode_t gen, jit_block_t block)
+{
+       void **fixup;
+       void **next;
+
+       /* Set the address of this block */
+       block->address = (void *)(gen->posn.ptr);
+
+       /* If this block has pending fixups, then apply them now */
+       fixup = (void **)(block->fixup_list);
+       while(fixup != 0)
+       {
+               next = (void **)(fixup[1]);
+               fixup[1] = (void *)(jit_nint)(((void **)(block->address)) - fixup);
+               fixup = next;
+       }
+       block->fixup_list = 0;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
+{
+       /* Reset the working area size to zero for the next block */
+       gen->working_area = 0;
+}
+
+/*@
+ * @deftypefun void _jit_gen_call_finally (jit_gencode_t gen, jit_function_t func, jit_label_t label)
+ * Call a @code{finally} clause at @code{label}.
+ * @end deftypefun
+@*/
+void _jit_gen_call_finally
+       (jit_gencode_t gen, jit_function_t func, jit_label_t label)
+{
+       jit_block_t block;
+       void **pc;
+       _jit_regs_spill_all(gen);
+       pc = (void **)(gen->posn.ptr);
+       jit_cache_opcode(&(gen->posn), JIT_OP_CALL_FINALLY);
+       block = jit_block_from_label(func, label);
+       if(!block)
+       {
+               return;
+       }
+       if(block->address)
+       {
+               /* We already know the address of the block */
+               jit_cache_native
+                       (&(gen->posn), ((void **)(block->address)) - pc);
+       }
+       else
+       {
+               /* Record this position on the block's fixup list */
+               jit_cache_native(&(gen->posn), block->fixup_list);
+               block->fixup_list = (void *)pc;
+       }
+}
+
+/*@
+ * @deftypefun void _jit_gen_unwind_stack ({void *} stacktop, {void *} catch_pc, {void *} object)
+ * Unwind the stack back to @code{stacktop}, restore the frame, and
+ * jump to @code{catch_pc}.  The registers are set up to arrange for
+ * @code{object} to be in the right place for a @code{catch} clause.
+ * @end deftypefun
+@*/
+void _jit_gen_unwind_stack(void *stacktop, void *catch_pc, void *object)
+{
+       /* Not used by the interpreted back end */
+}
+
+#endif /* JIT_BACKEND_INTERP */
diff --git a/jit/jit-rules-interp.h b/jit/jit-rules-interp.h
new file mode 100644 (file)
index 0000000..68112b2
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * jit-rules-interp.h - Rules that define the interpreter characteristics.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_RULES_INTERP_H
+#define        _JIT_RULES_INTERP_H
+
+#include "jit-interp.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Information about all of the registers, in allocation order.
+ */
+#define        JIT_REG_INFO    \
+       {"r0", 0, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                             JIT_REG_CALL_USED | JIT_REG_START_STACK | JIT_REG_IN_STACK}, \
+       {"r1", 1, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                             JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r2", 2, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                             JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r3", 3, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                             JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r4", 4, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                             JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r5", 5, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                             JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r6", 6, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                             JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r7", 7, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                             JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r8", 8, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                             JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r9", 9, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                             JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r10", 10, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                               JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r11", 11, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                               JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r12", 12, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                               JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r13", 13, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                               JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r14", 14, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                               JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"r15", 15, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
+                               JIT_REG_CALL_USED | JIT_REG_END_STACK | JIT_REG_IN_STACK},
+#define        JIT_NUM_REGS    16
+
+/*
+ * Define to 1 if we should always load values into registers
+ * before operating on them.  i.e. the CPU does not have reg-mem
+ * and mem-reg addressing modes.
+ */
+#define        JIT_ALWAYS_REG_REG              1
+
+/*
+ * The maximum number of bytes to allocate for the prolog.
+ * This may be shortened once we know the true prolog size.
+ */
+#define        JIT_PROLOG_SIZE                 jit_function_interp_size
+
+/*
+ * Preferred alignment for the start of functions.
+ */
+#define        JIT_FUNCTION_ALIGNMENT  (sizeof(void *))
+
+/*
+ * 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.
+ */
+#define        JIT_ALIGN_OVERRIDES             0
+
+/*
+ * Extra state information that is added to the "jit_gencode" structure.
+ */
+#define        jit_extra_gen_state     \
+                       int working_area; \
+                       int max_working_area
+#define        jit_extra_gen_init(gen) \
+                       do { \
+                               (gen)->working_area = 0; \
+                               (gen)->max_working_area = 0; \
+                       } while (0)
+#define        jit_extra_gen_cleanup(gen)      do { ; } while (0)
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_RULES_INTERP_H */
diff --git a/jit/jit-rules-x86.c b/jit/jit-rules-x86.c
new file mode 100644 (file)
index 0000000..92bc703
--- /dev/null
@@ -0,0 +1,1042 @@
+/*
+ * jit-rules-x86.c - Rules that define the characteristics of the x86.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-rules.h"
+#include "jit-apply-rules.h"
+
+#if defined(JIT_BACKEND_X86)
+
+#include "jit-gen-x86.h"
+
+/*
+ * Pseudo register numbers for the x86 registers.  These are not the
+ * same as the CPU instruction register numbers.  The order of these
+ * values must match the order in "JIT_REG_INFO".
+ */
+#define        X86_REG_EAX                     0
+#define        X86_REG_ECX                     1
+#define        X86_REG_EDX                     2
+#define        X86_REG_EBX                     3
+#define        X86_REG_ESI                     4
+#define        X86_REG_EDI                     5
+#define        X86_REG_EBP                     6
+#define        X86_REG_ESP                     7
+#define        X86_REG_ST0                     8
+#define        X86_REG_ST1                     9
+#define        X85_REG_ST2                     10
+#define        X86_REG_ST3                     11
+#define        X86_REG_ST4                     12
+#define        X86_REG_ST5                     13
+#define        X86_REG_ST6                     14
+#define        X86_REG_ST7                     15
+
+/*
+ * Round a size up to a multiple of the stack word size.
+ */
+#define        ROUND_STACK(size)       \
+               (((size) + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1))
+
+void _jit_init_backend(void)
+{
+       /* Nothing to do here for the x86 */
+}
+
+void _jit_gen_get_elf_info(jit_elf_info_t *info)
+{
+#ifdef JIT_NATIVE_INT32
+       info->machine = 3;      /* EM_386 */
+#else
+       info->machine = 62;     /* EM_X86_64 */
+#endif
+#if JIT_APPLY_X86_FASTCALL == 0
+       info->abi = 0;          /* ELFOSABI_SYSV */
+#else
+       info->abi = 186;        /* Private code, indicating STDCALL/FASTCALL support */
+#endif
+       info->abi_version = 0;
+}
+
+/*
+ * Force values out of fastcall registers that cannot be easily
+ * accessed in register form (i.e. long, float, and struct values).
+ */
+static int force_out_of_regs(jit_function_t func, jit_value_t param,
+                                                        int num_regs, unsigned int num_stack_words)
+{
+       jit_value_t address;
+       jit_value_t temp;
+       jit_nint offset = 0;
+       jit_nint frame_offset = 2 * sizeof(void *);
+
+       /* Get the address of the parameter, to force it into the frame,
+          and to set up for the later "jit_insn_store_relative" calls */
+       address = jit_insn_address_of(func, param);
+       if(!address)
+       {
+               return 0;
+       }
+
+       /* Force the values out of the registers */
+       while(num_regs > 0)
+       {
+               temp = jit_value_create(func, jit_type_void_ptr);
+               if(!temp)
+               {
+                       return 0;
+               }
+               if(num_regs == 2)
+               {
+                       if(!jit_insn_incoming_reg(func, temp, X86_REG_ECX))
+                       {
+                               return 0;
+                       }
+               }
+               else
+               {
+                       if(!jit_insn_incoming_reg(func, temp, X86_REG_EDX))
+                       {
+                               return 0;
+                       }
+               }
+               if(!jit_insn_store_relative(func, address, offset, temp))
+               {
+                       return 0;
+               }
+               offset += sizeof(void *);
+               --num_regs;
+       }
+
+
+       /* Force the rest of the value out of the incoming stack frame */
+       while(num_stack_words > 0)
+       {
+               temp = jit_value_create(func, jit_type_void_ptr);
+               if(!temp)
+               {
+                       return 0;
+               }
+               if(!jit_insn_incoming_frame_posn(func, temp, frame_offset))
+               {
+                       return 0;
+               }
+               if(!jit_insn_store_relative(func, address, offset, temp))
+               {
+                       return 0;
+               }
+               offset += sizeof(void *);
+               frame_offset += sizeof(void *);
+               --num_stack_words;
+       }
+       return 1;
+}
+
+int _jit_create_entry_insns(jit_function_t func)
+{
+       jit_type_t signature = func->signature;
+       jit_type_t type;
+       int num_regs;
+       jit_nint offset;
+       jit_value_t value;
+       unsigned int num_params;
+       unsigned int param;
+       unsigned int size;
+       unsigned int num_stack_words;
+
+       /* Reset the frame size for this function.  We start by assuming
+          that ESI, EDI, and EBX need to be saved in the local frame */
+       func->builder->frame_size = 3 * sizeof(void *);
+
+       /* Determine the number of registers to allocate to parameters */
+#if JIT_APPLY_X86_FASTCALL == 1
+       if(jit_type_get_abi(signature) == jit_abi_fastcall)
+       {
+               num_regs = 2;
+       }
+       else
+#endif
+       {
+               num_regs = 0;
+       }
+
+       /* The starting parameter offset (saved ebp and return address on stack) */
+       offset = 2 * sizeof(void *);
+
+       /* If the function is nested, then we need an extra parameter
+          to pass the pointer to the parent's local variable frame */
+       if(func->nested_parent)
+       {
+               if(num_regs > 0)
+               {
+                       --num_regs;
+               }
+               else
+               {
+                       offset += sizeof(void *);
+               }
+       }
+
+       /* Allocate the structure return pointer */
+       value = jit_value_get_struct_pointer(func);
+       if(value)
+       {
+               if(num_regs == 2)
+               {
+                       if(!jit_insn_incoming_reg(func, value, X86_REG_ECX))
+                       {
+                               return 0;
+                       }
+                       --num_regs;
+               }
+               else if(num_regs == 1)
+               {
+                       if(!jit_insn_incoming_reg(func, value, X86_REG_EDX))
+                       {
+                               return 0;
+                       }
+                       --num_regs;
+               }
+               else
+               {
+                       if(!jit_insn_incoming_frame_posn(func, value, offset))
+                       {
+                               return 0;
+                       }
+                       offset += sizeof(void *);
+               }
+       }
+
+       /* Allocate the parameter offsets */
+       num_params = jit_type_num_params(signature);
+       for(param = 0; param < num_params; ++param)
+       {
+               value = jit_value_get_param(func, param);
+               if(!value)
+               {
+                       continue;
+               }
+               type = jit_type_normalize(jit_value_get_type(value));
+               switch(type->kind)
+               {
+                       case JIT_TYPE_SBYTE:
+                       case JIT_TYPE_UBYTE:
+                       case JIT_TYPE_SHORT:
+                       case JIT_TYPE_USHORT:
+                       case JIT_TYPE_INT:
+                       case JIT_TYPE_UINT:
+                       case JIT_TYPE_NINT:
+                       case JIT_TYPE_NUINT:
+                       case JIT_TYPE_SIGNATURE:
+                       case JIT_TYPE_PTR:
+                       {
+                               if(num_regs == 2)
+                               {
+                                       if(!jit_insn_incoming_reg(func, value, X86_REG_ECX))
+                                       {
+                                               return 0;
+                                       }
+                                       --num_regs;
+                               }
+                               else if(num_regs == 1)
+                               {
+                                       if(!jit_insn_incoming_reg(func, value, X86_REG_EDX))
+                                       {
+                                               return 0;
+                                       }
+                                       --num_regs;
+                               }
+                               else
+                               {
+                                       if(!jit_insn_incoming_frame_posn(func, value, offset))
+                                       {
+                                               return 0;
+                                       }
+                                       offset += sizeof(void *);
+                               }
+                       }
+                       break;
+
+                       case JIT_TYPE_LONG:
+                       case JIT_TYPE_ULONG:
+                       case JIT_TYPE_FLOAT32:
+                       case JIT_TYPE_FLOAT64:
+                       case JIT_TYPE_NFLOAT:
+                       case JIT_TYPE_STRUCT:
+                       case JIT_TYPE_UNION:
+                       {
+                               /* Deal with the possibility that the value may be split
+                                  between registers and the stack */
+                               size = ROUND_STACK(jit_type_get_size(type));
+                               if(num_regs == 2)
+                               {
+                                       if(size <= sizeof(void *))
+                                       {
+                                               if(!force_out_of_regs(func, value, 1, 0))
+                                               {
+                                                       return 0;
+                                               }
+                                               --num_regs;
+                                       }
+                                       else
+                                       {
+                                               num_stack_words = (size / sizeof(void *)) - 2;
+                                               if(!force_out_of_regs(func, value, 2, num_stack_words))
+                                               {
+                                                       return 0;
+                                               }
+                                               num_regs = 0;
+                                               offset += num_stack_words * sizeof(void *);
+                                       }
+                               }
+                               else if(num_regs == 1)
+                               {
+                                       num_stack_words = (size / sizeof(void *)) - 1;
+                                       if(!force_out_of_regs(func, value, 1, num_stack_words))
+                                       {
+                                               return 0;
+                                       }
+                                       num_regs = 0;
+                                       offset += num_stack_words * sizeof(void *);
+                               }
+                               else
+                               {
+                                       if(!jit_insn_incoming_frame_posn(func, value, offset))
+                                       {
+                                               return 0;
+                                       }
+                                       offset += size;
+                               }
+                       }
+                       break;
+               }
+       }
+       return 1;
+}
+
+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 nesting_level, jit_value_t *struct_return)
+{
+       jit_type_t type = jit_type_get_return(signature);
+       jit_value_t value;
+       unsigned int size;
+       unsigned int index;
+       unsigned int num_stack_args;
+       unsigned int word_regs;
+       jit_value_t partial;
+
+       /* Determine which values are going to end up in fastcall registers */
+#if JIT_APPLY_X86_FASTCALL == 1
+       if(jit_type_get_abi(signature) == jit_abi_fastcall)
+       {
+               word_regs = 0;
+               if(func->nested_parent)
+               {
+                       ++word_regs;
+               }
+               if(jit_type_return_via_pointer(type))
+               {
+                       ++word_regs;
+               }
+               index = 0;
+               partial = 0;
+               while(index < num_args && word_regs < 2)
+               {
+                       size = jit_type_get_size(jit_value_get_type(args[index]));
+                       size = ROUND_STACK(size) / sizeof(void *);
+                       if(size <= (2 - word_regs))
+                       {
+                               /* This argument will fit entirely in registers */
+                               word_regs += size;
+                               ++index;
+                       }
+                       else
+                       {
+                               /* Partly in registers and partly on the stack.
+                                  We first copy it into a buffer that we can address */
+                               partial = jit_value_create
+                                       (func, jit_value_get_type(args[index]));
+                               if(!partial)
+                               {
+                                       return 0;
+                               }
+                               jit_value_set_addressable(partial);
+                               if(!jit_insn_store(func, partial, args[index]))
+                               {
+                                       return 0;
+                               }
+                               ++index;
+                               break;
+                       }
+               }
+               num_stack_args = num_args - index;
+       }
+       else
+#endif
+       {
+               word_regs = 0;
+               partial = 0;
+               num_stack_args = num_args;
+       }
+
+       /* Push all of the stacked arguments in reverse order */
+       while(num_stack_args > 0)
+       {
+               --num_stack_args;
+               --num_args;
+               if(!jit_insn_push(func, args[num_args]))
+               {
+                       return 0;
+               }
+       }
+
+       /* Handle a value that is partly on the stack and partly in registers */
+       if(partial)
+       {
+               --num_args;
+               index = (2 - word_regs) * sizeof(void *);
+               size = ROUND_STACK(jit_type_get_size(jit_value_get_type(partial)));
+               while(size > index)
+               {
+                       size -= sizeof(void *);
+                       value = jit_value_create(func, jit_type_void_ptr);
+                       if(!value)
+                       {
+                               return 0;
+                       }
+                       value = jit_insn_load_relative
+                               (func, value, (jit_nint)size, jit_type_void_ptr);
+                       if(!value)
+                       {
+                               return 0;
+                       }
+                       if(!jit_insn_push(func, value))
+                       {
+                               return 0;
+                       }
+               }
+               while(size > 0)
+               {
+                       size -= sizeof(void *);
+                       value = jit_value_create(func, jit_type_void_ptr);
+                       if(!value)
+                       {
+                               return 0;
+                       }
+                       value = jit_insn_load_relative
+                               (func, value, (jit_nint)size, jit_type_void_ptr);
+                       if(!value)
+                       {
+                               return 0;
+                       }
+                       if(word_regs == 2)
+                       {
+                               if(!jit_insn_outgoing_reg(func, value, X86_REG_EDX))
+                               {
+                                       return 0;
+                               }
+                               --word_regs;
+                       }
+                       else
+                       {
+                               if(!jit_insn_outgoing_reg(func, value, X86_REG_ECX))
+                               {
+                                       return 0;
+                               }
+                               --word_regs;
+                       }
+               }
+       }
+
+       /* Push arguments that will end up entirely in registers */
+       while(num_args > 0)
+       {
+               --num_args;
+               size = jit_type_get_size(jit_value_get_type(args[num_args]));
+               size = ROUND_STACK(size) / sizeof(void *);
+               if(size == 2)
+               {
+                       if(!jit_insn_outgoing_reg(func, args[num_args], X86_REG_ECX))
+                       {
+                               return 0;
+                       }
+                       word_regs = 0;
+               }
+               else if(word_regs == 2)
+               {
+                       if(!jit_insn_outgoing_reg(func, args[num_args], X86_REG_EDX))
+                       {
+                               return 0;
+                       }
+                       --word_regs;
+               }
+               else
+               {
+                       if(!jit_insn_outgoing_reg(func, args[num_args], X86_REG_ECX))
+                       {
+                               return 0;
+                       }
+                       --word_regs;
+               }
+       }
+
+       /* Do we need to add a structure return pointer argument? */
+       if(jit_type_return_via_pointer(type))
+       {
+               value = jit_value_create(func, type);
+               if(!value)
+               {
+                       return 0;
+               }
+               *struct_return = value;
+               value = jit_insn_address_of(func, value);
+               if(!value)
+               {
+                       return 0;
+               }
+               if(word_regs == 2)
+               {
+                       if(!jit_insn_outgoing_reg(func, value, X86_REG_EDX))
+                       {
+                               return 0;
+                       }
+                       --word_regs;
+               }
+               else if(word_regs == 1)
+               {
+                       if(!jit_insn_outgoing_reg(func, value, X86_REG_ECX))
+                       {
+                               return 0;
+                       }
+                       --word_regs;
+               }
+               else
+               {
+                       if(!jit_insn_push(func, value))
+                       {
+                               return 0;
+                       }
+               }
+       }
+       else
+       {
+               *struct_return = 0;
+       }
+
+       /* Do we need to add nested function scope information? */
+       if(is_nested)
+       {
+               if(word_regs > 0)
+               {
+                       if(!jit_insn_setup_for_nested(func, nesting_level, X86_REG_ECX))
+                       {
+                               return 0;
+                       }
+               }
+               else
+               {
+                       if(!jit_insn_setup_for_nested(func, nesting_level, -1))
+                       {
+                               return 0;
+                       }
+               }
+       }
+
+       /* The call is ready to proceed */
+       return 1;
+}
+
+int _jit_setup_indirect_pointer(jit_function_t func, jit_value_t value)
+{
+       return jit_insn_outgoing_reg(func, value, X86_REG_EAX);
+}
+
+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)
+{
+       jit_nint pop_bytes;
+       unsigned int size;
+       jit_type_t return_type;
+       int ptr_return;
+
+       /* Calculate the number of bytes that we need to pop */
+       return_type = jit_type_normalize(jit_type_get_return(signature));
+       ptr_return = jit_type_return_via_pointer(return_type);
+#if JIT_APPLY_X86_FASTCALL == 1
+       if(jit_type_get_abi(signature) == jit_abi_stdcall ||
+          jit_type_get_abi(signature) == jit_abi_fastcall)
+       {
+               /* STDCALL and FASTCALL functions pop their own arguments */
+               pop_bytes = 0;
+       }
+       else
+#endif
+       {
+               pop_bytes = 0;
+               while(num_args > 0)
+               {
+                       --num_args;
+                       size = jit_type_get_size(jit_value_get_type(args[num_args]));
+                       pop_bytes += ROUND_STACK(size);
+               }
+#if JIT_APPLY_X86_POP_STRUCT_RETURN == 1
+               if(ptr_return && is_nested)
+               {
+                       /* Note: we only need this for nested functions, because
+                          regular functions will pop the structure return for us */
+                       pop_bytes += sizeof(void *);
+               }
+#else
+               if(ptr_return)
+               {
+                       pop_bytes += sizeof(void *);
+               }
+#endif
+               if(is_nested)
+               {
+                       pop_bytes += sizeof(void *);
+               }
+       }
+
+       /* Pop the bytes from the system stack */
+       if(pop_bytes > 0)
+       {
+               if(!jit_insn_pop_stack(func, pop_bytes))
+               {
+                       return 0;
+               }
+       }
+
+       /* Bail out now if we don't need to worry about return values */
+       if(!return_value || ptr_return)
+       {
+               return 0;
+       }
+
+       /* Structure values must be flushed into the frame, and
+          everything else ends up in a register */
+       if(jit_type_is_struct(return_type) || jit_type_is_union(return_type))
+       {
+               if(!jit_insn_flush_struct(func, return_value))
+               {
+                       return 0;
+               }
+       }
+       else if(return_type == jit_type_float32 ||
+                       return_type == jit_type_float64 ||
+                       return_type == jit_type_nfloat)
+       {
+               if(!jit_insn_return_reg(func, return_value, X86_REG_ST0))
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               if(!jit_insn_return_reg(func, return_value, X86_REG_EAX))
+               {
+                       return 0;
+               }
+       }
+
+       /* Everything is back where it needs to be */
+       return 1;
+}
+
+void *_jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf)
+{
+       unsigned char prolog[JIT_PROLOG_SIZE];
+       unsigned char *inst = prolog;
+       int reg;
+       unsigned int saved;
+
+       /* Push ebp onto the stack */
+       x86_push_reg(inst, X86_EBP);
+
+       /* Initialize EBP for the current frame */
+       x86_mov_reg_reg(inst, X86_EBP, X86_ESP, sizeof(void *));
+
+       /* Save registers that we need to preserve */
+       saved = 0;
+       for(reg = 0; reg <= 7; ++reg)
+       {
+               if(jit_reg_is_used(gen->touched, reg) &&
+                  (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
+               {
+                       x86_push_reg(inst, _jit_reg_info[reg].cpu_reg);
+                       saved += sizeof(void *);
+               }
+       }
+
+       /* Allocate space for the local variable frame.  Subtract off
+          the space for the registers that we just saved */
+       if((func->builder->frame_size - saved) > 0)
+       {
+               x86_alu_reg_imm(inst, X86_SUB, X86_ESP,
+                                               (int)(func->builder->frame_size - saved));
+       }
+
+       /* Copy the prolog into place and return the adjusted entry position */
+       reg = (int)(inst - prolog);
+       jit_memcpy(((unsigned char *)buf) + JIT_PROLOG_SIZE - reg, prolog, reg);
+       return (void *)(((unsigned char *)buf) + JIT_PROLOG_SIZE - reg);
+}
+
+void _jit_gen_epilog(jit_gencode_t gen, jit_function_t func)
+{
+       jit_nint pop_bytes = 0;
+       int num_regs, reg;
+       unsigned char *inst;
+       int struct_return_offset = 0;
+
+       /* Bail out if there is insufficient space for the epilog */
+       if(!jit_cache_check_for_n(&(gen->posn), 32))
+       {
+               jit_cache_mark_full(&(gen->posn));
+               return;
+       }
+
+#if JIT_APPLY_X86_FASTCALL == 1
+       /* Determine the number of parameter bytes to pop when we return */
+       {
+               jit_type_t signature;
+               unsigned int num_params;
+               unsigned int param;
+               signature = func->signature;
+               if(jit_type_abi(signature) == jit_type_stdcall ||
+                  jit_type_abi(signature) == jit_type_fastcall)
+               {
+                       if(func->nested_parent)
+                       {
+                               pop_bytes += sizeof(void *);
+                       }
+                       if(jit_type_return_via_pointer(jit_type_get_return(signature)))
+                       {
+                               struct_return_offset = 2 * sizeof(void *) + pop_bytes;
+                               pop_bytes += sizeof(void *);
+                       }
+                       num_params = jit_type_num_params(signature);
+                       for(param = 0; param < num_params; ++param)
+                       {
+                               pop_bytes += ROUND_STACK
+                                               (jit_type_get_size
+                                                       (jit_type_get_param(signature, param)));
+                       }
+                       if(jit_type_abi(signature) == jit_type_fastcall)
+                       {
+                               /* The first two words are in fastcall registers */
+                               if(pop_bytes > (2 * sizeof(void *)))
+                               {
+                                       pop_bytes -= 2 * sizeof(void *);
+                               }
+                               else
+                               {
+                                       pop_bytes = 0;
+                               }
+                               struct_return_offset = 0;
+                       }
+               }
+               else if(!(func->nested_parent) &&
+                               jit_type_return_via_pointer(jit_type_get_return(signature)))
+               {
+#if JIT_APPLY_X86_POP_STRUCT_RETURN == 1
+                       pop_bytes += sizeof(void *);
+#endif
+                       struct_return_offset = 2 * sizeof(void *);
+               }
+       }
+#else
+       {
+               /* We only need to pop structure pointers in non-nested functions */
+               jit_type_t signature;
+               signature = func->signature;
+               if(!(func->nested_parent) &&
+                  jit_type_return_via_pointer(jit_type_get_return(signature)))
+               {
+#if JIT_APPLY_X86_POP_STRUCT_RETURN == 1
+                       pop_bytes += sizeof(void *);
+#endif
+                       struct_return_offset = 2 * sizeof(void *);
+               }
+       }
+#endif
+
+       /* If we are returning a structure via a pointer, then copy
+          the pointer value into EAX when we return */
+       if(struct_return_offset != 0)
+       {
+               x86_mov_reg_membase(inst, X86_EAX, X86_EBP, struct_return_offset, 4);
+       }
+
+       /* Determine the number of callee save registers on the stack */
+       num_regs = 0;
+       for(reg = 7; reg >= 0; --reg)
+       {
+               if(jit_reg_is_used(gen->touched, reg) &&
+                  (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
+               {
+                       ++num_regs;
+               }
+       }
+
+       /* Pop the local stack frame, and get back to the callee save regs */
+       inst = gen->posn.ptr;
+       if(num_regs == 0)
+       {
+               x86_mov_reg_reg(inst, X86_ESP, X86_EBP, sizeof(void *));
+       }
+       else
+       {
+               x86_lea_membase(inst, X86_ESP, X86_EBP, -(sizeof(void *) * num_regs));
+       }
+
+       /* Pop the callee save registers that we used */
+       for(reg = 7; reg >= 0; --reg)
+       {
+               if(jit_reg_is_used(gen->touched, reg) &&
+                  (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
+               {
+                       x86_pop_reg(inst, _jit_reg_info[reg].cpu_reg);
+               }
+       }
+
+       /* Pop the saved copy of ebp */
+       x86_pop_reg(inst, X86_EBP);
+
+       /* Return from the current function */
+       if(pop_bytes > 0)
+       {
+               x86_ret_imm(inst, pop_bytes);
+       }
+       else
+       {
+               x86_ret(inst);
+       }
+       gen->posn.ptr = inst;
+}
+
+void *_jit_gen_redirector(jit_gencode_t gen, jit_function_t func)
+{
+       void *ptr, *entry;
+       if(!jit_cache_check_for_n(&(gen->posn), 8))
+       {
+               jit_cache_mark_full(&(gen->posn));
+               return 0;
+       }
+       ptr = (void *)&(func->entry_point);
+       entry = gen->posn.ptr;
+       x86_jump_mem(gen->posn.ptr, ptr);
+       return entry;
+}
+
+/*
+ * Setup or teardown the x86 code output process.
+ */
+#define        jit_cache_setup_output(needed)  \
+       unsigned char *inst = gen->posn.ptr; \
+       if(!jit_cache_check_for_n(&(gen->posn), (needed))) \
+       { \
+               jit_cache_mark_full(&(gen->posn)); \
+               return; \
+       }
+#define        jit_cache_end_output()  \
+       gen->posn.ptr = inst
+
+void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
+                                               int other_reg, jit_value_t value)
+{
+       int offset;
+
+       /* Make sure that we have sufficient space */
+       jit_cache_setup_output(16);
+
+       /* Fix the value in place within the local variable frame */
+       _jit_gen_fix_value(value);
+
+       /* Output an appropriate instruction to spill the value */
+       offset = (int)(value->frame_offset);
+       if(reg < X86_REG_ST0)
+       {
+               /* Spill a word register */
+               reg = _jit_reg_info[reg].cpu_reg;
+               x86_mov_membase_reg(inst, X86_EBP, offset, reg, 4);
+               if(other_reg != -1)
+               {
+                       /* Spill the other word register in a pair */
+                       reg = _jit_reg_info[other_reg].cpu_reg;
+                       offset += sizeof(void *);
+                       x86_mov_membase_reg(inst, X86_EBP, offset, reg, 4);
+               }
+       }
+       else
+       {
+               /* Spill the top of the floating-point register stack */
+               switch(jit_type_normalize(value->type)->kind)
+               {
+                       case JIT_TYPE_FLOAT32:
+                       {
+                               x86_fst_membase(inst, X86_EBP, offset, 0, 1);
+                       }
+                       break;
+
+                       case JIT_TYPE_FLOAT64:
+                       {
+                               x86_fst_membase(inst, X86_EBP, offset, 1, 1);
+                       }
+                       break;
+
+                       case JIT_TYPE_NFLOAT:
+                       {
+                               x86_fst80_membase(inst, X86_EBP, offset);
+                       }
+                       break;
+               }
+       }
+
+       /* End the code output process */
+       jit_cache_end_output();
+}
+
+void _jit_gen_free_reg(jit_gencode_t gen, int reg,
+                                          int other_reg, int value_used)
+{
+       /* We only need to take explicit action if we are freeing a
+          floating-point register whose value hasn't been used yet */
+       if(!value_used && reg >= X86_REG_ST0 && reg <= X86_REG_ST7)
+       {
+               if(jit_cache_check_for_n(&(gen->posn), 2))
+               {
+                       x86_fstp(gen->posn.ptr, reg - X86_REG_ST0);
+               }
+               else
+               {
+                       jit_cache_mark_full(&(gen->posn));
+               }
+       }
+}
+
+void _jit_gen_load_value
+       (jit_gencode_t gen, int reg, int other_reg, jit_value_t value)
+{
+       /* TODO */
+}
+
+void _jit_gen_fix_value(jit_value_t value)
+{
+       if(!(value->has_frame_offset) && !(value->is_constant))
+       {
+               jit_nint size = (jit_nint)(ROUND_STACK(jit_type_get_size(value->type)));
+               value->block->func->builder->frame_size += size;
+               value->frame_offset = -(value->block->func->builder->frame_size);
+               value->has_frame_offset = 1;
+       }
+}
+
+void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
+                                  jit_block_t block, jit_insn_t insn)
+{
+       /* TODO */
+}
+
+void _jit_gen_start_block(jit_gencode_t gen, jit_block_t block)
+{
+       /* TODO: label fixups */
+}
+
+void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
+{
+       /* Nothing to do here for x86 */
+}
+
+void _jit_gen_call_finally
+       (jit_gencode_t gen, jit_function_t func, jit_label_t label)
+{
+       /* TODO */
+}
+
+void _jit_gen_unwind_stack(void *stacktop, void *catch_pc, void *object)
+{
+       void *frame;
+
+       /* Fetch the proper EBP value from the stack, just before
+          where we need to unwind back to */
+       frame = ((void **)stacktop)[-2];
+
+       /* Unwind the stack and jump to "catch_pc" */
+#if defined(__GNUC__)
+       __asm__ (
+               "movl %0, %%edx\n\t"
+               "movl %1, %%eax\n\t"
+               "movl %2, %%ecx\n\t"
+               "movl %3, %%ebx\n\t"
+               "movl %%ebx, %%ebp\n\t"
+               "movl %%edx, %%esp\n\t"
+               "jmp *(%%eax)\n\t"
+               : : "m"(stacktop), "m"(catch_pc), "m"(object), "m"(frame)
+               : "eax", "ebx", "ecx", "edx"
+       );
+#elif defined(_MSC_VER)
+       __asm {
+               mov edx, dword ptr stacktop
+               mov eax, dword ptr catch_pc
+               mov ecx, dword ptr object
+               mov ebx, dword ptr frame
+               mov ebp, ebx
+               mov esp, edx
+               jmp [eax]
+       }
+#else
+       #error "Don't know how to unwind the stack under x86"
+#endif
+}
+
+void _jit_unwind_stack(void *frame, void *pc, void *object)
+{
+#if defined(__GNUC__)
+       __asm__ (
+               "movl %0, %%edx\n\t"
+               "movl %1, %%eax\n\t"
+               "movl %2, %%ecx\n\t"
+               "movl %%edx, %%ebp\n\t"
+               "popl %%ebp\n\t"
+               "popl %%edx\n\t"
+               "jmp *%%eax\n\t"
+               : : "m"(frame), "m"(pc), "m"(object)
+               : "eax", "ecx", "edx"
+       );
+#elif defined(_MSC_VER)
+       __asm {
+               mov edx, dword ptr frame
+               mov eax, dword ptr pc
+               mov ecx, dword ptr object
+               mov ebp, edx
+               pop ebp
+               pop edx
+               jmp eax
+       }
+#else
+       #error "Don't know how to unwind the stack on x86 platforms"
+#endif
+}
+
+#endif /* JIT_BACKEND_X86 */
diff --git a/jit/jit-rules-x86.h b/jit/jit-rules-x86.h
new file mode 100644 (file)
index 0000000..c0feb39
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * jit-rules-x86.h - Rules that define the characteristics of the x86.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_RULES_X86_H
+#define        _JIT_RULES_X86_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Information about all of the registers, in allocation order.
+ */
+#define        JIT_REG_INFO    \
+       {"eax", 0, 2, JIT_REG_WORD | JIT_REG_CALL_USED}, \
+       {"ecx", 1, 3, JIT_REG_WORD | JIT_REG_CALL_USED}, \
+       {"edx", 2, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
+       {"ebx", 3, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
+       {"esi", 6, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
+       {"edi", 7, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
+       {"ebp", 4, -1, JIT_REG_FRAME | JIT_REG_FIXED}, \
+       {"esp", 5, -1, JIT_REG_STACK_PTR | JIT_REG_FIXED | JIT_REG_CALL_USED}, \
+       {"st",  0, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED | JIT_REG_START_STACK | \
+                                  JIT_REG_IN_STACK}, \
+       {"st1", 1, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"st2", 2, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"st3", 3, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"st4", 4, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"st5", 5, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"st6", 6, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+       {"st7", 7, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED | JIT_REG_END_STACK | \
+                                  JIT_REG_IN_STACK},
+#define        JIT_NUM_REGS    16
+
+/*
+ * Define to 1 if we should always load values into registers
+ * before operating on them.  i.e. the CPU does not have reg-mem
+ * and mem-reg addressing modes.
+ */
+#define        JIT_ALWAYS_REG_REG              0
+
+/*
+ * The maximum number of bytes to allocate for the prolog.
+ * This may be shortened once we know the true prolog size.
+ */
+#define        JIT_PROLOG_SIZE                 32
+
+/*
+ * Preferred alignment for the start of functions.
+ */
+#define        JIT_FUNCTION_ALIGNMENT  32
+
+/*
+ * 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.
+ */
+#define        JIT_ALIGN_OVERRIDES             1
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_RULES_X86_H */
diff --git a/jit/jit-rules.c b/jit/jit-rules.c
new file mode 100644 (file)
index 0000000..35ed926
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * jit-rules.c - Rules that define the characteristics of the back-end.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-rules.h"
+
+/*
+ * The information blocks for all registers in the system.
+ */
+jit_reginfo_t const _jit_reg_info[JIT_NUM_REGS] = {JIT_REG_INFO};
+
+int _jit_int_lowest_byte(void)
+{
+       union
+       {
+               unsigned char bytes[4];
+               jit_int value;
+       } volatile un;
+       int posn;
+       un.value = (jit_int)0x01020304;
+       posn = 0;
+       while(un.bytes[posn] != 0x04)
+       {
+               ++posn;
+       }
+       return posn;
+}
+
+int _jit_int_lowest_short(void)
+{
+       union
+       {
+               unsigned char bytes[4];
+               jit_int value;
+       } volatile un;
+       int posn;
+       un.value = (jit_int)0x01020304;
+       posn = 0;
+       while(un.bytes[posn] != 0x03 && un.bytes[posn] != 0x04)
+       {
+               ++posn;
+       }
+       return posn;
+}
+
+int _jit_nint_lowest_byte(void)
+{
+#ifdef JIT_NATIVE_INT32
+       return _jit_int_lowest_byte();
+#else
+       union
+       {
+               unsigned char bytes[8];
+               jit_long value;
+       } volatile un;
+       int posn;
+       un.value = (jit_long)0x0102030405060708;
+       posn = 0;
+       while(un.bytes[posn] != 0x08)
+       {
+               ++posn;
+       }
+       return posn;
+#endif
+}
+
+int _jit_nint_lowest_short(void)
+{
+#ifdef JIT_NATIVE_INT32
+       return _jit_int_lowest_short();
+#else
+       union
+       {
+               unsigned char bytes[8];
+               jit_long value;
+       } volatile un;
+       int posn;
+       un.value = (jit_long)0x0102030405060708;
+       posn = 0;
+       while(un.bytes[posn] != 0x07 && un.bytes[posn] != 0x08)
+       {
+               ++posn;
+       }
+       return posn;
+#endif
+}
+
+int _jit_nint_lowest_int(void)
+{
+#ifdef JIT_NATIVE_INT32
+       return 0;
+#else
+       union
+       {
+               unsigned char bytes[8];
+               jit_long value;
+       } volatile un;
+       int posn;
+       un.value = (jit_long)0x0102030405060708;
+       posn = 0;
+       while(un.bytes[posn] <= 0x04)
+       {
+               ++posn;
+       }
+       return posn;
+#endif
+}
diff --git a/jit/jit-rules.h b/jit/jit-rules.h
new file mode 100644 (file)
index 0000000..0337f71
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * jit-rules.h - Rules that define the characteristics of the back-end.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_RULES_H
+#define        _JIT_RULES_H
+
+#include "jit-cache.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Determine which backend to use.
+ */
+#define        JIT_BACKEND_INTERP              1
+/*#define      JIT_BACKEND_X86         1*/
+/*#define      JIT_BACKEND_ARM         1*/
+
+/*
+ * Information about a register.
+ */
+typedef struct
+{
+       const char *name;                       /* Name of the register, for debugging */
+       short           cpu_reg;                /* CPU register number */
+       short           other_reg;              /* Other register for a "long" pair, or -1 */
+       int                     flags;                  /* Flags that define the register type */
+
+} jit_reginfo_t;
+
+/*
+ * Register information flags.
+ */
+#define        JIT_REG_WORD            (1 << 0)        /* Can be used for word values */
+#define        JIT_REG_LONG            (1 << 1)        /* Can be used for long values */
+#define        JIT_REG_FLOAT           (1 << 2)        /* Can be used for float values */
+#define        JIT_REG_FRAME           (1 << 3)        /* Contains frame pointer */
+#define        JIT_REG_STACK_PTR       (1 << 4)        /* Contains CPU stack pointer */
+#define        JIT_REG_FIXED           (1 << 5)        /* Fixed use; not for allocation */
+#define        JIT_REG_CALL_USED       (1 << 6)        /* Destroyed by a call */
+#define        JIT_REG_START_STACK     (1 << 7)        /* Stack of stack-like allocation */
+#define        JIT_REG_END_STACK       (1 << 8)        /* End of stack-like allocation */
+#define        JIT_REG_IN_STACK        (1 << 9)        /* Middle of stack-like allocation */
+#define        JIT_REG_GLOBAL          (1 << 10)       /* Candidate for global allocation */
+
+/*
+ * Include definitions that are specific to the backend.
+ */
+#if defined(JIT_BACKEND_INTERP)
+       #include "jit-rules-interp.h"
+#elif defined(JIT_BACKEND_X86)
+       #include "jit-rules-x86.h"
+#elif defined(JIT_BACKEND_ARM)
+       #include "jit-rules-arm.h"
+#else
+       #error "unknown jit backend type"
+#endif
+
+/*
+ * The information blocks for all registers in the system.
+ */
+extern jit_reginfo_t const _jit_reg_info[JIT_NUM_REGS];
+
+/*
+ * Manipulate register usage masks.  The backend may override these
+ * definitions if it has more registers than can fit in a "jit_uint".
+ */
+#if !defined(jit_regused_init)
+typedef jit_uint jit_regused_t;
+#define        jit_regused_init                                (0)
+#define        jit_reg_is_used(mask,reg)               \
+                       (((mask) & (((jit_uint)1) << (reg))) != 0)
+#define        jit_reg_set_used(mask,reg)              ((mask) |= (((jit_uint)1) << (reg)))
+#define        jit_reg_clear_used(mask,reg)    ((mask) &= ~(((jit_uint)1) << (reg)))
+#endif
+
+/*
+ * Information about a register's contents.
+ */
+#define        JIT_MAX_REG_VALUES              8
+typedef struct jit_regcontents jit_regcontents_t;
+struct jit_regcontents
+{
+       /* List of values that are currently stored in this register */
+       jit_value_t             values[JIT_MAX_REG_VALUES];
+       short                   num_values;
+
+       /* Flag that indicates if this register is holding the first
+          word of a double-word long value (32-bit platforms only) */
+       char                    is_long_start;
+
+       /* Flag that indicates if this register is holding the second
+          word of a double-word long value (32-bit platforms only) */
+       char                    is_long_end;
+
+       /* Current age of this register.  Older registers are reclaimed first */
+       int                             age;
+
+       /* Remapped version of this register, when used in a stack */
+       short                   remap;
+
+       /* Flag that indicates if the register holds a valid value,
+          but there are no actual "jit_value_t" objects associated */
+       short                   used_for_temp;
+};
+
+/*
+ * Code generation information.
+ */
+typedef struct jit_gencode *jit_gencode_t;
+struct jit_gencode
+{
+       jit_regused_t           permanent;      /* Permanently allocated global regs */
+       jit_regused_t           touched;        /* All registers that were touched */
+       jit_cache_posn          posn;           /* Current cache output position */
+       jit_regcontents_t       contents[JIT_NUM_REGS]; /* Contents of each register */
+       int                                     current_age;/* Current age value for registers */
+       int                                     stack_map[JIT_NUM_REGS]; /* Reverse stack mappings */
+#ifdef jit_extra_gen_state
+       jit_extra_gen_state;                    /* CPU-specific extra information */
+#endif
+};
+
+/*
+ * ELF machine type and ABI information.
+ */
+typedef struct jit_elf_info jit_elf_info_t;
+struct jit_elf_info
+{
+       int             machine;
+       int             abi;
+       int             abi_version;
+
+};
+
+/*
+ * External function defintions.
+ */
+void _jit_init_backend(void);
+void _jit_gen_get_elf_info(jit_elf_info_t *info);
+int _jit_create_entry_insns(jit_function_t func);
+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 nesting_level, jit_value_t *struct_return);
+int _jit_setup_indirect_pointer(jit_function_t func, jit_value_t value);
+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);
+int _jit_opcode_is_supported(int opcode);
+void *_jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf);
+void _jit_gen_epilog(jit_gencode_t gen, jit_function_t func);
+void *_jit_gen_redirector(jit_gencode_t gen, jit_function_t func);
+void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
+                                           int other_reg, jit_value_t value);
+void _jit_gen_free_reg(jit_gencode_t gen, int reg,
+                                          int other_reg, int value_used);
+void _jit_gen_load_value
+       (jit_gencode_t gen, int reg, int other_reg, jit_value_t value);
+void _jit_gen_fix_value(jit_value_t value);
+void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
+                                  jit_block_t block, jit_insn_t insn);
+void _jit_gen_start_block(jit_gencode_t gen, jit_block_t block);
+void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block);
+void _jit_gen_call_finally
+       (jit_gencode_t gen, jit_function_t func, jit_label_t label);
+void _jit_gen_unwind_stack(void *stacktop, void *catch_pc, void *object);
+
+/*
+ * Determine the byte number within a "jit_int" where the low
+ * order byte can be found.
+ */
+int _jit_int_lowest_byte(void);
+
+/*
+ * Determine the byte number within a "jit_int" where the low
+ * order short can be found.
+ */
+int _jit_int_lowest_short(void);
+
+/*
+ * Determine the byte number within a "jit_nint" where the low
+ * order byte can be found.
+ */
+int _jit_nint_lowest_byte(void);
+
+/*
+ * Determine the byte number within a "jit_nint" where the low
+ * order short can be found.
+ */
+int _jit_nint_lowest_short(void);
+
+/*
+ * Determine the byte number within a "jit_nint" where the low
+ * order int can be found.
+ */
+int _jit_nint_lowest_int(void);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_RULES_H */
diff --git a/jit/jit-string.c b/jit/jit-string.c
new file mode 100644 (file)
index 0000000..bdc18af
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * jit-string.c - String handling routines.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include <config.h>
+#ifdef HAVE_STRING_H
+       #include <string.h>
+#elif defined(HAVE_STRINGS_H)
+       #include <strings.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDARG_H
+       #include <stdarg.h>
+#elif HAVE_VARARGS_H
+       #include <varargs.h>
+#endif
+
+/*@
+ * @section String operations
+ * @cindex 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.
+@*/
+
+/*@
+ * @deftypefun {unsigned int} jit_strlen ({const char *} str)
+ * Returns the length of @code{str}.
+ * @end deftypefun
+@*/
+unsigned int jit_strlen(const char *str)
+{
+#ifdef HAVE_STRLEN
+       return (unsigned int)(strlen(str));
+#else
+       unsigned int len = 0;
+       while(*str++ != '\0')
+       {
+               ++len;
+       }
+       return len;
+#endif
+}
+
+/*@
+ * @deftypefun {char *} jit_strcpy ({char *} dest, {const char *} src)
+ * Copy the string at @code{src} to @code{dest}.  Returns @code{dest}.
+ * @end deftypefun
+@*/
+char *jit_strcpy(char *dest, const char *src)
+{
+#ifdef HAVE_STRCPY
+       return strcpy(dest, src);
+#else
+       char ch;
+       char *d = dest;
+       while((ch = *src++) != '\0')
+       {
+               *d++ = ch;
+       }
+       *d = '\0';
+       return dest;
+#endif
+}
+
+/*@
+ * @deftypefun {char *} jit_strcat ({char *} dest, {const char *} src)
+ * Copy the string at @code{src} to the end of the string at @code{dest}.
+ * Returns @code{dest}.
+ * @end deftypefun
+@*/
+char *jit_strcat(char *dest, const char *src)
+{
+#ifdef HAVE_STRCAT
+       return strcat(dest, src);
+#else
+       char ch;
+       char *d = dest + jit_strlen(dest);
+       while((ch = *src++) != '\0')
+       {
+               *d++ = ch;
+       }
+       *d = '\0';
+       return dest;
+#endif
+}
+
+/*@
+ * @deftypefun {char *} jit_strncpy ({char *} dest, {const char *} src, {unsigned int} len)
+ * Copy at most @code{len} characters from the string at @code{src} to
+ * @code{dest}.  Returns @code{dest}.
+ * @end deftypefun
+@*/
+char *jit_strncpy(char *dest, const char *src, unsigned int len)
+{
+#ifdef HAVE_STRNCPY
+       return strncpy(dest, src, len);
+#else
+       char ch;
+       char *d = dest;
+       while(len > 0 && (ch = *src++) != '\0')
+       {
+               *d++ = ch;
+               --len;
+       }
+       while(len > 0)
+       {
+               *d++ = '\0';
+               --len;
+       }
+       return dest;
+#endif
+}
+
+/*@
+ * @deftypefun {char *} jit_strdup ({const char *} str)
+ * Allocate a block of memory using @code{jit_malloc} and copy
+ * @code{str} into it.  Returns NULL if @code{str} is NULL or there
+ * is insufficient memory to perform the @code{jit_malloc} operation.
+ * @end deftypefun
+@*/
+char *jit_strdup(const char *str)
+{
+       char *new_str;
+       if(!str)
+       {
+               return 0;
+       }
+       new_str = jit_malloc(strlen(str) + 1);
+       if(!new_str)
+       {
+               return 0;
+       }
+       strcpy(new_str, str);
+       return new_str;
+}
+
+/*@
+ * @deftypefun {char *} jit_strndup ({const char *} str, unsigned int len)
+ * Allocate a block of memory using @code{jit_malloc} and copy at most
+ * @code{len} characters of @code{str} into it.  The copied string is then
+ * NULL-terminated.  Returns NULL if @code{str} is NULL or there
+ * is insufficient memory to perform the @code{jit_malloc} operation.
+ * @end deftypefun
+@*/
+char *jit_strndup(const char *str, unsigned int len)
+{
+       char *new_str;
+       if(!str)
+       {
+               return 0;
+       }
+       new_str = jit_malloc(len + 1);
+       if(!new_str)
+       {
+               return 0;
+       }
+       jit_memcpy(new_str, str, len);
+       new_str[len] = '\0';
+       return new_str;
+}
+
+/*@
+ * @deftypefun int jit_strcmp ({const char *} str1, {const char *} str2)
+ * Compare the two strings @code{str1} and @code{str2}, returning
+ * a negative, zero, or positive value depending upon their relationship.
+ * @end deftypefun
+@*/
+int jit_strcmp(const char *str1, const char *str2)
+{
+#ifdef HAVE_STRCMP
+       return strcmp(str1, str2);
+#else
+       int ch1, ch2;
+       for(;;)
+       {
+               ch1 = *str1++;
+               ch2 = *str2++;
+               if(ch1 != ch2 || !ch1 || !ch2)
+               {
+                       break;
+               }
+       }
+       return (ch1 - ch2);
+#endif
+}
+
+/*@
+ * @deftypefun int jit_strncmp ({const char *} str1, {const char *} str2, {unsigned int} len)
+ * Compare the two strings @code{str1} and @code{str2}, returning
+ * a negative, zero, or positive value depending upon their relationship.
+ * At most @code{len} characters are compared.
+ * @end deftypefun
+@*/
+int jit_strncmp(const char *str1, const char *str2, unsigned int len)
+{
+#ifdef HAVE_STRNCMP
+       return strncmp(str1, str2, len);
+#else
+       int ch1, ch2;
+       while(len > 0)
+       {
+               ch1 = *str1++;
+               ch2 = *str2++;
+               if(ch1 != ch2 || !ch1 || !ch2)
+               {
+                       return (ch1 - ch2);
+               }
+               --len;
+       }
+       return 0;
+#endif
+}
+
+/*@
+ * @deftypefun int jit_stricmp ({const char *} str1, {const char *} str2)
+ * Compare the two strings @code{str1} and @code{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.  Use @code{jit_stricoll} for
+ * locale-sensitive string comparison.
+ * @end deftypefun
+@*/
+int jit_stricmp(const char *str1, const char *str2)
+{
+       int ch1, ch2;
+       for(;;)
+       {
+               ch1 = *str1++;
+               ch2 = *str2++;
+               if(ch1 >= 'A' && ch1 <= 'Z')
+               {
+                       ch1 = ch1 - 'A' + 'a';
+               }
+               if(ch2 >= 'A' && ch2 <= 'Z')
+               {
+                       ch2 = ch2 - 'A' + 'a';
+               }
+               if(ch1 != ch2 || !ch1 || !ch2)
+               {
+                       break;
+               }
+       }
+       return (ch1 - ch2);
+}
+
+/*@
+ * @deftypefun int jit_strnicmp ({const char *} str1, {const char *} str2, {unsigned int} len)
+ * Compare the two strings @code{str1} and @code{str2}, returning
+ * a negative, zero, or positive value depending upon their relationship.
+ * At most @code{len} characters are compared.  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.  Use @code{jit_strnicoll} for
+ * locale-sensitive string comparison.
+ * @end deftypefun
+@*/
+int jit_strnicmp(const char *str1, const char *str2, unsigned int len)
+{
+       int ch1, ch2;
+       while(len > 0)
+       {
+               ch1 = *str1++;
+               ch2 = *str2++;
+               if(ch1 >= 'A' && ch1 <= 'Z')
+               {
+                       ch1 = ch1 - 'A' + 'a';
+               }
+               if(ch2 >= 'A' && ch2 <= 'Z')
+               {
+                       ch2 = ch2 - 'A' + 'a';
+               }
+               if(ch1 != ch2 || !ch1 || !ch2)
+               {
+                       return (ch1 - ch2);
+               }
+               --len;
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun int jit_strcoll ({const char *} str1, {const char *} str2)
+ * Compare the two strings @code{str1} and @code{str2}, returning
+ * a negative, zero, or positive value depending upon their relationship.
+ * This function uses locale-sensitive comparison rules, but case is
+ * still considered significant.  If the system does not have locale
+ * sensitive comparisons, this function will be identical to
+ * @code{jit_strcmp}.
+ * @end deftypefun
+@*/
+int jit_strcoll(const char *str1, const char *str2)
+{
+#if defined(HAVE_STRCOLL)
+       return strcoll(str1, str2);
+#elif defined(HAVE__STRCOLL)
+       return _strcoll(str1, str2);
+#elif defined(HAVE_STRCMP)
+       return strcmp(str1, str2);
+#else
+       return jit_strcmp(str1, str2);
+#endif
+}
+
+/*@
+ * @deftypefun int jit_stricoll ({const char *} str1, {const char *} str2)
+ * Compare the two strings @code{str1} and @code{str2}, returning
+ * a negative, zero, or positive value depending upon their relationship.
+ * This function uses locale-sensitive comparison rules, while ignoring
+ * case.  If the system does not have locale sensitive comparisons, this
+ * function will be identical to @code{jit_stricmp}.
+ * @end deftypefun
+@*/
+int jit_stricoll(const char *str1, const char *str2)
+{
+#if defined(HAVE_STRICOLL)
+       return stricoll(str1, str2);
+#elif defined(HAVE__STRICOLL)
+       return _stricoll(str1, str2);
+#elif defined(HAVE_STRCASECMP)
+       return strcasecmp(str1, str2);
+#else
+       return jit_stricmp(str1, str2);
+#endif
+}
+
+/*@
+ * @deftypefun int jit_strncoll ({const char *} str1, {const char *} str2, {unsigned int} len)
+ * Compare the two strings @code{str1} and @code{str2}, returning
+ * a negative, zero, or positive value depending upon their relationship.
+ * At most @code{len} characters are compared, but it is otherwise
+ * the same as @code{jit_strcoll}.
+ * @end deftypefun
+@*/
+int jit_strncoll(const char *str1, const char *str2, unsigned int len)
+{
+#if defined(HAVE_STRNCOLL)
+       return strncoll(str1, str2, len);
+#elif defined(HAVE__STRNCOLL)
+       return _strncoll(str1, str2, len);
+#elif defined(HAVE_STRNCMP)
+       return strncmp(str1, str2, len);
+#else
+       return jit_strncmp(str1, str2, len);
+#endif
+}
+
+/*@
+ * @deftypefun int jit_strnicoll ({const char *} str1, {const char *} str2, {unsigned int} len)
+ * Compare the two strings @code{str1} and @code{str2}, returning
+ * a negative, zero, or positive value depending upon their relationship.
+ * At most @code{len} characters are compared, but it is otherwise
+ * the same as @code{jit_stricoll}.
+ * @end deftypefun
+@*/
+int jit_strnicoll(const char *str1, const char *str2, unsigned int len)
+{
+#if defined(HAVE_STRNICOLL)
+       return strincoll(str1, str2, len);
+#elif defined(HAVE__STRNICOLL)
+       return _strnicoll(str1, str2, len);
+#elif defined(HAVE_STRNCASECMP)
+       return strncasecmp(str1, str2, len);
+#else
+       return jit_strnicmp(str1, str2, len);
+#endif
+}
+
+/*@
+ * @deftypefun {char *} jit_strchr ({const char *} str, int ch)
+ * Search @code{str} for the first occurrence of @code{ch}.  Returns
+ * the address where @code{ch} was found, or NULL if not found.
+ * @end deftypefun
+@*/
+char *jit_strchr(const char *str, int ch)
+{
+#ifdef HAVE_STRCHR
+       return strchr(str, ch);
+#else
+       char *s = (char *)str;
+       for(;;)
+       {
+               if(*s == (char)ch)
+               {
+                       return s;
+               }
+               else if(*s == '\0')
+               {
+                       break;
+               }
+               ++s;
+       }
+       return 0;
+#endif
+}
+
+/*@
+ * @deftypefun {char *} jit_strrchr ({const char *} str, int ch)
+ * Search @code{str} for the first occurrence of @code{ch}, starting
+ * at the end of the string.  Returns the address where @code{ch}
+ * was found, or NULL if not found.
+ * @end deftypefun
+@*/
+char *jit_strrchr(const char *str, int ch)
+{
+#ifdef HAVE_STRRCHR
+       return strrchr(str, ch);
+#else
+       unsigned int len = jit_strlen(str);
+       char *s = (char *)(str + len);
+       while(len > 0)
+       {
+               --s;
+               if(*s == (char)ch)
+               {
+                       return s;
+               }
+               --len;
+       }
+       return 0;
+#endif
+}
+
+int jit_sprintf(char *str, const char *format, ...)
+{
+       va_list va;
+       int result;
+#ifdef HAVE_STDARG_H
+       va_start(va, format);
+#else
+       va_start(va);
+#endif
+#ifdef VSPRINTF
+       result = vsprintf(str, format, va);
+#else
+       *str = '\0';
+       result = 0;
+#endif
+       va_end(va);
+       return result;
+}
+
+int jit_snprintf(char *str, unsigned int len, const char *format, ...)
+{
+       va_list va;
+       int result;
+#ifdef HAVE_STDARG_H
+       va_start(va, format);
+#else
+       va_start(va);
+#endif
+#if defined(HAVE_VSNPRINTF)
+       result = vsnprintf(str, len, format, va);
+#elif defined(HAVE__VSNPRINTF)
+       result = _vsnprintf(str, len, format, va);
+#else
+       *str = '\0';
+       result = 0;
+#endif
+       va_end(va);
+       return result;
+}
diff --git a/jit/jit-thread.c b/jit/jit-thread.c
new file mode 100644 (file)
index 0000000..aceb660
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * jit-thread.c - Internal thread management routines for libjit.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+
+#if defined(JIT_THREADS_PTHREAD)
+
+/*
+ * The thread-specific key to use to fetch the control object.
+ */
+static pthread_key_t control_key;
+
+/*
+ * Initialize the pthread support routines.  Only called once.
+ */
+static void init_pthread(void)
+{
+       /* Allocate a thread-specific variable for the JIT's thread
+          control object, and arrange for it to be freed when the
+          thread exits or is otherwise terminated */
+       pthread_key_create(&control_key, jit_free);
+}
+
+#elif defined(JIT_THREADS_WIN32)
+
+/*
+ * The thread-specific key to use to fetch the control object.
+ */
+static DWORD control_key;
+
+/*
+ * Initialize the Win32 thread support routines.  Only called once.
+ */
+static void init_win32_thread(void)
+{
+       control_key = TlsAlloc();
+}
+
+#else /* No thread package */
+
+/*
+ * The control object for the only thread in the system.
+ */
+static void *control_object = 0;
+
+#endif /* No thread package */
+
+void _jit_thread_init(void)
+{
+#if defined(JIT_THREADS_PTHREAD)
+       static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+       pthread_once(&once_control, init_pthread);
+#elif defined(JIT_THREADS_WIN32)
+       static LONG volatile once_control = 0;
+       if(!InterlockedExchange((PLONG)&once_control, 1))
+       {
+               init_win32_thread();
+       }
+#endif
+}
+
+static void *get_raw_control(void)
+{
+       _jit_thread_init();
+#if defined(JIT_THREADS_PTHREAD)
+       return pthread_getspecific(control_key);
+#elif defined(JIT_THREADS_WIN32)
+       return (void *)(TlsGetValue(control_key));
+#else
+       return control_object;
+#endif
+}
+
+static void set_raw_control(void *obj)
+{
+       _jit_thread_init();
+#if defined(JIT_THREADS_PTHREAD)
+       pthread_setspecific(control_key, obj);
+#elif defined(JIT_THREADS_WIN32)
+       TlsSetValue(control_key, obj);
+#else
+       control_object = obj;
+#endif
+}
+
+jit_thread_control_t _jit_thread_get_control(void)
+{
+       jit_thread_control_t control;
+       control = (jit_thread_control_t)get_raw_control();
+       if(!control)
+       {
+               control = jit_cnew(struct jit_thread_control);
+               if(control)
+               {
+                       set_raw_control(control);
+               }
+       }
+       return control;
+}
+
+jit_thread_id_t _jit_thread_current_id(void)
+{
+#if defined(JIT_THREADS_PTHREAD)
+       return pthread_self();
+#elif defined(JIT_THREADS_WIN32)
+       return GetCurrentThread();
+#else
+       /* There is only one thread, so lets give it an identifier of 1 */
+       return 1;
+#endif
+}
diff --git a/jit/jit-thread.h b/jit/jit-thread.h
new file mode 100644 (file)
index 0000000..3737cd8
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * jit-thread.h - Internal thread management routines for libjit.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef        _JIT_THREAD_H
+#define        _JIT_THREAD_H
+
+#include <config.h>
+#if defined(HAVE_PTHREAD_H) && defined(HAVE_LIBPTHREAD)
+       #include <pthread.h>
+#elif defined(JIT_WIN32_PLATFORM)
+       #include <windows.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Determine the type of threading library that we are using.
+ */
+#if defined(HAVE_PTHREAD_H) && defined(HAVE_LIBPTHREAD)
+       #define JIT_THREADS_SUPPORTED   1
+       #define JIT_THREADS_PTHREAD             1
+#elif defined(JIT_WIN32_PLATFORM)
+       #define JIT_THREADS_SUPPORTED   1
+       #define JIT_THREADS_WIN32               1
+#else
+       #define JIT_THREADS_SUPPORTED   0
+#endif
+
+/*
+ * Type that describes a thread's identifier, and the id comparison function.
+ */
+#if defined(JIT_THREADS_PTHREAD)
+typedef pthread_t jit_thread_id_t;
+#define        jit_thread_id_equal(x,y)        (pthread_equal((x), (y)))
+#elif defined(JIT_THREADS_WIN32)
+typedef HANDLE jit_thread_id_t;
+#define        jit_thread_id_equal(x,y)        ((x) == (y))
+#else
+typedef int jit_thread_id_t;
+#define        jit_thread_id_equal(x,y)        ((x) == (y))
+#endif
+
+/*
+ * Control information that is associated with a thread.
+ */
+typedef struct jit_thread_control *jit_thread_control_t;
+
+/*
+ * Initialize the thread routines.  Ignored if called multiple times.
+ */
+void _jit_thread_init(void);
+
+/*
+ * Get the JIT control object for the current thread.
+ */
+jit_thread_control_t _jit_thread_get_control(void);
+
+/*
+ * Get the identifier for the current thread.
+ */
+jit_thread_id_t _jit_thread_current_id(void);
+
+/*
+ * Define the primitive mutex operations.
+ */
+#if defined(JIT_THREADS_PTHREAD)
+
+typedef pthread_mutex_t jit_mutex_t;
+#define        jit_mutex_create(mutex)         (pthread_mutex_init((mutex), 0))
+#define        jit_mutex_destroy(mutex)        (pthread_mutex_destroy((mutex)))
+#define        jit_mutex_lock(mutex)           (pthread_mutex_lock((mutex)))
+#define        jit_mutex_unlock(mutex)         (pthread_mutex_unlock((mutex)))
+
+#elif defined(JIT_THREADS_WIN32)
+
+typedef CRITICAL_SECTION jit_mutex_t;
+#define        jit_mutex_create(mutex)         (InitializeCriticalSection((mutex)))
+#define        jit_mutex_destroy(mutex)        (DeleteCriticalSection((mutex)))
+#define        jit_mutex_lock(mutex)           (EnterCriticalSection((mutex)))
+#define        jit_mutex_unlock(mutex)         (LeaveCriticalSection((mutex)))
+
+#else
+
+typedef int jit_mutex_t;
+#define        jit_mutex_create(mutex)         do { ; } while (0)
+#define        jit_mutex_destroy(mutex)        do { ; } while (0)
+#define        jit_mutex_lock(mutex)           do { ; } while (0)
+#define        jit_mutex_unlock(mutex)         do { ; } while (0)
+
+#endif
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _JIT_THREAD_H */
diff --git a/jit/jit-type.c b/jit/jit-type.c
new file mode 100644 (file)
index 0000000..9a5554d
--- /dev/null
@@ -0,0 +1,1323 @@
+/*
+ * jit-type.c - Functions for manipulating type descriptors.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-apply-rules.h"
+#include "jit-rules.h"
+#include <config.h>
+
+/*@
+
+@cindex jit-type.h
+@tindex jit_type_t
+
+The functions that are defined in @code{<jit/jit-type.h>} allow
+the library user to create and manipulate objects that represent
+native system types.  For example, @code{jit_type_int} represents
+the signed 32-bit integer type.
+
+Each @code{jit_type_t} object represents a basic system type,
+be it a primitive, a struct, a union, a pointer, or a function signature.
+The library uses this information to lay out values in memory.
+
+The following pre-defined types are available:
+
+@table @code
+@vindex jit_type_void
+@item jit_type_void
+Represents the @code{void} type.
+
+@vindex jit_type_sbyte
+@item jit_type_sbyte
+Represents a signed 8-bit integer type.
+
+@vindex jit_type_ubyte
+@item jit_type_ubyte
+Represents an unsigned 8-bit integer type.
+
+@vindex jit_type_short
+@item jit_type_short
+Represents a signed 16-bit integer type.
+
+@vindex jit_type_ushort
+@item jit_type_ushort
+Represents an unsigned 16-bit integer type.
+
+@vindex jit_type_int
+@item jit_type_int
+Represents a signed 32-bit integer type.
+
+@vindex jit_type_uint
+@item jit_type_uint
+Represents an unsigned 32-bit integer type.
+
+@vindex jit_type_nint
+@item jit_type_nint
+Represents a signed integer type that has the same size and
+alignment as a native pointer.
+
+@vindex jit_type_nuint
+@item jit_type_nuint
+Represents an unsigned integer type that has the same size and
+alignment as a native pointer.
+
+@vindex jit_type_long
+@item jit_type_long
+Represents a signed 64-bit integer type.
+
+@vindex jit_type_ulong
+@item jit_type_ulong
+Represents an unsigned 64-bit integer type.
+
+@vindex jit_type_float32
+@item jit_type_float32
+Represents a 32-bit floating point type.
+
+@vindex jit_type_float64
+@item jit_type_float64
+Represents a 64-bit floating point type.
+
+@vindex jit_type_nfloat
+@item jit_type_nfloat
+Represents a floating point type that represents the greatest
+precision supported on the native platform.
+
+@vindex jit_type_void_ptr
+@item jit_type_void_ptr
+Represents the system's @code{void *} type.  This can be used wherever
+a native pointer type is required.
+@end table
+
+Type descriptors are reference counted.  You can make a copy of a type
+descriptor using the @code{jit_type_copy} function, and free the copy with
+@code{jit_type_free}.
+
+Some languages have special versions of the primitive numeric types
+(e.g. boolean types, 16-bit Unicode character types, enumerations, etc).
+If it is important to distinguish these special versions from the
+numeric types, then you should use the @code{jit_type_create_tagged}
+function below.
+
+@*/
+
+/*
+ * Pre-defined type descriptors.
+ */
+struct _jit_type const _jit_type_void_def =
+       {1, JIT_TYPE_VOID, 0, 1, 0, 1, 1};
+jit_type_t const jit_type_void = (jit_type_t)&_jit_type_void_def;
+struct _jit_type const _jit_type_sbyte_def =
+       {1, JIT_TYPE_SBYTE, 0, 1, 0, sizeof(jit_sbyte), JIT_ALIGN_SBYTE};
+jit_type_t const jit_type_sbyte = (jit_type_t)&_jit_type_sbyte_def;
+struct _jit_type const _jit_type_ubyte_def =
+       {1, JIT_TYPE_UBYTE, 0, 1, 0, sizeof(jit_ubyte), JIT_ALIGN_UBYTE};
+jit_type_t const jit_type_ubyte = (jit_type_t)&_jit_type_ubyte_def;
+struct _jit_type const _jit_type_short_def =
+       {1, JIT_TYPE_SHORT, 0, 1, 0, sizeof(jit_short), JIT_ALIGN_SHORT};
+jit_type_t const jit_type_short = (jit_type_t)&_jit_type_short_def;
+struct _jit_type const _jit_type_ushort_def =
+       {1, JIT_TYPE_USHORT, 0, 1, 0, sizeof(jit_ushort), JIT_ALIGN_USHORT};
+jit_type_t const jit_type_ushort = (jit_type_t)&_jit_type_ushort_def;
+struct _jit_type const _jit_type_int_def =
+       {1, JIT_TYPE_INT, 0, 1, 0, sizeof(jit_int), JIT_ALIGN_INT};
+jit_type_t const jit_type_int = (jit_type_t)&_jit_type_int_def;
+struct _jit_type const _jit_type_uint_def =
+       {1, JIT_TYPE_UINT, 0, 1, 0, sizeof(jit_uint), JIT_ALIGN_UINT};
+jit_type_t const jit_type_uint = (jit_type_t)&_jit_type_uint_def;
+struct _jit_type const _jit_type_nint_def =
+       {1, JIT_TYPE_NINT, 0, 1, 0, sizeof(jit_nint), JIT_ALIGN_NINT};
+jit_type_t const jit_type_nint = (jit_type_t)&_jit_type_nint_def;
+struct _jit_type const _jit_type_nuint_def =
+       {1, JIT_TYPE_NUINT, 0, 1, 0, sizeof(jit_nuint), JIT_ALIGN_NUINT};
+jit_type_t const jit_type_nuint = (jit_type_t)&_jit_type_nuint_def;
+struct _jit_type const _jit_type_long_def =
+       {1, JIT_TYPE_LONG, 0, 1, 0, sizeof(jit_long), JIT_ALIGN_LONG};
+jit_type_t const jit_type_long = (jit_type_t)&_jit_type_long_def;
+struct _jit_type const _jit_type_ulong_def =
+       {1, JIT_TYPE_ULONG, 0, 1, 0, sizeof(jit_ulong), JIT_ALIGN_ULONG};
+jit_type_t const jit_type_ulong = (jit_type_t)&_jit_type_ulong_def;
+struct _jit_type const _jit_type_float32_def =
+       {1, JIT_TYPE_FLOAT32, 0, 1, 0, sizeof(jit_float32), JIT_ALIGN_FLOAT32};
+jit_type_t const jit_type_float32 = (jit_type_t)&_jit_type_float32_def;
+struct _jit_type const _jit_type_float64_def =
+       {1, JIT_TYPE_FLOAT64, 0, 1, 0, sizeof(jit_float64), JIT_ALIGN_FLOAT64};
+jit_type_t const jit_type_float64 = (jit_type_t)&_jit_type_float64_def;
+struct _jit_type const _jit_type_nfloat_def =
+       {1, JIT_TYPE_NFLOAT, 0, 1, 0, sizeof(jit_nfloat), JIT_ALIGN_NFLOAT};
+jit_type_t const jit_type_nfloat = (jit_type_t)&_jit_type_nfloat_def;
+struct _jit_type const _jit_type_void_ptr_def =
+       {1, JIT_TYPE_PTR, 0, 1, 0, sizeof(void *), JIT_ALIGN_PTR,
+        (jit_type_t)&_jit_type_void_def};
+jit_type_t const jit_type_void_ptr = (jit_type_t)&_jit_type_void_ptr_def;
+
+/*
+ * Type descriptors for the system "char", "int", "long", etc types.
+ * These are defined to one of the above values.
+ */
+#ifdef __CHAR_UNSIGNED__
+jit_type_t const jit_type_sys_char = (jit_type_t)&_jit_type_ubyte_def;
+#else
+jit_type_t const jit_type_sys_char = (jit_type_t)&_jit_type_sbyte_def;
+#endif
+jit_type_t const jit_type_sys_schar = (jit_type_t)&_jit_type_sbyte_def;
+jit_type_t const jit_type_sys_uchar = (jit_type_t)&_jit_type_ubyte_def;
+#if SIZEOF_SHORT == 4
+jit_type_t const jit_type_sys_short = (jit_type_t)&_jit_type_int_def;
+jit_type_t const jit_type_sys_ushort = (jit_type_t)&_jit_type_uint_def;
+#elif SIZEOF_SHORT == 8
+jit_type_t const jit_type_sys_short = (jit_type_t)&_jit_type_long_def;
+jit_type_t const jit_type_sys_ushort = (jit_type_t)&_jit_type_ulong_def;
+#else
+jit_type_t const jit_type_sys_short = (jit_type_t)&_jit_type_short_def;
+jit_type_t const jit_type_sys_ushort = (jit_type_t)&_jit_type_ushort_def;
+#endif
+#if SIZEOF_INT == 8
+jit_type_t const jit_type_sys_int = (jit_type_t)&_jit_type_long_def;
+jit_type_t const jit_type_sys_uint = (jit_type_t)&_jit_type_ulong_def;
+#elif SIZEOF_INT == 2
+jit_type_t const jit_type_sys_int = (jit_type_t)&_jit_type_short_def;
+jit_type_t const jit_type_sys_uint = (jit_type_t)&_jit_type_ushort_def;
+#else
+jit_type_t const jit_type_sys_int = (jit_type_t)&_jit_type_int_def;
+jit_type_t const jit_type_sys_uint = (jit_type_t)&_jit_type_uint_def;
+#endif
+#if SIZEOF_LONG == 8
+jit_type_t const jit_type_sys_long = (jit_type_t)&_jit_type_long_def;
+jit_type_t const jit_type_sys_ulong = (jit_type_t)&_jit_type_ulong_def;
+#elif SIZEOF_LONG == 2
+jit_type_t const jit_type_sys_long = (jit_type_t)&_jit_type_short_def;
+jit_type_t const jit_type_sys_ulong = (jit_type_t)&_jit_type_ushort_def;
+#else
+jit_type_t const jit_type_sys_long = (jit_type_t)&_jit_type_int_def;
+jit_type_t const jit_type_sys_ulong = (jit_type_t)&_jit_type_uint_def;
+#endif
+#if SIZEOF_LONG_LONG == 8 || SIZEOF___INT64 == 8
+jit_type_t const jit_type_sys_longlong = (jit_type_t)&_jit_type_long_def;
+jit_type_t const jit_type_sys_ulonglong = (jit_type_t)&_jit_type_ulong_def;
+#elif SIZEOF_LONG_LONG == 4
+jit_type_t const jit_type_sys_longlong = (jit_type_t)&_jit_type_int_def;
+jit_type_t const jit_type_sys_ulonglong = (jit_type_t)&_jit_type_uint_def;
+#elif SIZEOF_LONG_LONG == 2
+jit_type_t const jit_type_sys_longlong = (jit_type_t)&_jit_type_short_def;
+jit_type_t const jit_type_sys_ulonglong = (jit_type_t)&_jit_type_ushort_def;
+#else
+jit_type_t const jit_type_sys_longlong = (jit_type_t)&_jit_type_long_def;
+jit_type_t const jit_type_sys_ulonglong = (jit_type_t)&_jit_type_ulong_def;
+#endif
+jit_type_t const jit_type_sys_float = (jit_type_t)&_jit_type_float32_def;
+jit_type_t const jit_type_sys_double = (jit_type_t)&_jit_type_float64_def;
+jit_type_t const jit_type_sys_long_double = (jit_type_t)&_jit_type_nfloat_def;
+
+/*
+ * Special offset flags.
+ */
+#define        JIT_OFFSET_IS_INTERNAL  (((jit_nuint)1) << (sizeof(jit_nint) * 8 - 1))
+#define        JIT_OFFSET_NOT_SET              (~((jit_nuint)0))
+
+/*
+ * Layout flags.
+ */
+#define        JIT_LAYOUT_NEEDED                       1
+#define        JIT_LAYOUT_EXPLICIT_SIZE        2
+#define        JIT_LAYOUT_EXPLICIT_ALIGN       4
+
+/*
+ * Perform layout on a structure or union type.
+ */
+static void perform_layout(jit_type_t type)
+{
+       jit_nuint size = 0;
+       jit_nuint maxSize = 0;
+       jit_nuint maxAlign = 1;
+       jit_nuint alignLimit;
+       jit_nuint fieldSize;
+       jit_nuint fieldAlign;
+       unsigned int index;
+
+       /* Determine the alignment limit, if there is an override */
+#ifdef JIT_ALIGN_OVERRIDES
+       if((type->layout_flags & JIT_LAYOUT_EXPLICIT_ALIGN) != 0)
+       {
+               alignLimit = type->alignment;
+       }
+       else
+#endif
+       {
+               alignLimit = 0;
+       }
+
+       /* Lay out all of the fields in this structure */
+       for(index = 0; index < type->num_components; ++index)
+       {
+               /* Get the size and alignment of the field */
+               fieldSize = jit_type_get_size(type->components[index].type);
+               fieldAlign = jit_type_get_alignment(type->components[index].type);
+
+               /* Clamp the alignment if we have a limit */
+               if(alignLimit != 0 && fieldAlign > alignLimit)
+               {
+                       fieldAlign = alignLimit;
+               }
+
+               /* Update the size and alignment values */
+               if(type->kind == JIT_TYPE_STRUCT)
+               {
+                       /* Perform layout for a struct type */
+                       if((type->components[index].offset & JIT_OFFSET_IS_INTERNAL) != 0)
+                       {
+                               /* Calculate the offset for the field automatically */
+                               if((size % fieldAlign) != 0)
+                               {
+                                       size += fieldAlign - (size % fieldAlign);
+                               }
+                               type->components[index].offset = JIT_OFFSET_IS_INTERNAL | size;
+                               size += fieldSize;
+                       }
+                       else
+                       {
+                               /* Use the explicitly-supplied offset for the field */
+                               size = type->components[index].offset + fieldSize;
+                       }
+                       if(size > maxSize)
+                       {
+                               maxSize = size;
+                       }
+               }
+               else
+               {
+                       /* Perform layout for a union type (offset is always zero) */
+                       type->components[index].offset = JIT_OFFSET_IS_INTERNAL | 0;
+                       if((fieldSize % fieldAlign) != 0)
+                       {
+                               fieldSize += fieldAlign - (fieldSize % fieldAlign);
+                       }
+                       if(fieldSize > maxSize)
+                       {
+                               maxSize = fieldSize;
+                       }
+               }
+               if(fieldAlign > maxAlign)
+               {
+                       maxAlign = fieldAlign;
+               }
+       }
+
+       /* Align the full structure */
+       if((maxSize % maxAlign) != 0)
+       {
+               maxSize += maxAlign - (maxSize % maxAlign);
+       }
+
+       /* Record the final size and alignment values */
+       if((type->layout_flags & JIT_LAYOUT_EXPLICIT_SIZE) != 0)
+       {
+               if(maxSize > type->size)
+               {
+                       type->size = maxSize;
+               }
+       }
+       else
+       {
+               type->size = maxSize;
+       }
+       type->alignment = maxAlign;
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_copy (jit_type_t type)
+ * Make a copy of the type descriptor @code{type} by increasing
+ * its reference count.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_copy(jit_type_t type)
+{
+       if(!type || type->is_fixed)
+       {
+               return type;
+       }
+       ++(type->ref_count);
+       return type;
+}
+
+/*@
+ * @deftypefun void jit_type_free (jit_type_t type)
+ * Free a type descriptor by decreasing its reference count.
+ * This function is safe to use on pre-defined types, which are
+ * never actually freed.
+ * @end deftypefun
+@*/
+void jit_type_free(jit_type_t type)
+{
+       unsigned int index;
+       if(!type || type->is_fixed)
+       {
+               return;
+       }
+       if(--(type->ref_count) != 0)
+       {
+               return;
+       }
+       jit_type_free(type->sub_type);
+       for(index = 0; index < type->num_components; ++type)
+       {
+               jit_type_free(type->components[index].type);
+               if(type->components[index].name)
+               {
+                       jit_free(type->components[index].name);
+               }
+       }
+       if(type->kind >= JIT_TYPE_FIRST_TAGGED)
+       {
+               struct jit_tagged_type *tagged = (struct jit_tagged_type *)type;
+               if(tagged->free_func)
+               {
+                       (*(tagged->free_func))(tagged->data);
+               }
+       }
+       jit_free(type);
+}
+
+static jit_type_t create_complex(int kind, jit_type_t *types,
+                                                                unsigned int num, int incref)
+{
+       jit_type_t type;
+       unsigned int index;
+       if(num <= 1)
+       {
+               type = jit_cnew(struct _jit_type);
+       }
+       else
+       {
+               type = (jit_type_t)jit_calloc
+                               (1, sizeof(struct _jit_type) +
+                                   (num - 1) * sizeof(struct jit_component));
+       }
+       if(!type)
+       {
+               return 0;
+       }
+       type->ref_count = 1;
+       type->kind = kind;
+       type->layout_flags = JIT_LAYOUT_NEEDED;
+       type->num_components = num;
+       for(index = 0; index < num; ++index)
+       {
+               if(incref)
+               {
+                       type->components[index].type = jit_type_copy(types[index]);
+               }
+               else
+               {
+                       type->components[index].type = types[index];
+               }
+               type->components[index].offset = JIT_OFFSET_NOT_SET;
+               type->components[index].name = 0;
+       }
+       return type;
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_create_struct ({jit_type_t *} 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 @code{incref} is non-zero.
+ *
+ * The @code{libjit} library does not provide any special support for
+ * implementing structure inheritance, where one structure extends the
+ * definition of another.  The effect of inheritance can be achieved
+ * by always allocating the first field of a structure to be an instance
+ * of the inherited structure.  Multiple inheritance can be supported
+ * by allocating several special fields at the front of an inheriting
+ * structure.
+ *
+ * Similarly, no special support is provided for vtables.  The program
+ * is responsible for allocating an appropriate slot in a structure to
+ * contain the vtable pointer, and dereferencing it wherever necessary.
+ * The vtable will itself be a structure, containing signature types
+ * for each of the method slots.
+ *
+ * The choice not to provide special support for inheritance and vtables
+ * in @code{libjit} was deliberate.  The layout of objects and vtables
+ * is highly specific to the language and virtual machine being emulated,
+ * and no single scheme can hope to capture all possibilities.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_create_struct(jit_type_t *fields, unsigned int num_fields,
+                                                                 int incref)
+{
+       return create_complex(JIT_TYPE_STRUCT, fields, num_fields, incref);
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_create_union ({jit_type_t *} 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 @code{incref} is non-zero.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_create_union(jit_type_t *fields, unsigned int num_fields,
+                                                                int incref)
+{
+       return create_complex(JIT_TYPE_UNION, fields, num_fields, incref);
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_create_signature (jit_abi_t 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 @code{incref} is non-zero.
+ *
+ * When used as a structure or union field, function signatures are laid
+ * out like pointers.  That is, they represent a pointer to a function
+ * that has the specified parameters and return type.
+ *
+ * @tindex jit_abi_t
+ * The @code{abi} parameter specifies the Application Binary Interface (ABI)
+ * that the function uses.  It may be one of the following values:
+ *
+ * @table @code
+ * @vindex jit_abi_cdecl
+ * @item jit_abi_cdecl
+ * Use the native C ABI definitions of the underlying platform.
+ *
+ * @vindex jit_abi_vararg
+ * @item jit_abi_vararg
+ * Use the native C ABI definitions of the underlying platform,
+ * and allow for an optional list of variable argument parameters.
+ *
+ * @vindex jit_abi_stdcall
+ * @item jit_abi_stdcall
+ * Use the Win32 STDCALL ABI definitions, whereby the callee pops
+ * its arguments rather than the caller.  If the platform does
+ * not support this type of ABI, then @code{jit_abi_stdcall} will be
+ * identical to @code{jit_abi_cdecl}.
+ *
+ * @vindex jit_abi_fastcall
+ * @item jit_abi_fastcall
+ * Use the Win32 FASTCALL ABI definitions, whereby the callee pops
+ * its arguments rather than the caller, and the first two word
+ * arguments are passed in ECX and EDX.  If the platform does
+ * not support this type of ABI, then @code{jit_abi_fastcall} will be
+ * identical to @code{jit_abi_cdecl}.
+ * @end table
+ * @end deftypefun
+@*/
+jit_type_t jit_type_create_signature(jit_abi_t abi, jit_type_t return_type,
+                                     jit_type_t *params,
+                                                                        unsigned int num_params, int incref)
+{
+       jit_type_t type;
+       type = create_complex(JIT_TYPE_SIGNATURE, params, num_params, incref);
+       if(type)
+       {
+               type->abi = (int)abi;
+               type->layout_flags = 0;
+               type->size = 0;
+               type->alignment = JIT_ALIGN_PTR;
+               if(incref)
+               {
+                       type->sub_type = jit_type_copy(return_type);
+               }
+               else
+               {
+                       type->sub_type = return_type;
+               }
+       }
+       return type;
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_create_pointer (jit_type_t type, int incref)
+ * Create a type descriptor for a pointer to another type.  Returns NULL
+ * if out of memory.  The reference count on @code{type} is incremented if
+ * @code{incref} is non-zero.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_create_pointer(jit_type_t type, int incref)
+{
+       jit_type_t ntype;
+       if(type == jit_type_void)
+       {
+               return jit_type_void_ptr;
+       }
+       if((ntype = jit_cnew(struct _jit_type)) == 0)
+       {
+               return 0;
+       }
+       ntype->ref_count = 1;
+       ntype->kind = JIT_TYPE_PTR;
+       ntype->size = sizeof(void *);
+       ntype->alignment = JIT_ALIGN_PTR;
+       if(incref)
+       {
+               ntype->sub_type = jit_type_copy(type);
+       }
+       else
+       {
+               ntype->sub_type = type;
+       }
+       return ntype;
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_create_tagged (jit_type_t 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
+ * @code{libjit} itself does not support.
+ *
+ * As an example, a language might have a 16-bit Unicode character type
+ * and a 16-bit unsigned integer type that are distinct types, even though
+ * they share the same fundamental representation (@code{jit_ushort}).
+ * Tagging allows the program to distinguish these two types, when
+ * it is necessary to do so, without affecting @code{libjit}'s ability
+ * to compile the code efficiently.
+ *
+ * The @code{kind} is a small positive integer value that the program
+ * can use to distinguish multiple tag types.  The @code{data} pointer is
+ * the actual data that you wish to store.  And @code{free_func} is a
+ * function that is used to free @code{data} when the type is freed
+ * with @code{jit_type_free}.
+ *
+ * If you need to store more than one piece of information, you can
+ * tag a type multiple times.  The order in which multiple tags are
+ * applied is irrelevant to @code{libjit}, although it may be relevant
+ * to the higher-level program.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_create_tagged(jit_type_t type, int kind, void *data,
+                                                                 jit_meta_free_func free_func, int incref)
+{
+       struct jit_tagged_type *ntype;
+       if((ntype = jit_cnew(struct jit_tagged_type)) == 0)
+       {
+               return 0;
+       }
+       ntype->type.ref_count = 1;
+       ntype->type.kind = JIT_TYPE_FIRST_TAGGED + kind;
+       ntype->type.size = 0;
+       ntype->type.alignment = 1;
+       if(incref)
+       {
+               ntype->type.sub_type = jit_type_copy(type);
+       }
+       else
+       {
+               ntype->type.sub_type = type;
+       }
+       ntype->data = data;
+       ntype->free_func = free_func;
+       return &(ntype->type);
+}
+
+/*@
+ * @deftypefun int jit_type_set_names (jit_type_t type, {char **} names, {unsigned int} num_names)
+ * Set the field or parameter names for @code{type}.  Returns zero
+ * if there is insufficient memory to set the names.
+ *
+ * Normally fields are accessed via their index.  Field names are a
+ * convenience for front ends that prefer to use names to indices.
+ * @end deftypefun
+@*/
+int jit_type_set_names(jit_type_t type, char **names, unsigned int num_names)
+{
+       char *temp;
+       if(!type || type->is_fixed || !names)
+       {
+               return 1;
+       }
+       if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION ||
+          type->kind == JIT_TYPE_SIGNATURE)
+       {
+               if(num_names > type->num_components)
+               {
+                       num_names = type->num_components;
+               }
+               while(num_names > 0)
+               {
+                       --num_names;
+                       if(type->components[num_names].name)
+                       {
+                               jit_free(type->components[num_names].name);
+                               type->components[num_names].name = 0;
+                       }
+                       if(names[num_names])
+                       {
+                               temp = jit_strdup(names[num_names]);
+                               if(!temp)
+                               {
+                                       return 0;
+                               }
+                               type->components[num_names].name = temp;
+                       }
+               }
+       }
+       return 1;
+}
+
+/*@
+ * @deftypefun void jit_type_set_size_and_alignment (jit_type_t 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.
+ * @end deftypefun
+@*/
+void jit_type_set_size_and_alignment(jit_type_t type, jit_nint size,
+                                                                        jit_nint alignment)
+{
+       if(!type)
+       {
+               return;
+       }
+       if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
+       {
+               type->size = (jit_nuint)size;
+               type->alignment = (jit_nuint)alignment;
+               if(size != -1)
+               {
+                       type->layout_flags |= JIT_LAYOUT_EXPLICIT_SIZE;
+               }
+               if(alignment != -1)
+               {
+                       type->layout_flags |= JIT_LAYOUT_EXPLICIT_ALIGN;
+               }
+               type->layout_flags |= JIT_LAYOUT_NEEDED;
+       }
+}
+
+/*@
+ * @deftypefun void jit_type_set_offset (jit_type_t 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.
+ * @end deftypefun
+@*/
+void jit_type_set_offset(jit_type_t type, unsigned int field_index,
+                                                jit_nuint offset)
+{
+       if(!type || field_index >= type->num_components)
+       {
+               return;
+       }
+       if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
+       {
+               type->components[field_index].offset = offset;
+               type->layout_flags |= JIT_LAYOUT_NEEDED;
+       }
+}
+
+/*@
+ * @deftypefun jit_nuint jit_type_get_size (jit_type_t type)
+ * Get the size of a type in bytes.
+ * @end deftypefun
+@*/
+jit_nuint jit_type_get_size(jit_type_t type)
+{
+       if(!type)
+       {
+               return 0;
+       }
+       if(type->kind == JIT_TYPE_SIGNATURE)
+       {
+               /* The "size" field is used for argument size, not type size,
+                  so we ignore it and return the real size here */
+               return sizeof(void *);
+       }
+       else if(type->kind >= JIT_TYPE_FIRST_TAGGED)
+       {
+               return jit_type_get_size(type->sub_type);
+       }
+       if((type->layout_flags & JIT_LAYOUT_NEEDED) != 0)
+       {
+               perform_layout(type);
+       }
+       return type->size;
+}
+
+/*@
+ * @deftypefun jit_nuint jit_type_get_alignment (jit_type_t type)
+ * Get the alignment of a type.  An alignment value of 2 indicates
+ * that the type should be aligned on a two-byte boundary, for example.
+ * @end deftypefun
+@*/
+jit_nuint jit_type_get_alignment(jit_type_t type)
+{
+       if(!type)
+       {
+               return 0;
+       }
+       if(type->kind >= JIT_TYPE_FIRST_TAGGED)
+       {
+               return jit_type_get_alignment(type->sub_type);
+       }
+       if((type->layout_flags & JIT_LAYOUT_NEEDED) != 0)
+       {
+               perform_layout(type);
+       }
+       return type->alignment;
+}
+
+/*@
+ * @deftypefun {unsigned int} jit_type_num_fields (jit_type_t type)
+ * Get the number of fields in a structure or union type.
+ * @end deftypefun
+@*/
+unsigned int jit_type_num_fields(jit_type_t type)
+{
+       if(!type ||
+          (type->kind != JIT_TYPE_STRUCT && type->kind != JIT_TYPE_UNION))
+       {
+               return 0;
+       }
+       else
+       {
+               return type->num_components;
+       }
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_get_field (jit_type_t 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.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_get_field(jit_type_t type, unsigned int field_index)
+{
+       if(!type || field_index >= type->num_components)
+       {
+               return 0;
+       }
+       if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
+       {
+               return type->components[field_index].type;
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun jit_nuint jit_type_get_offset (jit_type_t 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.
+ * @end deftypefun
+@*/
+jit_nuint jit_type_get_offset(jit_type_t type, unsigned int field_index)
+{
+       if(!type || field_index >= type->num_components)
+       {
+               return 0;
+       }
+       if(type->kind != JIT_TYPE_STRUCT && type->kind != JIT_TYPE_UNION)
+       {
+               return 0;
+       }
+       if((type->layout_flags & JIT_LAYOUT_NEEDED) != 0)
+       {
+               perform_layout(type);
+       }
+       return type->components[field_index].offset & ~JIT_OFFSET_IS_INTERNAL;
+}
+
+/*@
+ * @deftypefun {const char *} jit_type_get_name (jit_type_t 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.
+ * @end deftypefun
+@*/
+const char *jit_type_get_name(jit_type_t type, unsigned int index)
+{
+       if(!type || index >= type->num_components)
+       {
+               return 0;
+       }
+       else
+       {
+               return type->components[index].name;
+       }
+}
+
+/*@
+ * @deftypefun {unsigned int} jit_type_find_name (jit_type_t type, {const char *} name)
+ * Find the field/parameter index for a particular name.  Returns
+ * @code{JIT_INVALID_NAME} if the name was not present.
+ * @end deftypefun
+@*/
+unsigned int jit_type_find_name(jit_type_t type, const char *name)
+{
+       unsigned int index;
+       if(!type || !name)
+       {
+               return JIT_INVALID_NAME;
+       }
+       if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION ||
+          type->kind == JIT_TYPE_SIGNATURE)
+       {
+               for(index = 0; index < type->num_components; ++index)
+               {
+                       if(type->components[index].name &&
+                          !jit_strcmp(type->components[index].name, name))
+                       {
+                               return index;
+                       }
+               }
+       }
+       return JIT_INVALID_NAME;
+}
+
+/*@
+ * @deftypefun {unsigned int} jit_type_num_params (jit_type_t type)
+ * Get the number of parameters in a signature type.
+ * @end deftypefun
+@*/
+unsigned int jit_type_num_params(jit_type_t type)
+{
+       if(!type || type->kind != JIT_TYPE_SIGNATURE)
+       {
+               return 0;
+       }
+       else
+       {
+               return type->num_components;
+       }
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_get_return (jit_type_t type)
+ * Get the return type from a signature type.  Returns NULL if
+ * not a signature type.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_get_return(jit_type_t type)
+{
+       if(type)
+       {
+               if(type->kind == JIT_TYPE_SIGNATURE)
+               {
+                       return type->sub_type;
+               }
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_get_param (jit_type_t 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.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_get_param(jit_type_t type, unsigned int param_index)
+{
+       if(!type || param_index >= type->num_components)
+       {
+               return 0;
+       }
+       if(type->kind == JIT_TYPE_SIGNATURE)
+       {
+               return type->components[param_index].type;
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun jit_abi_t jit_type_get_abi (jit_type_t type)
+ * Get the ABI code from a signature type.  Returns @code{jit_abi_cdecl}
+ * if not a signature type.
+ * @end deftypefun
+@*/
+jit_abi_t jit_type_get_abi(jit_type_t type)
+{
+       if(type)
+       {
+               return (jit_abi_t)(type->abi);
+       }
+       else
+       {
+               return jit_abi_cdecl;
+       }
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_get_ref (jit_type_t type)
+ * Get the type that is referred to by a pointer type.  Returns NULL
+ * if not a pointer type.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_get_ref(jit_type_t type)
+{
+       if(type)
+       {
+               if(type->kind == JIT_TYPE_PTR)
+               {
+                       return type->sub_type;
+               }
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_get_tagged_type (jit_type_t type)
+ * Get the type that underlies a tagged type.  Returns NULL
+ * if not a tagged type.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_get_tagged_type(jit_type_t type)
+{
+       if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
+       {
+               return type->sub_type;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun void jit_type_set_tagged_type (jit_type_t type, jit_type_t underlying)
+ * Set the type that underlies a tagged type.  Ignored if @code{type}
+ * is not a tagged type.  If @code{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.
+ * @end deftypefun
+@*/
+void jit_type_set_tagged_type(jit_type_t type, jit_type_t underlying,
+                              int incref)
+{
+       if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
+       {
+               if(type->sub_type != underlying)
+               {
+                       jit_type_free(type->sub_type);
+                       if(incref)
+                       {
+                               type->sub_type = jit_type_copy(underlying);
+                       }
+                       else
+                       {
+                               type->sub_type = underlying;
+                       }
+               }
+       }
+}
+
+/*@
+ * @deftypefun int jit_type_get_tagged_type (jit_type_t type)
+ * Get the kind of tag that is applied to a tagged type.  Returns -1
+ * if not a tagged type.
+ * @end deftypefun
+@*/
+int jit_type_get_tagged_kind(jit_type_t type)
+{
+       if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
+       {
+               return type->kind - JIT_TYPE_FIRST_TAGGED;
+       }
+       else
+       {
+               return -1;
+       }
+}
+
+/*@
+ * @deftypefun {void *} jit_type_get_tagged_data (jit_type_t type)
+ * Get the user data is associated with a tagged type.  Returns NULL
+ * if not a tagged type.
+ * @end deftypefun
+@*/
+void *jit_type_get_tagged_data(jit_type_t type)
+{
+       if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
+       {
+               return ((struct jit_tagged_type *)type)->data;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun void jit_type_set_tagged_data (jit_type_t type, {void *} data, jit_meta_free_func free_fun)
+ * Set the user data is associated with a tagged type.  The original data,
+ * if any, is freed.
+ * @end deftypefun
+@*/
+void jit_type_set_tagged_data(jit_type_t type, void *data,
+                              jit_meta_free_func free_func)
+{
+       if(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
+       {
+               struct jit_tagged_type *tagged = (struct jit_tagged_type *)type;
+               if(tagged->data != data)
+               {
+                       if(tagged->free_func)
+                       {
+                               (*(tagged->free_func))(tagged->data);
+                       }
+                       tagged->data = data;
+                       tagged->free_func = free_func;
+               }
+       }
+}
+
+/*@
+ * @deftypefun int jit_type_is_primitive (jit_type_t type)
+ * Determine if a type is primitive.
+ * @end deftypefun
+@*/
+int jit_type_is_primitive(jit_type_t type)
+{
+       if(type)
+       {
+               return (type->kind <= JIT_TYPE_MAX_PRIMITIVE);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun int jit_type_is_struct (jit_type_t type)
+ * Determine if a type is a structure.
+ * @end deftypefun
+@*/
+int jit_type_is_struct(jit_type_t type)
+{
+       if(type)
+       {
+               return (type->kind == JIT_TYPE_STRUCT);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun int jit_type_is_union (jit_type_t type)
+ * Determine if a type is a union.
+ * @end deftypefun
+@*/
+int jit_type_is_union(jit_type_t type)
+{
+       if(type)
+       {
+               return (type->kind == JIT_TYPE_UNION);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun int jit_type_is_signature (jit_type_t type)
+ * Determine if a type is a function signature.
+ * @end deftypefun
+@*/
+int jit_type_is_signature(jit_type_t type)
+{
+       if(type)
+       {
+               return (type->kind == JIT_TYPE_SIGNATURE);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun int jit_type_is_pointer (jit_type_t type)
+ * Determine if a type is a pointer.
+ * @end deftypefun
+@*/
+int jit_type_is_pointer(jit_type_t type)
+{
+       if(type)
+       {
+               return (type->kind == JIT_TYPE_PTR);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun int jit_type_is_tagged (jit_type_t type)
+ * Determine if a type is a tagged type.
+ * @end deftypefun
+@*/
+int jit_type_is_tagged(jit_type_t type)
+{
+       if(type)
+       {
+               return (type->kind >= JIT_TYPE_FIRST_TAGGED);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_nuint jit_type_best_alignment (void)
+ * Get the best alignment value for this platform.
+ * @end deftypefun
+@*/
+jit_nuint jit_type_best_alignment(void)
+{
+       return JIT_BEST_ALIGNMENT;
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_normalize (jit_type_t type)
+ * Normalize a type to its basic numeric form.  e.g. "jit_type_nint" is
+ * turned into "jit_type_int" or "jit_type_long", depending upon
+ * the underlying platform.  Pointers are normalized like "jit_type_nint".
+ * If the type does not have a normalized form, it is left unchanged.
+ *
+ * Normalization is typically used prior to applying a binary numeric
+ * instruction, to make it easier to determine the common type.
+ * It will also remove tags from the specified type.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_normalize(jit_type_t type)
+{
+       while(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
+       {
+               /* Remove any tags that are attached to the type */
+               type = type->sub_type;
+       }
+       if(!type)
+       {
+               return type;
+       }
+       if(type == jit_type_nint || type->kind == JIT_TYPE_PTR ||
+          type->kind == JIT_TYPE_SIGNATURE)
+       {
+       #ifdef JIT_NATIVE_INT32
+               return jit_type_int;
+       #else
+               return jit_type_long;
+       #endif
+       }
+       else if(type == jit_type_nuint)
+       {
+       #ifdef JIT_NATIVE_INT32
+               return jit_type_uint;
+       #else
+               return jit_type_ulong;
+       #endif
+       }
+       else if(type == jit_type_nfloat)
+       {
+               if(sizeof(jit_nfloat) == sizeof(jit_float64))
+               {
+                       return jit_type_float64;
+               }
+               else if(sizeof(jit_nfloat) == sizeof(jit_float32))
+               {
+                       return jit_type_float32;
+               }
+       }
+       return type;
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_remove_tags (jit_type_t type)
+ * Remove tags from a type, and return the underlying type.
+ * This is different from normalization, which will also collapses
+ * native types to their basic numeric counterparts.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_remove_tags(jit_type_t type)
+{
+       while(type && type->kind >= JIT_TYPE_FIRST_TAGGED)
+       {
+               type = type->sub_type;
+       }
+       return type;
+}
+
+/*@
+ * @deftypefun jit_type_t jit_type_promote_int (jit_type_t type)
+ * If @code{type} is @code{jit_type_sbyte}, @code{jit_type_ubyte},
+ * @code{jit_type_short}, or @code{jit_type_ushort}, then return
+ * @code{jit_type_int}.  Otherwise return @code{type} as-is.
+ * @end deftypefun
+@*/
+jit_type_t jit_type_promote_int(jit_type_t type)
+{
+       if(type == jit_type_sbyte || type == jit_type_ubyte ||
+          type == jit_type_short || type == jit_type_ushort)
+       {
+               return jit_type_int;
+       }
+       else
+       {
+               return type;
+       }
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+int jit_type_return_via_pointer(jit_type_t type)
+{
+       extern unsigned char const _jit_apply_return_in_reg[];
+       unsigned int size;
+
+       /* Normalize the type first, just in case the structure is tagged */
+       type = jit_type_normalize(type);
+
+       /* Only structure and union types require special handling */
+       if(!jit_type_is_struct(type) && !jit_type_is_union(type))
+       {
+               return 0;
+       }
+
+       /* Determine if the structure can be returned in a register */
+       size = jit_type_get_size(type);
+       if(size >= 1 && size <= 64)
+       {
+               if((_jit_apply_return_in_reg[(size - 1) / 8] &
+                       (1 << ((size - 1) % 8))) != 0)
+               {
+                       return 0;
+               }
+       }
+       return 1;
+}
diff --git a/jit/jit-value.c b/jit/jit-value.c
new file mode 100644 (file)
index 0000000..8bb7268
--- /dev/null
@@ -0,0 +1,2380 @@
+/*
+ * jit-value.c - Functions for manipulating temporary values.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+
+/*@
+
+@cindex jit-value.h
+
+Values form the backbone of the storage system in @code{libjit}.
+Every value in the system, be it a constant, a local variable,
+or a temporary result, is represented by an object of type
+@code{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:
+
+@example
+value1 = jit_value_create(func, jit_type_int);
+value2 = jit_value_create(func, jit_type_int);
+value3 = jit_value_create(func, jit_type_int);
+@end example
+
+Here, @code{func} is the function that we are building.  To add
+@code{value1} and @code{value2} and put the result into @code{value3},
+we use the following code:
+
+@example
+temp = jit_insn_add(func, value1, value2);
+jit_insn_store(func, value3, temp);
+@end example
+
+The @code{jit_insn_add} function allocates a temporary value
+(@code{temp}) and places the result of the addition into it.
+The @code{jit_insn_store} function then stores the temporary
+result into @code{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 @code{value3}?
+
+Behind the scenes, the JIT will typically optimize @code{temp} away,
+resulting in the final code that you expect (i.e. @code{value3 = value1 +
+value2}).  It is simply easier to use @code{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 @code{value4 = value1 * value2 +
+value3}):
+
+@example
+iload 1
+iload 2
+imul
+iload 3
+iadd
+istore 4
+@end example
+
+Let us demonstrate how this code would be translated, instruction
+by instruction.  We assume that we have a @code{stack} available,
+which keeps track of the temporary values in the system.  We also
+assume that @code{jit_value_t} objects representing the local variables
+are already stored in an array called @code{locals}.
+
+@noindent
+First, we load local variable 1 onto the stack:
+
+@example
+stack[size++] = jit_insn_load(func, locals[1]);
+@end example
+
+@noindent
+We repeat this for local variable 2:
+
+@example
+stack[size++] = jit_insn_load(func, locals[2]);
+@end example
+
+@noindent
+Now we pop these two values and push their multiplication:
+
+@example
+stack[size - 2] = jit_insn_mul(func, stack[size - 2], stack[size - 1]);
+--size;
+@end example
+
+@noindent
+Next, we need to push the value of local variable 3 and add it
+to the product that we just computed:
+
+@example
+stack[size++] = jit_insn_load(func, locals[3]);
+stack[size - 2] = jit_insn_add(func, stack[size - 2], stack[size - 1]);
+--size;
+@end example
+
+@noindent
+Finally, we store the result into local variable 4:
+
+@example
+jit_insn_store(func, locals[4], stack[--size]);
+@end example
+
+@noindent
+Collecting up all of the above code, we get the following:
+
+@example
+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]);
+@end example
+
+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 @code{reg4 = reg1 * reg2 + reg3}, with the intermediate
+result stored temporarily in @code{reg5}:
+
+@example
+mul reg5, reg1, reg2
+add reg4, reg5, reg3
+@end example
+
+You would start by allocating value objects for all of the registers
+in your system (with @code{jit_value_create}):
+
+@example
+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);
+@end example
+
+@noindent
+Then, the virtual register machine code is translated as follows:
+
+@example
+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);
+@end example
+
+Each virtual register machine instruction turns into two @code{libjit}
+function calls.  The JIT will normally optimize away the temporary
+results.  If the value in @code{reg5} is not used further down the code,
+then the JIT may also be able to optimize @code{reg5} away.
+
+The rest of this section describes the functions that are available
+to create and manipulate values.
+
+@*/
+
+/*
+ * Allocate a new value from a function's memory pool.
+ */
+static jit_value_t alloc_value(jit_function_t func, jit_type_t type)
+{
+       jit_value_t value;
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       value = jit_memory_pool_alloc(&(func->builder->value_pool),
+                                                                 struct _jit_value);
+       if(!value)
+       {
+               return 0;
+       }
+       value->block = func->builder->current_block;
+       value->type = jit_type_copy(type);
+       value->reg = -1;
+       value->frame_offset = JIT_INVALID_FRAME_OFFSET;
+       return value;
+}
+
+/*@
+ * @deftypefun 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 @code{jit_insn_load_relative}
+ * or @code{jit_insn_store_relative} to manipulate it.  It simplifies
+ * the JIT if it can assume that all values are local.
+ * @end deftypefun
+@*/
+jit_value_t jit_value_create(jit_function_t func, jit_type_t type)
+{
+       jit_value_t value = alloc_value(func, type);
+       if(!value)
+       {
+               return 0;
+       }
+       value->is_temporary = 1;
+       return value;
+}
+
+/*@
+ * @deftypefun 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 @code{type} parameter indicates the actual type of the constant,
+ * if it happens to be something other than @code{jit_type_nint}.
+ * For example, the following will create an unsigned byte constant:
+ *
+ * @example
+ * value = jit_value_create_nint_constant(context, jit_type_ubyte, 128);
+ * @end example
+ *
+ * This function can be used to create constants of type @code{jit_type_sbyte},
+ * @code{jit_type_ubyte}, @code{jit_type_short}, @code{jit_type_ushort},
+ * @code{jit_type_int}, @code{jit_type_uint}, @code{jit_type_nint},
+ * @code{jit_type_nuint}, and all pointer types.
+ * @end deftypefun
+@*/
+jit_value_t jit_value_create_nint_constant
+               (jit_function_t func, jit_type_t type, jit_nint const_value)
+{
+       jit_value_t value;
+       jit_type_t stripped;
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       if(!const_value)
+       {
+               /* Special cases: see if this is the NULL or zero constant */
+               stripped = jit_type_remove_tags(type);
+               if(jit_type_is_pointer(stripped) || stripped == jit_type_nint)
+               {
+                       if(func->builder->null_constant)
+                       {
+                               return func->builder->null_constant;
+                       }
+               }
+               else if(stripped == jit_type_int)
+               {
+                       if(func->builder->zero_constant)
+                       {
+                               return func->builder->zero_constant;
+                       }
+               }
+       }
+       value = alloc_value(func, type);
+       if(!value)
+       {
+               return 0;
+       }
+       value->is_constant = 1;
+       value->is_nint_constant = 1;
+       value->address = const_value;
+       if(!const_value)
+       {
+               /* Special cases: see if we need to cache this constant for later */
+               stripped = jit_type_remove_tags(type);
+               if(jit_type_is_pointer(stripped) || stripped == jit_type_nint)
+               {
+                       func->builder->null_constant = value;
+               }
+               else if(stripped == jit_type_int)
+               {
+                       func->builder->zero_constant = value;
+               }
+       }
+       return value;
+}
+
+/*@
+ * @deftypefun 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 @code{jit_type_ulong}.  Returns NULL if out of memory.
+ * @end deftypefun
+@*/
+jit_value_t jit_value_create_long_constant
+               (jit_function_t func, jit_type_t type, jit_long const_value)
+{
+       jit_value_t value = alloc_value(func, type);
+       if(!value)
+       {
+               return 0;
+       }
+       value->is_constant = 1;
+#ifdef JIT_NATIVE_INT64
+       value->address = (jit_nint)const_value;
+#else
+       value->address = (jit_nint)jit_malloc(sizeof(jit_long));
+       if(!(value->address))
+       {
+               return 0;
+       }
+       *((jit_long *)(value->address)) = const_value;
+       value->free_address = 1;
+#endif
+       return value;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_value_create_float32_constant
+               (jit_function_t func, jit_type_t type, jit_float32 const_value)
+{
+       jit_value_t value = alloc_value(func, type);
+       if(!value)
+       {
+               return 0;
+       }
+       value->is_constant = 1;
+       value->address = (jit_nint)jit_malloc(sizeof(jit_float32));
+       if(!(value->address))
+       {
+               return 0;
+       }
+       *((jit_float32 *)(value->address)) = const_value;
+       value->free_address = 1;
+       return value;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_value_create_float64_constant
+               (jit_function_t func, jit_type_t type, jit_float64 const_value)
+{
+       jit_value_t value = alloc_value(func, type);
+       if(!value)
+       {
+               return 0;
+       }
+       value->is_constant = 1;
+       value->address = (jit_nint)jit_malloc(sizeof(jit_float64));
+       if(!(value->address))
+       {
+               return 0;
+       }
+       *((jit_float64 *)(value->address)) = const_value;
+       value->free_address = 1;
+       return value;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_value_create_nfloat_constant
+               (jit_function_t func, jit_type_t type, jit_nfloat const_value)
+{
+       jit_value_t value = alloc_value(func, type);
+       if(!value)
+       {
+               return 0;
+       }
+       value->is_constant = 1;
+       value->address = (jit_nint)jit_malloc(sizeof(jit_nfloat));
+       if(!(value->address))
+       {
+               return 0;
+       }
+       *((jit_nfloat *)(value->address)) = const_value;
+       value->free_address = 1;
+       return value;
+}
+
+/*@
+ * @deftypefun 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
+ * @code{const_value} is not suitable for a constant.
+ * @end deftypefun
+@*/
+jit_value_t jit_value_create_constant
+               (jit_function_t func, const jit_constant_t *const_value)
+{
+       jit_type_t stripped = jit_type_normalize(const_value->type);
+       if(!stripped)
+       {
+               return 0;
+       }
+       switch(stripped->kind)
+       {
+               case JIT_TYPE_SBYTE:
+               case JIT_TYPE_UBYTE:
+               case JIT_TYPE_SHORT:
+               case JIT_TYPE_USHORT:
+               case JIT_TYPE_INT:
+               case JIT_TYPE_UINT:
+                       return jit_value_create_nint_constant
+                               (func, const_value->type, const_value->un.int_value);
+
+               case JIT_TYPE_NINT:
+               case JIT_TYPE_NUINT:
+                       return jit_value_create_nint_constant
+                               (func, const_value->type, const_value->un.nint_value);
+
+               case JIT_TYPE_LONG:
+               case JIT_TYPE_ULONG:
+                       return jit_value_create_long_constant
+                               (func, const_value->type, const_value->un.long_value);
+
+               case JIT_TYPE_FLOAT32:
+                       return jit_value_create_float32_constant
+                               (func, const_value->type, const_value->un.float32_value);
+
+               case JIT_TYPE_FLOAT64:
+                       return jit_value_create_float64_constant
+                               (func, const_value->type, const_value->un.float64_value);
+
+               case JIT_TYPE_NFLOAT:
+                       return jit_value_create_nfloat_constant
+                               (func, const_value->type, const_value->un.nfloat_value);
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_value_get_param(jit_function_t func, unsigned int param)
+{
+       jit_type_t signature;
+       unsigned int num_params, current;
+       jit_value_t *values;
+
+       /* Ensure that we have a builder for this function */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* If we have already created the values, then exit immediately */
+       values = func->builder->param_values;
+       if(values)
+       {
+               return values[param];
+       }
+
+       /* Create the values for the first time */
+       signature = func->signature;
+       num_params = jit_type_num_params(signature);
+       values = (jit_value_t *)jit_calloc(num_params, sizeof(jit_value_t));
+       if(!values)
+       {
+               return 0;
+       }
+       func->builder->param_values = values;
+       for(current = 0; current < num_params; ++current)
+       {
+               values[current] = jit_value_create
+                       (func, jit_type_get_param(signature, current));
+               if(values[current])
+               {
+                       /* The value belongs to the entry block, no matter
+                          where it happens to be created */
+                       values[current]->block = func->builder->entry;
+               }
+       }
+
+       /* Return the value block for the desired parameter */
+       return values[param];
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+jit_value_t jit_value_get_struct_pointer(jit_function_t func)
+{
+       jit_type_t type;
+       jit_value_t value;
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       type = jit_type_normalize(jit_type_get_return(func->signature));
+       if(jit_type_is_struct(type) || jit_type_is_union(type))
+       {
+               if(jit_type_return_via_pointer(type))
+               {
+                       if(!(func->builder->struct_return))
+                       {
+                               type = jit_type_create_pointer(type, 1);
+                               if(!type)
+                               {
+                                       return 0;
+                               }
+                               value = jit_value_create(func, type);
+                               func->builder->struct_return = value;
+                               if(value)
+                               {
+                                       /* The value belongs to the entry block, no matter
+                                          where it happens to be created */
+                                       value->block = func->builder->entry;
+                               }
+                               jit_type_free(type);
+                       }
+                       return func->builder->struct_return;
+               }
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+int jit_value_is_temporary(jit_value_t value)
+{
+       return value->is_temporary;
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+int jit_value_is_local(jit_value_t value)
+{
+       return value->is_local;
+}
+
+/*@
+ * @deftypefun int jit_value_is_constant (jit_value_t value)
+ * Determine if a value is a constant.
+ * @end deftypefun
+@*/
+int jit_value_is_constant(jit_value_t value)
+{
+       return value->is_constant;
+}
+
+/*@
+ * @deftypefun void jit_value_ref (jit_function_t func, jit_value_t value)
+ * Create a reference to the specified @code{value} from the current
+ * block in @code{func}.  This will convert a temporary value into
+ * a local value if @code{value} is being referenced from a different
+ * block than its original.
+ *
+ * It is not necessary that @code{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.
+ * @end deftypefun
+@*/
+void jit_value_ref(jit_function_t func, jit_value_t value)
+{
+       if(!_jit_function_ensure_builder(func))
+       {
+               return;
+       }
+       if(value->is_temporary)
+       {
+               if(value->block->func != func)
+               {
+                       /* Reference from a different function: local and addressable */
+                       value->is_temporary = 0;
+                       value->is_local = 1;
+                       value->is_addressable = 1;
+                       value->live = 1;
+
+                       /* Mark the two functions as not leaves because we will need
+                          them to set up proper frame pointers to allow us to access
+                          the local variable across the nested function boundary */
+                       value->block->func->builder->non_leaf = 1;
+                       func->builder->non_leaf = 1;
+               }
+               else if(value->block != func->builder->current_block)
+               {
+                       /* Reference from another block in same function: local */
+                       value->is_temporary = 0;
+                       value->is_local = 1;
+                       value->live = 1;
+               }
+       }
+       else if(value->is_local && value->block->func != func)
+       {
+               /* Convert a previously local value into an addressable one */
+               value->is_addressable = 1;
+               value->block->func->builder->non_leaf = 1;
+               func->builder->non_leaf = 1;
+       }
+}
+
+/*@
+ * @deftypefun 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.
+ * @end deftypefun
+@*/
+void jit_value_set_volatile(jit_value_t value)
+{
+       value->is_volatile = 1;
+}
+
+/*@
+ * @deftypefun int jit_value_is_volatile (jit_value_t value)
+ * Determine if a value is volatile.
+ * @end deftypefun
+@*/
+int jit_value_is_volatile(jit_value_t value)
+{
+       return value->is_volatile;
+}
+
+/*@
+ * @deftypefun 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. @code{&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 (@code{jit_value_ref}),
+ * then the value will be automatically marked as addressable.
+ * @end deftypefun
+@*/
+void jit_value_set_addressable(jit_value_t value)
+{
+       value->is_addressable = 1;
+}
+
+/*@
+ * @deftypefun int jit_value_is_addressable (jit_value_t value)
+ * Determine if a value is addressable.
+ * @end deftypefun
+@*/
+int jit_value_is_addressable(jit_value_t value)
+{
+       return value->is_addressable;
+}
+
+/*@
+ * @deftypefun jit_type_t jit_value_get_type (jit_value_t value)
+ * Get the type that is associated with a value.
+ * @end deftypefun
+@*/
+jit_type_t jit_value_get_type(jit_value_t value)
+{
+       if(value)
+       {
+               return value->type;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_function_t jit_value_get_function (jit_value_t value)
+ * Get the function which owns a particular @code{value}.
+ * @end deftypefun
+@*/
+jit_function_t jit_value_get_function(jit_value_t value)
+{
+       if(value)
+       {
+               return value->block->func;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_block_t jit_value_get_block (jit_value_t value)
+ * Get the block which owns a particular @code{value}.
+ * @end deftypefun
+@*/
+jit_block_t jit_value_get_block(jit_value_t value)
+{
+       if(value)
+       {
+               return value->block;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_context_t jit_value_get_context (jit_value_t value)
+ * Get the context which owns a particular @code{value}.
+ * @end deftypefun
+@*/
+jit_context_t jit_value_get_context(jit_value_t value)
+{
+       if(value)
+       {
+               return value->block->func->context;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_constant_t jit_value_get_constant (jit_value_t value)
+ * Get the constant value within a particular @code{value}.  The returned
+ * structure's @code{type} field will be @code{jit_type_void} if
+ * @code{value} is not a constant.
+ * @end deftypefun
+@*/
+jit_constant_t jit_value_get_constant(jit_value_t value)
+{
+       jit_constant_t result;
+       if(!value || !(value->is_constant))
+       {
+               result.type = jit_type_void;
+               return result;
+       }
+       result.type = value->type;
+       switch(jit_type_normalize(value->type)->kind)
+       {
+               case JIT_TYPE_SBYTE:
+               case JIT_TYPE_UBYTE:
+               case JIT_TYPE_SHORT:
+               case JIT_TYPE_USHORT:
+               case JIT_TYPE_INT:
+               case JIT_TYPE_UINT:
+               {
+                       result.un.int_value = (jit_int)(value->address);
+               }
+               break;
+
+               case JIT_TYPE_NINT:
+               case JIT_TYPE_NUINT:
+               {
+                       result.un.nint_value = value->address;
+               }
+               break;
+
+               case JIT_TYPE_LONG:
+               case JIT_TYPE_ULONG:
+               {
+               #ifdef JIT_NATIVE_INT64
+                       result.un.long_value = (jit_long)(value->address);
+               #else
+                       result.un.long_value = *((jit_long *)(value->address));
+               #endif
+               }
+               break;
+
+               case JIT_TYPE_FLOAT32:
+               {
+                       result.un.float32_value = *((jit_float32 *)(value->address));
+               }
+               break;
+
+               case JIT_TYPE_FLOAT64:
+               {
+                       result.un.float64_value = *((jit_float64 *)(value->address));
+               }
+               break;
+
+               case JIT_TYPE_NFLOAT:
+               {
+                       result.un.nfloat_value = *((jit_nfloat *)(value->address));
+               }
+               break;
+
+               default:
+               {
+                       result.type = jit_type_void;
+               }
+               break;
+       }
+       return result;
+}
+
+/*@
+ * @deftypefun jit_nint jit_value_get_nint_constant (jit_value_t value)
+ * Get the constant value within a particular @code{value}, assuming
+ * that its type is compatible with @code{jit_type_nint}.
+ * @end deftypefun
+@*/
+jit_nint jit_value_get_nint_constant(jit_value_t value)
+{
+       if(value->is_nint_constant)
+       {
+               return (jit_nint)(value->address);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun jit_nint jit_value_get_nint_constant (jit_value_t value)
+ * Get the constant value within a particular @code{value}, assuming
+ * that its type is compatible with @code{jit_type_nint}.
+ * @end deftypefun
+@*/
+jit_long jit_value_get_long_constant(jit_value_t value)
+{
+       if(!(value->is_constant))
+       {
+               return 0;
+       }
+       switch(jit_type_normalize(value->type)->kind)
+       {
+               case JIT_TYPE_LONG:
+               case JIT_TYPE_ULONG:
+               {
+               #ifdef JIT_NATIVE_INT64
+                       return (jit_long)(value->address);
+               #else
+                       return *((jit_long *)(value->address));
+               #endif
+               }
+               /* Not reached */
+       }
+       return 0;
+}
+
+/*@
+ * @deftypefun jit_float32 jit_value_get_float32_constant (jit_value_t value)
+ * Get the constant value within a particular @code{value}, assuming
+ * that its type is compatible with @code{jit_type_float32}.
+ * @end deftypefun
+@*/
+jit_float32 jit_value_get_float32_constant(jit_value_t value)
+{
+       if(!(value->is_constant))
+       {
+               return (jit_float32)0.0;
+       }
+       if(jit_type_normalize(value->type)->kind == JIT_TYPE_FLOAT32)
+       {
+               return *((jit_float32 *)(value->address));
+       }
+       return (jit_float32)0.0;
+}
+
+/*@
+ * @deftypefun jit_float64 jit_value_get_float64_constant (jit_value_t value)
+ * Get the constant value within a particular @code{value}, assuming
+ * that its type is compatible with @code{jit_type_float64}.
+ * @end deftypefun
+@*/
+jit_float64 jit_value_get_float64_constant(jit_value_t value)
+{
+       if(!(value->is_constant))
+       {
+               return (jit_float64)0.0;
+       }
+       if(jit_type_normalize(value->type)->kind == JIT_TYPE_FLOAT64)
+       {
+               return *((jit_float64 *)(value->address));
+       }
+       return (jit_float64)0.0;
+}
+
+/*@
+ * @deftypefun jit_nfloat jit_value_get_nfloat_constant (jit_value_t value)
+ * Get the constant value within a particular @code{value}, assuming
+ * that its type is compatible with @code{jit_type_nfloat}.
+ * @end deftypefun
+@*/
+jit_nfloat jit_value_get_nfloat_constant(jit_value_t value)
+{
+       if(!(value->is_constant))
+       {
+               return (jit_nfloat)0.0;
+       }
+       if(jit_type_normalize(value->type)->kind == JIT_TYPE_FLOAT64)
+       {
+               return *((jit_nfloat *)(value->address));
+       }
+       return (jit_nfloat)0.0;
+}
+
+/*@
+ * @deftypefun int jit_constant_convert ({jit_constant_t *} result, {const jit_constant_t *} value, jit_type_t type, int overflow_check)
+ * Convert a the constant @code{value} into a new @code{type}, and
+ * return its value in @code{result}.  Returns zero if the conversion
+ * is not possible, usually due to overflow.
+ * @end deftypefun
+@*/
+int jit_constant_convert
+               (jit_constant_t *result, const jit_constant_t *value,
+                jit_type_t type, int overflow_check)
+{
+       jit_type_t srctype;
+       jit_type_t desttype;
+
+       /* Normalize the source and destination types.  The source type
+          is also promoted, to reduce the number of cases in the
+          inner switch statements below */
+       if(!result || !value)
+       {
+               return 0;
+       }
+       srctype = jit_type_promote_int(jit_type_normalize(value->type));
+       if(!srctype)
+       {
+               return 0;
+       }
+       desttype = jit_type_normalize(type);
+       if(!desttype)
+       {
+               return 0;
+       }
+
+       /* Determine what kind of conversion to perform */
+       result->type = type;
+       switch(desttype->kind)
+       {
+               case JIT_TYPE_SBYTE:
+               {
+                       /* Convert to a signed 8-bit integer */
+                       switch(srctype->kind)
+                       {
+                               case JIT_TYPE_INT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_int_to_sbyte_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_sbyte(value->un.int_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_UINT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_uint_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.uint_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_sbyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_sbyte(value->un.int_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_long_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.long_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_sbyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_sbyte
+                                                               (jit_long_to_int(value->un.long_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_ULONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_ulong_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.ulong_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_sbyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_sbyte
+                                                               (jit_ulong_to_int(value->un.ulong_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.float32_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_sbyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_sbyte
+                                                               (jit_nfloat_to_int(value->un.float32_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.float64_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_sbyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_sbyte
+                                                               (jit_nfloat_to_int(value->un.float64_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.nfloat_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_sbyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_sbyte
+                                                               (jit_nfloat_to_int(value->un.nfloat_value));
+                                       }
+                               }
+                               break;
+
+                               default: return 0;
+                       }
+               }
+               break;
+
+               case JIT_TYPE_UBYTE:
+               {
+                       /* Convert to an unsigned 8-bit integer */
+                       switch(srctype->kind)
+                       {
+                               case JIT_TYPE_INT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_int_to_ubyte_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ubyte(value->un.int_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_UINT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_uint_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.uint_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ubyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ubyte(value->un.int_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_long_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.long_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ubyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ubyte
+                                                               (jit_long_to_int(value->un.long_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_ULONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_ulong_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.ulong_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ubyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ubyte
+                                                               (jit_ulong_to_int(value->un.ulong_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.float32_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ubyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ubyte
+                                                               (jit_nfloat_to_int(value->un.float32_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.float64_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ubyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ubyte
+                                                               (jit_nfloat_to_int(value->un.float64_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.nfloat_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ubyte_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ubyte
+                                                               (jit_nfloat_to_int(value->un.nfloat_value));
+                                       }
+                               }
+                               break;
+
+                               default: return 0;
+                       }
+               }
+               break;
+
+               case JIT_TYPE_SHORT:
+               {
+                       /* Convert to a signed 16-bit integer */
+                       switch(srctype->kind)
+                       {
+                               case JIT_TYPE_INT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_int_to_short_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_short(value->un.int_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_UINT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_uint_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.uint_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_short_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_short(value->un.int_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_long_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.long_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_short_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_short
+                                                               (jit_long_to_int(value->un.long_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_ULONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_ulong_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.ulong_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_short_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_short
+                                                               (jit_ulong_to_int(value->un.ulong_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.float32_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_short_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_short
+                                                               (jit_nfloat_to_int(value->un.float32_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.float64_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_short_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_short
+                                                               (jit_nfloat_to_int(value->un.float64_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.nfloat_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_short_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_short
+                                                               (jit_nfloat_to_int(value->un.nfloat_value));
+                                       }
+                               }
+                               break;
+
+                               default: return 0;
+                       }
+               }
+               break;
+
+               case JIT_TYPE_USHORT:
+               {
+                       /* Convert to an unsigned 16-bit integer */
+                       switch(srctype->kind)
+                       {
+                               case JIT_TYPE_INT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_int_to_ushort_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ushort(value->un.int_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_UINT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_uint_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.uint_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ushort_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ushort(value->un.int_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_long_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.long_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ushort_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ushort
+                                                               (jit_long_to_int(value->un.long_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_ULONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_ulong_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.ulong_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ushort_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ushort
+                                                               (jit_ulong_to_int(value->un.ulong_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.float32_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ushort_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ushort
+                                                               (jit_nfloat_to_int(value->un.float32_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.float64_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ushort_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ushort
+                                                               (jit_nfloat_to_int(value->un.float64_value));
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.nfloat_value))
+                                               {
+                                                       return 0;
+                                               }
+                                               if(!jit_int_to_ushort_ovf
+                                                               (&(result->un.int_value),
+                                                                result->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_int_to_ushort
+                                                               (jit_nfloat_to_int(value->un.nfloat_value));
+                                       }
+                               }
+                               break;
+
+                               default: return 0;
+                       }
+               }
+               break;
+
+               case JIT_TYPE_INT:
+               {
+                       /* Convert to a signed 32-bit integer */
+                       switch(srctype->kind)
+                       {
+                               case JIT_TYPE_INT:
+                               {
+                                       result->un.int_value = value->un.int_value;
+                               }
+                               break;
+
+                               case JIT_TYPE_UINT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_uint_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.uint_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_uint_to_int(value->un.uint_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_long_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.long_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_long_to_int(value->un.long_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_ULONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_ulong_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.ulong_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_ulong_to_int(value->un.ulong_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.float32_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_nfloat_to_int(value->un.float32_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.float64_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_nfloat_to_int(value->un.float64_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_int_ovf
+                                                               (&(result->un.int_value),
+                                                                value->un.nfloat_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.int_value =
+                                                       jit_nfloat_to_int(value->un.nfloat_value);
+                                       }
+                               }
+                               break;
+
+                               default: return 0;
+                       }
+               }
+               break;
+
+               case JIT_TYPE_UINT:
+               {
+                       /* Convert to an unsigned 32-bit integer */
+                       switch(srctype->kind)
+                       {
+                               case JIT_TYPE_INT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_int_to_uint_ovf
+                                                               (&(result->un.uint_value),
+                                                                value->un.uint_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.uint_value =
+                                                       jit_int_to_uint(value->un.int_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_UINT:
+                               {
+                                       result->un.uint_value = value->un.uint_value;
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_long_to_uint_ovf
+                                                               (&(result->un.uint_value),
+                                                                value->un.long_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.uint_value =
+                                                       jit_long_to_uint(value->un.long_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_ULONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_ulong_to_uint_ovf
+                                                               (&(result->un.uint_value),
+                                                                value->un.ulong_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.uint_value =
+                                                       jit_ulong_to_uint(value->un.ulong_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_uint_ovf
+                                                               (&(result->un.uint_value),
+                                                                value->un.float32_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.uint_value =
+                                                       jit_nfloat_to_uint(value->un.float32_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_uint_ovf
+                                                               (&(result->un.uint_value),
+                                                                value->un.float64_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.uint_value =
+                                                       jit_nfloat_to_uint(value->un.float64_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_uint_ovf
+                                                               (&(result->un.uint_value),
+                                                                value->un.nfloat_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.uint_value =
+                                                       jit_nfloat_to_uint(value->un.nfloat_value);
+                                       }
+                               }
+                               break;
+
+                               default: return 0;
+                       }
+               }
+               break;
+
+               case JIT_TYPE_LONG:
+               {
+                       /* Convert to a signed 64-bit integer */
+                       switch(srctype->kind)
+                       {
+                               case JIT_TYPE_INT:
+                               {
+                                       result->un.long_value =
+                                               jit_int_to_long(value->un.int_value);
+                               }
+                               break;
+
+                               case JIT_TYPE_UINT:
+                               {
+                                       result->un.long_value =
+                                               jit_uint_to_long(value->un.int_value);
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               {
+                                       result->un.long_value = value->un.long_value;
+                               }
+                               break;
+
+                               case JIT_TYPE_ULONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_ulong_to_long_ovf
+                                                               (&(result->un.long_value),
+                                                                value->un.ulong_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.long_value =
+                                                       jit_ulong_to_long(value->un.ulong_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_long_ovf
+                                                               (&(result->un.long_value),
+                                                                value->un.float32_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.long_value =
+                                                       jit_nfloat_to_long(value->un.float32_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_long_ovf
+                                                               (&(result->un.long_value),
+                                                                value->un.float64_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.long_value =
+                                                       jit_nfloat_to_long(value->un.float64_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_long_ovf
+                                                               (&(result->un.long_value),
+                                                                value->un.nfloat_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.long_value =
+                                                       jit_nfloat_to_long(value->un.nfloat_value);
+                                       }
+                               }
+                               break;
+
+                               default: return 0;
+                       }
+               }
+               break;
+
+               case JIT_TYPE_ULONG:
+               {
+                       /* Convert to an unsigned 64-bit integer */
+                       switch(srctype->kind)
+                       {
+                               case JIT_TYPE_INT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_int_to_ulong_ovf
+                                                               (&(result->un.ulong_value),
+                                                                value->un.int_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.ulong_value =
+                                                       jit_int_to_ulong(value->un.int_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_UINT:
+                               {
+                                       result->un.ulong_value =
+                                               jit_uint_to_ulong(value->un.uint_value);
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_long_to_ulong_ovf
+                                                               (&(result->un.ulong_value),
+                                                                value->un.long_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.ulong_value =
+                                                       jit_long_to_ulong(value->un.long_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_ULONG:
+                               {
+                                       result->un.ulong_value = value->un.ulong_value;
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_ulong_ovf
+                                                               (&(result->un.ulong_value),
+                                                                value->un.float32_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.ulong_value =
+                                                       jit_nfloat_to_ulong(value->un.float32_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_ulong_ovf
+                                                               (&(result->un.ulong_value),
+                                                                value->un.float64_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.ulong_value =
+                                                       jit_nfloat_to_ulong(value->un.float64_value);
+                                       }
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       if(overflow_check)
+                                       {
+                                               if(!jit_nfloat_to_ulong_ovf
+                                                               (&(result->un.ulong_value),
+                                                                value->un.nfloat_value))
+                                               {
+                                                       return 0;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result->un.ulong_value =
+                                                       jit_nfloat_to_ulong(value->un.nfloat_value);
+                                       }
+                               }
+                               break;
+
+                               default: return 0;
+                       }
+               }
+               break;
+
+               case JIT_TYPE_FLOAT32:
+               {
+                       /* Convert to a 32-bit float */
+                       switch(srctype->kind)
+                       {
+                               case JIT_TYPE_INT:
+                               {
+                                       result->un.float32_value =
+                                               jit_nfloat_to_float32
+                                                       (jit_int_to_nfloat(value->un.int_value));
+                               }
+                               break;
+
+                               case JIT_TYPE_UINT:
+                               {
+                                       result->un.float32_value =
+                                               jit_nfloat_to_float32
+                                                       (jit_uint_to_nfloat(value->un.uint_value));
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               {
+                                       result->un.float32_value =
+                                               jit_nfloat_to_float32
+                                                       (jit_long_to_nfloat(value->un.long_value));
+                               }
+                               break;
+
+                               case JIT_TYPE_ULONG:
+                               {
+                                       result->un.float32_value =
+                                               jit_nfloat_to_float32
+                                                       (jit_ulong_to_nfloat(value->un.ulong_value));
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       result->un.float32_value = value->un.float32_value;
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       result->un.float32_value =
+                                               jit_nfloat_to_float32(value->un.float64_value);
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       result->un.float32_value =
+                                               jit_nfloat_to_float32(value->un.nfloat_value);
+                               }
+                               break;
+
+                               default: return 0;
+                       }
+               }
+               break;
+
+               case JIT_TYPE_FLOAT64:
+               {
+                       /* Convert to a 64-bit float */
+                       switch(srctype->kind)
+                       {
+                               case JIT_TYPE_INT:
+                               {
+                                       result->un.float64_value =
+                                               jit_nfloat_to_float64
+                                                       (jit_int_to_nfloat(value->un.int_value));
+                               }
+                               break;
+
+                               case JIT_TYPE_UINT:
+                               {
+                                       result->un.float64_value =
+                                               jit_nfloat_to_float64
+                                                       (jit_uint_to_nfloat(value->un.uint_value));
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               {
+                                       result->un.float64_value =
+                                               jit_nfloat_to_float64
+                                                       (jit_long_to_nfloat(value->un.long_value));
+                               }
+                               break;
+
+                               case JIT_TYPE_ULONG:
+                               {
+                                       result->un.float64_value =
+                                               jit_nfloat_to_float64
+                                                       (jit_ulong_to_nfloat(value->un.ulong_value));
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       result->un.float64_value =
+                                               jit_nfloat_to_float64(value->un.float32_value);
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       result->un.float64_value = value->un.float64_value;
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       result->un.float64_value =
+                                               jit_nfloat_to_float64(value->un.nfloat_value);
+                               }
+                               break;
+
+                               default: return 0;
+                       }
+               }
+               break;
+
+               case JIT_TYPE_NFLOAT:
+               {
+                       /* Convert to a native float */
+                       switch(srctype->kind)
+                       {
+                               case JIT_TYPE_INT:
+                               {
+                                       result->un.nfloat_value =
+                                               jit_int_to_nfloat(value->un.int_value);
+                               }
+                               break;
+
+                               case JIT_TYPE_UINT:
+                               {
+                                       result->un.nfloat_value =
+                                               jit_uint_to_nfloat(value->un.uint_value);
+                               }
+                               break;
+
+                               case JIT_TYPE_LONG:
+                               {
+                                       result->un.nfloat_value =
+                                               jit_long_to_nfloat(value->un.long_value);
+                               }
+                               break;
+
+                               case JIT_TYPE_ULONG:
+                               {
+                                       result->un.nfloat_value =
+                                               jit_ulong_to_nfloat(value->un.ulong_value);
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT32:
+                               {
+                                       result->un.nfloat_value =
+                                               jit_float32_to_nfloat(value->un.float32_value);
+                               }
+                               break;
+
+                               case JIT_TYPE_FLOAT64:
+                               {
+                                       result->un.nfloat_value =
+                                               jit_float64_to_nfloat(value->un.float64_value);
+                               }
+                               break;
+
+                               case JIT_TYPE_NFLOAT:
+                               {
+                                       result->un.nfloat_value = value->un.nfloat_value;
+                               }
+                               break;
+
+                               default: return 0;
+                       }
+               }
+               break;
+
+               default:        return 0;
+       }
+       return 1;
+}
+
+void _jit_value_free(void *_value)
+{
+       jit_value_t value = (jit_value_t)_value;
+       jit_type_free(value->type);
+       if(value->free_address && value->address)
+       {
+               /* We need to free the memory for a large constant */
+               jit_free((void *)(value->address));
+       }
+}
diff --git a/jit/jit-walk.c b/jit/jit-walk.c
new file mode 100644 (file)
index 0000000..a55aacb
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * jit-walk.c - Routines for performing native stack walking.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include "jit-apply-rules.h"
+
+/*
+ * The routines here are system specific to a large extent,
+ * but we can avoid a lot of the nastiness using gcc builtins.
+ * It is highly recommended that you use gcc to build libjit.
+ *
+ * The following macros may need to be tweaked on some platforms.
+ */
+
+/*
+ * Some platforms store the return address in an altered form
+ * (e.g. an offset rather than a pointer).  We use this macro to
+ * fix such address values.
+ */
+#if defined(__GNUC__)
+#define        jit_fix_return_address(x)       (__builtin_extract_return_addr((x)))
+#else
+#define        jit_fix_return_address(x)       (x)
+#endif
+
+#if JIT_APPLY_BROKEN_FRAME_BUILTINS == 0
+
+/*
+ * Extract the next frame pointer in the chain.
+ */
+#define        jit_next_frame_pointer(x)       \
+       (*((void **)(((unsigned char *)(x)) + JIT_APPLY_PARENT_FRAME_OFFSET)))
+
+/*
+ * Extract the return address from a particular frame.
+ */
+#define        jit_extract_return_address(x)   \
+       (*((void **)(((unsigned char *)(x)) + JIT_APPLY_RETURN_ADDRESS_OFFSET)))
+
+#else  /* JIT_APPLY_BROKEN_FRAME_BUILTINS */
+
+/*
+ * Extract the next frame pointer in the chain.
+ */
+#define        jit_next_frame_pointer(x)               0
+
+/*
+ * Extract the return address from a particular frame.
+ */
+#define        jit_extract_return_address(x)   0
+
+#endif /* JIT_APPLY_BROKEN_FRAME_BUILTINS */
+
+/*
+ * Fetch the starting frame address if the caller did not supply it
+ * (probably because the caller wasn't compiled with gcc).  The address
+ * that we want is actually one frame out from where we are at the moment.
+ */
+#if defined(__GNUC__)
+#define        jit_get_starting_frame()        \
+       do { \
+               start = __builtin_frame_address(0); \
+               if(start) \
+               { \
+                       start = jit_next_frame_pointer(start); \
+               } \
+       } while (0)
+#elif defined(_MSC_VER) && defined(_M_IX86)
+#define        jit_get_starting_frame()        \
+       __asm \
+       { \
+               __asm mov eax, [ebp] \
+               __asm mov dword ptr start, eax \
+       }
+#else
+#define        jit_get_starting_frame()        do { ; } while (0)
+#endif
+
+/*@
+
+@section Stack walking
+@cindex Stack walking
+@cindex jit-walk.h
+
+The functions in @code{<jit/jit-walk.h>} allow the caller to walk
+up the native execution stack, inspecting frames and return addresses.
+
+@*/
+
+/*@
+ * @deftypefun {void *} jit_get_frame_address (unsigned int n)
+ * Get the frame address for the call frame @code{n} levels up
+ * the stack.  Setting @code{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.
+ * @end deftypefun
+ *
+ * @deftypefun {void *} jit_get_current_frame (void)
+ * Get the frame address for the current function.  This may be more
+ * efficient on some platforms than using @code{jit_get_frame_address(0)}.
+ * Returns NULL if it isn't possible to retrieve the address of
+ * the current frame.
+ * @end deftypefun
+@*/
+void *_jit_get_frame_address(void *start, unsigned int n)
+{
+       /* Fetch the starting frame address if the caller did not supply it */
+       if(!start)
+       {
+               jit_get_starting_frame();
+       }
+
+       /* Scan up the stack until we find the frame we want */
+       while(start != 0 && n > 0)
+       {
+               start = jit_next_frame_pointer(start);
+               --n;
+       }
+       return start;
+}
+
+/*@
+ * @deftypefun {void *} jit_get_next_frame_address ({void *} frame)
+ * Get the address of the next frame up the stack from @code{frame}.
+ * Returns NULL if it isn't possible to retrieve the address of
+ * the next frame up the stack.
+ * @end deftypefun
+@*/
+void *jit_get_next_frame_address(void *frame)
+{
+       if(frame)
+       {
+               return jit_next_frame_pointer(frame);
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun {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.
+ * @end deftypefun
+ *
+ * @deftypefun {void *} jit_get_current_return (void)
+ * Get the return address for the current function.  This may be more
+ * efficient on some platforms than using @code{jit_get_return_address(0)}.
+ * Returns NULL if it isn't possible to retrieve the return address of
+ * the current frame.
+ * @end deftypefun
+@*/
+void *_jit_get_return_address(void *frame, void *frame0, void *return0)
+{
+       /* If the caller was compiled with gcc, it may have already figured
+          out the return address for us using builtin gcc facilities */
+       if(frame && frame == frame0)
+       {
+               return jit_fix_return_address(return0);
+       }
+       else if(frame)
+       {
+               return jit_fix_return_address(jit_extract_return_address(frame));
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/*@
+ * @deftypefun int jit_frame_contains_crawl_mark ({void *}frame, {jit_crawl_mark_t *} mark)
+ * Determine if the stack frame that resides just above @code{frame}
+ * contains a local variable whose address is @code{mark}.  The @code{mark}
+ * parameter should be the address of a local variable that is declared with
+ * @code{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.
+ * @end deftypefun
+@*/
+int jit_frame_contains_crawl_mark(void *frame, jit_crawl_mark_t *mark)
+{
+       void *markptr = (void *)mark;
+       void *next;
+       if(!frame)
+       {
+               /* We don't have a frame to check against */
+               return 0;
+       }
+       next = jit_next_frame_pointer(frame);
+       if(!next)
+       {
+               /* We are at the top of the stack crawl */
+               return 0;
+       }
+       if(frame <= next)
+       {
+               /* The stack grows downwards in memory */
+               return (markptr >= frame && markptr < next);
+       }
+       else
+       {
+               /* The stack grows upwards in memory */
+               return (markptr >= next && markptr < frame);
+       }
+}
diff --git a/jitplus/.cvsignore b/jitplus/.cvsignore
new file mode 100644 (file)
index 0000000..051d1bd
--- /dev/null
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+.deps
diff --git a/jitplus/Makefile.am b/jitplus/Makefile.am
new file mode 100644 (file)
index 0000000..6df7893
--- /dev/null
@@ -0,0 +1,9 @@
+
+lib_LIBRARIES = libjitplus.a
+
+libjitplus_a_SOURCES = \
+               jit-plus-context.cpp \
+               jit-plus-function.cpp \
+               jit-plus-value.cpp
+
+AM_CXXFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I. -I$(srcdir)
diff --git a/jitplus/jit-plus-context.cpp b/jitplus/jit-plus-context.cpp
new file mode 100644 (file)
index 0000000..a7a6ca0
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * jit-plus-context.cpp - C++ wrapper for JIT contexts.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <jit/jit-plus.h>
+
+/*@
+
+The @code{jit_context} class provides a C++ counterpart to the
+C @code{jit_context_t} type.  @xref{Initialization}, for more
+information on creating and managing contexts.
+
+@*/
+
+/*@
+ * @defop Constructor jit_context jit_context ()
+ * Construct a new JIT context.  This is equivalent to calling
+ * @code{jit_context_create} in the C API.  The raw C context is
+ * destroyed when the @code{jit_context} object is destructed.
+ * @end defop
+@*/
+jit_context::jit_context()
+{
+       jit_init();
+       context = jit_context_create();
+       copied = 0;
+}
+
+/*@
+ * @defop Constructor 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 this form of construction, @code{jit_context_destroy}
+ * will not be called on the context when the @code{jit_context}
+ * object is destructed.  You will need to arrange for that manually.
+ * @end defop
+@*/
+jit_context::jit_context(jit_context_t context)
+{
+       this->context = context;
+       this->copied = 1;
+}
+
+/*@
+ * @defop Destructor jit_context ~jit_context ()
+ * Destruct a JIT context.
+ * @end defop
+@*/
+jit_context::~jit_context()
+{
+       if(!copied)
+       {
+               jit_context_destroy(context);
+       }
+}
+
+/*@
+ * @deftypemethod jit_context jit_context_t raw () const
+ * Get the raw C context pointer that underlies this object.
+ * @end deftypemethod
+@*/
diff --git a/jitplus/jit-plus-function.cpp b/jitplus/jit-plus-function.cpp
new file mode 100644 (file)
index 0000000..cf858d4
--- /dev/null
@@ -0,0 +1,1159 @@
+/*
+ * jit-plus-function.cpp - C++ wrapper for JIT functions.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <jit/jit-plus.h>
+#include <config.h>
+#ifdef HAVE_STDARG_H
+       #include <stdarg.h>
+#elif HAVE_VARARGS_H
+       #include <varargs.h>
+#endif
+
+/*@
+
+The @code{jit_function} class provides a C++ counterpart to the
+C @code{jit_function_t} type.  @xref{Functions}, for more information
+on creating and managing functions.
+
+The @code{jit_function} class also provides a large number of methods
+for creating the instructions within a function body.  @xref{Instructions},
+for more information on creating and managing instructions.
+
+@*/
+
+#define        JITPP_MAPPING           20000
+
+class jit_build_exception
+{
+public:
+       jit_build_exception(int result) { this->result = result; }
+       ~jit_build_exception() {}
+
+       int result;
+};
+
+jit_type_t const jit_function::end_params = (jit_type_t)0;
+
+/*@
+ * @defop Constructor jit_function jit_function ({jit_context&} context, jit_type_t signature)
+ * Constructs a new function handler with the specified @code{signature} in
+ * the given @code{context}.  It then calls @code{create(signature)} to
+ * create the actual function.
+ * @end defop
+@*/
+jit_function::jit_function(jit_context& context, jit_type_t signature)
+{
+       // Save the context for the "create" method.
+       this->context = context.raw();
+       this->func = 0;
+
+       // Create the function.
+       create(signature);
+}
+
+/*@
+ * @defop Constructor jit_function jit_function ({jit_context&} context)
+ * Constructs a new function handler in the specified @code{context}.
+ * The actual function is not created until you call @code{create()}.
+ * @end defop
+@*/
+jit_function::jit_function(jit_context& context)
+{
+       // Save the context, but don't create the function yet.
+       this->context = context.raw();
+       this->func = 0;
+}
+
+/*@
+ * @defop Constructor jit_function jit_function (jit_function_t func)
+ * Constructs a new function handler and wraps it around the specified
+ * raw C @code{jit_function_t} object.  This can be useful for layering
+ * the C++ on-demand building facility on top of an existing C function.
+ * @end defop
+@*/
+jit_function::jit_function(jit_function_t func)
+{
+       this->context = jit_function_get_context(func);
+       this->func = func;
+       if(func)
+       {
+               jit_context_build_start(context);
+               jit_function_set_meta(func, JITPP_MAPPING, (void *)this, 0, 0);
+               register_on_demand();
+               jit_context_build_end(context);
+       }
+}
+
+/*@
+ * @defop Destructor jit_function ~jit_function ()
+ * Destroy this function handler.  The raw function will persist
+ * until the context is destroyed.
+ * @end defop
+@*/
+jit_function::~jit_function()
+{
+       if(func)
+       {
+               jit_context_build_start(context);
+               jit_function_free_meta(func, JITPP_MAPPING);
+               jit_context_build_end(context);
+       }
+}
+
+/*@
+ * @deftypemethod jit_function jit_function_t raw () const
+ * Get the raw C @code{jit_function_t} value that underlies this object.
+ * @end deftypemethod
+ *
+ * @deftypemethod jit_function int is_valid () const
+ * Determine if the raw C @code{jit_function_t} value that
+ * underlies this object is valid.
+ * @end deftypemethod
+@*/
+
+/*@
+ * @deftypemethod jit_function {static jit_function *} from_raw (jit_function_t func)
+ * Find the C++ @code{jit_function} object that is associated with a
+ * raw C @code{jit_function_t} pointer.  Returns NULL if there is
+ * no such object.
+ * @end deftypemethod
+@*/
+jit_function *jit_function::from_raw(jit_function_t func)
+{
+       return (jit_function *)jit_function_get_meta(func, JITPP_MAPPING);
+}
+
+/*@
+ * @deftypemethod jit_function jit_type_t signature () const
+ * Get the signature type for this function.
+ * @end deftypemethod
+@*/
+
+/*@
+ * @deftypemethod jit_function void create (jit_type_t signature)
+ * Create this function if it doesn't already exist.
+ * @end deftypemethod
+@*/
+void jit_function::create(jit_type_t signature)
+{
+       // Bail out if the function is already created.
+       if(func)
+       {
+               return;
+       }
+
+       // Lock down the context.
+       jit_context_build_start(context);
+
+       // Create the new function.
+       func = jit_function_create(context, signature);
+       if(!func)
+       {
+               jit_context_build_end(context);
+               return;
+       }
+
+       // Store this object's pointer on the raw function so that we can
+       // map the raw function back to this object later.
+       jit_function_set_meta(func, JITPP_MAPPING, (void *)this, 0, 0);
+
+       // Register us as the on-demand compiler.
+       register_on_demand();
+
+       // Unlock the context.
+       jit_context_build_end(context);
+}
+
+/*@
+ * @deftypemethod jit_function void create ()
+ * Create this function if it doesn't already exist.  This version will
+ * call the virtual @code{create_signature()} method to obtain the
+ * signature from the subclass.
+ * @end deftypemethod
+@*/
+void jit_function::create()
+{
+       if(!func)
+       {
+               jit_type_t signature = create_signature();
+               create(signature);
+               if(!func)
+               {
+                       jit_type_free(signature);
+               }
+       }
+}
+
+/*@
+ * @deftypemethod 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:
+ *
+ * @enumerate
+ * @item
+ * Invoke the @code{build_start} method to lock down the function builder.
+ *
+ * @item
+ * Build the function by calling the value-related and instruction-related
+ * methods within @code{jit_function}.
+ *
+ * @item
+ * Compile the function with the @code{compile} method.
+ *
+ * @item
+ * Unlock the function builder by invoking @code{build_end}.
+ * @end enumerate
+ * @end deftypemethod
+ *
+ * @deftypemethod jit_function int is_compiled () const
+ * Determine if this function has already been compiled.
+ * @end deftypemethod
+@*/
+int jit_function::compile()
+{
+       if(!func)
+       {
+               return 0;
+       }
+       else
+       {
+               return jit_function_compile(func);
+       }
+}
+
+/*@
+ * @deftypemethod jit_function int recompile ()
+ * Force a function to be recompiled.
+ * @end deftypemethod
+ *
+ * @deftypemethod jit_function int is_recompilable () const
+ * Determine if this function is recompilable.
+ * @end deftypemethod
+ *
+ * @deftypemethod jit_function void set_recompilable ()
+ * @deftypemethodx jit_function void clear_recompilable ()
+ * @deftypemethodx jit_function void set_recompilable (int flag)
+ * Modify the "recompilable" flag on this function.
+ * @end deftypemethod
+@*/
+int jit_function::recompile()
+{
+       if(!func)
+       {
+               return JIT_RESULT_COMPILE_ERROR;
+       }
+       else
+       {
+               return jit_function_recompile(func);
+       }
+}
+
+/*@
+ * @deftypemethod jit_function void set_optimization_level ({unsigned int} level)
+ * @deftypemethodx jit_function {unsigned int} optimization_level () const
+ * Set or get the optimization level for this function.
+ * @end deftypemethod
+ *
+ * @deftypemethod jit_function {static unsigned int} max_optimization_level ()
+ * Get the maximum optimization level for @code{libjit}.
+ * @end deftypemethod
+ *
+ * @deftypemethod jit_function {void *} closure () const
+ * @deftypemethodx jit_function {void *} vtable_pointer () const
+ * Get the closure or vtable pointer form of this function.
+ * @end deftypemethod
+ *
+ * @deftypemethod jit_function int apply ({void **} args, {void *} result)
+ * @deftypemethodx jit_function int apply (jit_type_t signature, {void **} args, {void *} return_area)
+ * Call this function, applying the specified arguments.
+ * @end deftypemethod
+@*/
+
+/*@
+ * @deftypemethod jit_function {static jit_type_t} signature_helper (jit_type_t return_type, ...)
+ * You can call this method from @code{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 @code{jit_function::end_params}.
+ *
+ * A maximum of 32 parameter types can be supplied, and the signature
+ * ABI is always set to @code{jit_abi_cdecl}.
+ * @end deftypemethod
+@*/
+jit_type_t jit_function::signature_helper(jit_type_t return_type, ...)
+{
+       va_list va;
+       jit_type_t params[32];
+       unsigned int num_params = 0;
+       jit_type_t type;
+#ifdef HAVE_STDARG_H
+       va_start(va, return_type);
+#else
+       va_start(va);
+#endif
+       while(num_params < 32 && (type = va_arg(va, jit_type_t)) != 0)
+       {
+               params[num_params++] = type;
+       }
+       va_end(va);
+       return jit_type_create_signature
+               (jit_abi_cdecl, return_type, params, num_params, 1);
+}
+
+/*@
+ * @deftypemethod jit_function void build ()
+ * This method is called when the function has to be build on-demand,
+ * or in response to an explicit @code{recompile} request.  You build the
+ * function by calling the value-related and instruction-related
+ * methods within @code{jit_function} that are described below.
+ *
+ * The default implementation of @code{build} will fail, so you must
+ * override it if you didn't build the function manually and call
+ * @code{compile}.
+ * @end deftypemethod
+@*/
+void jit_function::build()
+{
+       // Normally overridden by subclasses.
+       fail();
+}
+
+/*@
+ * @deftypemethod jit_function jit_type_t create_signature ()
+ * This method is called by @code{create()} to create the function's
+ * signature.  The default implementation creates a signature that
+ * returns @code{void} and has no parameters.
+ * @end deftypemethod
+@*/
+jit_type_t jit_function::create_signature()
+{
+       // Normally overridden by subclasses.
+       return signature_helper(jit_type_void, end_params);
+}
+
+/*@
+ * @deftypemethod jit_function void fail ()
+ * This method can be called by @code{build} to fail the on-demand
+ * compilation process.  It throws an exception to unwind the build.
+ * @end deftypemethod
+@*/
+void jit_function::fail()
+{
+       throw jit_build_exception(JIT_RESULT_COMPILE_ERROR);
+}
+
+/*@
+ * @deftypemethod jit_function void out_of_memory ()
+ * This method can be called by @code{build} to indicate that the on-demand
+ * compilation process ran out of memory.  It throws an exception to
+ * unwind the build.
+ * @end deftypemethod
+@*/
+void jit_function::out_of_memory()
+{
+       throw jit_build_exception(JIT_RESULT_OUT_OF_MEMORY);
+}
+
+/*@
+ * @deftypemethod jit_function void build_start ()
+ * Start an explicit build process.  Not needed if you will be using
+ * on-demand compilation.
+ * @end deftypemethod
+ *
+ * @deftypemethod jit_function void build_end ()
+ * End an explicit build process.
+ * @end deftypemethod
+@*/
+
+#define        value_wrap(x)   \
+                       jit_value val((x)); \
+                       if(!(val.raw())) \
+                               out_of_memory(); \
+                       return val
+
+/*@
+ * @deftypemethod jit_function jit_value new_value (jit_type_t type)
+ * Create a new temporary value.  This is the C++ counterpart to
+ * @code{jit_value_create}.
+ * @end deftypemethod
+@*/
+jit_value jit_function::new_value(jit_type_t type)
+{
+       value_wrap(jit_value_create(func, type));
+}
+
+/*@
+ * @deftypemethod jit_function jit_value new_constant (jit_sbyte value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant (jit_ubyte value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant (jit_short value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant (jit_ushort value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant (jit_int value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant (jit_uint value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant (jit_long value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant (jit_ulong value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant (jit_float32 value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant (jit_float64 value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant (jit_nfloat value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant ({void *} value, jit_type_t type)
+ * @deftypemethodx jit_function jit_value new_constant ({const jit_constant_t&} value)
+ * Create constant values of various kinds.  @xref{Values}, for more
+ * information on creating and managing constants.
+ * @end deftypemethod
+@*/
+jit_value jit_function::new_constant(jit_sbyte value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_sbyte;
+       }
+       value_wrap(jit_value_create_nint_constant(func, type, (jit_nint)value));
+}
+
+jit_value jit_function::new_constant(jit_ubyte value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_ubyte;
+       }
+       value_wrap(jit_value_create_nint_constant(func, type, (jit_nint)value));
+}
+
+jit_value jit_function::new_constant(jit_short value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_short;
+       }
+       value_wrap(jit_value_create_nint_constant(func, type, (jit_nint)value));
+}
+
+jit_value jit_function::new_constant(jit_ushort value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_ushort;
+       }
+       value_wrap(jit_value_create_nint_constant(func, type, (jit_nint)value));
+}
+
+jit_value jit_function::new_constant(jit_int value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_int;
+       }
+       value_wrap(jit_value_create_nint_constant(func, type, (jit_nint)value));
+}
+
+jit_value jit_function::new_constant(jit_uint value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_uint;
+       }
+       value_wrap(jit_value_create_nint_constant(func, type, (jit_nint)value));
+}
+
+jit_value jit_function::new_constant(jit_long value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_long;
+       }
+       value_wrap(jit_value_create_long_constant(func, type, value));
+}
+
+jit_value jit_function::new_constant(jit_ulong value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_ulong;
+       }
+       value_wrap(jit_value_create_long_constant(func, type, (jit_long)value));
+}
+
+jit_value jit_function::new_constant(jit_float32 value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_float32;
+       }
+       value_wrap(jit_value_create_float32_constant(func, type, value));
+}
+
+jit_value jit_function::new_constant(jit_float64 value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_float64;
+       }
+       value_wrap(jit_value_create_float64_constant(func, type, value));
+}
+
+#ifndef JIT_NFLOAT_IS_DOUBLE
+
+jit_value jit_function::new_constant(jit_nfloat value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_nfloat;
+       }
+       value_wrap(jit_value_create_nfloat_constant(func, type, value));
+}
+
+#endif
+
+jit_value jit_function::new_constant(void *value, jit_type_t type)
+{
+       if(!type)
+       {
+               type = jit_type_void_ptr;
+       }
+       value_wrap(jit_value_create_nint_constant(func, type, (jit_nint)value));
+}
+
+jit_value jit_function::new_constant(const jit_constant_t& value)
+{
+       value_wrap(jit_value_create_constant(func, &value));
+}
+
+/*@
+ * @deftypemethod jit_function jit_value get_param ({unsigned int} param)
+ * Get the value that corresponds to parameter @code{param}.
+ * @end deftypemethod
+@*/
+jit_value jit_function::get_param(unsigned int param)
+{
+       value_wrap(jit_value_get_param(func, param));
+}
+
+/*@
+ * @deftypemethod 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.
+ * @end deftypemethod
+@*/
+jit_value jit_function::get_struct_pointer()
+{
+       value_wrap(jit_value_get_struct_pointer(func));
+}
+
+/*@
+ * @deftypemethod jit_function void insn_label ({jit_label&} label)
+ * @deftypemethodx jit_function jit_value insn_load ({const jit_value&} value)
+ * @deftypemethodx jit_function jit_value insn_dup ({const jit_value&} value)
+ * @deftypemethodx jit_function jit_value insn_load_small ({const jit_value&} value)
+ * @deftypemethodx jit_function void store ({const jit_value&} dest, {const jit_value&} value)
+ * @deftypemethodx jit_function jit_value insn_load_relative ({const jit_value&} value, jit_nint offset, jit_type_t type)
+ * @deftypemethodx jit_function void insn_store_relative ({const jit_value&} dest, jit_nint offset, {const jit_value&} value)
+ * @deftypemethodx jit_function jit_value insn_add_relative ({const jit_value&} value, jit_nint offset)
+ * @deftypemethodx jit_function void insn_check_null ({const jit_value&} value)
+ * @deftypemethodx jit_function jit_value insn_add ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_add_ovf ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_sub ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_sub_ovf ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_mul ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_mul_ovf ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_div ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_rem ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_rem_ieee ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_neg ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_and ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_or ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_xor ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_not ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_shl ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_shr ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_ushr ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_sshr ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_eq ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_ne ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_lt ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_le ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_gt ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_ge ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_cmpl ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_cmpg ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_to_bool ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_to_not_bool ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_acos ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_asin ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_atan ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_atan2 ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_ceil ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_cos ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_cosh ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_exp ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_floor ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_log ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_log10 ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_pow ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_rint ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_round ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_sin ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_sinh ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_sqrt ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_tan ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_tanh ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_is_nan ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_is_finite ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_is_inf ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_abs ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_min ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_max ({const jit_value&} value1, {const jit_value&} value2)
+ * @deftypemethodx jit_function jit_value insn_sign ({const jit_value&} value1)
+ * @deftypemethodx jit_function void insn_branch ({jit_label&} label)
+ * @deftypemethodx jit_function void insn_branch_if ({const jit_value&} value, {jit_label&} label)
+ * @deftypemethodx jit_function void insn_branch_if_not ({const jit_value&} value, {jit_label&} label)
+ * @deftypemethodx jit_function jit_value insn_address_of ({const jit_value&} value1)
+ * @deftypemethodx jit_function jit_value insn_convert ({const jit_value&} value, jit_type_t type, int overflow_check)
+ * @deftypemethodx 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)
+ * @deftypemethodx 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)
+ * @deftypemethodx 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)
+ * @deftypemethodx 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)
+ * @deftypemethodx 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)
+ * @deftypemethodx jit_function jit_value insn_import (jit_value value)
+ * @deftypemethodx jit_function void insn_return ({const jit_value&} value)
+ * @deftypemethodx jit_function void insn_return ()
+ * @deftypemethodx jit_function void insn_default_return ()
+ * @deftypemethodx jit_function void insn_throw ({const jit_value&} value)
+ * @deftypemethodx jit_function jit_value insn_get_call_stack ()
+ * Create instructions of various kinds.  @xref{Instructions}, for more
+ * information on the individual instructions and their arguments.
+ * @end deftypemethod
+@*/
+
+void jit_function::insn_label(jit_label& label)
+{
+       if(!jit_insn_label(func, label.rawp()))
+       {
+               out_of_memory();
+       }
+}
+
+jit_value jit_function::insn_load(const jit_value& value)
+{
+       value_wrap(jit_insn_load(func, value.raw()));
+}
+
+jit_value jit_function::insn_dup(const jit_value& value)
+{
+       value_wrap(jit_insn_dup(func, value.raw()));
+}
+
+jit_value jit_function::insn_load_small(const jit_value& value)
+{
+       value_wrap(jit_insn_load_small(func, value.raw()));
+}
+
+void jit_function::store(const jit_value& dest, const jit_value& value)
+{
+       if(!jit_insn_store(func, dest.raw(), value.raw()))
+       {
+               out_of_memory();
+       }
+}
+
+jit_value jit_function::insn_load_relative
+       (const jit_value& value, jit_nint offset, jit_type_t type)
+{
+       value_wrap(jit_insn_load_relative(func, value.raw(), offset, type));
+}
+
+void jit_function::insn_store_relative
+       (const jit_value& dest, jit_nint offset, const jit_value& value)
+{
+       if(!jit_insn_store_relative(func, dest.raw(), offset, value.raw()))
+       {
+               out_of_memory();
+       }
+}
+
+jit_value jit_function::insn_add_relative
+       (const jit_value& value, jit_nint offset)
+{
+       value_wrap(jit_insn_add_relative(func, value.raw(), offset));
+}
+
+void jit_function::insn_check_null(const jit_value& value)
+{
+       if(!jit_insn_check_null(func, value.raw()))
+       {
+               out_of_memory();
+       }
+}
+
+jit_value jit_function::insn_add
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_add(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_add_ovf
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_add_ovf(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_sub
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_sub(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_sub_ovf
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_sub_ovf(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_mul
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_mul(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_mul_ovf
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_mul_ovf(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_div
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_div(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_rem
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_rem(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_rem_ieee
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_rem_ieee(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_neg(const jit_value& value1)
+{
+       value_wrap(jit_insn_neg(func, value1.raw()));
+}
+
+jit_value jit_function::insn_and
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_and(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_or
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_or(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_xor
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_xor(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_not(const jit_value& value1)
+{
+       value_wrap(jit_insn_not(func, value1.raw()));
+}
+
+jit_value jit_function::insn_shl
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_shl(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_shr
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_shr(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_ushr
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_ushr(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_sshr
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_sshr(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_eq
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_eq(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_ne
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_ne(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_lt
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_lt(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_le
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_le(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_gt
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_gt(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_ge
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_ge(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_cmpl
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_cmpl(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_cmpg
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_cmpg(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_to_bool(const jit_value& value1)
+{
+       value_wrap(jit_insn_to_bool(func, value1.raw()));
+}
+
+jit_value jit_function::insn_to_not_bool(const jit_value& value1)
+{
+       value_wrap(jit_insn_to_not_bool(func, value1.raw()));
+}
+
+jit_value jit_function::insn_acos(const jit_value& value1)
+{
+       value_wrap(jit_insn_acos(func, value1.raw()));
+}
+
+jit_value jit_function::insn_asin(const jit_value& value1)
+{
+       value_wrap(jit_insn_asin(func, value1.raw()));
+}
+
+jit_value jit_function::insn_atan(const jit_value& value1)
+{
+       value_wrap(jit_insn_atan(func, value1.raw()));
+}
+
+jit_value jit_function::insn_atan2
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_atan2(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_ceil(const jit_value& value1)
+{
+       value_wrap(jit_insn_ceil(func, value1.raw()));
+}
+
+jit_value jit_function::insn_cos(const jit_value& value1)
+{
+       value_wrap(jit_insn_cos(func, value1.raw()));
+}
+
+jit_value jit_function::insn_cosh(const jit_value& value1)
+{
+       value_wrap(jit_insn_cosh(func, value1.raw()));
+}
+
+jit_value jit_function::insn_exp(const jit_value& value1)
+{
+       value_wrap(jit_insn_exp(func, value1.raw()));
+}
+
+jit_value jit_function::insn_floor(const jit_value& value1)
+{
+       value_wrap(jit_insn_floor(func, value1.raw()));
+}
+
+jit_value jit_function::insn_log(const jit_value& value1)
+{
+       value_wrap(jit_insn_log(func, value1.raw()));
+}
+
+jit_value jit_function::insn_log10(const jit_value& value1)
+{
+       value_wrap(jit_insn_log10(func, value1.raw()));
+}
+
+jit_value jit_function::insn_pow
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_pow(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_rint(const jit_value& value1)
+{
+       value_wrap(jit_insn_rint(func, value1.raw()));
+}
+
+jit_value jit_function::insn_round(const jit_value& value1)
+{
+       value_wrap(jit_insn_round(func, value1.raw()));
+}
+
+jit_value jit_function::insn_sin(const jit_value& value1)
+{
+       value_wrap(jit_insn_sin(func, value1.raw()));
+}
+
+jit_value jit_function::insn_sinh(const jit_value& value1)
+{
+       value_wrap(jit_insn_sinh(func, value1.raw()));
+}
+
+jit_value jit_function::insn_sqrt(const jit_value& value1)
+{
+       value_wrap(jit_insn_sqrt(func, value1.raw()));
+}
+
+jit_value jit_function::insn_tan(const jit_value& value1)
+{
+       value_wrap(jit_insn_tan(func, value1.raw()));
+}
+
+jit_value jit_function::insn_tanh(const jit_value& value1)
+{
+       value_wrap(jit_insn_tanh(func, value1.raw()));
+}
+
+jit_value jit_function::insn_is_nan(const jit_value& value1)
+{
+       value_wrap(jit_insn_is_nan(func, value1.raw()));
+}
+
+jit_value jit_function::insn_is_finite(const jit_value& value1)
+{
+       value_wrap(jit_insn_is_finite(func, value1.raw()));
+}
+
+jit_value jit_function::insn_is_inf(const jit_value& value1)
+{
+       value_wrap(jit_insn_is_inf(func, value1.raw()));
+}
+
+jit_value jit_function::insn_abs(const jit_value& value1)
+{
+       value_wrap(jit_insn_abs(func, value1.raw()));
+}
+
+jit_value jit_function::insn_min
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_min(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_max
+       (const jit_value& value1, const jit_value& value2)
+{
+       value_wrap(jit_insn_max(func, value1.raw(), value2.raw()));
+}
+
+jit_value jit_function::insn_sign(const jit_value& value1)
+{
+       value_wrap(jit_insn_sign(func, value1.raw()));
+}
+
+void jit_function::insn_branch(jit_label& label)
+{
+       if(!jit_insn_branch(func, label.rawp()))
+       {
+               out_of_memory();
+       }
+}
+
+void jit_function::insn_branch_if(const jit_value& value, jit_label& label)
+{
+       if(!jit_insn_branch_if(func, value.raw(), label.rawp()))
+       {
+               out_of_memory();
+       }
+}
+
+void jit_function::insn_branch_if_not(const jit_value& value, jit_label& label)
+{
+       if(!jit_insn_branch_if_not(func, value.raw(), label.rawp()))
+       {
+               out_of_memory();
+       }
+}
+
+jit_value jit_function::insn_address_of(const jit_value& value1)
+{
+       value_wrap(jit_insn_address_of(func, value1.raw()));
+}
+
+jit_value jit_function::insn_convert
+       (const jit_value& value, jit_type_t type, int overflow_check)
+{
+       value_wrap(jit_insn_convert(func, value.raw(), type, overflow_check));
+}
+
+jit_value jit_function::insn_call
+       (const char *name, jit_function_t jit_func,
+        jit_type_t signature, jit_value_t *args, unsigned int num_args,
+        int flags)
+{
+       value_wrap(jit_insn_call
+               (func, name, jit_func, signature, args, num_args, flags));
+}
+
+jit_value jit_function::insn_call_indirect
+       (const jit_value& value, jit_type_t signature,
+        jit_value_t *args, unsigned int num_args, int flags)
+{
+       value_wrap(jit_insn_call_indirect
+               (func, value.raw(), signature, args, num_args, flags));
+}
+
+jit_value jit_function::insn_call_indirect_vtable
+       (const jit_value& value, jit_type_t signature,
+        jit_value_t *args, unsigned int num_args, int flags)
+{
+       value_wrap(jit_insn_call_indirect_vtable
+               (func, value.raw(), signature, args, num_args, flags));
+}
+
+jit_value jit_function::insn_call_native
+       (const char *name, void *native_func, jit_type_t signature,
+     jit_value_t *args, unsigned int num_args, int flags)
+{
+       value_wrap(jit_insn_call_native
+               (func, name, native_func, signature, args, num_args, flags));
+}
+
+jit_value jit_function::insn_call_intrinsic
+       (const char *name, void *intrinsic_func,
+        const jit_intrinsic_descr_t& descriptor,
+        const jit_value& arg1, const jit_value& arg2)
+{
+       value_wrap(jit_insn_call_intrinsic
+               (func, name, intrinsic_func, &descriptor, arg1.raw(), arg2.raw()));
+}
+
+jit_value jit_function::insn_import(jit_value value)
+{
+       value_wrap(jit_insn_import(func, value.raw()));
+}
+
+void jit_function::insn_return(const jit_value& value)
+{
+       if(!jit_insn_return(func, value.raw()))
+       {
+               out_of_memory();
+       }
+}
+
+void jit_function::insn_return()
+{
+       if(!jit_insn_return(func, 0))
+       {
+               out_of_memory();
+       }
+}
+
+void jit_function::insn_default_return()
+{
+       if(!jit_insn_default_return(func))
+       {
+               out_of_memory();
+       }
+}
+
+void jit_function::insn_throw(const jit_value& value)
+{
+       if(!jit_insn_throw(func, value.raw()))
+       {
+               out_of_memory();
+       }
+}
+
+jit_value jit_function::insn_get_call_stack()
+{
+       value_wrap(jit_insn_get_call_stack(func));
+}
+
+void jit_function::register_on_demand()
+{
+       jit_function_set_on_demand_compiler(func, on_demand_compiler);
+}
+
+int jit_function::on_demand_compiler(jit_function_t func)
+{
+       jit_function *func_object;
+
+       // Get the object that corresponds to the raw function.
+       func_object = from_raw(func);
+       if(!func_object)
+       {
+               return JIT_RESULT_COMPILE_ERROR;
+       }
+
+       // Attempt to build the function's contents.
+       try
+       {
+               func_object->build();
+               if(!jit_insn_default_return(func))
+               {
+                       func_object->out_of_memory();
+               }
+               return JIT_RESULT_OK;
+       }
+       catch(jit_build_exception e)
+       {
+               return e.result;
+       }
+}
+
+void jit_function::free_mapping(void *data)
+{
+       // If we were called during the context's shutdown,
+       // then the raw function pointer is no longer valid.
+       ((jit_function *)data)->func = 0;
+}
diff --git a/jitplus/jit-plus-value.cpp b/jitplus/jit-plus-value.cpp
new file mode 100644 (file)
index 0000000..4032a8a
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * jit-plus-value.cpp - C++ wrapper for JIT values.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <jit/jit-plus.h>
+
+/*@
+
+The @code{jit_value} class provides a C++ counterpart to the
+@code{jit_value_t} type.  Values normally result by calling methods
+on the @code{jit_function} class during the function building process.
+@xref{Values}, for more information on creating and managing values.
+
+@defop Constructor jit_value jit_value ()
+Construct an empty value.
+@end defop
+
+@defop Constructor jit_value jit_value (jit_value_t value)
+Construct a value by wrapping up a raw C @code{jit_value_t} object.
+@end defop
+
+@defop Constructor jit_value jit_value ({const jit_value&} value)
+Create a copy of @code{value}.
+@end defop
+
+@defop Destructor jit_value ~jit_value ()
+Destroy the C++ value wrapper, but leave the underlying raw C
+value alone.
+@end defop
+
+@defop Operator jit_value {jit_value& operator=} ({const jit_value&} value)
+Copy @code{jit_value} objects.
+@end defop
+
+@deftypemethod jit_value jit_value_t raw () const
+Get the raw C @code{jit_value_t} value that underlies this object.
+@end deftypemethod
+
+@deftypemethod jit_value int is_valid () const
+Determine if this @code{jit_value} object contains a valid raw
+C @code{jit_value_t} value.
+@end deftypemethod
+
+@deftypemethod jit_value int is_temporary () const
+@deftypemethodx jit_value int is_local () const
+@deftypemethodx jit_value int is_constant () const
+Determine if this @code{jit_value} is temporary, local, or constant.
+@end deftypemethod
+
+@deftypemethod jit_value void set_volatile ()
+@deftypemethodx jit_value int is_volatile () const
+Set or check the "volatile" state on this value.
+@end deftypemethod
+
+@deftypemethod jit_value void set_addressable ()
+@deftypemethodx jit_value int is_addressable () const
+Set or check the "addressable" state on this value.
+@end deftypemethod
+
+@deftypemethod jit_value jit_type_t type () const
+Get the type of this value.
+@end deftypemethod
+
+@deftypemethod jit_value jit_function_t function () const
+@deftypemethodx jit_value jit_block_t block () const
+@deftypemethodx jit_value jit_context_t context () const
+Get the owning function, block, or context for this value.
+@end deftypemethod
+
+@deftypemethod jit_value jit_constant_t constant () const
+@deftypemethodx jit_value jit_nint nint_constant () const
+@deftypemethodx jit_value jit_long long_constant () const
+@deftypemethodx jit_value jit_float32 float32_constant () const
+@deftypemethodx jit_value jit_float64 float64_constant () const
+@deftypemethodx jit_value jit_nfloat nfloat_constant () const
+Extract the constant stored in this value.
+@end deftypemethod
+
+@defop Operator jit_value {jit_value operator+} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator-} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator*} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator/} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator%} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator-} ({const jit_value&} value1)
+@defopx Operator jit_value {jit_value operator&} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator|} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator^} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator~} ({const jit_value&} value1)
+@defopx Operator jit_value {jit_value operator<<} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator>>} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator==} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator!=} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator<} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator<=} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator jit_value {jit_value operator>} ({const jit_value&} value1, {const jit_value&} value2)
+@defopx Operator 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 @code{jit_value} objects.  These operators are shortcuts
+for calling @code{insn_add}, @code{insn_sub}, etc on the
+@code{jit_function} object.
+@end defop
+
+@*/
+
+// Get the function that owns a pair of values.  It will choose
+// the function for the first value, unless it is NULL (e.g. for
+// global values).  In that case, it will choose the function
+// for the second value.
+static inline jit_function_t value_owner
+       (const jit_value& value1, const jit_value& value2)
+{
+       jit_function_t func = jit_value_get_function(value1.raw());
+       if(func)
+       {
+               return func;
+       }
+       else
+       {
+               return jit_value_get_function(value2.raw());
+       }
+}
+
+jit_value operator+(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_add(value_owner(value1, value2),
+                                                                 value1.raw(), value2.raw()));
+}
+
+jit_value operator-(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_sub(value_owner(value1, value2),
+                                                                 value1.raw(), value2.raw()));
+}
+
+jit_value operator*(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_mul(value_owner(value1, value2),
+                                                                 value1.raw(), value2.raw()));
+}
+
+jit_value operator/(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_div(value_owner(value1, value2),
+                                                                 value1.raw(), value2.raw()));
+}
+
+jit_value operator%(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_rem(value_owner(value1, value2),
+                                                                 value1.raw(), value2.raw()));
+}
+
+jit_value operator-(const jit_value& value1)
+{
+       return jit_value(jit_insn_neg(jit_value_get_function(value1.raw()),
+                                                                 value1.raw()));
+}
+
+jit_value operator&(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_and(value_owner(value1, value2),
+                                                                 value1.raw(), value2.raw()));
+}
+
+jit_value operator|(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_or(value_owner(value1, value2),
+                                                                value1.raw(), value2.raw()));
+}
+
+jit_value operator^(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_xor(value_owner(value1, value2),
+                                                                 value1.raw(), value2.raw()));
+}
+
+jit_value operator~(const jit_value& value1)
+{
+       return jit_value(jit_insn_not(jit_value_get_function(value1.raw()),
+                                                                 value1.raw()));
+}
+
+jit_value operator<<(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_shl(value_owner(value1, value2),
+                                                                 value1.raw(), value2.raw()));
+}
+
+jit_value operator>>(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_shr(value_owner(value1, value2),
+                                                                 value1.raw(), value2.raw()));
+}
+
+jit_value operator==(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_eq(value_owner(value1, value2),
+                                                                value1.raw(), value2.raw()));
+}
+
+jit_value operator!=(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_ne(value_owner(value1, value2),
+                                                                value1.raw(), value2.raw()));
+}
+
+jit_value operator<(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_lt(value_owner(value1, value2),
+                                                                value1.raw(), value2.raw()));
+}
+
+jit_value operator<=(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_le(value_owner(value1, value2),
+                                                                value1.raw(), value2.raw()));
+}
+
+jit_value operator>(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_gt(value_owner(value1, value2),
+                                                                value1.raw(), value2.raw()));
+}
+
+jit_value operator>=(const jit_value& value1, const jit_value& value2)
+{
+       return jit_value(jit_insn_ge(value_owner(value1, value2),
+                                                                value1.raw(), value2.raw()));
+}
diff --git a/missing b/missing
new file mode 100755 (executable)
index 0000000..6a37006
--- /dev/null
+++ b/missing
@@ -0,0 +1,336 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997, 1999, 2000, 2002 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+  configure_ac=configure.ac
+else
+  configure_ac=configure.in
+fi
+
+case "$1" in
+--run)
+  # Try to run requested program, and just exit if it succeeds.
+  run=
+  shift
+  "$@" && exit 0
+  ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+  --run           try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  help2man     touch the output file
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  tar          try tar, gnutar, gtar, then tar without non-portable flags
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]"
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing 0.4 - GNU automake"
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+  aclocal*)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`${configure_ac}'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case "$f" in
+      *:*) touch_files="$touch_files "`echo "$f" |
+                                      sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake*)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+          sed 's/\.am$/.in/' |
+          while read f; do touch "$f"; done
+    ;;
+
+  autom4te)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.
+         You can get \`$1Help2man' as part of \`Autoconf' from any GNU
+         archive site."
+
+    file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+    test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+    if test -f "$file"; then
+       touch $file
+    else
+       test -z "$file" || exec >$file
+       echo "#! /bin/sh"
+       echo "# Created by GNU Automake missing as a replacement of"
+       echo "#  $ $@"
+       echo "exit 0"
+       chmod +x $file
+       exit 1
+    fi
+    ;;
+
+  bison|yacc)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+       case "$LASTARG" in
+       *.y)
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" y.tab.c
+           fi
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" y.tab.h
+           fi
+         ;;
+       esac
+    fi
+    if [ ! -f y.tab.h ]; then
+       echo >y.tab.h
+    fi
+    if [ ! -f y.tab.c ]; then
+       echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex|flex)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+       case "$LASTARG" in
+       *.l)
+           SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" lex.yy.c
+           fi
+         ;;
+       esac
+    fi
+    if [ ! -f lex.yy.c ]; then
+       echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  help2man)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+        you modified a dependency of a manual page.  You may need the
+        \`Help2man' package in order for those modifications to take
+        effect.  You can get \`Help2man' from any GNU archive site."
+
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+       file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+    fi
+    if [ -f "$file" ]; then
+       touch $file
+    else
+       test -z "$file" || exec >$file
+       echo ".ab help2man is required to generate this page"
+       exit 1
+    fi
+    ;;
+
+  makeinfo)
+    if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
+       # We have makeinfo, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+      file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+    fi
+    touch $file
+    ;;
+
+  tar)
+    shift
+    if test -n "$run"; then
+      echo 1>&2 "ERROR: \`tar' requires --run"
+      exit 1
+    fi
+
+    # We have already tried tar in the generic part.
+    # Look for gnutar/gtar before invocation to avoid ugly error
+    # messages.
+    if (gnutar --version > /dev/null 2>&1); then
+       gnutar "$@" && exit 0
+    fi
+    if (gtar --version > /dev/null 2>&1); then
+       gtar "$@" && exit 0
+    fi
+    firstarg="$1"
+    if shift; then
+       case "$firstarg" in
+       *o*)
+           firstarg=`echo "$firstarg" | sed s/o//`
+           tar "$firstarg" "$@" && exit 0
+           ;;
+       esac
+       case "$firstarg" in
+       *h*)
+           firstarg=`echo "$firstarg" | sed s/h//`
+           tar "$firstarg" "$@" && exit 0
+           ;;
+       esac
+    fi
+
+    echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+         You may want to install GNU tar or Free paxutils, or check the
+         command line arguments."
+    exit 1
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequirements for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755 (executable)
index 0000000..d3d085b
--- /dev/null
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.1 2004/04/30 23:29:35 rweather Exp $
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp"
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+         errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/tools/.cvsignore b/tools/.cvsignore
new file mode 100644 (file)
index 0000000..8a86675
--- /dev/null
@@ -0,0 +1,5 @@
+Makefile
+Makefile.in
+.deps
+gen-apply
+gen-apply.exe
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644 (file)
index 0000000..a48f253
--- /dev/null
@@ -0,0 +1,14 @@
+
+noinst_PROGRAMS = gen-apply
+
+gen_apply_SOURCES = gen-apply.c
+
+all-local: $(top_builddir)/jit/jit-apply-rules.h
+
+$(top_builddir)/jit/jit-apply-rules.h: gen-apply$(EXEEXT)
+       ./gen-apply >$@
+
+AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include \
+                       -I$(top_srcdir)/jit -I$(top_builddir)/jit
+
+CLEANFILES = $(top_builddir)/jit/jit-apply-rules.h
diff --git a/tools/gen-apply.c b/tools/gen-apply.c
new file mode 100644 (file)
index 0000000..072dfe6
--- /dev/null
@@ -0,0 +1,2211 @@
+/*
+ * gen-apply.c - Generate the rules that are needed to use "__builtin_apply".
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <jit/jit-defs.h>
+#include "jit-apply-func.h"
+#include <stdio.h>
+#include <config.h>
+#if HAVE_ALLOCA_H
+       #include <alloca.h>
+#endif
+
+/*
+
+This program tries to automatically discover the register assignment rules
+that are used by gcc's "__builtin_apply" operator.  It is used to generate
+the "jit-apply-rules.h" file.
+
+*/
+
+#if defined(__GNUC__)
+       #define PLATFORM_IS_GCC         1
+#endif
+#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
+       #define PLATFORM_IS_X86         1
+#if defined(__CYGWIN__) || defined(__CYGWIN32__) || \
+       defined(_WIN32) || defined(WIN32)
+       #define PLATFORM_IS_WIN32       1
+       #include <malloc.h>
+       #ifndef alloca
+               #define alloca  _alloca
+       #endif
+#endif
+#endif
+
+#if defined(PLATFORM_IS_GCC) || defined(PLATFORM_IS_WIN32)
+
+/*
+ * Values that are detected.
+ */
+int num_word_regs = 0;
+int num_float_regs = 0;
+int pass_stack_float_as_double = 0;
+int pass_stack_float_as_nfloat = 0;
+int pass_stack_double_as_nfloat = 0;
+int pass_stack_nfloat_as_double = 0;
+int pass_reg_float_as_double = 0;
+int pass_reg_float_as_nfloat = 0;
+int pass_reg_double_as_nfloat = 0;
+int pass_reg_nfloat_as_double = 0;
+int return_float_as_double = 0;
+int return_float_as_nfloat = 0;
+int return_double_as_nfloat = 0;
+int return_nfloat_as_double = 0;
+int floats_in_word_regs = 0;
+int return_floats_after = 0;
+int varargs_on_stack = 0;
+int struct_return_special_reg = 0;
+int struct_reg_overlaps_word_reg = 0;
+int struct_return_in_reg[64];
+int align_long_regs = 0;
+int align_long_stack = 0;
+int max_apply_size = 0;
+int x86_fastcall = 0;
+int parent_frame_offset = 0;
+int return_address_offset = 0;
+int broken_frame_builtins = 0;
+int max_struct_in_reg = 0;
+int x86_pop_struct_return = 0;
+
+void *mem_copy(void *dest, const void *src, unsigned int len)
+{
+       unsigned char *d = (unsigned char *)dest;
+       const unsigned char *s = (const unsigned char *)src;
+       while(len > 0)
+       {
+               *d++ = *s++;
+               --len;
+       }
+       return dest;
+}
+#define        jit_memcpy mem_copy
+
+void mem_set(void *dest, int value, unsigned int len)
+{
+       unsigned char *d = (unsigned char *)dest;
+       while(len > 0)
+       {
+               *d++ = (unsigned char)value;
+               --len;
+       }
+}
+
+int mem_cmp(const void *s1, const void *s2, unsigned int len)
+{
+       const unsigned char *str1 = (const unsigned char *)s1;
+       const unsigned char *str2 = (const unsigned char *)s2;
+       while(len > 0)
+       {
+               if(*str1 < *str2)
+                       return -1;
+               else if(*str1 > *str2)
+                       return 1;
+               ++str1;
+               ++str2;
+               --len;
+       }
+       return 0;
+}
+
+/*
+ * Detect the number of word registers that are used in function calls.
+ * We assume that the platform uses less than 32 registers in outgoing calls.
+ */
+void detect_word_regs(jit_nint arg1, jit_nint arg2, jit_nint arg3,
+                                         jit_nint arg4, jit_nint arg5, jit_nint arg6,
+                                         jit_nint arg7, jit_nint arg8, jit_nint arg9,
+                                         jit_nint arg10, jit_nint arg11, jit_nint arg12,
+                                         jit_nint arg13, jit_nint arg14, jit_nint arg15,
+                                         jit_nint arg16, jit_nint arg17, jit_nint arg18,
+                                         jit_nint arg19, jit_nint arg20, jit_nint arg21,
+                                         jit_nint arg22, jit_nint arg23, jit_nint arg24,
+                                         jit_nint arg25, jit_nint arg26, jit_nint arg27,
+                                         jit_nint arg28, jit_nint arg29, jit_nint arg30,
+                                         jit_nint arg31, jit_nint arg32)
+{
+       /* We fetch the number in the first stack argument, which will
+          correspond to the number of word registers that are present */
+       jit_nint *args, *stack_args;
+       jit_builtin_apply_args(jit_nint *, args);
+       stack_args = (jit_nint *)(args[0]);
+       num_word_regs = (int)(stack_args[0]);
+
+       /* Detect the presence of a structure return register by checking
+          to see if "arg1" is in the second word position after "stack_args" */
+       if(num_word_regs > 1 && args[2] == 0)
+       {
+               struct_return_special_reg = 1;
+       }
+}
+
+/*
+ * Detect the presence of a structure return register if there are 0 or 1
+ * word registers as detected by "detect_word_regs".  The structure
+ * below must be big enough to avoid being returned in a register.
+ */
+struct detect_struct_reg
+{
+       void *field1;
+       void *field2;
+       void *field3;
+       void *field4;
+       void *field5;
+       void *field6;
+       void *field7;
+       void *field8;
+};
+static struct detect_struct_reg detect_struct_buf;
+struct detect_struct_reg detect_struct_return(jit_nint arg1, jit_nint arg2)
+{
+       struct detect_struct_reg ret;
+       jit_nint *args, *stack_args;
+       jit_builtin_apply_args(jit_nint *, args);
+       stack_args = (jit_nint *)(args[0]);
+
+       /* Set the return value */
+       ret.field1 = 0;
+       ret.field2 = 0;
+       ret.field3 = 0;
+       ret.field4 = 0;
+       ret.field5 = 0;
+       ret.field6 = 0;
+       ret.field7 = 0;
+       ret.field8 = 0;
+
+       /* If the stack starts with something other than 1 or 2,
+          then the structure return pointer is passed on the stack */
+       if(stack_args[0] != 1 && stack_args[0] != 2)
+       {
+               return ret;
+       }
+
+       /* Check the slots to determine where the pointer resides */
+       if(num_word_regs == 0)
+       {
+               /* If there are no word registers and the stack top
+                  does not look like a return pointer, then the
+                  structure return must be in a special register
+                  that is separate from the normal word regsiters */
+               struct_return_special_reg = 1;
+       }
+       else
+       {
+               if(stack_args[0] == 2)
+               {
+                       /* The first word argument is still in a register,
+                          so there must be a special structure register.
+                          If the first word argument was on the stack, then
+                          the structure return is in an ordinary register */
+                       struct_return_special_reg = 1;
+               }
+       }
+
+       /* Done */
+       return ret;
+}
+
+/*
+ * Determine if a special structure return register overlaps
+ * with the first word register.
+ */
+struct detect_struct_reg detect_struct_overlap(jit_nint arg1, jit_nint arg2)
+{
+       struct detect_struct_reg ret;
+       jit_nint *args;
+       jit_builtin_apply_args(jit_nint *, args);
+
+       /* Set the return value */
+       ret.field1 = 0;
+       ret.field2 = 0;
+       ret.field3 = 0;
+       ret.field4 = 0;
+       ret.field5 = 0;
+       ret.field6 = 0;
+       ret.field7 = 0;
+       ret.field8 = 0;
+
+       /* Check for overlap */
+       if(struct_return_special_reg && num_word_regs > 0)
+       {
+               if(args[1] == args[2])
+               {
+                       struct_reg_overlaps_word_reg = 1;
+               }
+       }
+
+       /* Done */
+       return ret;
+}
+
+/*
+ * Detect the number of floating-point registers.
+ */
+void detect_float_regs(double arg1, double arg2, double arg3,
+                                          double arg4, double arg5, double arg6,
+                                          double arg7, double arg8, double arg9,
+                                          double arg10, double arg11, double arg12,
+                                          double arg13, double arg14, double arg15,
+                                          double arg16, double arg17, double arg18,
+                                          double arg19, double arg20, double arg21,
+                                          double arg22, double arg23, double arg24,
+                                          double arg25, double arg26, double arg27,
+                                          double arg28, double arg29, double arg30,
+                                          double arg31, double arg32)
+{
+       jit_nint *args;
+       double *stack_args;
+       jit_builtin_apply_args(jit_nint *, args);
+       stack_args = (double *)(args[0]);
+
+       /* The first stack argument indicates the number of floating-point
+          registers.  At the moment we don't know if they overlap with
+          the word registers or not */
+       num_float_regs = (int)(stack_args[0]);
+}
+
+#ifdef JIT_NATIVE_INT32
+
+/*
+ * Detect if a "float" value will use a word register.
+ */
+void detect_float_overlap(float x, jit_nint y)
+{
+       /* We have an overlap if "y" is on the stack */
+       jit_nint *args;
+       jit_builtin_apply_args(jit_nint *, args);
+       if(args[struct_return_special_reg + 1] != 1)
+       {
+               floats_in_word_regs = 1;
+               num_float_regs = 0;
+       }
+}
+
+#endif /* JIT_NATIVE_INT32 */
+
+/*
+ * Detect if a "double" value will use a word register.
+ */
+void detect_double_overlap(double x, jit_nint y, jit_nint z)
+{
+       /* We have an overlap if "x" is in the first word register slot */
+       double temp;
+       jit_nint *args;
+       jit_builtin_apply_args(jit_nint *, args);
+       mem_copy(&temp, args + struct_return_special_reg + 1, sizeof(temp));
+       if(!mem_cmp(&temp, &x, sizeof(double)))
+       {
+               floats_in_word_regs = 1;
+               num_float_regs = 0;
+       }
+}
+
+/*
+ * Detect if floating-point registers are "double" or "long double" in size.
+ */
+void detect_float_reg_size_regs(double x, double y)
+{
+       double temp;
+       jit_nint *args;
+       jit_builtin_apply_args(jit_nint *, args);
+       mem_copy(&temp, args + 1 + struct_return_special_reg + num_word_regs,
+                        sizeof(temp));
+       if(!mem_cmp(&temp, &x, sizeof(double)))
+       {
+               pass_reg_nfloat_as_double = 1;
+       }
+       else
+       {
+               pass_reg_double_as_nfloat = 1;
+       }
+}
+void detect_float_reg_size_stack(jit_nfloat x, jit_nfloat y)
+{
+       double temp;
+       double dx;
+       jit_nint *args;
+       jit_builtin_apply_args(jit_nint *, args);
+       mem_copy(&temp, (void *)(args[0]), sizeof(temp));
+       dx = (double)x;
+       if(!mem_cmp(&temp, &dx, sizeof(double)))
+       {
+               pass_stack_nfloat_as_double = 1;
+       }
+}
+
+/*
+ * Detect the promotion rules for "float" values.
+ */
+void detect_float_promotion(float arg1, float arg2, float arg3,
+                                               float arg4, float arg5, float arg6,
+                                               float arg7, float arg8, float arg9,
+                                               float arg10, float arg11, float arg12,
+                                               float arg13, float arg14, float arg15,
+                                               float arg16, float arg17, float arg18,
+                                               float arg19, float arg20, float arg21,
+                                               float arg22, float arg23, float arg24,
+                                               float arg25, float arg26, float arg27,
+                                               float arg28, float arg29, float arg30,
+                                               float arg31, float arg32)
+{
+       jit_nint *args, *stack_args;
+       float value, test;
+       double dvalue;
+       int reg_promote;
+       int stack_promote;
+       int index;
+
+       /* Extract the arguments */
+       jit_builtin_apply_args(jit_nint *, args);
+       stack_args = (jit_nint *)(args[0]);
+       reg_promote = 0;
+       stack_promote = 0;
+
+       /* Handle the easy promotion cases first */
+       if(floats_in_word_regs)
+       {
+               /* The value will either be in 1 or 2 word registers */
+               mem_copy(&value, args + 1 + struct_return_special_reg, sizeof(value));
+               if(value != arg1)
+               {
+                       reg_promote = 1;
+               }
+       }
+       else if(num_float_regs > 0)
+       {
+               /* The value is in a float register, which is always promoted */
+               reg_promote = 1;
+       }
+
+       /* Skip the arguments that will be stored in registers */
+       index = 1;
+       if(floats_in_word_regs)
+       {
+               if(reg_promote && sizeof(jit_nint) == sizeof(jit_int))
+               {
+                       index += num_word_regs / 2;
+               }
+               else
+               {
+                       index += num_word_regs;
+               }
+       }
+       else if(num_float_regs > 0)
+       {
+               index += num_float_regs;
+       }
+
+       /* Get the value corresponding to argument "index" */
+       switch(index)
+       {
+               case 1:                 test = arg1; break;
+               case 2:                 test = arg2; break;
+               case 3:                 test = arg3; break;
+               case 4:                 test = arg4; break;
+               case 5:                 test = arg5; break;
+               case 6:                 test = arg6; break;
+               case 7:                 test = arg7; break;
+               case 8:                 test = arg8; break;
+               case 9:                 test = arg9; break;
+               case 10:                test = arg10; break;
+               case 11:                test = arg11; break;
+               case 12:                test = arg12; break;
+               case 13:                test = arg13; break;
+               case 14:                test = arg14; break;
+               case 15:                test = arg15; break;
+               case 16:                test = arg16; break;
+               case 17:                test = arg17; break;
+               case 18:                test = arg18; break;
+               case 19:                test = arg19; break;
+               case 20:                test = arg20; break;
+               case 30:                test = arg30; break;
+               case 31:                test = arg31; break;
+               case 32:                test = arg32; break;
+               default:                test = (float)(-1.0); break;
+       }
+
+       /* Determine if stacked values are promoted */
+       mem_copy(&value, stack_args, sizeof(value));
+       if(value != test)
+       {
+               stack_promote = 1;
+               mem_copy(&dvalue, stack_args, sizeof(dvalue));
+               if(dvalue != (double)test)
+               {
+                       stack_promote = 2;
+               }
+       }
+
+       /* Set the appropriate promotion rules */
+       if(reg_promote)
+       {
+               /* Promoting "float" to "nfloat" in registers */
+               if(pass_reg_nfloat_as_double)
+               {
+                       pass_reg_float_as_double = 1;
+               }
+               else
+               {
+                       pass_reg_float_as_nfloat = 1;
+               }
+       }
+       if(stack_promote == 2)
+       {
+               /* Promoting "float" to "nfloat" on the stack */
+               if(pass_stack_nfloat_as_double)
+               {
+                       pass_stack_float_as_double = 1;
+               }
+               else
+               {
+                       pass_stack_float_as_nfloat = 1;
+               }
+       }
+       else if(stack_promote)
+       {
+               /* Promoting "float" to "double" on the stack */
+               pass_stack_float_as_double = 1;
+       }
+}
+
+/*
+ * Detect the stack promotion rules for "double" values.
+ */
+void detect_double_promotion(double arg1, double arg2, double arg3,
+                                                double arg4, double arg5, double arg6,
+                                                double arg7, double arg8, double arg9,
+                                                double arg10, double arg11, double arg12,
+                                                double arg13, double arg14, double arg15,
+                                                double arg16, double arg17, double arg18,
+                                                double arg19, double arg20, double arg21,
+                                                double arg22, double arg23, double arg24,
+                                                double arg25, double arg26, double arg27,
+                                                double arg28, double arg29, double arg30,
+                                                double arg31, double arg32)
+{
+       jit_nint *args, *stack_args;
+       double value, test;
+       int stack_promote;
+       int index;
+
+       /* Extract the arguments */
+       jit_builtin_apply_args(jit_nint *, args);
+       stack_args = (jit_nint *)(args[0]);
+       stack_promote = 0;
+
+       /* Skip the arguments that will be stored in registers */
+       index = 1;
+       if(floats_in_word_regs)
+       {
+               if(sizeof(jit_nint) == sizeof(jit_int))
+               {
+                       index += num_word_regs / 2;
+               }
+               else
+               {
+                       index += num_word_regs;
+               }
+       }
+       else if(num_float_regs > 0)
+       {
+               index += num_float_regs;
+       }
+
+       /* Get the value corresponding to argument "index" */
+       switch(index)
+       {
+               case 1:                 test = arg1; break;
+               case 2:                 test = arg2; break;
+               case 3:                 test = arg3; break;
+               case 4:                 test = arg4; break;
+               case 5:                 test = arg5; break;
+               case 6:                 test = arg6; break;
+               case 7:                 test = arg7; break;
+               case 8:                 test = arg8; break;
+               case 9:                 test = arg9; break;
+               case 10:                test = arg10; break;
+               case 11:                test = arg11; break;
+               case 12:                test = arg12; break;
+               case 13:                test = arg13; break;
+               case 14:                test = arg14; break;
+               case 15:                test = arg15; break;
+               case 16:                test = arg16; break;
+               case 17:                test = arg17; break;
+               case 18:                test = arg18; break;
+               case 19:                test = arg19; break;
+               case 20:                test = arg20; break;
+               case 30:                test = arg30; break;
+               case 31:                test = arg31; break;
+               case 32:                test = arg32; break;
+               default:                test = (double)(-1.0); break;
+       }
+
+       /* Determine if stacked values are promoted to "nfloat" */
+       mem_copy(&value, stack_args, sizeof(value));
+       if(value != test)
+       {
+               stack_promote = 1;
+       }
+
+       /* Set the appropriate promotion rules */
+       if(stack_promote)
+       {
+               /* Promoting "double" to "nfloat" on the stack */
+               pass_stack_double_as_nfloat = 1;
+       }
+}
+
+/*
+ * Determine if variable arguments are always passed on the stack,
+ * even if the values would otherwise fit into a register.
+ */
+void detect_varargs_on_stack(jit_nint start, ...)
+{
+       jit_nint *args, *stack_args;
+       jit_builtin_apply_args(jit_nint *, args);
+       stack_args = (jit_nint *)(args[0]);
+       if(num_word_regs == 0)
+       {
+               varargs_on_stack = 1;
+       }
+       else if(stack_args[0] == 1)
+       {
+               varargs_on_stack = 1;
+       }
+}
+
+/*
+ * Dummy functions for helping detect the size and position of "float",
+ * "double", and "long double" return values.
+ */
+float return_float(void)
+{
+       return (float)123.0;
+}
+double return_double(void)
+{
+       return (double)456.7;
+}
+jit_nfloat return_nfloat(void)
+{
+       return (jit_nfloat)8901.2;
+}
+
+/*
+ * Detect the behaviour of floating-point values in return blocks.
+ */
+void detect_float_return(void)
+{
+       jit_nint *args;
+       int offset;
+       unsigned char *return_value;
+       float float_value;
+       double double_value;
+       jit_nfloat nfloat_value;
+       int float_size;
+       int double_size;
+       int nfloat_size;
+
+       /* Allocate space for the outgoing arguments */
+       jit_builtin_apply_args(jit_nint *, args);
+
+       /* Call "return_float" and get its return structure */
+       jit_builtin_apply(return_float, args, 0, 1, return_value);
+
+       /* Find the location of the return value */
+       offset = 0;
+       while(offset < 64)
+       {
+               mem_copy(&float_value, return_value + offset, sizeof(float));
+               if(float_value != (float)123.0)
+               {
+                       mem_copy(&double_value, return_value + offset, sizeof(double));
+                       if(double_value != (double)123.0)
+                       {
+                               mem_copy(&nfloat_value, return_value + offset,
+                                                sizeof(jit_nfloat));
+                               if(nfloat_value == (jit_nfloat)123.0)
+                               {
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               break;
+                       }
+               }
+               else
+               {
+                       break;
+               }
+               offset += sizeof(void *);
+       }
+
+       /* Determine the size of the "float" return value */
+       mem_copy(&float_value, return_value + offset, sizeof(float));
+       if(float_value == (float)123.0)
+       {
+               float_size = 1;
+       }
+       else
+       {
+               mem_copy(&double_value, return_value + offset, sizeof(double));
+               if(double_value == (double)123.0)
+               {
+                       float_size = 2;
+               }
+               else
+               {
+                       float_size = 3;
+               }
+       }
+
+       /* Call "return_double" and get its return structure */
+       jit_builtin_apply(return_double, args, 0, 1, return_value);
+
+       /* Determine the size of the "double" return value */
+       mem_copy(&double_value, return_value + offset, sizeof(double));
+       if(double_value == (double)456.7)
+       {
+               double_size = 2;
+       }
+       else
+       {
+               double_size = 3;
+       }
+
+       /* Call "return_nfloat" and get its return structure */
+       jit_builtin_apply(return_nfloat, args, 0, 1, return_value);
+
+       /* Determine the size of the "nfloat" return value */
+       mem_copy(&double_value, return_value + offset, sizeof(double));
+       if(double_value == (double)8901.2)
+       {
+               nfloat_size = 2;
+       }
+       else
+       {
+               nfloat_size = 3;
+       }
+
+       /* Use the offset and size information to set the final parameters */
+       return_floats_after = offset;
+       if(float_size == 2)
+       {
+               return_float_as_double = 1;
+       }
+       else if(float_size == 3)
+       {
+               return_float_as_nfloat = 1;
+       }
+       if(double_size == 3)
+       {
+               return_double_as_nfloat = 1;
+       }
+       if(nfloat_size == 2)
+       {
+               return_nfloat_as_double = 1;
+       }
+}
+
+/*
+ * Detect whether small struct values are returned in registers.
+ */
+#define        declare_struct_test(n)  \
+       struct detect_##n \
+       { \
+               jit_sbyte value[(n)]; \
+       }; \
+       struct detect_##n detect_struct_##n(void) \
+       { \
+               struct detect_##n d; \
+               mem_set(&d, 0xFF, sizeof(d)); \
+               return d; \
+       }
+#define        call_struct_test(n)     \
+       mem_set(buffer, 0, sizeof(buffer)); \
+       jit_builtin_apply(detect_struct_##n, args, \
+                                         sizeof(jit_nint), 0, apply_return); \
+       if(((struct detect_##n *)buffer)->value[0] == 0x00) \
+       { \
+               /* The buffer doesn't contain the value, so it must be in registers */ \
+               struct_return_in_reg[(n) - 1] = 1; \
+       }
+declare_struct_test(1);
+declare_struct_test(2);
+declare_struct_test(3);
+declare_struct_test(4);
+declare_struct_test(5);
+declare_struct_test(6);
+declare_struct_test(7);
+declare_struct_test(8);
+declare_struct_test(9);
+declare_struct_test(10);
+declare_struct_test(11);
+declare_struct_test(12);
+declare_struct_test(13);
+declare_struct_test(14);
+declare_struct_test(15);
+declare_struct_test(16);
+declare_struct_test(17);
+declare_struct_test(18);
+declare_struct_test(19);
+declare_struct_test(20);
+declare_struct_test(21);
+declare_struct_test(22);
+declare_struct_test(23);
+declare_struct_test(24);
+declare_struct_test(25);
+declare_struct_test(26);
+declare_struct_test(27);
+declare_struct_test(28);
+declare_struct_test(29);
+declare_struct_test(30);
+declare_struct_test(31);
+declare_struct_test(32);
+declare_struct_test(33);
+declare_struct_test(34);
+declare_struct_test(35);
+declare_struct_test(36);
+declare_struct_test(37);
+declare_struct_test(38);
+declare_struct_test(39);
+declare_struct_test(40);
+declare_struct_test(41);
+declare_struct_test(42);
+declare_struct_test(43);
+declare_struct_test(44);
+declare_struct_test(45);
+declare_struct_test(46);
+declare_struct_test(47);
+declare_struct_test(48);
+declare_struct_test(49);
+declare_struct_test(50);
+declare_struct_test(51);
+declare_struct_test(52);
+declare_struct_test(53);
+declare_struct_test(54);
+declare_struct_test(55);
+declare_struct_test(56);
+declare_struct_test(57);
+declare_struct_test(58);
+declare_struct_test(59);
+declare_struct_test(60);
+declare_struct_test(61);
+declare_struct_test(62);
+declare_struct_test(63);
+declare_struct_test(64);
+void detect_struct_conventions(void)
+{
+       jit_nint *args;
+       jit_nint stack[1];
+       jit_nint buffer[64 / sizeof(jit_nint)];
+       void *apply_return;
+
+       /* Initialize the arguments as though we'll be using a struct pointer */
+       jit_builtin_apply_args(jit_nint *, args);
+       args[0] = (jit_nint)stack;
+       stack[0] = (jit_nint)buffer;
+       if(struct_return_special_reg || num_word_regs > 0)
+       {
+               args[1] = (jit_nint)buffer;
+       }
+
+       /* Apply the structure return tests for all sizes from 1 to 64 */
+       call_struct_test(1);
+       call_struct_test(2);
+       call_struct_test(3);
+       call_struct_test(4);
+       call_struct_test(5);
+       call_struct_test(6);
+       call_struct_test(7);
+       call_struct_test(8);
+       call_struct_test(9);
+       call_struct_test(10);
+       call_struct_test(11);
+       call_struct_test(12);
+       call_struct_test(13);
+       call_struct_test(14);
+       call_struct_test(15);
+       call_struct_test(16);
+       call_struct_test(17);
+       call_struct_test(18);
+       call_struct_test(19);
+       call_struct_test(20);
+       call_struct_test(21);
+       call_struct_test(22);
+       call_struct_test(23);
+       call_struct_test(24);
+       call_struct_test(25);
+       call_struct_test(26);
+       call_struct_test(27);
+       call_struct_test(28);
+       call_struct_test(29);
+       call_struct_test(30);
+       call_struct_test(31);
+       call_struct_test(32);
+       call_struct_test(33);
+       call_struct_test(34);
+       call_struct_test(35);
+       call_struct_test(36);
+       call_struct_test(37);
+       call_struct_test(38);
+       call_struct_test(39);
+       call_struct_test(40);
+       call_struct_test(41);
+       call_struct_test(42);
+       call_struct_test(43);
+       call_struct_test(44);
+       call_struct_test(45);
+       call_struct_test(46);
+       call_struct_test(47);
+       call_struct_test(48);
+       call_struct_test(49);
+       call_struct_test(50);
+       call_struct_test(51);
+       call_struct_test(52);
+       call_struct_test(53);
+       call_struct_test(54);
+       call_struct_test(55);
+       call_struct_test(56);
+       call_struct_test(57);
+       call_struct_test(58);
+       call_struct_test(59);
+       call_struct_test(60);
+       call_struct_test(61);
+       call_struct_test(62);
+       call_struct_test(63);
+       call_struct_test(64);
+}
+
+/*
+ * Determine the maximum size for the apply structure.
+ */
+void detect_max_sizes(void)
+{
+       max_apply_size = (struct_return_special_reg + num_word_regs + 1)
+                                               * sizeof(jit_nint);
+       if(pass_reg_nfloat_as_double)
+       {
+               max_apply_size += num_float_regs * sizeof(double);
+       }
+       else
+       {
+               max_apply_size += num_float_regs * sizeof(jit_nfloat);
+       }
+       if(x86_fastcall && max_apply_size < 12)
+       {
+               max_apply_size = 12;
+       }
+}
+
+/*
+ * Detect the offsets of parent frame and return address pointers
+ * in the values returned by "__builtin_frame_address".  We have to
+ * do this carefully, to deal with architectures that don't create
+ * a real frame for leaf functions.
+ */
+#if defined(PLATFORM_IS_GCC)
+void find_frame_offset_inner(void *looking_for, void **frame)
+{
+       int offset;
+       for(offset = 0; offset >= -8; --offset)
+       {
+               if(frame[offset] == looking_for)
+               {
+                       parent_frame_offset = offset * sizeof(void *);
+                       return;
+               }
+       }
+       for(offset = 1; offset <= 8; ++offset)
+       {
+               if(frame[offset] == looking_for)
+               {
+                       parent_frame_offset = offset * sizeof(void *);
+                       return;
+               }
+       }
+}
+void find_frame_offset_outer(void *looking_for)
+{
+       find_frame_offset_inner(looking_for, (void **)__builtin_frame_address(0));
+}
+void find_return_offset(void *looking_for, void **frame)
+{
+       int offset;
+       for(offset = 1; offset <= 8; ++offset)
+       {
+               if(frame[offset] == looking_for)
+               {
+                       return_address_offset = offset * sizeof(void *);
+                       return;
+               }
+       }
+       for(offset = 0; offset >= -8; --offset)
+       {
+               if(frame[offset] == looking_for)
+               {
+                       return_address_offset = offset * sizeof(void *);
+                       return;
+               }
+       }
+}
+void detect_frame_offsets(void)
+{
+       void *frame_address = __builtin_frame_address(0);
+       void *return_address = __builtin_return_address(0);
+       find_frame_offset_outer(frame_address);
+       find_return_offset(return_address, frame_address);
+       if(parent_frame_offset == 0 && return_address_offset == 0)
+       {
+               /* Can happen on platforms like ia64 where there are so
+                  many registers that the frame is almost never concrete */
+               broken_frame_builtins = 1;
+       }
+}
+#else
+void detect_frame_offsets(void)
+{
+       /* We don't know how to detect the offsets, so assume some defaults */
+       parent_frame_offset = 0;
+       return_address_offset = sizeof(void *);
+}
+#endif
+
+/*
+ * Dump the definition of the "jit_apply_return" union, which defines
+ * the layout of the return value from "__builtin_apply".
+ */
+void dump_return_union(void)
+{
+       const char *float_type;
+       const char *double_type;
+       const char *nfloat_type;
+
+       /* Dump the definition of "jit_apply_float" */
+       printf("typedef union\n{\n");
+       if(return_float_as_nfloat)
+       {
+               float_type = "jit_nfloat";
+       }
+       else if(return_float_as_double)
+       {
+               float_type = "double";
+       }
+       else
+       {
+               float_type = "float";
+       }
+       if(return_double_as_nfloat)
+       {
+               double_type = "jit_nfloat";
+       }
+       else
+       {
+               double_type = "double";
+       }
+       if(return_nfloat_as_double)
+       {
+               nfloat_type = "double";
+       }
+       else
+       {
+               nfloat_type = "jit_nfloat";
+       }
+       printf("\t%s float_value;\n", float_type);
+       printf("\t%s double_value;\n", double_type);
+       printf("\t%s nfloat_value;\n", nfloat_type);
+       printf("\n} jit_apply_float;\n");
+
+       /* Dump the definition of "jit_apply_return" */
+       printf("typedef union\n{\n");
+       printf("\tjit_nint int_value;\n");
+       printf("\tjit_nuint uint_value;\n");
+       printf("\tjit_long long_value;\n");
+       printf("\tjit_ulong ulong_value;\n");
+       if(return_floats_after)
+       {
+               printf("\tstruct { jit_ubyte pad[%d]; jit_apply_float inner_value; } f_value;\n",
+                          return_floats_after);
+       }
+       else
+       {
+               printf("\tstruct { jit_apply_float inner_value; } f_value;\n");
+       }
+       if(max_struct_in_reg > 0)
+       {
+               printf("\tjit_ubyte small_struct_value[%d];\n", max_struct_in_reg);
+       }
+       printf("\n} jit_apply_return;\n\n");
+
+       /* Output access macros for manipulating the contents */
+       printf("#define jit_apply_return_get_sbyte(result)\t\\\n");
+       printf("\t((jit_sbyte)((result)->int_value))\n");
+       printf("#define jit_apply_return_get_ubyte(result)\t\\\n");
+       printf("\t((jit_ubyte)((result)->int_value))\n");
+       printf("#define jit_apply_return_get_short(result)\t\\\n");
+       printf("\t((jit_short)((result)->int_value))\n");
+       printf("#define jit_apply_return_get_ushort(result)\t\\\n");
+       printf("\t((jit_ushort)((result)->int_value))\n");
+       printf("#define jit_apply_return_get_int(result)\t\\\n");
+       printf("\t((jit_int)((result)->int_value))\n");
+       printf("#define jit_apply_return_get_uint(result)\t\\\n");
+       printf("\t((jit_uint)((result)->uint_value))\n");
+       printf("#define jit_apply_return_get_nint(result)\t\\\n");
+       printf("\t((jit_nint)((result)->int_value))\n");
+       printf("#define jit_apply_return_get_nuint(result)\t\\\n");
+       printf("\t((jit_nuint)((result)->uint_value))\n");
+       printf("#define jit_apply_return_get_long(result)\t\\\n");
+       printf("\t((jit_long)((result)->long_value))\n");
+       printf("#define jit_apply_return_get_ulong(result)\t\\\n");
+       printf("\t((jit_ulong)((result)->ulong_value))\n");
+       printf("#define jit_apply_return_get_float32(result)\t\\\n");
+       printf("\t((jit_float32)((result)->f_value.inner_value.float_value))\n");
+       printf("#define jit_apply_return_get_float64(result)\t\\\n");
+       printf("\t((jit_float64)((result)->f_value.inner_value.double_value))\n");
+       printf("#define jit_apply_return_get_nfloat(result)\t\\\n");
+       printf("\t((jit_nfloat)((result)->f_value.inner_value.nfloat_value))\n");
+       printf("\n");
+       printf("#define jit_apply_return_set_sbyte(result,value)\t\\\n");
+       printf("\t(((result)->int_value) = ((jit_nint)(value)))\n");
+       printf("#define jit_apply_return_set_ubyte(result,value)\t\\\n");
+       printf("\t(((result)->int_value) = ((jit_nint)(value)))\n");
+       printf("#define jit_apply_return_set_short(result,value)\t\\\n");
+       printf("\t(((result)->int_value) = ((jit_nint)(value)))\n");
+       printf("#define jit_apply_return_set_ushort(result,value)\t\\\n");
+       printf("\t(((result)->int_value) = ((jit_nint)(value)))\n");
+       printf("#define jit_apply_return_set_int(result,value)\t\\\n");
+       printf("\t(((result)->int_value) = ((jit_nint)(value)))\n");
+       printf("#define jit_apply_return_set_uint(result,value)\t\\\n");
+       printf("\t(((result)->uint_value) = ((jit_nuint)(value)))\n");
+       printf("#define jit_apply_return_set_nint(result,value)\t\\\n");
+       printf("\t(((result)->int_value) = ((jit_nint)(value)))\n");
+       printf("#define jit_apply_return_set_nuint(result,value)\t\\\n");
+       printf("\t(((result)->uint_value) = ((jit_nuint)(value)))\n");
+       printf("#define jit_apply_return_set_long(result,value)\t\\\n");
+       printf("\t(((result)->long_value) = ((jit_long)(value)))\n");
+       printf("#define jit_apply_return_set_ulong(result,value)\t\\\n");
+       printf("\t(((result)->ulong_value) = ((jit_ulong)(value)))\n");
+       printf("#define jit_apply_return_set_float32(result,value)\t\\\n");
+       printf("\t(((result)->f_value.inner_value.float_value) = ((%s)(value)))\n",
+                  float_type);
+       printf("#define jit_apply_return_set_float64(result,value)\t\\\n");
+       printf("\t(((result)->f_value.inner_value.double_value) = ((%s)(value)))\n",
+                  double_type);
+       printf("#define jit_apply_return_set_nfloat(result,value)\t\\\n");
+       printf("\t(((result)->f_value.inner_value.nfloat_value) = ((%s)(value)))\n",
+                  nfloat_type);
+       printf("\n");
+}
+
+/*
+ * Dump macro definitions that are used to build the apply parameter block.
+ */
+void dump_apply_macros(void)
+{
+       int apply_size;
+       int reg_offset;
+       const char *name;
+
+       /* Declare the "jit_apply_builder" structure */
+       printf("typedef struct\n{\n");
+       printf("\tunsigned char *apply_args;\n");
+       printf("\tunsigned char *stack_args;\n");
+       printf("\tunsigned int stack_used;\n");
+       if(num_word_regs > 0 || x86_fastcall)
+       {
+               printf("\tunsigned char *word_regs;\n");
+               printf("\tunsigned int word_left;\n");
+               if(align_long_regs)
+               {
+                       printf("\tunsigned int word_max;\n");
+               }
+       }
+       if(num_float_regs > 0)
+       {
+               printf("\tunsigned char *float_regs;\n");
+               printf("\tunsigned int float_left;\n");
+       }
+       printf("\tvoid *struct_return;\n");
+       printf("\n} jit_apply_builder;\n\n");
+
+       /* Macro to initialize the apply builder */
+       printf("#define jit_apply_builder_init(builder,type)\t\\\n");
+       printf("\tdo { \\\n");
+       apply_size = max_apply_size;
+       printf("\t\t(builder)->apply_args = (unsigned char *)alloca(%d); \\\n", apply_size);
+       if(apply_size > sizeof(void *))
+       {
+               printf("\t\tjit_memset((builder)->apply_args, 0, %d); \\\n", apply_size);
+       }
+       printf("\t\t(builder)->stack_args = (unsigned char *)alloca(jit_type_get_max_arg_size((type))); \\\n");
+       printf("\t\t((void **)((builder)->apply_args))[0] = (builder)->stack_args; \\\n");
+       printf("\t\t(builder)->stack_used = 0; \\\n");
+       reg_offset = sizeof(void *);
+       if(struct_return_special_reg)
+       {
+               reg_offset += sizeof(void *);
+       }
+       if(x86_fastcall)
+       {
+               printf("\t\t(builder)->word_regs = (builder)->apply_args + %d; \\\n",
+                          reg_offset);
+               printf("\t\tif(jit_type_get_abi((type)) == jit_abi_fastcall) \\\n");
+               printf("\t\t\t(builder)->word_left = 2; \\\n");
+               printf("\t\telse; \\\n");
+               printf("\t\t\t(builder)->word_left = 0; \\\n");
+               reg_offset += 2 * sizeof(void *);
+       }
+       else if(num_word_regs > 0)
+       {
+               printf("\t\t(builder)->word_regs = (builder)->apply_args + %d; \\\n",
+                          reg_offset);
+               printf("\t\t(builder)->word_left = %d; \\\n", num_word_regs);
+               reg_offset += num_word_regs * sizeof(void *);
+       }
+       if(align_long_regs)
+       {
+               printf("\t\t(builder)->word_max = (builder)->word_left; \\\n");
+       }
+       if(num_float_regs > 0)
+       {
+               printf("\t\t(builder)->float_regs = (builder)->apply_args + %d; \\\n",
+                          reg_offset);
+               printf("\t\t(builder)->float_left = %d; \\\n", num_float_regs);
+       }
+       printf("\t\t(builder)->struct_return = 0; \\\n");
+       printf("\t} while (0)\n\n");
+
+       /* Macro to initialize the apply builder in closure parse mode.
+          The "args" parameter is the result of calling "__builtin_apply_args" */
+       printf("#define jit_apply_parser_init(builder,type,args)\t\\\n");
+       printf("\tdo { \\\n");
+       printf("\t\t(builder)->apply_args = (unsigned char *)(args); \\\n");
+       printf("\t\t(builder)->stack_args = (unsigned char *)(((void **)((builder)->apply_args))[0]); \\\n");
+       printf("\t\t(builder)->stack_used = 0; \\\n");
+       reg_offset = sizeof(void *);
+       if(struct_return_special_reg)
+       {
+               reg_offset += sizeof(void *);
+       }
+       if(x86_fastcall)
+       {
+               printf("\t\t(builder)->word_regs = (builder)->apply_args + %d; \\\n",
+                          reg_offset);
+               printf("\t\tif(jit_type_get_abi((type)) == jit_abi_fastcall) \\\n");
+               printf("\t\t\t(builder)->word_left = 2; \\\n");
+               printf("\t\telse; \\\n");
+               printf("\t\t\t(builder)->word_left = 0; \\\n");
+               reg_offset += 2 * sizeof(void *);
+       }
+       else if(num_word_regs > 0)
+       {
+               printf("\t\t(builder)->word_regs = (builder)->apply_args + %d; \\\n",
+                          reg_offset);
+               printf("\t\t(builder)->word_left = %d; \\\n", num_word_regs);
+               reg_offset += num_word_regs * sizeof(void *);
+       }
+       if(align_long_regs)
+       {
+               printf("\t\t(builder)->word_max = (builder)->word_left; \\\n");
+       }
+       if(num_float_regs > 0)
+       {
+               printf("\t\t(builder)->float_regs = (builder)->apply_args + %d; \\\n",
+                          reg_offset);
+               printf("\t\t(builder)->float_left = %d; \\\n", num_float_regs);
+       }
+       printf("\t\t(builder)->struct_return = 0; \\\n");
+       printf("\t} while (0)\n\n");
+
+       /* Macro to add a word argument to the apply parameters */
+       printf("#define jit_apply_builder_add_word(builder,value) \\\n");
+       printf("\tdo { \\\n");
+       if(num_word_regs > 0 || x86_fastcall)
+       {
+               printf("\t\tif((builder)->word_left > 0) \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\t*((jit_nint *)((builder)->word_regs)) = (jit_nint)(value); \\\n");
+               printf("\t\t\t(builder)->word_regs += sizeof(jit_nint); \\\n");
+               if(struct_reg_overlaps_word_reg)
+               {
+                       /* We need to set the struct register slot as well */
+                       printf("\t\t\tif((builder)->word_left == %d) \\\n", num_word_regs);
+                       printf("\t\t\t{ \\\n");
+                       printf("\t\t\t\t((jit_nint *)((builder)->apply_args))[1] = (jit_nint)(value); \\\n");
+                       printf("\t\t\t} \\\n");
+               }
+               printf("\t\t\t--((builder)->word_left); \\\n");
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\t*((jit_nint*)((builder)->stack_args + (builder)->stack_used)) = (jit_nint)(value); \\\n");
+               printf("\t\t\t(builder)->stack_used += sizeof(jit_nint); \\\n");
+               printf("\t\t} \\\n");
+       }
+       else
+       {
+               printf("\t\t*((jit_nint*)((builder)->stack_args + (builder)->stack_used)) = (jit_nint)(value); \\\n");
+               printf("\t\t(builder)->stack_used += sizeof(jit_nint); \\\n");
+       }
+       printf("\t} while (0)\n\n");
+
+       /* Macro to get a word argument from the apply parameters */
+       printf("#define jit_apply_parser_get_word(builder,type,value) \\\n");
+       printf("\tdo { \\\n");
+       if(num_word_regs > 0 || x86_fastcall)
+       {
+               printf("\t\tif((builder)->word_left > 0) \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\t(value) = (type)(*((jit_nint *)((builder)->word_regs))); \\\n");
+               printf("\t\t\t(builder)->word_regs += sizeof(jit_nint); \\\n");
+               printf("\t\t\t--((builder)->word_left); \\\n");
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\t(value) = (type)(*((jit_nint*)((builder)->stack_args + (builder)->stack_used))); \\\n");
+               printf("\t\t\t(builder)->stack_used += sizeof(jit_nint); \\\n");
+               printf("\t\t} \\\n");
+       }
+       else
+       {
+               printf("\t\t(value) = (type)(*((jit_nint*)((builder)->stack_args + (builder)->stack_used))); \\\n");
+               printf("\t\t(builder)->stack_used += sizeof(jit_nint); \\\n");
+       }
+       printf("\t} while (0)\n\n");
+
+       /* Macro to add a large (e.g. dword) argument to the apply parameters */
+       printf("#define jit_apply_builder_add_large(builder,type,value) \\\n");
+       printf("\tdo { \\\n");
+       printf("\t\ttype __temp = (type)(value); \\\n");
+       printf("\t\tunsigned int __num_words = (sizeof(__temp) + sizeof(jit_nint) - 1) / sizeof(jit_nint); \\\n");
+       if(num_word_regs > 0 || x86_fastcall)
+       {
+               if(align_long_regs)
+               {
+                       printf("\t\tif((builder)->word_left > 0 && \\\n");
+                       printf("\t\t   (((builder)->word_max - (builder)->word_left) %% 2) == 1) \\\n");
+                       printf("\t\t{ \\\n");
+                       printf("\t\t\t(builder)->word_regs += sizeof(jit_nint); \\\n");
+                       printf("\t\t\t--((builder)->word_left); \\\n");
+                       printf("\t\t} \\\n");
+               }
+               printf("\t\tif((builder)->word_left >= __num_words) \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\tjit_memcpy((builder)->word_regs, &__temp, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->word_regs += __num_words * sizeof(jit_nint); \\\n");
+               printf("\t\t\t(builder)->word_left -= __num_words; \\\n");
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               printf("\t\t{ \\\n");
+               if(align_long_stack)
+               {
+                       printf("\t\t\tif(((builder)->stack_used %% sizeof(jit_long)) != 0) \\\n");
+                       printf("\t\t\t{ \\\n");
+                       printf("\t\t\t\t(builder)->stack_used += sizeof(jit_long) - ((builder)->stack_used %% sizeof(jit_long)); \\\n");
+                       printf("\t\t\t} \\\n");
+               }
+               printf("\t\t\tjit_memcpy((builder)->stack_args + (builder)->stack_used, &__temp, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+               printf("\t\t\t(builder)->word_left = 0; \\\n");
+               printf("\t\t} \\\n");
+       }
+       else
+       {
+               if(align_long_stack)
+               {
+                       printf("\t\tif(((builder)->stack_used %% sizeof(jit_long)) != 0) \\\n");
+                       printf("\t\t{ \\\n");
+                       printf("\t\t\t(builder)->stack_used += sizeof(jit_long) - ((builder)->stack_used %% sizeof(jit_long)); \\\n");
+                       printf("\t\t} \\\n");
+               }
+               printf("\t\tjit_memcpy((builder)->stack_args + (builder)->stack_used, &__temp, sizeof(__temp)); \\\n");
+               printf("\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+       }
+       printf("\t} while (0)\n\n");
+
+       /* Macro to get a large (e.g. dword) argument from the apply parameters */
+       printf("#define jit_apply_parser_get_large(builder,type,finaltype,value) \\\n");
+       printf("\tdo { \\\n");
+       printf("\t\ttype __temp; \\\n");
+       printf("\t\tunsigned int __num_words = (sizeof(__temp) + sizeof(jit_nint) - 1) / sizeof(jit_nint); \\\n");
+       if(num_word_regs > 0 || x86_fastcall)
+       {
+               if(align_long_regs)
+               {
+                       printf("\t\tif((builder)->word_left > 0 && \\\n");
+                       printf("\t\t   (((builder)->word_max - (builder)->word_left) %% 2) == 1) \\\n");
+                       printf("\t\t{ \\\n");
+                       printf("\t\t\t(builder)->word_regs += sizeof(jit_nint); \\\n");
+                       printf("\t\t\t--((builder)->word_left); \\\n");
+                       printf("\t\t} \\\n");
+               }
+               printf("\t\tif((builder)->word_left >= __num_words) \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\tjit_memcpy(&__temp, (builder)->word_regs, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->word_regs += __num_words * sizeof(jit_nint); \\\n");
+               printf("\t\t\t(builder)->word_left -= __num_words; \\\n");
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               printf("\t\t{ \\\n");
+               if(align_long_stack)
+               {
+                       printf("\t\t\tif(((builder)->stack_used %% sizeof(jit_long)) != 0) \\\n");
+                       printf("\t\t\t{ \\\n");
+                       printf("\t\t\t\t(builder)->stack_used += sizeof(jit_long) - ((builder)->stack_used %% sizeof(jit_long)); \\\n");
+                       printf("\t\t\t} \\\n");
+               }
+               printf("\t\t\tjit_memcpy(&__temp, (builder)->stack_args + (builder)->stack_used, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+               printf("\t\t\t(builder)->word_left = 0; \\\n");
+               printf("\t\t} \\\n");
+       }
+       else
+       {
+               if(align_long_stack)
+               {
+                       printf("\t\tif(((builder)->stack_used %% sizeof(jit_long)) != 0) \\\n");
+                       printf("\t\t{ \\\n");
+                       printf("\t\t\t(builder)->stack_used += sizeof(jit_long) - ((builder)->stack_used %% sizeof(jit_long)); \\\n");
+                       printf("\t\t} \\\n");
+               }
+               printf("\t\tjit_memcpy(&__temp, (builder)->stack_args + (builder)->stack_used, sizeof(__temp)); \\\n");
+               printf("\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+       }
+       printf("\t\t(value) = (finaltype)(__temp); \\\n");
+       printf("\t} while (0)\n\n");
+
+       /* Macro to add a large (e.g. dword) argument to the apply parameters
+          on the stack, ignoring word registers */
+       printf("#define jit_apply_builder_add_large_stack(builder,type,value) \\\n");
+       printf("\tdo { \\\n");
+       printf("\t\ttype __temp = (type)(value); \\\n");
+       printf("\t\tunsigned int __num_words = (sizeof(__temp) + sizeof(jit_nint) - 1) / sizeof(jit_nint); \\\n");
+       if(align_long_stack)
+       {
+               printf("\t\tif(((builder)->stack_used %% sizeof(jit_long)) != 0) \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\t(builder)->stack_used += sizeof(jit_long) - ((builder)->stack_used %% sizeof(jit_long)); \\\n");
+               printf("\t\t} \\\n");
+       }
+       printf("\t\tjit_memcpy((builder)->stack_args + (builder)->stack_used, &__temp, sizeof(__temp)); \\\n");
+       printf("\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+       printf("\t} while (0)\n\n");
+
+       /* Macro to get a large (e.g. dword) argument from the apply parameters
+          on the stack, ignoring word registers */
+       printf("#define jit_apply_parser_get_large_stack(builder,type,finaltype,value) \\\n");
+       printf("\tdo { \\\n");
+       printf("\t\ttype __temp; \\\n");
+       printf("\t\tunsigned int __num_words = (sizeof(__temp) + sizeof(jit_nint) - 1) / sizeof(jit_nint); \\\n");
+       if(align_long_stack)
+       {
+               printf("\t\tif(((builder)->stack_used %% sizeof(jit_long)) != 0) \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\t(builder)->stack_used += sizeof(jit_long) - ((builder)->stack_used %% sizeof(jit_long)); \\\n");
+               printf("\t\t} \\\n");
+       }
+       printf("\t\tjit_memcpy(&__temp, (builder)->stack_args + (builder)->stack_used, sizeof(__temp)); \\\n");
+       printf("\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+       printf("\t\t(value) = (finaltype)(__temp); \\\n");
+       printf("\t} while (0)\n\n");
+
+       /* Macro to add a large argument to the apply parameters with no alignment */
+       printf("#define jit_apply_builder_add_large_noalign(builder,type,value) \\\n");
+       printf("\tdo { \\\n");
+       printf("\t\ttype __temp = (type)(value); \\\n");
+       printf("\t\tunsigned int __num_words = (sizeof(__temp) + sizeof(jit_nint) - 1) / sizeof(jit_nint); \\\n");
+       if(num_word_regs > 0 || x86_fastcall)
+       {
+               printf("\t\tif((builder)->word_left >= __num_words) \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\tjit_memcpy((builder)->word_regs, &__temp, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->word_regs += __num_words * sizeof(jit_nint); \\\n");
+               printf("\t\t\t(builder)->word_left -= __num_words; \\\n");
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\tjit_memcpy((builder)->stack_args + (builder)->stack_used, &__temp, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+               printf("\t\t\t(builder)->word_left = 0; \\\n");
+               printf("\t\t} \\\n");
+       }
+       else
+       {
+               printf("\t\tjit_memcpy((builder)->stack_args + (builder)->stack_used, &__temp, sizeof(__temp)); \\\n");
+               printf("\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+       }
+       printf("\t} while (0)\n\n");
+
+       /* Macro to set the structure return area */
+       printf("#define jit_apply_builder_add_struct_return(builder,size,return_buf) \\\n");
+       printf("\tdo { \\\n");
+       printf("\t\tunsigned int __struct_size = (unsigned int)(size); \\\n");
+       printf("\t\tif(__struct_size >= 1 && __struct_size <= 64 && \\\n");
+       printf("\t\t   (_jit_apply_return_in_reg[(__struct_size - 1) / 8] \\\n");
+       printf("\t\t       & (1 << ((__struct_size - 1) %% 8))) != 0) \\\n");
+       printf("\t\t{ \\\n");
+       printf("\t\t\t(builder)->struct_return = 0; \\\n");
+       printf("\t\t} \\\n");
+       printf("\t\telse \\\n");
+       printf("\t\t{ \\\n");
+       printf("\t\t\tif((return_buf) != 0) \\\n");
+       printf("\t\t\t\t(builder)->struct_return = (void *)(return_buf); \\\n");
+       printf("\t\t\telse \\\n");
+       printf("\t\t\t\t(builder)->struct_return = alloca(__struct_size); \\\n");
+       if(struct_return_special_reg && !struct_reg_overlaps_word_reg)
+       {
+               printf("\t\t\t((void **)((builder)->apply_args))[1] = (builder)->struct_return; \\\n");
+       }
+       else
+       {
+               printf("\t\t\tjit_apply_builder_add_word((builder), (builder)->struct_return); \\\n");
+       }
+       printf("\t\t} \\\n");
+       printf("\t} while (0)\n\n");
+
+       /* Macro to extract the structure return value, if it is in registers */
+       printf("#define jit_apply_builder_get_struct_return(builder,size,return_buf,apply_return) \\\n");
+       printf("\tdo { \\\n");
+       printf("\t\tif(!((builder)->struct_return)) \\\n");
+       printf("\t\t{ \\\n");
+       printf("\t\t\tjit_memcpy((return_buf), (apply_return), (size)); \\\n");
+       printf("\t\t} \\\n");
+       printf("\t\telse if((builder)->struct_return != (void *)(return_buf)) \\\n");
+       printf("\t\t{ \\\n");
+       printf("\t\t\tjit_memcpy((return_buf), (builder)->struct_return, (size)); \\\n");
+       printf("\t\t} \\\n");
+       printf("\t} while (0)\n\n");
+
+       /* Macro to start the vararg area */
+       printf("#define jit_apply_builder_start_varargs(builder) \\\n");
+       printf("\tdo { \\\n");
+       if(varargs_on_stack)
+       {
+               if(num_word_regs > 0 || x86_fastcall)
+               {
+                       printf("\t\t(builder)->word_left = 0; \\\n");
+               }
+               if(num_float_regs > 0)
+               {
+                       printf("\t\t(builder)->float_left = 0; \\\n");
+               }
+       }
+       printf("\t} while (0)\n\n");
+
+       /* Macro to start the vararg area when parsing a closure */
+       printf("#define jit_apply_parser_start_varargs(builder) \\\n");
+       printf("\tdo { \\\n");
+       if(varargs_on_stack)
+       {
+               if(num_word_regs > 0 || x86_fastcall)
+               {
+                       printf("\t\t(builder)->word_left = 0; \\\n");
+               }
+               if(num_float_regs > 0)
+               {
+                       printf("\t\t(builder)->float_left = 0; \\\n");
+               }
+       }
+       printf("\t} while (0)\n\n");
+
+       /* Add parameter values of various types */
+       printf("#define jit_apply_builder_add_sbyte(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_word((builder), (value));\n");
+       printf("#define jit_apply_builder_add_ubyte(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_word((builder), (value));\n");
+       printf("#define jit_apply_builder_add_short(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_word((builder), (value));\n");
+       printf("#define jit_apply_builder_add_ushort(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_word((builder), (value));\n");
+       printf("#define jit_apply_builder_add_int(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_word((builder), (value));\n");
+       printf("#define jit_apply_builder_add_uint(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_word((builder), (jit_nuint)(value));\n");
+       printf("#define jit_apply_builder_add_nint(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_word((builder), (value));\n");
+       printf("#define jit_apply_builder_add_nuint(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_word((builder), (jit_nuint)(value));\n");
+#ifdef JIT_NATIVE_INT32
+       printf("#define jit_apply_builder_add_long(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_large((builder), jit_long, (value));\n");
+       printf("#define jit_apply_builder_add_ulong(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_large((builder), jit_ulong, (value));\n");
+#else
+       printf("#define jit_apply_builder_add_long(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_word((builder), (value));\n");
+       printf("#define jit_apply_builder_add_ulong(builder,value) \\\n");
+       printf("\tjit_apply_builder_add_word((builder), (jit_nuint)(value));\n");
+#endif
+       if(num_float_regs > 0)
+       {
+               /* Pass floating point values in registers, if possible */
+               printf("#define jit_apply_builder_add_float32(builder,value) \\\n");
+               printf("\tdo { \\\n");
+               printf("\t\tif((builder)->float_left > 0) \\\n");
+               printf("\t\t{ \\\n");
+               if(pass_reg_float_as_double)
+                       name = "jit_float64";
+               else if(pass_reg_float_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float32";
+               printf("\t\t\t*((%s *)((builder)->float_regs)) = (%s)(value); \\\n",
+                          name, name);
+               printf("\t\t\t(builder)->float_regs += sizeof(%s); \\\n", name);
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               printf("\t\t{ \\\n");
+               if(pass_stack_float_as_double)
+                       name = "jit_float64";
+               else if(pass_stack_float_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float32";
+               printf("\t\t\t%s __temp = (%s)(value); \\\n", name, name);
+               printf("\t\t\tjit_memcpy((builder)->stack_args + (builder)->stack_used, &__temp, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->stack_used += (sizeof(%s) + sizeof(jit_nint) - 1) & ~(sizeof(jit_nint) - 1); \\\n", name);
+               printf("\t\t} \\\n");
+               printf("\t} while (0)\n");
+
+               printf("#define jit_apply_builder_add_float64(builder,value) \\\n");
+               printf("\tdo { \\\n");
+               printf("\t\tif((builder)->float_left > 0) \\\n");
+               printf("\t\t{ \\\n");
+               if(pass_reg_double_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float64";
+               printf("\t\t\t*((%s *)((builder)->float_regs)) = (%s)(value); \\\n",
+                          name, name);
+               printf("\t\t\t(builder)->float_regs += sizeof(%s); \\\n", name);
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               if(pass_stack_double_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float64";
+               printf("\t\t{ \\\n");
+               printf("\t\t\t%s __temp = (%s)(value); \\\n", name, name);
+               printf("\t\t\tjit_memcpy((builder)->stack_args + (builder)->stack_used, &__temp, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->stack_used += (sizeof(%s) + sizeof(jit_nint) - 1) & ~(sizeof(jit_nint) - 1); \\\n", name);
+               printf("\t\t} \\\n");
+               printf("\t} while (0)\n");
+
+               printf("#define jit_apply_builder_add_nfloat(builder,value) \\\n");
+               printf("\tdo { \\\n");
+               printf("\t\tif((builder)->float_left > 0) \\\n");
+               printf("\t\t{ \\\n");
+               if(pass_reg_nfloat_as_double)
+                       name = "jit_float64";
+               else
+                       name = "jit_nfloat";
+               printf("\t\t\t*((%s *)((builder)->float_regs)) = (%s)(value); \\\n",
+                          name, name);
+               printf("\t\t\t(builder)->float_regs += sizeof(%s); \\\n", name);
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               if(pass_stack_nfloat_as_double)
+                       name = "jit_float64";
+               else
+                       name = "jit_nfloat";
+               printf("\t\t{ \\\n");
+               printf("\t\t\t%s __temp = (%s)(value); \\\n", name, name);
+               printf("\t\t\tjit_memcpy((builder)->stack_args + (builder)->stack_used, &__temp, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->stack_used += (sizeof(%s) + sizeof(jit_nint) - 1) & ~(sizeof(jit_nint) - 1); \\\n", name);
+               printf("\t\t} \\\n");
+               printf("\t} while (0)\n");
+       }
+       else if(floats_in_word_regs)
+       {
+               /* Pass floating point values in word registers */
+               if(pass_reg_float_as_double)
+                       name = "jit_float64";
+               else if(pass_reg_float_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float32";
+               printf("#define jit_apply_builder_add_float32(builder,value) \\\n");
+               printf("\tjit_apply_builder_add_large((builder), %s, (value));\n", name);
+
+               if(pass_reg_double_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float64";
+               printf("#define jit_apply_builder_add_float64(builder,value) \\\n");
+               printf("\tjit_apply_builder_add_large((builder), %s, (value));\n", name);
+
+               if(pass_reg_nfloat_as_double)
+                       name = "jit_float64";
+               else
+                       name = "jit_nfloat";
+               printf("#define jit_apply_builder_add_nfloat(builder,value) \\\n");
+               printf("\tjit_apply_builder_add_large((builder), %s, (value));\n", name);
+       }
+       else
+       {
+               /* Pass floating point values on the stack */
+               if(pass_stack_float_as_double)
+                       name = "jit_float64";
+               else if(pass_stack_float_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float32";
+               printf("#define jit_apply_builder_add_float32(builder,value) \\\n");
+               printf("\tjit_apply_builder_add_large_stack((builder), %s, (value));\n", name);
+
+               if(pass_stack_double_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float64";
+               printf("#define jit_apply_builder_add_float64(builder,value) \\\n");
+               printf("\tjit_apply_builder_add_large_stack((builder), %s, (value));\n", name);
+
+               if(pass_stack_nfloat_as_double)
+                       name = "jit_float64";
+               else
+                       name = "jit_nfloat";
+               printf("#define jit_apply_builder_add_nfloat(builder,value) \\\n");
+               printf("\tjit_apply_builder_add_large_stack((builder), %s, (value));\n", name);
+       }
+       printf("#define jit_apply_builder_add_struct(builder,value,size,align) \\\n");
+       printf("\tdo { \\\n");
+       printf("\t\tunsigned int __size = (size); \\\n");
+       if(align_long_regs || align_long_stack)
+       {
+               printf("\t\tunsigned int __align = (align); \\\n");
+       }
+       printf("\t\tunsigned int __num_words = (__size + sizeof(jit_nint) - 1) / sizeof(jit_nint); \\\n");
+       if(num_word_regs > 0 || x86_fastcall)
+       {
+               if(align_long_regs)
+               {
+                       printf("\t\tif(__align >= sizeof(jit_long) && \\\n");
+                       printf("\t\t   (builder)->word_left > 0 && \\\n");
+                       printf("\t\t   (((builder)->word_max - (builder)->word_left) %% 2) == 1) \\\n");
+                       printf("\t\t{ \\\n");
+                       printf("\t\t\t(builder)->word_regs += sizeof(jit_nint); \\\n");
+                       printf("\t\t\t--((builder)->word_left); \\\n");
+                       printf("\t\t} \\\n");
+               }
+               printf("\t\tif((builder)->word_left >= __num_words) \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\tjit_memcpy((builder)->word_regs, (value), __size); \\\n");
+               printf("\t\t\t(builder)->word_regs += __num_words * sizeof(jit_nint); \\\n");
+               printf("\t\t\t(builder)->word_left -= __num_words; \\\n");
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               printf("\t\t{ \\\n");
+               if(align_long_stack)
+               {
+                       printf("\t\t\tif(__align >= sizeof(jit_long) && \\\n");
+                       printf("\t\t\t   ((builder)->stack_used %% sizeof(jit_long)) != 0) \\\n");
+                       printf("\t\t\t{ \\\n");
+                       printf("\t\t\t\t(builder)->stack_used += sizeof(jit_long) - ((builder)->stack_used %% sizeof(jit_long)); \\\n");
+                       printf("\t\t\t} \\\n");
+               }
+               printf("\t\t\tjit_memcpy((builder)->stack_args + (builder)->stack_used, (value), __size); \\\n");
+               printf("\t\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+               printf("\t\t\t(builder)->word_left = 0; \\\n");
+               printf("\t\t} \\\n");
+       }
+       else
+       {
+               if(align_long_stack)
+               {
+                       printf("\t\tif(__align >= sizeof(jit_long) && \\\n");
+                       printf("\t\t   ((builder)->stack_used %% sizeof(jit_long)) != 0) \\\n");
+                       printf("\t\t{ \\\n");
+                       printf("\t\t\t(builder)->stack_used += sizeof(jit_long) - ((builder)->stack_used %% sizeof(jit_long)); \\\n");
+                       printf("\t\t} \\\n");
+               }
+               printf("\t\tjit_memcpy((builder)->stack_args + (builder)->stack_used, (value), __size); \\\n");
+               printf("\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+       }
+       printf("\t} while (0)\n\n");
+
+       printf("\n");
+
+       /* Get parameter values of various types from a closure's arguments */
+       printf("#define jit_apply_parser_get_sbyte(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_word((builder), jit_sbyte, (value));\n");
+       printf("#define jit_apply_parser_get_ubyte(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_word((builder), jit_ubyte, (value));\n");
+       printf("#define jit_apply_parser_get_short(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_word((builder), jit_short, (value));\n");
+       printf("#define jit_apply_parser_get_ushort(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_word((builder), jit_ushort, (value));\n");
+       printf("#define jit_apply_parser_get_int(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_word((builder), jit_int, (value));\n");
+       printf("#define jit_apply_parser_get_uint(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_word((builder), jit_uint, (value));\n");
+       printf("#define jit_apply_parser_get_nint(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_word((builder), jit_nint, (value));\n");
+       printf("#define jit_apply_parser_get_nuint(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_word((builder), jit_nuint, (value));\n");
+#ifdef JIT_NATIVE_INT32
+       printf("#define jit_apply_parser_get_long(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_large((builder), jit_long, jit_long, (value));\n");
+       printf("#define jit_apply_parser_get_ulong(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_large((builder), jit_ulong, jit_ulong, (value));\n");
+#else
+       printf("#define jit_apply_parser_get_long(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_word((builder), jit_long, (value));\n");
+       printf("#define jit_apply_parser_get_ulong(builder,value) \\\n");
+       printf("\tjit_apply_parser_get_word((builder), jit_ulong, (value));\n");
+#endif
+       if(num_float_regs > 0)
+       {
+               /* Pass floating point values in registers, if possible */
+               printf("#define jit_apply_parser_get_float32(builder,value) \\\n");
+               printf("\tdo { \\\n");
+               printf("\t\tif((builder)->float_left > 0) \\\n");
+               printf("\t\t{ \\\n");
+               if(pass_reg_float_as_double)
+                       name = "jit_float64";
+               else if(pass_reg_float_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float32";
+               printf("\t\t\t(value) = (jit_float32)(*((%s *)((builder)->float_regs))); \\\n",
+                          name);
+               printf("\t\t\t(builder)->float_regs += sizeof(%s); \\\n", name);
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               printf("\t\t{ \\\n");
+               if(pass_stack_float_as_double)
+                       name = "jit_float64";
+               else if(pass_stack_float_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float32";
+               printf("\t\t\t%s __temp; \\\n", name);
+               printf("\t\t\tjit_memcpy(&__temp, (builder)->stack_args + (builder)->stack_used, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->stack_used += (sizeof(%s) + sizeof(jit_nint) - 1) & ~(sizeof(jit_nint) - 1); \\\n", name);
+               printf("\t\t\t(value) = (jit_float32)__temp; \\\n");
+               printf("\t\t} \\\n");
+               printf("\t} while (0)\n");
+
+               printf("#define jit_apply_parser_get_float64(builder,value) \\\n");
+               printf("\tdo { \\\n");
+               printf("\t\tif((builder)->float_left > 0) \\\n");
+               printf("\t\t{ \\\n");
+               if(pass_reg_double_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float64";
+               printf("\t\t\t(value) = (jit_float64)(*((%s *)((builder)->float_regs))); \\\n",
+                          name);
+               printf("\t\t\t(builder)->float_regs += sizeof(%s); \\\n", name);
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               if(pass_stack_double_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float64";
+               printf("\t\t{ \\\n");
+               printf("\t\t\t%s __temp; \\\n", name);
+               printf("\t\t\tjit_memcpy(&__temp, (builder)->stack_args + (builder)->stack_used, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->stack_used += (sizeof(%s) + sizeof(jit_nint) - 1) & ~(sizeof(jit_nint) - 1); \\\n", name);
+               printf("\t\t\t(value) = (jit_float64)__temp; \\\n");
+               printf("\t\t} \\\n");
+               printf("\t} while (0)\n");
+
+               printf("#define jit_apply_parser_get_nfloat(builder,value) \\\n");
+               printf("\tdo { \\\n");
+               printf("\t\tif((builder)->float_left > 0) \\\n");
+               printf("\t\t{ \\\n");
+               if(pass_reg_nfloat_as_double)
+                       name = "jit_float64";
+               else
+                       name = "jit_nfloat";
+               printf("\t\t\t(value) = (jit_nfloat)(*((%s *)((builder)->float_regs))); \\\n",
+                          name);
+               printf("\t\t\t(builder)->float_regs += sizeof(%s); \\\n", name);
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               if(pass_stack_nfloat_as_double)
+                       name = "jit_float64";
+               else
+                       name = "jit_nfloat";
+               printf("\t\t{ \\\n");
+               printf("\t\t\t%s __temp; \\\n", name);
+               printf("\t\t\tjit_memcpy(&__temp, (builder)->stack_args + (builder)->stack_used, sizeof(__temp)); \\\n");
+               printf("\t\t\t(builder)->stack_used += (sizeof(%s) + sizeof(jit_nint) - 1) & ~(sizeof(jit_nint) - 1); \\\n", name);
+               printf("\t\t\t(value) = (jit_nfloat)__temp; \\\n");
+               printf("\t\t} \\\n");
+               printf("\t} while (0)\n");
+       }
+       else if(floats_in_word_regs)
+       {
+               /* Pass floating point values in word registers */
+               if(pass_reg_float_as_double)
+                       name = "jit_float64";
+               else if(pass_reg_float_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float32";
+               printf("#define jit_apply_parser_get_float32(builder,value) \\\n");
+               printf("\tjit_apply_parser_get_large((builder), %s, jit_float32, (value));\n", name);
+
+               if(pass_reg_double_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float64";
+               printf("#define jit_apply_parser_get_float64(builder,value) \\\n");
+               printf("\tjit_apply_parser_get_large((builder), %s, jit_float64, (value));\n", name);
+
+               if(pass_reg_nfloat_as_double)
+                       name = "jit_float64";
+               else
+                       name = "jit_nfloat";
+               printf("#define jit_apply_parser_get_nfloat(builder,value) \\\n");
+               printf("\tjit_apply_parser_get_large((builder), %s, jit_nfloat, (value));\n", name);
+       }
+       else
+       {
+               /* Pass floating point values on the stack */
+               if(pass_stack_float_as_double)
+                       name = "jit_float64";
+               else if(pass_stack_float_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float32";
+               printf("#define jit_apply_parser_get_float32(builder,value) \\\n");
+               printf("\tjit_apply_parser_get_large_stack((builder), %s, jit_float32, (value));\n", name);
+
+               if(pass_stack_double_as_nfloat)
+                       name = "jit_nfloat";
+               else
+                       name = "jit_float64";
+               printf("#define jit_apply_parser_get_float64(builder,value) \\\n");
+               printf("\tjit_apply_parser_get_large_stack((builder), %s, jit_float64, (value));\n", name);
+
+               if(pass_stack_nfloat_as_double)
+                       name = "jit_float64";
+               else
+                       name = "jit_nfloat";
+               printf("#define jit_apply_parser_get_nfloat(builder,value) \\\n");
+               printf("\tjit_apply_parser_get_large_stack((builder), %s, jit_nfloat, (value));\n", name);
+       }
+       printf("#define jit_apply_parser_get_struct_return(builder,value) \\\n");
+       if(struct_return_special_reg && !struct_reg_overlaps_word_reg)
+       {
+               printf("\tdo { \\\n");
+               printf("\t\t(value) = ((void **)((builder)->apply_args))[1]; \\\n");
+               printf("\t} while (0)\n");
+       }
+       else
+       {
+               printf("\tjit_apply_parser_get_word((builder), void *, (value));\n");
+       }
+       printf("#define jit_apply_parser_get_struct(builder,size,align,value) \\\n");
+       printf("\tdo { \\\n");
+       printf("\t\tunsigned int __size = (size); \\\n");
+       if(align_long_regs || align_long_stack)
+       {
+               printf("\t\tunsigned int __align = (align); \\\n");
+       }
+       printf("\t\tunsigned int __num_words = (__size + sizeof(jit_nint) - 1) / sizeof(jit_nint); \\\n");
+       if(num_word_regs > 0 || x86_fastcall)
+       {
+               if(align_long_regs)
+               {
+                       printf("\t\tif(__align >= sizeof(jit_long) && \\\n");
+                       printf("\t\t   (builder)->word_left > 0 && \\\n");
+                       printf("\t\t   (((builder)->word_max - (builder)->word_left) %% 2) == 1) \\\n");
+                       printf("\t\t{ \\\n");
+                       printf("\t\t\t(builder)->word_regs += sizeof(jit_nint); \\\n");
+                       printf("\t\t\t--((builder)->word_left); \\\n");
+                       printf("\t\t} \\\n");
+               }
+               printf("\t\tif((builder)->word_left >= __num_words) \\\n");
+               printf("\t\t{ \\\n");
+               printf("\t\t\tjit_memcpy((value), (builder)->word_regs, __size); \\\n");
+               printf("\t\t\t(builder)->word_regs += __num_words * sizeof(jit_nint); \\\n");
+               printf("\t\t\t(builder)->word_left -= __num_words; \\\n");
+               printf("\t\t} \\\n");
+               printf("\t\telse \\\n");
+               printf("\t\t{ \\\n");
+               if(align_long_stack)
+               {
+                       printf("\t\t\tif(__align >= sizeof(jit_long) && \\\n");
+                       printf("\t\t\t   ((builder)->stack_used %% sizeof(jit_long)) != 0) \\\n");
+                       printf("\t\t\t{ \\\n");
+                       printf("\t\t\t\t(builder)->stack_used += sizeof(jit_long) - ((builder)->stack_used %% sizeof(jit_long)); \\\n");
+                       printf("\t\t\t} \\\n");
+               }
+               printf("\t\t\tjit_memcpy((value), (builder)->stack_args + (builder)->stack_used, __size); \\\n");
+               printf("\t\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+               printf("\t\t\t(builder)->word_left = 0; \\\n");
+               printf("\t\t} \\\n");
+       }
+       else
+       {
+               if(align_long_stack)
+               {
+                       printf("\t\tif(__align >= sizeof(jit_long) && \\\n");
+                       printf("\t\t   ((builder)->stack_used %% sizeof(jit_long)) != 0) \\\n");
+                       printf("\t\t{ \\\n");
+                       printf("\t\t\t(builder)->stack_used += sizeof(jit_long) - ((builder)->stack_used %% sizeof(jit_long)); \\\n");
+                       printf("\t\t} \\\n");
+               }
+               printf("\t\tjit_memcpy((value), (builder)->stack_args + (builder)->stack_used, __size); \\\n");
+               printf("\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
+       }
+       printf("\t} while (0)\n");
+       printf("\n");
+}
+
+int main(int argc, char *argv[])
+{
+       int size;
+       int flags;
+
+       /* Detect the number of word registers */
+       detect_word_regs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+                        14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+                                        27, 28, 29, 30, 31);
+
+       /* Detect the presence of a structure return register if
+          "detect_word_regs" was unable to do so */
+       if(num_word_regs <= 1)
+       {
+               detect_struct_buf = detect_struct_return(1, 2);
+       }
+
+       /* Determine if the special structure register overlaps a word register */
+       detect_struct_buf = detect_struct_overlap(1, 2);
+
+       /* Detect the number of floating-point registers */
+       detect_float_regs(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0,
+                                         9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0,
+                                         17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0,
+                                         25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0);
+
+       /* Determine if floating-point values are passed in word registers */
+       if(num_float_regs > 0 && num_word_regs > 0)
+       {
+       #ifdef JIT_NATIVE_INT32
+               if(num_word_regs == 1)
+               {
+                       detect_float_overlap((float)(123.78), 1);
+               }
+               else
+       #endif
+               {
+                       detect_double_overlap(123.78, 1, 2);
+               }
+       }
+
+       /* Determine if "long double" values should be demoted to "double" */
+       if(floats_in_word_regs)
+       {
+               pass_reg_nfloat_as_double = 1;
+       }
+       else if(num_float_regs > 0)
+       {
+               detect_float_reg_size_regs(48.67, 182.36);
+       }
+       else
+       {
+               detect_float_reg_size_stack(48.67, 182.36);
+       }
+       if(sizeof(jit_float64) == sizeof(jit_nfloat))
+       {
+               pass_stack_nfloat_as_double = 1;
+               pass_reg_nfloat_as_double = 1;
+       }
+
+       /* Determine if "float" should be promoted to "double" */
+       detect_float_promotion(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0,
+                                              9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0,
+                                              17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0,
+                                              25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0);
+
+       /* Determine if "double" should be promoted to "nfloat" */
+       detect_double_promotion(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0,
+                                               9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0,
+                                               17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0,
+                                               25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0);
+
+       /* Detect the alignment of "long" values in registers and on the stack */
+#ifdef JIT_NATIVE_INT32
+       if(num_word_regs > 1)
+       {
+               /* TODO */
+       }
+       else
+       {
+               /* TODO */
+       }
+#endif
+
+       /* Determine if variable arguments are always passed on the stack */
+       detect_varargs_on_stack(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+                               14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+                                               27, 28, 29, 30, 31);
+
+       /* Detect the size and positioning of floating-point return values */
+       detect_float_return();
+
+       /* Detect the calling conventions for structures */
+       detect_struct_conventions();
+
+       /* Detect support for x86 FASTCALL handling code (Win32 only) */
+#if defined(PLATFORM_IS_WIN32)
+       x86_fastcall = 1;
+#endif
+
+       /* Detect whether x86 platforms pop the structure return pointer */
+#if defined(PLATFORM_IS_X86)
+       x86_pop_struct_return = 1;
+       /* TODO */
+#endif
+
+       /* Determine the maximum sizes */
+       detect_max_sizes();
+
+       /* Detect the location of parent frames and return addresses
+          in the value returned by "__builtin_frame_address" */
+       detect_frame_offsets();
+
+       /* Print the results */
+       printf("/%c This file was auto-generated by \"gen-apply\" - DO NOT EDIT %c/\n\n", '*', '*');
+       printf("#ifndef _JIT_APPLY_RULES_H\n");
+       printf("#define _JIT_APPLY_RULES_H\n\n");
+       printf("#define JIT_APPLY_NUM_WORD_REGS %d\n", num_word_regs);
+       printf("#define JIT_APPLY_NUM_FLOAT_REGS %d\n", num_float_regs);
+       printf("#define JIT_APPLY_PASS_STACK_FLOAT_AS_DOUBLE %d\n",
+                  pass_stack_float_as_double);
+       printf("#define JIT_APPLY_PASS_STACK_FLOAT_AS_NFLOAT %d\n",
+                  pass_stack_float_as_nfloat);
+       printf("#define JIT_APPLY_PASS_STACK_DOUBLE_AS_NFLOAT %d\n",
+                  pass_stack_double_as_nfloat);
+       printf("#define JIT_APPLY_PASS_STACK_NFLOAT_AS_DOUBLE %d\n",
+                  pass_stack_nfloat_as_double);
+       printf("#define JIT_APPLY_PASS_REG_FLOAT_AS_DOUBLE %d\n",
+                  pass_reg_float_as_double);
+       printf("#define JIT_APPLY_PASS_REG_FLOAT_AS_NFLOAT %d\n",
+                  pass_reg_float_as_nfloat);
+       printf("#define JIT_APPLY_PASS_REG_DOUBLE_AS_NFLOAT %d\n",
+                  pass_reg_double_as_nfloat);
+       printf("#define JIT_APPLY_PASS_REG_NFLOAT_AS_DOUBLE %d\n",
+                  pass_reg_nfloat_as_double);
+       printf("#define JIT_APPLY_RETURN_FLOAT_AS_DOUBLE %d\n", return_float_as_double);
+       printf("#define JIT_APPLY_RETURN_FLOAT_AS_NFLOAT %d\n", return_float_as_nfloat);
+       printf("#define JIT_APPLY_RETURN_DOUBLE_AS_NFLOAT %d\n", return_double_as_nfloat);
+       printf("#define JIT_APPLY_RETURN_NFLOAT_AS_DOUBLE %d\n", return_nfloat_as_double);
+       printf("#define JIT_APPLY_FLOATS_IN_WORD_REGS %d\n", floats_in_word_regs);
+       printf("#define JIT_APPLY_RETURN_FLOATS_AFTER %d\n", return_floats_after);
+       printf("#define JIT_APPLY_VARARGS_ON_STACK %d\n", varargs_on_stack);
+       printf("#define JIT_APPLY_STRUCT_RETURN_SPECIAL_REG %d\n", struct_return_special_reg);
+       printf("#define JIT_APPLY_STRUCT_REG_OVERLAPS_WORD_REG %d\n",
+                  struct_reg_overlaps_word_reg);
+       printf("#define JIT_APPLY_ALIGN_LONG_REGS %d\n", align_long_regs);
+       printf("#define JIT_APPLY_ALIGN_LONG_STACK %d\n", align_long_stack);
+       printf("#define JIT_APPLY_STRUCT_RETURN_IN_REG_INIT \\\n\t{");
+       max_struct_in_reg = 0;
+       for(size = 0; size < 64; size += 8)
+       {
+               flags = 0;
+               if(struct_return_in_reg[size])
+               {
+                       flags |= 0x01;
+                       max_struct_in_reg = size + 1;
+               }
+               if(struct_return_in_reg[size + 1])
+               {
+                       flags |= 0x02;
+                       max_struct_in_reg = size + 2;
+               }
+               if(struct_return_in_reg[size + 2])
+               {
+                       flags |= 0x04;
+                       max_struct_in_reg = size + 3;
+               }
+               if(struct_return_in_reg[size + 3])
+               {
+                       flags |= 0x08;
+                       max_struct_in_reg = size + 4;
+               }
+               if(struct_return_in_reg[size + 4])
+               {
+                       flags |= 0x10;
+                       max_struct_in_reg = size + 5;
+               }
+               if(struct_return_in_reg[size + 5])
+               {
+                       flags |= 0x20;
+                       max_struct_in_reg = size + 6;
+               }
+               if(struct_return_in_reg[size + 6])
+               {
+                       flags |= 0x40;
+                       max_struct_in_reg = size + 7;
+               }
+               if(struct_return_in_reg[size + 7])
+               {
+                       flags |= 0x80;
+                       max_struct_in_reg = size + 8;
+               }
+               if(size != 0)
+               {
+                       printf(", 0x%02X", flags);
+               }
+               else
+               {
+                       printf("0x%02X", flags);
+               }
+       }
+       printf("}\n");
+       printf("#define JIT_APPLY_MAX_STRUCT_IN_REG %d\n", max_struct_in_reg);
+       printf("#define JIT_APPLY_MAX_APPLY_SIZE %d\n", max_apply_size);
+       printf("#define JIT_APPLY_X86_FASTCALL %d\n", x86_fastcall);
+       printf("#define JIT_APPLY_PARENT_FRAME_OFFSET %d\n", parent_frame_offset);
+       printf("#define JIT_APPLY_RETURN_ADDRESS_OFFSET %d\n",
+                  return_address_offset);
+       printf("#define JIT_APPLY_BROKEN_FRAME_BUILTINS %d\n",
+                  broken_frame_builtins);
+       printf("#define JIT_APPLY_X86_POP_STRUCT_RETURN %d\n",
+                  x86_pop_struct_return);
+       printf("\n");
+
+       /* Dump the definition of the "jit_apply_return" union */
+       dump_return_union();
+
+       /* Dump the macros that are used to perform function application */
+       dump_apply_macros();
+
+       /* Print the footer on the output */
+       printf("#endif /%c _JIT_APPLY_RULES_H %c/\n", '*', '*');
+
+       /* Done */
+       return 0;
+}
+
+#else /* !(PLATFORM_IS_GCC || PLATFORM_IS_WIN32) */
+
+int main(int argc, char *argv[])
+{
+       printf("#error \"gcc is required to detect the apply rules\"\n");
+       return 0;
+}
+
+#endif /* !(PLATFORM_IS_GCC || PLATFORM_IS_WIN32) */
diff --git a/tutorial/.cvsignore b/tutorial/.cvsignore
new file mode 100644 (file)
index 0000000..9b064a5
--- /dev/null
@@ -0,0 +1,8 @@
+Makefile
+Makefile.in
+.deps
+*.exe
+t1
+t2
+t3
+t4
diff --git a/tutorial/Makefile.am b/tutorial/Makefile.am
new file mode 100644 (file)
index 0000000..89186a7
--- /dev/null
@@ -0,0 +1,24 @@
+
+noinst_PROGRAMS = t1 t2 t3 t4
+
+CCLD = $(CXX)
+
+t1_SOURCES = t1.c
+t1_LDADD = $(top_builddir)/jit/libjit.a
+t1_DEPENDENCIES = $(top_builddir)/jit/libjit.a
+
+t2_SOURCES = t2.c
+t2_LDADD = $(top_builddir)/jit/libjit.a
+t2_DEPENDENCIES = $(top_builddir)/jit/libjit.a
+
+t3_SOURCES = t3.c
+t3_LDADD = $(top_builddir)/jit/libjit.a
+t3_DEPENDENCIES = $(top_builddir)/jit/libjit.a
+
+t4_SOURCES = t4.cpp
+t4_LDADD = $(top_builddir)/jitplus/libjitplus.a $(top_builddir)/jit/libjit.a
+t4_DEPENDENCIES = $(top_builddir)/jitplus/libjitplus.a \
+                                 $(top_builddir)/jit/libjit.a
+
+AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I. -I$(srcdir)
+AM_CXXFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I. -I$(srcdir)
diff --git a/tutorial/README b/tutorial/README
new file mode 100644 (file)
index 0000000..9e30466
--- /dev/null
@@ -0,0 +1,11 @@
+
+This directory contains the source code for the tutorial programs.
+The tutorials themselves can be found in "libjit/doc/libjit.texi".
+
+The source code for these tutorials is hereby placed into the public domain.
+You can do whatever you wish with the source, including cutting and pasting
+bits and pieces into your own program.
+
+However, libjit itself remains under the terms of the GNU General Public
+License, so you must still obey the terms of the GPL when you link your
+program against libjit.
diff --git a/tutorial/t1.c b/tutorial/t1.c
new file mode 100644 (file)
index 0000000..99a1019
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+
+Tutorial 1 - mul_add
+
+Builds and compiles the following function:
+
+int mul_add(int x, int y, int z)
+{
+       return x * y + z;
+}
+
+*/
+
+#include <stdio.h>
+#include <jit/jit.h>
+
+int main(int argc, char **argv)
+{
+       jit_context_t context;
+       jit_type_t params[3];
+       jit_type_t signature;
+       jit_function_t function;
+       jit_value_t x, y, z;
+       jit_value_t temp1, temp2;
+       jit_int arg1, arg2, arg3;
+       void *args[3];
+       jit_int result;
+
+       /* Create a context to hold the JIT's primary state */
+       context = jit_context_create();
+
+       /* Lock the context while we build and compile the function */
+       jit_context_build_start(context);
+
+       /* Build the function 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);
+
+       /* Create the function object */
+       function = jit_function_create(context, signature);
+
+       /* Construct the function body */
+       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);
+
+       /* Compile the function */
+       jit_function_compile(function);
+
+       /* Unlock the context */
+       jit_context_build_end(context);
+
+       /* Execute the function and print the 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);
+
+       /* Clean up */
+       jit_context_destroy(context);
+
+       /* Finished */
+       return 0;
+}
diff --git a/tutorial/t2.c b/tutorial/t2.c
new file mode 100644 (file)
index 0000000..1160e2b
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+
+Tutorial 2 - gcd
+
+Builds and compiles the following function:
+
+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);
+    }
+}
+
+*/
+
+#include <stdio.h>
+#include <jit/jit.h>
+
+int main(int argc, char **argv)
+{
+       jit_context_t context;
+       jit_type_t params[2];
+       jit_type_t signature;
+       jit_function_t function;
+       jit_value_t x, y;
+       jit_value_t temp1, temp2;
+       jit_value_t temp3, temp4;
+       jit_value_t temp_args[2];
+       jit_label_t label1 = jit_label_undefined;
+       jit_label_t label2 = jit_label_undefined;
+       jit_uint arg1, arg2;
+       void *args[2];
+       jit_uint result;
+
+       /* Create a context to hold the JIT's primary state */
+       context = jit_context_create();
+
+       /* Lock the context while we build and compile the function */
+       jit_context_build_start(context);
+
+       /* Build the function signature */
+       params[0] = jit_type_uint;
+       params[1] = jit_type_uint;
+       signature = jit_type_create_signature
+               (jit_abi_cdecl, jit_type_uint, params, 2, 1);
+
+       /* Create the function object */
+       function = jit_function_create(context, signature);
+
+       /* Check the condition "if(x == y)" */
+       x = jit_value_get_param(function, 0);
+       y = jit_value_get_param(function, 1);
+       temp1 = jit_insn_eq(function, x, y);
+       jit_insn_branch_if_not(function, temp1, &label1);
+
+       /* Implement "return x" */
+       jit_insn_return(function, x);
+
+       /* Set "label1" at this position */
+       jit_insn_label(function, &label1);
+
+       /* Check the condition "if(x < y)" */
+       temp2 = jit_insn_lt(function, x, y);
+       jit_insn_branch_if_not(function, temp2, &label2);
+
+       /* Implement "return gcd(x, y - x)" */
+       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);
+
+       /* Set "label2" at this position */
+       jit_insn_label(function, &label2);
+
+       /* Implement "return gcd(x - y, y)" */
+       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);
+
+       /* Compile the function */
+       jit_function_compile(function);
+
+       /* Unlock the context */
+       jit_context_build_end(context);
+
+       /* Execute the function and print the result */
+       arg1 = 27;
+       arg2 = 14;
+       args[0] = &arg1;
+       args[1] = &arg2;
+       jit_function_apply(function, args, &result);
+       printf("gcd(27, 14) = %u\n", (unsigned int)result);
+
+       /* Clean up */
+       jit_context_destroy(context);
+
+       /* Finished */
+       return 0;
+}
diff --git a/tutorial/t3.c b/tutorial/t3.c
new file mode 100644 (file)
index 0000000..d40f19d
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+
+Tutorial 3 - compiling on-demand
+
+Builds and compiles the following function:
+
+int mul_add(int x, int y, int z)
+{
+       return x * y + z;
+}
+
+Differs from Tutorial 1 in that this version only builds the function
+when it is called, not at startup time.
+
+*/
+
+#include <stdio.h>
+#include <jit/jit.h>
+
+int compile_mul_add(jit_function_t function)
+{
+       jit_value_t x, y, z;
+       jit_value_t temp1, temp2;
+
+       printf("Compiling mul_add on demand\n");
+
+       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;
+}
+
+int main(int argc, char **argv)
+{
+       jit_context_t context;
+       jit_type_t params[3];
+       jit_type_t signature;
+       jit_function_t function;
+       jit_int arg1, arg2, arg3;
+       void *args[3];
+       jit_int result;
+
+       /* Create a context to hold the JIT's primary state */
+       context = jit_context_create();
+
+       /* Lock the context while we construct the function */
+       jit_context_build_start(context);
+
+       /* Build the function 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);
+
+       /* Create the function object */
+       function = jit_function_create(context, signature);
+
+       /* Make the function recompilable */
+       jit_function_set_recompilable(function);
+
+       /* Set the on-demand compiler for "mul_add" */
+       jit_function_set_on_demand_compiler(function, compile_mul_add);
+
+       /* Unlock the context.  It will be automatically locked for
+          us when the on-demand compiler is called */
+       jit_context_build_end(context);
+
+       /* Execute the function and print the result.  This will arrange
+          to call the on-demand compiler to build the function's body */
+       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);
+
+       /* Execute the function again, to demonstrate that the
+          on-demand compiler is not invoked a second time */
+       arg1 = 13;
+       arg2 = 5;
+       arg3 = 7;
+       args[0] = &arg1;
+       args[1] = &arg2;
+       args[2] = &arg3;
+       jit_function_apply(function, args, &result);
+       printf("mul_add(13, 5, 7) = %d\n", (int)result);
+
+       /* Force the function to be recompiled.  Normally we'd use another
+          on-demand compiler with greater optimization capabilities */
+       jit_function_recompile(function);
+
+       /* Execute the function a third time, after it is recompiled */
+       arg1 = 2;
+       arg2 = 18;
+       arg3 = -3;
+       args[0] = &arg1;
+       args[1] = &arg2;
+       args[2] = &arg3;
+       jit_function_apply(function, args, &result);
+       printf("mul_add(2, 18, -3) = %d\n", (int)result);
+
+       /* Clean up */
+       jit_context_destroy(context);
+
+       /* Finished */
+       return 0;
+}
diff --git a/tutorial/t4.cpp b/tutorial/t4.cpp
new file mode 100644 (file)
index 0000000..6354a58
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+
+Tutorial 4 - mul_add, C++ version
+
+Builds and compiles the following function:
+
+int mul_add(int x, int y, int z)
+{
+       return x * y + z;
+}
+
+Differs from Tutorial 3 in that this version is written in C++.
+
+*/
+
+#include <stdio.h>
+#include <jit/jit-plus.h>
+
+class mul_add_function : public jit_function
+{
+public:
+       mul_add_function(jit_context& context) : jit_function(context)
+       {
+               create();
+               set_recompilable();
+       }
+
+protected:
+       virtual jit_type_t create_signature();
+       virtual void build();
+};
+
+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);
+}
+
+void mul_add_function::build()
+{
+       printf("Compiling mul_add on demand\n");
+
+       jit_value x = get_param(0);
+       jit_value y = get_param(1);
+       jit_value z = get_param(2);
+
+       insn_return(x * y + z);
+}
+
+int main(int argc, char **argv)
+{
+       jit_int arg1, arg2, arg3;
+       void *args[3];
+       jit_int result;
+
+       // Create a context to hold the JIT's primary state.
+       jit_context context;
+
+       // Create the function object.
+       mul_add_function mul_add(context);
+
+       // Execute the function and print the result.  This will arrange
+       // to call "mul_add_function::build" to build the function's body.
+       arg1 = 3;
+       arg2 = 5;
+       arg3 = 2;
+       args[0] = &arg1;
+       args[1] = &arg2;
+       args[2] = &arg3;
+       mul_add.apply(args, &result);
+       printf("mul_add(3, 5, 2) = %d\n", (int)result);
+
+       // Execute the function again, to demonstrate that the
+       // on-demand compiler is not invoked a second time.
+       arg1 = 13;
+       arg2 = 5;
+       arg3 = 7;
+       args[0] = &arg1;
+       args[1] = &arg2;
+       args[2] = &arg3;
+       mul_add.apply(args, &result);
+       printf("mul_add(13, 5, 7) = %d\n", (int)result);
+
+       // Force the function to be recompiled.
+       mul_add.recompile();
+
+       // Execute the function a third time, after it is recompiled.
+       arg1 = 2;
+       arg2 = 18;
+       arg3 = -3;
+       args[0] = &arg1;
+       args[1] = &arg2;
+       args[2] = &arg3;
+       mul_add.apply(args, &result);
+       printf("mul_add(2, 18, -3) = %d\n", (int)result);
+
+       /* Finished */
+       return 0;
+}