--- /dev/null
+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
--- /dev/null
+Rhys Weatherley <rweather@southern-storm.com.au>
--- /dev/null
+ 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.
--- /dev/null
+
+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.
--- /dev/null
+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.
--- /dev/null
+
+SUBDIRS = include tools jit jitplus dpas tutorial doc
--- /dev/null
+
+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.
--- /dev/null
+#!/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
--- /dev/null
+#! /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:
--- /dev/null
+#! /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:
--- /dev/null
+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])
--- /dev/null
+Makefile
+Makefile.in
+.deps
+libjit.info*
+libjitext-*
+*.pdf
--- /dev/null
+
+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
--- /dev/null
+#!/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
--- /dev/null
+.\" 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.
--- /dev/null
+\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
--- /dev/null
+#!/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"
--- /dev/null
+#!/bin/sh
+#
+# mkpdf - Make the PDF version of texinfo documentation
+
+exec texi2dvi --pdf libjit.texi
--- /dev/null
+% 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\}\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:
--- /dev/null
+Makefile
+Makefile.in
+.deps
+dpas-parser.h
+dpas-parser.c
+dpas-scanner.c
+dpas
--- /dev/null
+
+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
--- /dev/null
+
+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".
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+%{
+/*
+ * 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;
+ }
+ ;
--- /dev/null
+%{
+/*
+ * 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;
+ }
+ }
+}
+
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+Makefile
+Makefile.in
+.deps
--- /dev/null
+
+SUBDIRS = jit
--- /dev/null
+Makefile
+Makefile.in
+.deps
+jit-defs.h
--- /dev/null
+
+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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * <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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#!/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
--- /dev/null
+Makefile
+Makefile.in
+.deps
+jit-apply-rules.h
--- /dev/null
+
+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)
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/* 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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, ¬_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, <_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, >_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;
+ }
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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));
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+Makefile
+Makefile.in
+.deps
--- /dev/null
+
+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)
--- /dev/null
+/*
+ * 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
+@*/
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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()));
+}
--- /dev/null
+#! /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
--- /dev/null
+#! /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
--- /dev/null
+Makefile
+Makefile.in
+.deps
+gen-apply
+gen-apply.exe
--- /dev/null
+
+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
--- /dev/null
+/*
+ * 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) */
--- /dev/null
+Makefile
+Makefile.in
+.deps
+*.exe
+t1
+t2
+t3
+t4
--- /dev/null
+
+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)
--- /dev/null
+
+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.
--- /dev/null
+/*
+
+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;
+}
--- /dev/null
+/*
+
+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;
+}
--- /dev/null
+/*
+
+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;
+}
--- /dev/null
+/*
+
+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;
+}