-Quick start instructions
-========================
+Installation Instructions
+*************************
-You can check the configure options via `./configure --help'. But the
-default settings should be ok. For building the package type:
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007 Free Software Foundation, Inc.
- $ ./configure
- $ make
- $ make install
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
-The default installation prefix is `/usr/local/cacao'. You can change
-this destination by providing the `--prefix=PATH' option to configure.
+Basic Installation
+==================
-This version of cacao only supports the `--prefix' option, even if
-configure processes the other options (`--bindir', `--libdir', etc.),
-it will screw up your installation since CACAO tries to setup a
-directory tree like the JVMs from Sun or IBM do.
+Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
+ 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, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
-Requirements:
--------------
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ 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 you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' 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.
+
+ Running `configure' might take a while. 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.
+
+ 6. Often, you can also type `make uninstall' to remove the installed
+ files again.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about. Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+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 can use 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 `..'.
+
+ With a non-GNU `make', it is safer 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' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' 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' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ 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 machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+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.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug. Until the bug is fixed you can use this workaround:
+
+ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--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.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
-In order to compile the Java classes from GNU classpath, you need a
-Java compiler supported by GNU classpath. To get a working classpath
-in an appropriate time, we recommend IBM jikes 1.18 or newer. For
-further instructions concerning GNU classpath, please refer to
-`src/classpath/INSTALL'.
JAVA_ARCH="m68k"
;;
-mips | mipsel )
+mips )
ARCH_DIR="mips"
ARCH_FLAGS="-D__MIPS__"
- dnl Is this correct for mipsel?
JAVA_ARCH="mips"
;;
+mipsel )
+ ARCH_DIR="mips"
+ ARCH_FLAGS="-D__MIPS__"
+ JAVA_ARCH="mipsel"
+ ;;
+
powerpc )
ARCH_DIR="powerpc"
ARCH_FLAGS="-m32 -D__POWERPC__"
# define DYNAMIC_LOADING
extern int _end[];
# define DATAEND (_end)
- extern int __data_start[];
-# define DATASTART ((ptr_t)(__data_start))
+# define SEARCH_FOR_DATA_START
# define CPP_WORDSZ _MIPS_SZPTR
# define ALIGNMENT (_MIPS_SZPTR/8)
# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2
# define OS_TYPE "LINUX"
# define LINUX_STACKBOTTOM
# define DYNAMIC_LOADING
- extern int __data_start[];
-# define DATASTART ((ptr_t)(__data_start))
- extern int _end[];
+# define SEARCH_FOR_DATA_START
+ extern int _end[];
# define DATAEND (_end)
# define CACHE_LINE_SIZE 256
# define GETPAGESIZE() 4096
linenumbertable.hpp \
methodtree.c \
methodtree.h \
- parse.c \
- parse.h \
+ parse.cpp \
+ parse.hpp \
patcher-common.cpp \
patcher-common.hpp \
$(RECOMPILE_SOURCES) \
#include "vm/jit/codegen-common.hpp"
#include "vm/jit/jit.hpp"
-#include "vm/jit/inline/inline.h"
+#include "vm/jit/inline/inline.hpp"
/* function prototypes ********************************************************/
#include "vm/jit/emit-common.hpp"
#include "vm/jit/jit.hpp"
#include "vm/jit/linenumbertable.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/patcher-common.hpp"
#include "vm/jit/reg.h"
#include "vm/jit/replace.hpp"
#include "vm/jit/jitcache.hpp"
#include "vm/jit/linenumbertable.hpp"
#include "vm/jit/methodheader.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/patcher-common.hpp"
#include "vm/jit/reg.h"
#if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER
-void emit_label_beqz(codegendata *cd, s4 label, s4 reg)
+void emit_label_beqz(codegendata* cd, int label, int reg)
{
emit_label_bccz(cd, label, BRANCH_EQ, reg, BRANCH_OPT_NONE);
}
-void emit_label_bnez(codegendata *cd, s4 label, s4 reg)
+void emit_label_bnez(codegendata* cd, int label, int reg)
{
emit_label_bccz(cd, label, BRANCH_NE, reg, BRANCH_OPT_NONE);
}
+void emit_label_bltz(codegendata* cd, int label, int reg)
+{
+ emit_label_bccz(cd, label, BRANCH_LT, reg, BRANCH_OPT_NONE);
+}
+
+void emit_label_bgtz(codegendata* cd, int label, int reg)
+{
+ emit_label_bccz(cd, label, BRANCH_GT, reg, BRANCH_OPT_NONE);
+}
+
#endif /* SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER */
+/* emit_label_bxx **************************************************************
+
+ Wrappers for label-branches on two integer registers.
+
+ We use PACK_REGS here, so we don't have to change the branchref
+ data structure and the emit_bccz function.
+
+*******************************************************************************/
+
+#if SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS
+
+void emit_label_bne(codegendata* cd, int label, int s1, int s2)
+{
+ emit_label_bccz(cd, label, BRANCH_NE, PACK_REGS(s1, s2), BRANCH_OPT_NONE);
+}
+
+#endif /* SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS */
+
+
/* emit_label_bxx **************************************************************
Wrappers for label-branches on condition codes.
/* src/vm/jit/emit-common.hpp - common code emitter functions
- Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates,
- R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
- C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
- Institut f. Computersprachen - TU Wien
+ Copyright (C) 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
void emit_label_br(codegendata *cd, s4 label);
#if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER
-void emit_label_beqz(codegendata *cd, s4 label, s4 reg);
-void emit_label_bnez(codegendata *cd, s4 label, s4 reg);
+void emit_label_beqz(codegendata* cd, int label, int reg);
+void emit_label_bnez(codegendata* cd, int label, int reg);
+void emit_label_bltz(codegendata* cd, int label, int reg);
+void emit_label_bgtz(codegendata* cd, int label, int reg);
+#endif
+
+#if SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS
+void emit_label_bne(codegendata* cd, int label, int s1, int s2);
#endif
#if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER
#include "vm/jit/jit.hpp"
#include "vm/jit/jitcache.hpp"
#include "vm/jit/linenumbertable.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/patcher-common.hpp"
#include "vm/jit/reg.h"
#include "vm/jit/replace.hpp"
libinline.la
libinline_la_SOURCES = \
- inline.c \
- inline.h \
+ inline.cpp \
+ inline.hpp \
inline_debug.inc
+++ /dev/null
-/* src/vm/jit/inline/inline.c - method inlining
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- 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., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-#include <assert.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "vm/types.h"
-
-#include "mm/memory.h"
-
-#include "threads/lock.hpp"
-#include "threads/mutex.hpp"
-#include "threads/thread.hpp"
-
-#include "toolbox/logging.h"
-
-#include "vm/jit/builtin.hpp"
-#include "vm/class.hpp"
-#include "vm/global.h"
-#include "vm/initialize.hpp"
-#include "vm/method.h"
-#include "vm/options.h"
-#include "vm/statistics.h"
-
-#include "vm/jit/jit.hpp"
-#include "vm/jit/parse.h"
-#include "vm/jit/reg.h"
-#include "vm/jit/show.hpp"
-#include "vm/jit/stack.h"
-
-#include "vm/jit/inline/inline.h"
-#include "vm/jit/loop/loop.h"
-
-#include "vm/jit/verify/typecheck.h"
-
-
-/* algorithm tuning constants *************************************************/
-
-/* Algorithm Selection */
-/* Define exactly one of the following three to select the inlining */
-/* heuristics. */
-
-/*#define INLINE_DEPTH_FIRST*/
-/*#define INLINE_BREADTH_FIRST*/
-#define INLINE_KNAPSACK
-
-/* Parameters for knapsack heuristics: */
-
-#if defined(INLINE_KNAPSACK)
-
-#define INLINE_COUNTDOWN_INIT 1000
-#define INLINE_COST_OFFSET -16
-#define INLINE_COST_BUDGET 100
-/*#define INLINE_WEIGHT_BUDGET 5.0*/
-/*#define INLINE_ADD_NEGATIVE_TO_BUDGET*/
-/*#define INLINE_MAX_DEPTH 3*/
-/*#define INLINE_DIVIDE_COST_BY_FREQ */
-
-#endif
-
-/* Parameters for depth-first heuristics: */
-
-#if defined(INLINE_DEPTH_FIRST)
-
-#define INLINE_MAX_DEPTH 3
-#define INLINE_MAX_BLOCK_EXPANSION 10
-/*#define INLINE_MAX_ICMD_EXPANSION 10*/
-/*#define INLINE_CANCEL_ON_THRESHOLD*/
-
-#endif
-
-/* Parameters for breadth-first heuristics: */
-
-#if defined(INLINE_BREADTH_FIRST)
-
-/*#define INLINE_MAX_BLOCK_EXPANSION 10*/
-#define INLINE_MAX_ICMD_EXPANSION 5
-
-#endif
-
-
-/* debugging ******************************************************************/
-
-#if !defined(NDEBUG)
-#define INLINE_VERBOSE
-#define DOLOG(code) do{ if (opt_TraceInlining >= 2) { code; } }while(0)
-#define DOLOG_SHORT(code) do{ if (opt_TraceInlining >= 1) { code; } }while(0)
-#else
-#define DOLOG(code)
-#endif
-
-#if defined(ENABLE_VERIFIER) && !defined(NDEBUG)
-/* Define this to verify the resulting code after inlining. */
-/* Note: This is only useful for development and may require patches to the */
-/* verifier code. */
-/* #define INLINE_VERIFY_RESULT */
-#endif
-
-
-/* types **********************************************************************/
-
-typedef struct inline_node inline_node;
-typedef struct inline_target_ref inline_target_ref;
-typedef struct inline_context inline_context;
-typedef struct inline_block_map inline_block_map;
-typedef struct inline_site inline_site;
-typedef struct inline_candidate inline_candidate;
-
-struct inline_node {
- inline_context *ctx;
-
- jitdata *jd;
- methodinfo *m;
- inline_node *children;
- inline_node *next; /* next node at this depth */
- inline_node *prev; /* prev node at this depth */
- int depth; /* inlining depth, 0 for root */
-
- /* info about the call site (if depth > 0)*/
- inline_node *parent; /* node of the caller (NULL for root) */
- basicblock *callerblock; /* original block containing the INVOKE* */
- instruction *callerins; /* the original INVOKE* instruction */
- s4 callerpc;
- s4 *n_passthroughvars;
- int n_passthroughcount;
- int n_selfpassthroughcount; /* # of pass-through vars of the call itself */
- exception_entry **o_handlers;
- int n_handlercount; /* # of handlers protecting this call */
- int n_resultlocal;
- int synclocal; /* variable used for synchr., or UNUSED */
- bool isstatic; /* this is a static call */
-
- bool blockbefore; /* block boundary before inlined body? */
- bool blockafter; /* block boundary after inlined body? */
-
- /* info about the callee */
- int localsoffset;
- int prolog_instructioncount; /* # of ICMDs in the inlining prolog */
- int epilog_instructioncount; /* # of ICMDs in the inlining epilog */
- int extra_instructioncount;
- int extra_exceptiontablelength; /* # of extra handlers to put in caller */
- bool synchronize; /* do we have to synchronize enter/exit? */
- basicblock *handler_monitorexit; /* handler for synchronized inlinees */
- s4 *varmap;
-
- /* cumulative values */
- int cumul_instructioncount; /* ICMDs in this node and its children */
- int cumul_basicblockcount; /* BBs started by this node and its children */
- int cumul_basicblockcount_root; /* BBs that have to be added to the root */
- /* node if this node is inlined */
- int cumul_blockmapcount;
- int cumul_maxlocals;
- int cumul_exceptiontablelength;
-
- /* output */
- instruction *inlined_iinstr;
- instruction *inlined_iinstr_cursor;
- basicblock *inlined_basicblocks;
- basicblock *inlined_basicblocks_cursor;
-
- /* register data */
- registerdata *regdata;
-
- /* temporary */
- inline_target_ref *refs;
- instruction *inline_start_instruction;
- s4 *javalocals;
-
- /* XXX debug */
- char *indent;
- int debugnr;
-};
-
-struct inline_target_ref {
- inline_target_ref *next;
- union {
- basicblock **block;
- s4 *nr;
- } ref;
- basicblock *target;
- bool isnumber;
-};
-
-struct inline_block_map {
- inline_node *iln;
- basicblock *o_block;
- basicblock *n_block;
-};
-
-struct inline_context {
- inline_node *master;
-
- jitdata *resultjd;
-
- inline_candidate *candidates;
-
- int next_block_number;
- inline_block_map *blockmap;
- int blockmap_index;
-
- int maxinoutdepth;
-
- bool stopped;
-
- int next_debugnr; /* XXX debug */
-};
-
-struct inline_site {
- bool speculative; /* true, if inlining would be speculative */
- bool inlined; /* true, if this site has been inlined */
-
- basicblock *bptr; /* basic block containing the call site */
- instruction *iptr; /* the invocation instruction */
- exception_entry **handlers; /* active handlers at the call site */
- s4 nhandlers; /* number of active handlers */
- s4 pc; /* PC of the invocation instruction */
-};
-
-struct inline_candidate {
- inline_candidate *next;
- int freq;
- int cost;
- double weight;
- inline_node *caller;
- methodinfo *callee;
- inline_site site;
-};
-
-
-/* prototypes *****************************************************************/
-
-static bool inline_analyse_code(inline_node *iln);
-static void inline_post_process(jitdata *jd);
-
-
-/* debug helpers **************************************************************/
-
-#if !defined(NDEBUG)
-#include "inline_debug.inc"
-#endif
-
-
-/* statistics *****************************************************************/
-
-/*#define INLINE_STATISTICS*/
-
-#if !defined(NDEBUG)
-#define INLINE_STATISTICS
-#endif
-
-#if defined(INLINE_STATISTICS)
-int inline_stat_roots = 0;
-int inline_stat_roots_transformed = 0;
-int inline_stat_inlined_nodes = 0;
-int inline_stat_max_depth = 0;
-
-void inline_print_stats()
-{
- printf("inlining statistics:\n");
- printf(" roots analysed : %d\n", inline_stat_roots);
- printf(" roots transformed: %d\n", inline_stat_roots_transformed);
- printf(" inlined nodes : %d\n", inline_stat_inlined_nodes);
- printf(" max depth : %d\n", inline_stat_max_depth);
-}
-#endif
-
-
-/* compilation of callees *****************************************************/
-
-static bool inline_jit_compile_intern(jitdata *jd)
-{
- methodinfo *m;
-
- /* XXX should share code with jit.c */
-
- assert(jd);
-
- /* XXX initialize the static function's class */
-
- m = jd->m;
-
- /* call the compiler passes ***********************************************/
-
- /* call parse pass */
-
- DOLOG( log_message_class("Parsing ", m->clazz) );
- if (!parse(jd)) {
- return false;
- }
-
- /* call stack analysis pass */
-
- if (!stack_analyse(jd)) {
- return false;
- }
-
- return true;
-}
-
-
-static bool inline_jit_compile(inline_node *iln)
-{
- bool r;
- methodinfo *m;
- jitdata *jd;
-
- /* XXX should share code with jit.c */
-
- assert(iln);
- m = iln->m;
- assert(m);
-
- /* enter a monitor on the method */
-
- Mutex_lock(m->mutex);
-
- /* allocate jitdata structure and fill it */
-
- jd = jit_jitdata_new(m);
- iln->jd = jd;
-
- jd->flags = 0; /* XXX */
-
- /* initialize the register allocator */
-
- reg_setup(jd);
-
- /* setup the codegendata memory */
-
- /* XXX do a pseudo setup */
- jd->cd = DNEW(codegendata);
- MZERO(jd->cd, codegendata, 1);
- jd->cd->method = m;
- /* XXX uses too much dump memory codegen_setup(jd); */
-
- /* now call internal compile function */
-
- r = inline_jit_compile_intern(jd);
-
- if (r) {
- iln->regdata = jd->rd;
- }
-
- /* free some memory */
-#if 0
-
-#if defined(ENABLE_JIT)
-# if defined(ENABLE_INTRP)
- if (!opt_intrp)
-# endif
- codegen_free(jd);
-#endif
-
-#endif
-
- /* leave the monitor */
-
- Mutex_unlock(m->mutex);
-
- return r;
-}
-
-
-/* inlining tree handling *****************************************************/
-
-static void inline_insert_inline_node(inline_node *parent, inline_node *child)
-{
- inline_node *first;
- inline_node *succ;
-
- assert(parent && child);
-
- child->parent = parent;
-
- child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
-
- first = parent->children;
- if (!first) {
- /* insert as only node */
- parent->children = child;
- child->next = child;
- child->prev = child;
- return;
- }
-
- /* {there is at least one child already there} */
-
- /* XXX is this search necessary, or could we always add at the end? */
-
- succ = first;
- while (succ->callerpc < child->callerpc) {
- succ = succ->next;
- if (succ == first) {
- /* insert as last node */
- child->prev = first->prev;
- child->next = first;
- child->prev->next = child;
- child->next->prev = child;
- return;
- }
- }
-
- assert(succ->callerpc > child->callerpc);
-
- /* insert before succ */
-
- child->prev = succ->prev;
- child->next = succ;
- child->prev->next = child;
- child->next->prev = child;
-
- if (parent->children == succ)
- parent->children = child;
-}
-
-
-static void inline_remove_inline_node(inline_node *parent, inline_node *child)
-{
- assert(parent);
- assert(child);
- assert(child->parent == parent);
-
- if (child->prev == child) {
- /* remove the only child node */
- parent->children = NULL;
- }
- else {
- child->prev->next = child->next;
- child->next->prev = child->prev;
-
- if (parent->children == child)
- parent->children = child->next;
- }
-}
-
-
-/* inlining candidate handling ************************************************/
-
-#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
-static void inline_add_candidate(inline_context *ctx,
- inline_node *caller,
- methodinfo *callee,
- inline_site *site)
-{
- inline_candidate **link;
- inline_candidate *cand;
-
- cand = DNEW(inline_candidate);
-#if defined(INLINE_DIVIDE_COST_BY_FREQ)
- cand->freq = INLINE_COUNTDOWN_INIT - callee->hitcountdown;
- if (cand->freq < 1)
-#endif
- cand->freq = 1;
-#if defined(INLINE_KNAPSACK)
- cand->cost = callee->jcodelength + INLINE_COST_OFFSET;
-#endif
-#if defined(INLINE_BREADTH_FIRST)
- cand->cost = caller->depth;
-#endif
- cand->caller = caller;
- cand->callee = callee;
- cand->site = *site;
-
- cand->weight = (double)cand->cost / cand->freq;
-
- for (link = &(ctx->candidates); ; link = &((*link)->next)) {
- if (!*link || (*link)->weight > cand->weight) {
- cand->next = *link;
- *link = cand;
- break;
- }
- }
-}
-#endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
-
-#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
-static inline_candidate * inline_pick_best_candidate(inline_context *ctx)
-{
- inline_candidate *cand;
-
- cand = ctx->candidates;
-
- if (cand)
- ctx->candidates = cand->next;
-
- return cand;
-}
-#endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
-
-#if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
-static void inline_candidate_println(inline_candidate *cand)
-{
- printf("%10g (%5d / %5d) depth %2d ",
- cand->weight, cand->cost, cand->freq, cand->caller->depth + 1);
- method_println(cand->callee);
-}
-#endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
-
-
-#if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
-static void inline_candidates_println(inline_context *ctx)
-{
- inline_candidate *cand;
-
- for (cand = ctx->candidates; cand != NULL; cand = cand->next) {
- printf(" ");
- inline_candidate_println(cand);
- }
-}
-#endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
-
-
-/* variable handling **********************************************************/
-
-static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
-{
- s4 index;
- s4 newcount;
-
- index = jd->vartop++;
- if (index >= jd->varcount) {
- newcount = jd->vartop * 2; /* XXX */
- jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, newcount);
- MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
- jd->varcount = newcount;
- }
-
- jd->var[index].type = type;
- jd->var[index].flags = flags;
-
- return index;
-}
-
-
-static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
-{
- varinfo *v;
- s4 newidx;
-
- v = &(origjd->var[origidx]);
-
- newidx = inline_new_variable(jd, v->type, v->flags);
-
- jd->var[newidx].vv = v->vv;
-
- return newidx;
-}
-
-
-static s4 inline_new_temp_variable(jitdata *jd, s4 type)
-{
- return inline_new_variable(jd, type, 0);
-}
-
-
-static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
-{
- s4 idx;
-
- idx = varmap[index];
-
- if (idx < 0) {
- idx = inline_new_variable_clone(jd, origjd, index);
- varmap[index] = idx;
- }
-
- return idx;
-}
-
-
-static s4 *create_variable_map(inline_node *callee)
-{
- s4 *varmap;
- s4 i, t;
- s4 varindex;
- s4 n_javaindex;
- s4 avail;
- varinfo *v;
-
- /* create the variable mapping */
-
- varmap = DMNEW(s4, callee->jd->varcount);
- for (i=0; i<callee->jd->varcount; ++i)
- varmap[i] = -1;
-
- /* translate local variables */
-
- for (i=0; i<callee->m->maxlocals; ++i) {
- for (t=0; t<5; ++t) {
- varindex = callee->jd->local_map[5*i + t];
- if (varindex == UNUSED)
- continue;
-
- v = &(callee->jd->var[varindex]);
- assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
- v->type = t; /* XXX restore if it is TYPE_VOID */
-
- avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
-
- if (avail == UNUSED) {
- avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, varindex);
- callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
- }
-
- varmap[varindex] = avail;
- }
- }
-
- /* for synchronized instance methods we need an extra local */
-
- if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
- n_javaindex = callee->localsoffset - 1;
- assert(n_javaindex >= 0);
- assert(callee->parent);
- assert(n_javaindex == callee->parent->localsoffset + callee->parent->m->maxlocals);
-
- avail = callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR];
-
- if (avail == UNUSED) {
- avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
- callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR] = avail;
- }
-
- callee->synclocal = avail;
- }
- else {
- callee->synclocal = UNUSED;
- }
-
- return varmap;
-}
-
-
-/* basic block translation ****************************************************/
-
-#define INLINE_RETURN_REFERENCE(callee) \
- ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
-
-
-static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
-{
- inline_target_ref *ref;
-
- ref = DNEW(inline_target_ref);
- ref->ref.block = blockp;
- ref->isnumber = false;
- ref->next = iln->refs;
- iln->refs = ref;
-}
-
-
-#if 0
-static void inline_add_blocknr_reference(inline_node *iln, s4 *nrp)
-{
- inline_target_ref *ref;
-
- ref = DNEW(inline_target_ref);
- ref->ref.nr = nrp;
- ref->isnumber = true;
- ref->next = iln->refs;
- iln->refs = ref;
-}
-#endif
-
-
-static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
-{
- inline_context *ctx;
-
- ctx = iln->ctx;
- assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
-
- ctx->blockmap[ctx->blockmap_index].iln = iln;
- ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
- ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
-
- ctx->blockmap_index++;
-}
-
-
-static basicblock * inline_map_block(inline_node *iln,
- basicblock *o_block,
- inline_node *targetiln)
-{
- inline_block_map *bm;
- inline_block_map *bmend;
-
- assert(iln);
- assert(targetiln);
-
- if (!o_block)
- return NULL;
-
- bm = iln->ctx->blockmap;
- bmend = bm + iln->ctx->blockmap_index;
-
- while (bm < bmend) {
- assert(bm->iln && bm->o_block && bm->n_block);
- if (bm->o_block == o_block && bm->iln == targetiln)
- return bm->n_block;
- bm++;
- }
-
- assert(false);
- return NULL; /* not reached */
-}
-
-
-static void inline_resolve_block_refs(inline_target_ref **refs,
- basicblock *o_bptr,
- basicblock *n_bptr,
- bool returnref)
-{
- inline_target_ref *ref;
- inline_target_ref *prev;
-
- prev = NULL;
- for (ref = *refs; ref != NULL; ref = ref->next) {
- if (ref->isnumber && !returnref) {
- if (*(ref->ref.nr) == JAVALOCAL_FROM_RETADDR(o_bptr->nr)) {
- *(ref->ref.nr) = JAVALOCAL_FROM_RETADDR(n_bptr->nr);
- goto remove_ref;
- }
- }
- else {
- if (*(ref->ref.block) == o_bptr) {
- *(ref->ref.block) = n_bptr;
- goto remove_ref;
- }
- }
-
- /* skip this ref */
-
- prev = ref;
- continue;
-
-remove_ref:
- /* remove this ref */
-
- if (prev) {
- prev->next = ref->next;
- }
- else {
- *refs = ref->next;
- }
- }
-}
-
-
-/* basic block creation *******************************************************/
-
-static basicblock * create_block(inline_node *container,
- inline_node *iln,
- inline_node *inner,
- int indepth)
-{
- basicblock *n_bptr;
- inline_node *outer;
- s4 i;
- s4 depth;
- s4 varidx;
- s4 newvaridx;
-
- assert(container);
- assert(iln);
- assert(inner);
- assert(indepth >= 0);
-
- n_bptr = container->inlined_basicblocks_cursor++;
- assert(n_bptr);
- assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
-
- BASICBLOCK_INIT(n_bptr, iln->m);
-
- n_bptr->iinstr = container->inlined_iinstr_cursor;
- n_bptr->next = n_bptr + 1;
- n_bptr->nr = container->ctx->next_block_number++;
- n_bptr->indepth = indepth;
- n_bptr->flags = BBFINISHED; /* XXX */
-
- /* set the inlineinfo of the new block */
-
- if (iln->inline_start_instruction)
- n_bptr->inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
-
- if (indepth > container->ctx->maxinoutdepth)
- container->ctx->maxinoutdepth = indepth;
-
- if (indepth) {
- n_bptr->invars = DMNEW(s4, indepth);
-
-
- for (i=0; i<indepth; ++i)
- n_bptr->invars[i] = -1; /* XXX debug */
-
- /* pass-through variables enter the block */
-
- outer = inner->parent;
- while (outer != NULL) {
- depth = outer->n_passthroughcount;
-
- assert(depth + inner->n_selfpassthroughcount <= indepth);
-
- for (i=0; i<inner->n_selfpassthroughcount; ++i) {
- varidx = inner->n_passthroughvars[i];
- newvaridx =
- inline_new_variable_clone(container->ctx->resultjd,
- outer->jd,
- varidx);
- n_bptr->invars[depth + i] = newvaridx;
- outer->varmap[varidx] = newvaridx;
- }
- inner = outer;
- outer = outer->parent;
- }
- }
- else {
- n_bptr->invars = NULL;
- }
-
- /* XXX for the verifier. should not be here */
-
- {
- varinfo *dv;
-
- dv = DMNEW(varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
- MZERO(dv, varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
- n_bptr->inlocals = dv;
- }
-
- return n_bptr;
-}
-
-
-static s4 *translate_javalocals(inline_node *iln, s4 *javalocals)
-{
- s4 *jl;
- s4 i, j;
-
- jl = DMNEW(s4, iln->jd->maxlocals);
-
- for (i=0; i<iln->jd->maxlocals; ++i) {
- j = javalocals[i];
- if (j > UNUSED)
- j = inline_translate_variable(iln->ctx->resultjd, iln->jd, iln->varmap, j);
- jl[i] = j;
-
-#if 0
- if (j < UNUSED) {
- /* an encoded returnAddress value - must be relocated */
- inline_add_blocknr_reference(iln, &(jl[i]));
- }
-#endif
- }
-
- return jl;
-}
-
-
-static basicblock * create_body_block(inline_node *iln,
- basicblock *o_bptr, s4 *varmap)
-{
- basicblock *n_bptr;
- s4 i;
-
- n_bptr = create_block(iln, iln, iln,
- o_bptr->indepth + iln->n_passthroughcount);
-
- n_bptr->type = o_bptr->type;
- n_bptr->flags = o_bptr->flags;
- n_bptr->bitflags = o_bptr->bitflags;
-
- /* resolve references to this block */
-
- inline_resolve_block_refs(&(iln->refs), o_bptr, n_bptr, false);
-
- /* translate the invars of the original block */
-
- for (i=0; i<o_bptr->indepth; ++i) {
- n_bptr->invars[iln->n_passthroughcount + i] =
- inline_translate_variable(iln->ctx->resultjd, iln->jd,
- varmap,
- o_bptr->invars[i]);
- }
-
- /* translate javalocals info (not for dead code) */
-
- if (n_bptr->flags >= BBREACHED)
- n_bptr->javalocals = translate_javalocals(iln, o_bptr->javalocals);
-
- return n_bptr;
-}
-
-
-static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
-{
- basicblock *n_bptr;
- s4 retcount;
- s4 idx;
-
- /* number of return variables */
-
- retcount = (callee->n_resultlocal == -1
- && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
-
- /* start the epilog block */
-
- n_bptr = create_block(caller, caller, callee,
- callee->n_passthroughcount + retcount);
-
- /* resolve references to the return block */
-
- inline_resolve_block_refs(&(callee->refs),
- INLINE_RETURN_REFERENCE(callee),
- n_bptr,
- true);
-
- /* return variable */
-
- if (retcount) {
- idx = inline_new_variable(caller->ctx->resultjd,
- callee->m->parseddesc->returntype.type, 0 /* XXX */);
- n_bptr->invars[callee->n_passthroughcount] = idx;
- varmap[callee->callerins->dst.varindex] = idx;
- }
-
- /* set javalocals */
-
- n_bptr->javalocals = DMNEW(s4, caller->jd->maxlocals);
- MCOPY(n_bptr->javalocals, caller->javalocals, s4, caller->jd->maxlocals);
-
- /* set block flags & type */
-
- n_bptr->flags = /* XXX original block flags */ BBFINISHED;
- n_bptr->type = BBTYPE_STD;
-
- return n_bptr;
-}
-
-
-static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
-{
- inline_node *outer;
- s4 i;
- s4 depth;
- s4 varidx;
-
- n_bptr->outdepth = outdepth;
- n_bptr->outvars = DMNEW(s4, outdepth);
-
- for (i=0; i<outdepth; ++i)
- n_bptr->outvars[i] = 0; /* XXX debug */
-
- if (outdepth > iln->ctx->maxinoutdepth)
- iln->ctx->maxinoutdepth = outdepth;
-
- /* pass-through variables leave the block */
-
- outer = inner->parent;
- while (outer != NULL) {
- depth = outer->n_passthroughcount;
-
- assert(depth + inner->n_selfpassthroughcount <= outdepth);
-
- for (i=0; i<inner->n_selfpassthroughcount; ++i) {
- varidx = inner->n_passthroughvars[i];
- n_bptr->outvars[depth + i] =
- inline_translate_variable(iln->ctx->resultjd,
- outer->jd,
- outer->varmap,
- varidx);
- }
- inner = outer;
- outer = outer->parent;
- }
-}
-
-
-static void close_prolog_block(inline_node *iln,
- basicblock *n_bptr,
- inline_node *nextcall)
-{
- /* XXX add original outvars! */
- close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
-
- /* pass-through variables */
-
- DOLOG( printf("closed prolog block:\n");
- show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
-}
-
-
-static void close_body_block(inline_node *iln,
- basicblock *n_bptr,
- basicblock *o_bptr,
- s4 *varmap,
- s4 retcount,
- s4 retidx)
-{
- s4 i;
-
- close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
-
- /* translate the outvars of the original block */
-
- /* XXX reuse code */
- for (i=0; i<o_bptr->outdepth; ++i) {
- n_bptr->outvars[iln->n_passthroughcount + i] =
- inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
- o_bptr->outvars[i]);
- }
-
- /* set the return variable, if any */
-
- if (retcount) {
- assert(retidx >= 0);
- n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
- }
-}
-
-
-/* inlined code generation ****************************************************/
-
-static instruction * inline_instruction(inline_node *iln,
- s4 opcode,
- instruction *o_iptr)
-{
- instruction *n_iptr;
-
- n_iptr = (iln->inlined_iinstr_cursor++);
- assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
-
- n_iptr->opc = opcode;
- n_iptr->flags.bits = o_iptr->flags.bits & INS_FLAG_ID_MASK;
- n_iptr->line = o_iptr->line;
-
- return n_iptr;
-}
-
-static void inline_generate_sync_builtin(inline_node *iln,
- inline_node *callee,
- instruction *o_iptr,
- s4 instancevar,
- functionptr func)
-{
- int syncvar;
- instruction *n_ins;
-
- if (callee->m->flags & ACC_STATIC) {
- /* ACONST */
- syncvar = inline_new_temp_variable(iln->ctx->resultjd, TYPE_ADR);
-
- n_ins = inline_instruction(iln, ICMD_ACONST, o_iptr);
- n_ins->sx.val.c.cls = callee->m->clazz;
- n_ins->dst.varindex = syncvar;
- n_ins->flags.bits |= INS_FLAG_CLASS;
- }
- else {
- syncvar = instancevar;
- }
-
- assert(syncvar != UNUSED);
-
- /* MONITORENTER / MONITOREXIT */
-
- n_ins = inline_instruction(iln, ICMD_BUILTIN, o_iptr);
- n_ins->sx.s23.s3.bte = builtintable_get_internal(func);
- n_ins->s1.argcount = 1; /* XXX add through-vars */
- n_ins->sx.s23.s2.args = DMNEW(s4, 1);
- n_ins->sx.s23.s2.args[0] = syncvar;
-}
-
-static s4 emit_inlining_prolog(inline_node *iln,
- inline_node *callee,
- instruction *o_iptr,
- s4 *varmap)
-{
- methodinfo *calleem;
- methoddesc *md;
- int i;
- int localindex;
- int type;
- instruction *n_ins;
- insinfo_inline *insinfo;
- s4 varindex;
-
- assert(iln && callee && o_iptr);
-
- calleem = callee->m;
- md = calleem->parseddesc;
-
- /* INLINE_START instruction */
-
- n_ins = inline_instruction(iln, ICMD_INLINE_START, o_iptr);
-
- insinfo = DNEW(insinfo_inline);
- insinfo->method = callee->m;
- insinfo->outer = iln->m;
- insinfo->synclocal = callee->synclocal;
- insinfo->synchronize = callee->synchronize;
- insinfo->javalocals_start = NULL;
- insinfo->javalocals_end = NULL;
-
- /* info about stack vars live at the INLINE_START */
-
- insinfo->throughcount = callee->n_passthroughcount;
- insinfo->paramcount = md->paramcount;
- insinfo->stackvarscount = o_iptr->s1.argcount;
- insinfo->stackvars = DMNEW(s4, insinfo->stackvarscount);
- for (i=0; i<insinfo->stackvarscount; ++i)
- insinfo->stackvars[i] = iln->varmap[o_iptr->sx.s23.s2.args[i]];
-
- /* info about the surrounding inlining */
-
- if (iln->inline_start_instruction)
- insinfo->parent = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
- else
- insinfo->parent = NULL;
-
- /* finish the INLINE_START instruction */
-
- n_ins->sx.s23.s3.inlineinfo = insinfo;
- callee->inline_start_instruction = n_ins;
-
- DOLOG( printf("%sprolog: ", iln->indent);
- show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
-
- /* handle parameters for the inlined callee */
-
- localindex = callee->localsoffset + md->paramslots;
-
- for (i=md->paramcount-1; i>=0; --i) {
- assert(iln);
-
- type = md->paramtypes[i].type;
-
- localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
- assert(callee->regdata);
-
- /* translate the argument variable */
-
- varindex = varmap[o_iptr->sx.s23.s2.args[i]];
- assert(varindex != UNUSED);
-
- /* remove preallocation from the argument variable */
-
- iln->ctx->resultjd->var[varindex].flags &= ~(PREALLOC | INMEMORY);
-
- /* check the instance slot against NULL */
- /* we don't need that for <init> methods, as the verifier */
- /* ensures that they are only called for an uninit. object */
- /* (which may not be NULL). */
-
- if (!callee->isstatic && i == 0 && calleem->name != utf_init) {
- assert(type == TYPE_ADR);
- n_ins = inline_instruction(iln, ICMD_CHECKNULL, o_iptr);
- n_ins->s1.varindex = varindex;
- n_ins->dst.varindex = n_ins->s1.varindex;
- }
-
- /* store argument into local variable of inlined callee */
-
- if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
- {
- /* this value is used in the callee */
-
- if (i == 0 && callee->synclocal != UNUSED) {
- /* we also need it for synchronization, so copy it */
- assert(type == TYPE_ADR);
- n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
- }
- else {
- n_ins = inline_instruction(iln, ICMD_ISTORE + type, o_iptr);
- n_ins->sx.s23.s3.javaindex = UNUSED;
- }
- n_ins->s1.varindex = varindex;
- n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
- assert(n_ins->dst.varindex != UNUSED);
- }
- else if (i == 0 && callee->synclocal != UNUSED) {
- /* the value is not used inside the callee, but we need it for */
- /* synchronization */
- /* XXX In this case it actually makes no sense to create a */
- /* separate synchronization variable. */
-
- n_ins = inline_instruction(iln, ICMD_NOP, o_iptr);
- }
- else {
- /* this value is not used, pop it */
-
- n_ins = inline_instruction(iln, ICMD_POP, o_iptr);
- n_ins->s1.varindex = varindex;
- }
-
- DOLOG( printf("%sprolog: ", iln->indent);
- show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
- }
-
- /* COPY for synchronized instance methods */
-
- if (callee->synclocal != UNUSED) {
- n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
- n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
- n_ins->dst.varindex = callee->synclocal;
-
- assert(n_ins->s1.varindex != UNUSED);
- }
-
- if (callee->synchronize) {
- inline_generate_sync_builtin(iln, callee, o_iptr,
- (callee->isstatic) ? UNUSED : varmap[o_iptr->sx.s23.s2.args[0]],
- LOCK_monitor_enter);
- }
-
- /* INLINE_BODY instruction */
-
- n_ins = inline_instruction(iln, ICMD_INLINE_BODY, callee->jd->basicblocks[0].iinstr);
- n_ins->sx.s23.s3.inlineinfo = insinfo;
-
- return 0; /* XXX */
-}
-
-
-static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
-{
- instruction *n_ins;
- s4 *jl;
-
- assert(iln && callee && o_iptr);
- assert(callee->inline_start_instruction);
-
- if (callee->synchronize) {
- inline_generate_sync_builtin(iln, callee, o_iptr,
- callee->synclocal,
- LOCK_monitor_exit);
- }
-
- /* INLINE_END instruction */
-
- n_ins = inline_instruction(iln, ICMD_INLINE_END, o_iptr);
- n_ins->sx.s23.s3.inlineinfo = callee->inline_start_instruction->sx.s23.s3.inlineinfo;
-
- /* set the javalocals */
-
- jl = DMNEW(s4, iln->jd->maxlocals);
- MCOPY(jl, iln->javalocals, s4, iln->jd->maxlocals);
- n_ins->sx.s23.s3.inlineinfo->javalocals_end = jl;
-
- DOLOG( printf("%sepilog: ", iln->indent);
- show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
-}
-
-
-#define TRANSLATE_VAROP(vo) \
- n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
-
-
-static void inline_clone_instruction(inline_node *iln,
- jitdata *jd,
- jitdata *origjd,
- s4 *varmap,
- instruction *o_iptr,
- instruction *n_iptr)
-{
- icmdtable_entry_t *icmdt;
- builtintable_entry *bte;
- methoddesc *md;
- s4 i, j;
- branch_target_t *table;
- lookup_target_t *lookup;
- inline_node *scope;
-
- *n_iptr = *o_iptr;
-
- icmdt = &(icmd_table[o_iptr->opc]);
-
- switch (icmdt->dataflow) {
- case DF_0_TO_0:
- break;
-
- case DF_3_TO_0:
- TRANSLATE_VAROP(sx.s23.s3);
- case DF_2_TO_0:
- TRANSLATE_VAROP(sx.s23.s2);
- case DF_1_TO_0:
- TRANSLATE_VAROP(s1);
- break;
-
- case DF_2_TO_1:
- TRANSLATE_VAROP(sx.s23.s2);
- case DF_1_TO_1:
- case DF_COPY:
- case DF_MOVE:
- TRANSLATE_VAROP(s1);
- case DF_0_TO_1:
- TRANSLATE_VAROP(dst);
- break;
-
- case DF_N_TO_1:
- n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
- for (i=0; i<n_iptr->s1.argcount; ++i) {
- n_iptr->sx.s23.s2.args[i] =
- inline_translate_variable(jd, origjd, varmap,
- o_iptr->sx.s23.s2.args[i]);
- }
- TRANSLATE_VAROP(dst);
- break;
-
- case DF_INVOKE:
- INSTRUCTION_GET_METHODDESC(n_iptr, md);
-clone_call:
- n_iptr->s1.argcount += iln->n_passthroughcount;
- n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
- for (i=0; i<o_iptr->s1.argcount; ++i) {
- n_iptr->sx.s23.s2.args[i] =
- inline_translate_variable(jd, origjd, varmap,
- o_iptr->sx.s23.s2.args[i]);
- }
- for (scope = iln; scope != NULL; scope = scope->parent) {
- for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
- n_iptr->sx.s23.s2.args[i++] =
- scope->parent->varmap[scope->n_passthroughvars[j]];
- }
- }
- if (md->returntype.type != TYPE_VOID)
- TRANSLATE_VAROP(dst);
- break;
-
- case DF_BUILTIN:
- bte = n_iptr->sx.s23.s3.bte;
- md = bte->md;
- goto clone_call;
-
- default:
- assert(0);
- }
-
- switch (icmdt->controlflow) {
- case CF_RET:
- TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
- /* FALLTHROUGH */
- case CF_IF:
- case CF_GOTO:
- inline_add_block_reference(iln, &(n_iptr->dst.block));
- break;
-
- case CF_JSR:
- inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
- break;
-
- case CF_TABLE:
- i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
-
- table = DMNEW(branch_target_t, i);
- MCOPY(table, o_iptr->dst.table, branch_target_t, i);
- n_iptr->dst.table = table;
-
- while (--i >= 0) {
- inline_add_block_reference(iln, &(table->block));
- table++;
- }
- break;
-
- case CF_LOOKUP:
- inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
-
- i = n_iptr->sx.s23.s2.lookupcount;
- lookup = DMNEW(lookup_target_t, i);
- MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
- n_iptr->dst.lookup = lookup;
-
- while (--i >= 0) {
- inline_add_block_reference(iln, &(lookup->target.block));
- lookup++;
- }
- break;
- }
-
- /* XXX move this to dataflow section? */
-
- switch (n_iptr->opc) {
- case ICMD_ASTORE:
-#if 0
- if (n_iptr->flags.bits & INS_FLAG_RETADDR)
- inline_add_blocknr_reference(iln, &(n_iptr->sx.s23.s2.retaddrnr));
-#endif
- /* FALLTHROUGH! */
- case ICMD_ISTORE:
- case ICMD_LSTORE:
- case ICMD_FSTORE:
- case ICMD_DSTORE:
- stack_javalocals_store(n_iptr, iln->javalocals);
- break;
- }
-}
-
-
-static void inline_rewrite_method(inline_node *iln)
-{
- basicblock *o_bptr;
- s4 len;
- instruction *o_iptr;
- instruction *n_iptr;
- inline_node *nextcall;
- basicblock *n_bptr;
- inline_block_map *bm;
- int i;
- int icount;
- jitdata *resultjd;
- jitdata *origjd;
- char indent[100]; /* XXX debug */
- s4 retcount;
- s4 retidx;
-
- assert(iln);
-
- resultjd = iln->ctx->resultjd;
- origjd = iln->jd;
-
- n_bptr = NULL;
- nextcall = iln->children;
-
- /* XXX debug */
- for (i=0; i<iln->depth; ++i)
- indent[i] = '\t';
- indent[i] = 0;
- iln->indent = indent;
-
- DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
- printf("%s(passthrough: %d+%d)\n",
- indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
- iln->n_passthroughcount); );
-
- /* set memory cursors */
-
- iln->inlined_iinstr_cursor = iln->inlined_iinstr;
- iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
-
- /* allocate temporary buffers */
-
- iln->javalocals = DMNEW(s4, iln->jd->maxlocals);
-
- /* loop over basic blocks */
-
- o_bptr = iln->jd->basicblocks;
- for (; o_bptr; o_bptr = o_bptr->next) {
-
- if (o_bptr->flags < BBREACHED) {
-
- /* ignore the dummy end block */
-
- if (o_bptr->icount == 0 && o_bptr->next == NULL) {
- /* enter the following block as translation, for exception handler ranges */
- inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
- continue;
- }
-
- DOLOG(
- printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
- indent,
- o_bptr->nr, o_bptr->flags, o_bptr->type,
- o_bptr->indepth);
- method_println(iln->m);
- );
-
- n_bptr = create_body_block(iln, o_bptr, iln->varmap);
-
- /* enter it in the blockmap */
-
- inline_block_translation(iln, o_bptr, n_bptr);
-
- close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
- continue;
- }
-
- len = o_bptr->icount;
- o_iptr = o_bptr->iinstr;
-
- DOLOG(
- printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
- indent,
- o_bptr->nr, o_bptr->flags, o_bptr->type,
- o_bptr->indepth);
- method_println(iln->m);
- show_basicblock(iln->jd, o_bptr, SHOW_STACK);
- );
-
- if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
- /* create an inlined clone of this block */
-
- n_bptr = create_body_block(iln, o_bptr, iln->varmap);
- icount = 0;
-
- /* enter it in the blockmap */
-
- inline_block_translation(iln, o_bptr, n_bptr);
-
- /* initialize the javalocals */
-
- MCOPY(iln->javalocals, n_bptr->javalocals, s4, iln->jd->maxlocals);
- }
- else {
- s4 *jl;
-
- /* continue caller block */
-
- n_bptr = iln->inlined_basicblocks_cursor - 1;
- icount = n_bptr->icount;
-
- /* translate the javalocals */
-
- jl = translate_javalocals(iln, o_bptr->javalocals);
- iln->inline_start_instruction->sx.s23.s3.inlineinfo->javalocals_start = jl;
-
- MCOPY(iln->javalocals, jl, s4, iln->jd->maxlocals);
- }
-
- /* iterate over the ICMDs of this block */
-
- retcount = 0;
- retidx = UNUSED;
-
- while (--len >= 0) {
-
- DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false, SHOW_STACK);
- printf("\n") );
-
- /* handle calls that will be inlined */
-
- if (nextcall && o_iptr == nextcall->callerins) {
-
- /* write the inlining prolog */
-
- (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
- icount += nextcall->prolog_instructioncount;
-
- /* end current block, or glue blocks together */
-
- n_bptr->icount = icount;
-
- if (nextcall->blockbefore) {
- close_prolog_block(iln, n_bptr, nextcall);
- }
- else {
- /* XXX */
- }
-
- /* check if the result is a local variable */
-
- if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
- && o_iptr->dst.varindex < iln->jd->localcount)
- {
- nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
- }
- else
- nextcall->n_resultlocal = -1;
-
- /* set memory pointers in the callee */
-
- nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
- nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
-
- /* recurse */
-
- DOLOG( printf("%sentering inline ", indent);
- show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
-
- inline_rewrite_method(nextcall);
-
- DOLOG( printf("%sleaving inline ", indent);
- show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
-
- /* update memory cursors */
-
- assert(nextcall->inlined_iinstr_cursor
- <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
- assert(nextcall->inlined_basicblocks_cursor
- == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
- iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
- iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
-
- /* start new block, or glue blocks together */
-
- if (nextcall->blockafter) {
- n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
- icount = 0;
- }
- else {
- n_bptr = iln->inlined_basicblocks_cursor - 1;
- icount = n_bptr->icount;
- /* XXX */
- }
-
- /* emit inlining epilog */
-
- emit_inlining_epilog(iln, nextcall, o_iptr);
- icount += nextcall->epilog_instructioncount;
-
- /* proceed to next call */
-
- nextcall = nextcall->next;
- }
- else {
- n_iptr = (iln->inlined_iinstr_cursor++);
- assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
-
- switch (o_iptr->opc) {
- case ICMD_RETURN:
- if (iln->depth == 0)
- goto default_clone;
- goto return_tail;
-
- case ICMD_IRETURN:
- case ICMD_ARETURN:
- case ICMD_LRETURN:
- case ICMD_FRETURN:
- case ICMD_DRETURN:
- if (iln->depth == 0)
- goto default_clone;
- retcount = 1;
- retidx = iln->varmap[o_iptr->s1.varindex];
- if (iln->n_resultlocal != -1) {
- /* store result in a local variable */
-
- DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
- /* This relies on the same sequence of types for */
- /* ?STORE and ?RETURN opcodes. */
- n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
- n_iptr->s1.varindex = retidx;
- n_iptr->dst.varindex = iln->n_resultlocal;
- n_iptr->sx.s23.s3.javaindex = UNUSED; /* XXX set real javaindex? */
-
- retcount = 0;
- retidx = UNUSED;
-
- n_iptr = (iln->inlined_iinstr_cursor++);
- assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
- icount++;
- }
- else if ((retidx < resultjd->localcount && iln->blockafter)
- || !iln->blockafter) /* XXX do we really always need the MOVE? */
- {
- /* local must not become outvar, insert a MOVE */
-
- n_iptr->opc = ICMD_MOVE;
- n_iptr->s1.varindex = retidx;
- retidx = inline_new_temp_variable(resultjd,
- resultjd->var[retidx].type);
- n_iptr->dst.varindex = retidx;
-
- n_iptr = (iln->inlined_iinstr_cursor++);
- assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
- icount++;
- }
-return_tail:
- if (iln->blockafter) {
- n_iptr->opc = ICMD_GOTO;
- n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
- inline_add_block_reference(iln, &(n_iptr->dst.block));
- }
- else {
- n_iptr->opc = ICMD_NOP;
- }
- break;
-#if 0
- if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
- n_iptr->opc = ICMD_NOP;
- break;
- }
- goto default_clone;
- break;
-#endif
-
- default:
-default_clone:
- inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
- }
-
- DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
- printf("\n"););
-
- icount++;
- }
-
- o_iptr++;
- }
-
- /* end of basic block */
-
- if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
- close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
- n_bptr->icount = icount;
-
- DOLOG( printf("closed body block:\n");
- show_basicblock(resultjd, n_bptr, SHOW_STACK); );
- }
- else {
- n_bptr->icount = icount;
- assert(iln->parent);
- if (retidx != UNUSED)
- iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
- }
- }
-
- bm = iln->ctx->blockmap;
- for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
- assert(bm->iln && bm->o_block && bm->n_block);
- if (bm->iln == iln)
- inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block, false);
- }
-
-#if !defined(NDEBUG)
- if (iln->refs) {
- inline_target_ref *ref;
- ref = iln->refs;
- while (ref) {
- if (!iln->depth || ref->isnumber || *(ref->ref.block) != INLINE_RETURN_REFERENCE(iln)) {
- DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
- (void*)*(ref->ref.block)) );
- assert(false);
- }
- ref = ref->next;
- }
- }
-#endif
-}
-
-
-static exception_entry * inline_exception_tables(inline_node *iln,
- exception_entry *n_extable,
- exception_entry **prevextable)
-{
- inline_node *child;
- inline_node *scope;
- exception_entry *et;
-
- assert(iln);
- assert(n_extable);
- assert(prevextable);
-
- child = iln->children;
- if (child) {
- do {
- n_extable = inline_exception_tables(child, n_extable, prevextable);
- child = child->next;
- } while (child != iln->children);
- }
-
- et = iln->jd->exceptiontable;
- for (; et != NULL; et = et->down) {
- assert(et);
- MZERO(n_extable, exception_entry, 1);
- n_extable->start = inline_map_block(iln, et->start , iln);
- n_extable->end = inline_map_block(iln, et->end , iln);
- n_extable->handler = inline_map_block(iln, et->handler, iln);
- n_extable->catchtype = et->catchtype;
-
- if (*prevextable) {
- (*prevextable)->down = n_extable;
- }
- *prevextable = n_extable;
-
- n_extable++;
- }
-
- if (iln->handler_monitorexit) {
- exception_entry **activehandlers;
-
- MZERO(n_extable, exception_entry, 1);
- n_extable->start = iln->inlined_basicblocks;
- n_extable->end = iln->inlined_basicblocks_cursor;
- n_extable->handler = iln->handler_monitorexit;
- n_extable->catchtype.any = NULL; /* finally */
-
- if (*prevextable) {
- (*prevextable)->down = n_extable;
- }
- *prevextable = n_extable;
-
- n_extable++;
-
- /* We have to protect the created handler with the same handlers */
- /* that protect the method body itself. */
-
- for (scope = iln; scope->parent != NULL; scope = scope->parent) {
-
- activehandlers = scope->o_handlers;
- assert(activehandlers);
-
- while (*activehandlers) {
-
- assert(scope->parent);
-
- MZERO(n_extable, exception_entry, 1);
- n_extable->start = iln->handler_monitorexit;
- n_extable->end = iln->handler_monitorexit + 1; /* XXX ok in this case? */
- n_extable->handler = inline_map_block(scope->parent,
- (*activehandlers)->handler,
- scope->parent);
- n_extable->catchtype = (*activehandlers)->catchtype;
-
- if (*prevextable) {
- (*prevextable)->down = n_extable;
- }
- *prevextable = n_extable;
-
- n_extable++;
- activehandlers++;
- }
- }
- }
-
- return n_extable;
-}
-
-
-static void inline_locals(inline_node *iln)
-{
- inline_node *child;
-
- assert(iln);
-
- iln->varmap = create_variable_map(iln);
-
- child = iln->children;
- if (child) {
- do {
- inline_locals(child);
- child = child->next;
- } while (child != iln->children);
- }
-
- if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
- iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
- if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
- iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
- if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
- iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
-}
-
-
-static void inline_interface_variables(inline_node *iln)
-{
- basicblock *bptr;
- jitdata *resultjd;
- s4 i;
- varinfo *v;
-
- resultjd = iln->ctx->resultjd;
-
- resultjd->interface_map = DMNEW(interface_info, 5*iln->ctx->maxinoutdepth);
- for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
- resultjd->interface_map[i].flags = UNUSED;
-
- for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
- assert(bptr->indepth <= iln->ctx->maxinoutdepth);
- assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
-
- for (i=0; i<bptr->indepth; ++i) {
- v = &(resultjd->var[bptr->invars[i]]);
- v->flags |= INOUT;
- if (v->type == TYPE_RET)
- v->flags |= PREALLOC;
- else
- v->flags &= ~PREALLOC;
- v->flags &= ~INMEMORY;
- assert(bptr->invars[i] >= resultjd->localcount);
-
- if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
- resultjd->interface_map[5*i + v->type].flags = v->flags;
- }
- else {
- resultjd->interface_map[5*i + v->type].flags |= v->flags;
- }
- }
-
- for (i=0; i<bptr->outdepth; ++i) {
- v = &(resultjd->var[bptr->outvars[i]]);
- v->flags |= INOUT;
- if (v->type == TYPE_RET)
- v->flags |= PREALLOC;
- else
- v->flags &= ~PREALLOC;
- v->flags &= ~INMEMORY;
- assert(bptr->outvars[i] >= resultjd->localcount);
-
- if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
- resultjd->interface_map[5*i + v->type].flags = v->flags;
- }
- else {
- resultjd->interface_map[5*i + v->type].flags |= v->flags;
- }
- }
- }
-}
-
-
-static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
-{
- basicblock *n_bptr;
- instruction *n_ins;
- inline_node *child;
- builtintable_entry *bte;
- s4 exvar;
- s4 syncvar;
- s4 i;
-
- child = iln->children;
- if (child) {
- do {
- inline_write_exception_handlers(master, child);
- child = child->next;
- } while (child != iln->children);
- }
-
- if (iln->synchronize) {
- /* create the monitorexit handler */
- n_bptr = create_block(master, iln, iln,
- iln->n_passthroughcount + 1);
- n_bptr->type = BBTYPE_EXH;
- n_bptr->flags = BBFINISHED;
-
- exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
- n_bptr->invars[iln->n_passthroughcount] = exvar;
-
- iln->handler_monitorexit = n_bptr;
-
- /* ACONST / ALOAD */
-
- n_ins = master->inlined_iinstr_cursor++;
- if (iln->m->flags & ACC_STATIC) {
- n_ins->opc = ICMD_ACONST;
- n_ins->sx.val.c.cls = iln->m->clazz;
- n_ins->flags.bits = INS_FLAG_CLASS;
- }
- else {
- n_ins->opc = ICMD_ALOAD;
- n_ins->s1.varindex = iln->synclocal;
- assert(n_ins->s1.varindex != UNUSED);
- }
- /* XXX could be PREALLOCed for builtin call */
- syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
- n_ins->dst.varindex = syncvar;
- n_ins->line = 0;
-
- /* MONITOREXIT */
-
- bte = builtintable_get_internal(LOCK_monitor_exit);
-
- n_ins = master->inlined_iinstr_cursor++;
- n_ins->opc = ICMD_BUILTIN;
- n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
- n_ins->sx.s23.s2.args = DMNEW(s4, n_ins->s1.argcount);
- n_ins->sx.s23.s2.args[0] = syncvar;
- for (i=0; i < iln->n_passthroughcount + 1; ++i) {
- n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
- }
- n_ins->sx.s23.s3.bte = bte;
- n_ins->line = 0;
-
- /* ATHROW */
-
- n_ins = master->inlined_iinstr_cursor++;
- n_ins->opc = ICMD_ATHROW;
- n_ins->flags.bits = 0;
- n_ins->s1.varindex = exvar;
- n_ins->line = 0;
-
- /* close basic block */
-
- close_block(iln, iln, n_bptr, iln->n_passthroughcount);
- n_bptr->icount = 3;
- }
-}
-
-
-/* second pass driver *********************************************************/
-
-static bool inline_transform(inline_node *iln, jitdata *jd)
-{
- instruction *n_ins;
- basicblock *n_bb;
- basicblock *n_bptr;
- exception_entry *n_ext;
- exception_entry *prevext;
- codegendata *n_cd;
- jitdata *n_jd;
- s4 i;
-#if defined(INLINE_VERIFY_RESULT)
- static int debug_verify_inlined_code = 1;
-#endif
-#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
- static int debug_counter = 0;
-#endif
-
- DOLOG( dump_inline_tree(iln, 0); );
-
- assert(iln && jd);
-
- n_ins = DMNEW(instruction, iln->cumul_instructioncount);
- MZERO(n_ins, instruction, iln->cumul_instructioncount);
- iln->inlined_iinstr = n_ins;
-
- n_bb = DMNEW(basicblock, iln->cumul_basicblockcount);
- MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
- iln->inlined_basicblocks = n_bb;
-
- iln->ctx->blockmap = DMNEW(inline_block_map, iln->cumul_blockmapcount);
-
- n_jd = jit_jitdata_new(iln->m);
- n_jd->flags = jd->flags;
- n_jd->code->optlevel = jd->code->optlevel;
- iln->ctx->resultjd = n_jd;
-
- reg_setup(n_jd);
-
- /* create the local_map */
-
- n_jd->local_map = DMNEW(s4, 5*iln->cumul_maxlocals);
- for (i=0; i<5*iln->cumul_maxlocals; ++i)
- n_jd->local_map[i] = UNUSED;
-
- /* create / coalesce local variables */
-
- n_jd->varcount = 0;
- n_jd->vartop = 0;
- n_jd->var = NULL;
-
- inline_locals(iln);
-
- n_jd->localcount = n_jd->vartop;
-
- /* extra variables for verification (debugging) */
-
-#if defined(INLINE_VERIFY_RESULT)
- if (debug_verify_inlined_code) {
- n_jd->vartop += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
- if (n_jd->vartop > n_jd->varcount) {
- /* XXX why? */
- n_jd->var = DMREALLOC(n_jd->var, varinfo, n_jd->varcount, n_jd->vartop);
- n_jd->varcount = n_jd->vartop;
- }
- }
-#endif /* defined(INLINE_VERIFY_RESULT) */
-
- /* write inlined code */
-
- inline_rewrite_method(iln);
-
- /* create exception handlers */
-
- inline_write_exception_handlers(iln, iln);
-
- /* write the dummy end block */
-
- n_bptr = create_block(iln, iln, iln, 0);
- n_bptr->flags = BBUNDEF;
- n_bptr->type = BBTYPE_STD;
-
- /* store created code in jitdata */
-
- n_jd->basicblocks = iln->inlined_basicblocks;
- n_jd->instructioncount = iln->cumul_instructioncount;
- n_jd->instructions = iln->inlined_iinstr;
-
- /* link the basic blocks (dummy end block is not counted) */
-
- n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
- for (i=0; i<n_jd->basicblockcount + 1; ++i)
- n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
- if (i)
- n_jd->basicblocks[i-1].next = NULL;
-
- /* check basicblock numbers */
-
-#if !defined(NDEBUG)
- jit_check_basicblock_numbers(n_jd);
-#endif
-
- /* create the exception table */
-
- if (iln->cumul_exceptiontablelength) {
- exception_entry *tableend;
-
- n_ext = DMNEW(exception_entry, iln->cumul_exceptiontablelength);
- prevext = NULL;
- tableend = inline_exception_tables(iln, n_ext, &prevext);
- assert(tableend == n_ext + iln->cumul_exceptiontablelength);
- if (prevext)
- prevext->down = NULL;
-
- n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
- n_jd->exceptiontable = n_ext;
- }
- else {
- n_ext = NULL;
- }
-
- /*******************************************************************************/
-
- n_cd = n_jd->cd;
- memcpy(n_cd, jd->cd, sizeof(codegendata));
-
- n_cd->method = NULL; /* XXX */
- n_jd->maxlocals = iln->cumul_maxlocals;
- n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
-
- inline_post_process(n_jd);
-
- inline_interface_variables(iln);
-
- /* for debugging, verify the inlined result */
-
-#if defined(INLINE_VERIFY_RESULT)
- if (debug_verify_inlined_code) {
- debug_verify_inlined_code = 0;
- DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
- if (!typecheck(n_jd)) {
- exceptions_clear_exception();
- DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
- return false;
- }
- else {
- DOLOG( printf("VERIFICATION PASSED.\n") );
- }
- debug_verify_inlined_code = 1;
- }
-#endif /* defined(INLINE_VERIFY_RESULT) */
-
- /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
-
- n_jd->rd->freemem = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
-
-#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
- if ( (n_jd->instructioncount >= opt_InlineMinSize)
- && (n_jd->instructioncount <= opt_InlineMaxSize))
- {
- if (debug_counter < opt_InlineCount)
-#endif /* defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) */
- {
- /* install the inlined result */
-
- *jd->code = *n_jd->code;
- n_jd->code = jd->code;
- *jd = *n_jd;
-
- /* statistics and logging */
-
-#if !defined(NDEBUG)
- inline_stat_roots++;
-
- DOLOG_SHORT(
- printf("==== %d.INLINE ==================================================================\n",
- debug_counter);
- printf("\ninline tree:\n");
- dump_inline_tree(iln, 0);
- n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
- /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
- printf("-------- DONE -----------------------------------------------------------\n");
- fflush(stdout);
- );
-#endif
- }
-
-#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
- debug_counter++;
- }
-#endif
- return true;
-}
-
-
-/******************************************************************************/
-/* FIRST PASS: build inlining tree */
-/******************************************************************************/
-
-
-/* inline_pre_parse_heuristics *************************************************
-
- Perform heuristic checks whether a call site should be inlined.
- These checks are evaluated before the callee has been parsed and analysed.
-
- IN:
- caller...........inlining node of the caller
- callee...........the called method
- site.............information on the call site
-
- RETURN VALUE:
- true........consider for inlining
- false.......don't inline
-
-*******************************************************************************/
-
-static bool inline_pre_parse_heuristics(const inline_node *caller,
- const methodinfo *callee,
- inline_site *site)
-{
-#if defined(INLINE_MAX_DEPTH)
- if (caller->depth >= INLINE_MAX_DEPTH)
- return false;
-#endif
-
- return true;
-}
-
-
-/* inline_post_parse_heuristics ************************************************
-
- Perform heuristic checks whether a call site should be inlined.
- These checks are evaluated after the callee has been parsed and analysed.
-
- IN:
- caller...........inlining node of the caller (const)
- callee...........the called method (const)
-
- RETURN VALUE:
- true........consider for inlining
- false.......don't inline
-
-*******************************************************************************/
-
-static bool inline_post_parse_heuristics(const inline_node *caller,
- const inline_node *callee)
-{
- return true;
-}
-
-
-/* inline_afterwards_heuristics ************************************************
-
- Perform heuristic checks whether a call site should be inlined.
- These checks are evaluated after the inlining plan for the callee has
- been made.
-
- IN:
- caller...........inlining node of the caller (const)
- callee...........the called method (const)
-
- RETURN VALUE:
- true........consider for inlining
- false.......don't inline
-
-*******************************************************************************/
-
-static bool inline_afterwards_heuristics(const inline_node *caller,
- const inline_node *callee)
-{
- inline_node *cumulator;
-
-#if defined(INLINE_DEPTH_FIRST)
- cumulator = caller;
-#else
- cumulator = caller->ctx->master;
-#endif
-
- if (0
-#if defined(INLINE_MAX_BLOCK_EXPANSION)
- || (cumulator->cumul_basicblockcount + callee->cumul_basicblockcount
- > INLINE_MAX_BLOCK_EXPANSION*caller->ctx->master->jd->basicblockcount)
-#endif
-#if defined(INLINE_MAX_ICMD_EXPANSION)
- || (cumulator->cumul_instructioncount + callee->cumul_instructioncount
- > INLINE_MAX_ICMD_EXPANSION*caller->ctx->master->jd->instructioncount)
-#endif
- )
- {
- return false;
- }
-
- return true;
-}
-
-
-/* inline_is_monomorphic *******************************************************
-
- Check if the given call site can be proven to be monomorphic.
-
- IN:
- callee...........the called method
- call.............the invocation instruction
-
- OUT:
- site->speculative.....flags whether the inlining is speculative
- (only defined if return value is true)
-
- RETURN VALUE:
- true if the call site is (currently) monomorphic,
- false if not or unknown
-
-*******************************************************************************/
-
-static bool inline_is_monomorphic(const methodinfo *callee,
- const instruction *call,
- inline_site *site)
-{
- if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
- || call->opc == ICMD_INVOKESPECIAL))
- {
- site->speculative = false;
- return true;
- }
-
- /* XXX search single implementation for abstract monomorphics */
-
- if ((callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED
- | ACC_ABSTRACT))
- == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED))
- {
- if (1) {
- DOLOG( printf("SPECULATIVE INLINE: "); method_println((methodinfo*)callee); );
- site->speculative = true;
-
- return true;
- }
- }
-
- /* possibly polymorphic call site */
-
- return false;
-}
-
-
-/* inline_can_inline ***********************************************************
-
- Check if inlining of the given call site is possible.
-
- IN:
- caller...........inlining node of the caller
- callee...........the called method
- call.............the invocation instruction
-
- OUT:
- site->speculative.....flags whether the inlining is speculative
- (only defined if return value is true)
-
- RETURN VALUE:
- true if inlining is possible, false if not
-
-*******************************************************************************/
-
-static bool inline_can_inline(const inline_node *caller,
- const methodinfo *callee,
- const instruction *call,
- inline_site *site)
-{
- const inline_node *active;
-
- /* cannot inline native methods */
-
- if (callee->flags & ACC_NATIVE)
- return false;
-
- /* cannot inline possibly polymorphic calls */
-
- if (!inline_is_monomorphic(callee, call, site))
- return false;
-
- /* cannot inline recursive calls */
-
- for (active = caller; active; active = active->parent) {
- if (callee == active->m) {
- DOLOG( printf("RECURSIVE!\n") );
- return false;
- }
- }
-
- /* inlining is possible */
-
- return true;
-}
-
-
-/* inline_create_callee_node ***************************************************
-
- Create an inlining node for the given callee.
-
- IN:
- caller...........inlining node of the caller (const)
- callee...........the called method
-
- RETURN VALUE:
- the new inlining node
-
-*******************************************************************************/
-
-static inline_node * inline_create_callee_node(const inline_node *caller,
- methodinfo *callee)
-{
- inline_node *cn; /* the callee inline_node */
-
- cn = DNEW(inline_node);
- MZERO(cn, inline_node, 1);
-
- cn->depth = caller->depth + 1;
- cn->ctx = caller->ctx;
- cn->m = callee;
- cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
- cn->isstatic = (callee->flags & ACC_STATIC);
-
- return cn;
-}
-
-
-/* inline_set_callee_properties ************************************************
-
- Set properties of the inlined call site.
-
- IN:
- caller...........inlining node of the caller (const)
- cn...............the called method
- site.............info about the call site (const)
-
- OUT:
- *cn..............has the properties set
-
-*******************************************************************************/
-
-static void inline_set_callee_properties(const inline_node *caller,
- inline_node *cn,
- const inline_site *site)
-{
- s4 argi;
- s4 i, j;
- basicblock *bptr;
-
- /* set info about the call site */
-
- cn->callerblock = site->bptr;
- cn->callerins = site->iptr;
- cn->callerpc = site->pc;
- cn->o_handlers = site->handlers;
- cn->n_handlercount = caller->n_handlercount + site->nhandlers;
-
- /* determine if we need basic block boundaries before/after */
-
- cn->blockbefore = false;
- cn->blockafter = false;
-
- if (cn->jd->branchtoentry)
- cn->blockbefore = true;
-
- if (cn->jd->branchtoend)
- cn->blockafter = true;
-
- if (cn->jd->returncount > 1)
- cn->blockafter = true;
-
- /* XXX make safer and reusable (maybe store last real block) */
- for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
- ;
-
- if (cn->jd->returnblock != bptr)
- cn->blockafter = true;
-
- /* info about the callee */
-
- cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
- cn->prolog_instructioncount = cn->m->parseddesc->paramcount + 2;
- cn->epilog_instructioncount = 1; /* INLINE_END */
- cn->extra_instructioncount = 0;
-
- /* we need a CHECKNULL for instance methods, except for <init> */
-
- if (!cn->isstatic && cn->m->name != utf_init)
- cn->prolog_instructioncount += 1;
-
- /* deal with synchronized callees */
-
- if (cn->synchronize) {
- methoddesc *md;
- builtintable_entry *bte;
-
- /* we need basic block boundaries because of the handler */
-
- cn->blockbefore = true;
- cn->blockafter = true;
-
- /* for synchronized static methods */
- /* we need an ACONST, MONITORENTER in the prolog */
- /* and ACONST, MONITOREXIT in the epilog */
-
- /* for synchronized instance methods */
- /* we need an COPY, MONITORENTER in the prolog */
- /* and MONITOREXIT in the epilog */
-
- if (cn->isstatic) {
- cn->prolog_instructioncount += 2;
- cn->epilog_instructioncount += 2;
- }
- else {
- cn->prolog_instructioncount += 2;
- cn->epilog_instructioncount += 1;
- cn->localsoffset += 1;
- }
-
- /* and exception handler */
- /* ALOAD, builtin_monitorexit, ATHROW */
-
- cn->extra_instructioncount += 3;
-
- /* exception table entries */
-
- cn->extra_exceptiontablelength = 1 + cn->n_handlercount;
-
- /* add exception handler block */
-
- cn->cumul_basicblockcount_root++;
-
- /* we must call the builtins */
-
- bte = builtintable_get_internal(LOCK_monitor_enter);
- md = bte->md;
- if (md->memuse > cn->regdata->memuse)
- cn->regdata->memuse = md->memuse;
- if (md->argintreguse > cn->regdata->argintreguse)
- cn->regdata->argintreguse = md->argintreguse;
-
- bte = builtintable_get_internal(LOCK_monitor_exit);
- md = bte->md;
- if (md->memuse > cn->regdata->memuse)
- cn->regdata->memuse = md->memuse;
- if (md->argintreguse > cn->regdata->argintreguse)
- cn->regdata->argintreguse = md->argintreguse;
- }
-
- /* determine pass-through variables */
-
- i = site->iptr->s1.argcount - cn->m->parseddesc->paramcount; /* max # of pass-though vars */
-
- cn->n_passthroughvars = DMNEW(s4, i);
- j = 0;
- for (argi = site->iptr->s1.argcount - 1; argi >= cn->m->parseddesc->paramcount; --argi) {
- s4 idx = site->iptr->sx.s23.s2.args[argi];
- if (idx >= caller->jd->localcount) {
- cn->n_passthroughvars[j] = idx;
- j++;
- }
- else {
- DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
- }
- }
- assert(j <= i);
- cn->n_selfpassthroughcount = j;
- cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
-}
-
-
-/* inline_cumulate_counters ****************************************************
-
- Cumulate counters after a node has been decided to become inlined.
-
- IN:
- caller...........inlining node of the caller
- callee...........inlining node of the callee (const)
-
- OUT:
- *caller..........gets cumulated values added
-
-*******************************************************************************/
-
-static void inline_cumulate_counters(inline_node *caller,
- const inline_node *cn)
-{
- caller->cumul_instructioncount += cn->prolog_instructioncount;
- caller->cumul_instructioncount += cn->epilog_instructioncount;
- caller->cumul_instructioncount += cn->extra_instructioncount;
- caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
-
- caller->cumul_basicblockcount += cn->cumul_basicblockcount;
- caller->cumul_basicblockcount_root += cn->cumul_basicblockcount_root;
- caller->cumul_blockmapcount += cn->cumul_blockmapcount;
- caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
- caller->cumul_exceptiontablelength += cn->extra_exceptiontablelength;
-
- if (cn->cumul_maxlocals > caller->cumul_maxlocals)
- caller->cumul_maxlocals = cn->cumul_maxlocals;
-
- /* XXX extra block after inlined call */
- if (cn->blockafter) {
- caller->cumul_basicblockcount += 1;
- caller->cumul_blockmapcount += 1;
- }
-}
-
-
-/* inline_analyse_callee *******************************************************
-
- Analyse an inlining candidate callee.
-
- IN:
- caller...........inlining node of the caller
- callee...........the called method
- site.............info about the call site
-
- OUT:
- site->inlined....true if the callee has been selected for inlining
-
- RETURN VALUE:
- the inline node of the callee, or
- NULL if an error has occurred (don't use the inlining plan in this case)
-
-*******************************************************************************/
-
-static inline_node * inline_analyse_callee(inline_node *caller,
- methodinfo *callee,
- inline_site *site)
-{
- inline_node *cn; /* the callee inline_node */
-
- /* create an inline tree node */
-
- cn = inline_create_callee_node(caller, callee);
-
- /* get the intermediate representation of the callee */
-
- if (!inline_jit_compile(cn))
- return NULL;
-
- /* evaluate heuristics after parsing the callee */
-
- if (!inline_post_parse_heuristics(caller, cn))
- return cn;
-
- /* the call site will be inlined */
-
- site->inlined = true;
-
- /* set info about the call site */
-
- inline_set_callee_properties(caller, cn, site);
-
- /* insert the node into the inline tree */
-
- inline_insert_inline_node(caller, cn);
-
- /* analyse recursively */
-
- if (!inline_analyse_code(cn))
- return NULL;
-
- if (!inline_afterwards_heuristics(caller, cn)) {
-#if defined(INLINE_CANCEL_ON_THRESHOLD)
- return NULL;
-#else
- inline_remove_inline_node(caller, cn);
- caller->ctx->stopped = true;
- site->inlined = false;
- return cn;
-#endif
- }
-
- /* cumulate counters */
-
-#if defined(INLINE_DEPTH_FIRST)
- inline_cumulate_counters(caller, cn);
-#endif
-
-#if defined(INLINE_BREADTH_FIRST)
- while (caller) {
- inline_cumulate_counters(caller, cn);
- caller = caller->parent;
- }
-#endif
-
- return cn;
-}
-
-
-/* inline_process_candidate ****************************************************
-
- Process a selected inlining candidate.
-
- IN:
- cand.............the candidate
-
- RETURN VALUE:
- true........everything ok
- false.......an error has occurred, don't use the plan
-
-*******************************************************************************/
-
-static bool inline_process_candidate(inline_candidate *cand)
-{
- inline_node *cn;
-
- cn = inline_analyse_callee(cand->caller,
- cand->callee,
- &(cand->site));
-
- if (!cn)
- return false;
-
- if (!cand->site.inlined)
- return true;
-
- /* store assumptions */
-
- if (cand->site.speculative)
- method_add_assumption_monomorphic(cand->callee, cand->caller->ctx->master->m);
-
- return true;
-}
-
-
-/* inline_analyse_code *********************************************************
-
- Analyse the intermediate code of the given inlining node.
-
- IN:
- iln..............the inlining node
-
- OUT:
- *iln.............the inlining plan
-
- RETURN VALUE:
- true........everything ok
- false.......an error has occurred, don't use the plan
-
-*******************************************************************************/
-
-static bool inline_analyse_code(inline_node *iln)
-{
- methodinfo *m;
- basicblock *bptr;
- s4 len;
- instruction *iptr;
- methodinfo *callee;
- exception_entry **handlers;
- exception_entry *ex;
- s4 nhandlers;
- s4 blockendpc;
- jitdata *mjd;
- inline_site site;
-
- assert(iln);
-
- m = iln->m;
- mjd = iln->jd;
-
- /* initialize cumulative counters */
-
- iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
- iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
-
- /* iterate over basic blocks */
-
- blockendpc = 0;
-
- for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
-
- /* count the block */
- /* ignore dummy end blocks (but count them for the blockmap) */
-
- iln->cumul_blockmapcount++;
- if ((bptr != mjd->basicblocks || iln->blockbefore)
- &&
- (bptr->icount > 0 || bptr->next != NULL))
- iln->cumul_basicblockcount++;
-
- /* skip dead code */
-
- if (bptr->flags < BBREACHED)
- continue;
-
- /* allocate the buffer of active exception handlers */
- /* XXX this wastes some memory, but probably it does not matter */
-
- handlers = DMNEW(exception_entry*, mjd->exceptiontablelength + 1);
-
- /* determine the active exception handlers for this block */
- /* XXX maybe the handlers of a block should be part of our IR */
- /* XXX this should share code with the type checkers */
- nhandlers = 0;
- for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
- if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
- handlers[nhandlers++] = ex;
- }
- }
- handlers[nhandlers] = NULL;
-
- len = bptr->icount;
- iptr = bptr->iinstr;
-
- blockendpc += len;
- iln->cumul_instructioncount += len;
-
- /* iterate over the instructions of the block */
-
- for (; --len >= 0; ++iptr) {
-
- switch (iptr->opc) {
- case ICMD_INVOKEVIRTUAL:
- case ICMD_INVOKESPECIAL:
- case ICMD_INVOKESTATIC:
- case ICMD_INVOKEINTERFACE:
-
- if (!INSTRUCTION_IS_UNRESOLVED(iptr) && !iln->ctx->stopped) {
- callee = iptr->sx.s23.s3.fmiref->p.method;
-
- if (inline_can_inline(iln, callee, iptr, &site)) {
- site.inlined = false;
- site.bptr = bptr;
- site.iptr = iptr;
- site.pc = blockendpc - len - 1;
- site.handlers = handlers;
- site.nhandlers = nhandlers;
-
- if (inline_pre_parse_heuristics(iln, callee, &site)) {
-#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
- inline_add_candidate(iln->ctx, iln, callee, &site);
-#else
- inline_candidate cand;
- cand.caller = iln;
- cand.callee = callee;
- cand.site = site;
-
- if (!inline_process_candidate(&cand))
- return false;
-#endif
- }
- }
- }
- break;
-
- case ICMD_RETURN:
- case ICMD_IRETURN:
- case ICMD_ARETURN:
- case ICMD_LRETURN:
- case ICMD_FRETURN:
- case ICMD_DRETURN:
- /* extra ICMD_MOVE may be necessary */
- iln->cumul_instructioncount++;
- break;
- }
- }
-
- /* end of basic block */
- }
-
- return true;
-}
-
-
-static void inline_cumulate_counters_recursive(inline_node *iln)
-{
- inline_node *child;
-
- child = iln->children;
- if (child) {
- do {
- inline_cumulate_counters_recursive(child);
- inline_cumulate_counters(iln, child);
- child = child->next;
- } while (child != iln->children);
- }
-}
-
-
-/* inline_make_inlining_plan ***************************************************
-
- Make an inlining plan for the given root node
-
- IN:
- iln..............the root node
-
- OUT:
- *iln.............the inlining plan
-
- RETURN VALUE:
- true........everything ok
- false.......an error has occurred, don't use the plan
-
-*******************************************************************************/
-
-#if defined(INLINE_KNAPSACK)
-static bool inline_make_inlining_plan(inline_node *iln)
-{
- inline_candidate *cand;
-#if defined(INLINE_COST_BUDGET)
- s4 budget = INLINE_COST_BUDGET;
-# define BUDGETMEMBER cost
-#endif
-#if defined(INLINE_WEIGHT_BUDGET)
- double budget = INLINE_WEIGHT_BUDGET;
-# define BUDGETMEMBER weight
-#endif
-
- inline_analyse_code(iln);
-
- DOLOG( printf("candidates in "); method_println(iln->m);
- inline_candidates_println(iln->ctx); );
-
- while ((cand = inline_pick_best_candidate(iln->ctx)) != NULL)
- {
- if (cand->BUDGETMEMBER <= budget) {
- DOLOG( printf(" picking: "); inline_candidate_println(cand); );
-
- if (!inline_process_candidate(cand))
- return false;
-
-#if !defined(INLINE_ADD_NEGATIVE_TO_BUDGET)
- if (cand->BUDGETMEMBER > 0)
-#endif
- budget -= cand->BUDGETMEMBER;
- }
- }
-
- inline_cumulate_counters_recursive(iln);
-
- return true;
-}
-#endif /* defined(INLINE_KNAPSACK) */
-
-
-#if defined(INLINE_DEPTH_FIRST)
-static bool inline_make_inlining_plan(inline_node *iln)
-{
- return inline_analyse_code(iln);
-}
-#endif /* defined(INLINE_DEPTH_FIRST) */
-
-
-#if defined(INLINE_BREADTH_FIRST)
-static bool inline_make_inlining_plan(inline_node *iln)
-{
- inline_candidate *cand;
-
- inline_analyse_code(iln);
-
- DOLOG( printf("candidates in "); method_println(iln->m);
- inline_candidates_println(iln->ctx); );
-
- while (!iln->ctx->stopped
- && (cand = inline_pick_best_candidate(iln->ctx)) != NULL)
- {
- DOLOG( printf(" picking: "); inline_candidate_println(cand); );
-
- if (!inline_process_candidate(cand))
- return false;
- }
-
- return true;
-}
-#endif /* defined(INLINE_BREADTH_FIRST) */
-
-
-/* statistics *****************************************************************/
-
-#if defined(INLINE_STATISTICS)
-static void inline_gather_statistics_recursive(inline_node *iln)
-{
- inline_node *child;
-
- inline_stat_inlined_nodes++;
-
- if (iln->depth > inline_stat_max_depth)
- inline_stat_max_depth++;
-
- child = iln->children;
- if (child) {
- do {
- inline_gather_statistics_recursive(child);
- child = child->next;
- } while (child != iln->children);
- }
-}
-#endif /* defined(INLINE_STATISTICS) */
-
-
-#if defined(INLINE_STATISTICS)
-static void inline_gather_statistics(inline_node *iln)
-{
- inline_stat_roots_transformed++;
-
- inline_gather_statistics_recursive(iln);
-}
-#endif /* defined(INLINE_STATISTICS) */
-
-
-/* post processing ************************************************************/
-
-#define POSTPROCESS_SRC(varindex) live[varindex]--
-#define POSTPROCESS_DST(varindex) live[varindex]++
-
-#define POSTPROCESS_SRCOP(s) POSTPROCESS_SRC(iptr->s.varindex)
-#define POSTPROCESS_DSTOP(d) POSTPROCESS_DST(iptr->d.varindex)
-
-#define MARKSAVED(varindex) jd->var[varindex].flags |= SAVEDVAR
-
-#define MARK_ALL_SAVED \
- do { \
- for (i=0; i<jd->vartop; ++i) \
- if (live[i]) \
- MARKSAVED(i); \
- } while (0)
-
-static void inline_post_process(jitdata *jd)
-{
- codeinfo *code;
- basicblock *bptr;
- instruction *iptr;
- instruction *iend;
- s4 i;
- icmdtable_entry_t *icmdt;
- s4 *live;
- methoddesc *md;
- builtintable_entry *bte;
-
- /* Get required compiler data. */
-
- code = jd->code;
-
- /* reset the SAVEDVAR flag of all variables */
-
- for (i=0; i<jd->vartop; ++i)
- jd->var[i].flags &= ~SAVEDVAR;
-
- /* allocate the life counters */
-
- live = DMNEW(s4, jd->vartop);
- MZERO(live, s4, jd->vartop);
-
- /* iterate over all basic blocks */
-
- for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
- if (bptr->flags < BBREACHED)
- continue;
-
- /* make invars live */
-
- for (i=0; i<bptr->indepth; ++i)
- POSTPROCESS_DST(bptr->invars[i]);
-
- iptr = bptr->iinstr;
- iend = iptr + bptr->icount;
-
- for (; iptr < iend; ++iptr) {
-
- icmdt = &(icmd_table[iptr->opc]);
-
- switch (icmdt->dataflow) {
- case DF_3_TO_0:
- POSTPROCESS_SRCOP(sx.s23.s3);
- case DF_2_TO_0:
- POSTPROCESS_SRCOP(sx.s23.s2);
- case DF_1_TO_0:
- POSTPROCESS_SRCOP(s1);
- case DF_0_TO_0:
- if (icmdt->flags & ICMDTABLE_CALLS) {
- code_unflag_leafmethod(code);
- MARK_ALL_SAVED;
- }
- break;
-
- case DF_2_TO_1:
- POSTPROCESS_SRCOP(sx.s23.s2);
- case DF_1_TO_1:
- case DF_MOVE:
- POSTPROCESS_SRCOP(s1);
- case DF_0_TO_1:
- if (icmdt->flags & ICMDTABLE_CALLS) {
- code_unflag_leafmethod(code);
- MARK_ALL_SAVED;
- }
- case DF_COPY:
- POSTPROCESS_DSTOP(dst);
- break;
-
- case DF_N_TO_1:
- for (i=0; i<iptr->s1.argcount; ++i) {
- POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
- }
- if (icmdt->flags & ICMDTABLE_CALLS) {
- code_unflag_leafmethod(code);
- MARK_ALL_SAVED;
- }
- POSTPROCESS_DSTOP(dst);
- break;
-
- case DF_INVOKE:
- INSTRUCTION_GET_METHODDESC(iptr, md);
- post_process_call:
- code_unflag_leafmethod(code);
- for (i=0; i<md->paramcount; ++i) {
- POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
- }
- for (; i<iptr->s1.argcount; ++i) {
- MARKSAVED(iptr->sx.s23.s2.args[i]);
- }
- if (md->returntype.type != TYPE_VOID)
- POSTPROCESS_DSTOP(dst);
- break;
-
- case DF_BUILTIN:
- bte = iptr->sx.s23.s3.bte;
- md = bte->md;
- goto post_process_call;
-
- default:
- assert(0);
- }
-
- } /* end instruction loop */
-
- /* consume outvars */
-
- for (i=0; i<bptr->outdepth; ++i)
- POSTPROCESS_SRC(bptr->outvars[i]);
-
-#if !defined(NDEBUG)
- for (i=jd->localcount; i < jd->vartop; ++i)
- assert(live[i] == 0);
-#endif
-
- } /* end basic block loop */
-}
-
-
-/* inline_create_root_node *****************************************************
-
- Create the root node of the inlining tree.
-
- IN:
- jd...............the current jitdata of the root method
-
- RETURN VALUE:
- the root node of the inlining tree
-
-*******************************************************************************/
-
-static inline_node * inline_create_root_node(jitdata *jd)
-{
- inline_node *iln;
-
- iln = DNEW(inline_node);
- MZERO(iln, inline_node, 1);
-
- iln->m = jd->m;
- iln->jd = jd;
- iln->regdata = jd->rd;
-
- iln->blockbefore = true;
- iln->blockafter = true;
-
- iln->cumul_instructioncount = 0;
- iln->cumul_basicblockcount = 1 /* dummy end block */;
-
- /* create inlining context */
-
- iln->ctx = DNEW(inline_context);
- MZERO(iln->ctx, inline_context, 1);
- iln->ctx->master = iln;
- iln->ctx->next_debugnr = 1; /* XXX debug */
-
- return iln;
-}
-
-
-/******************************************************************************/
-/* MAIN DRIVER FUNCTION */
-/******************************************************************************/
-
-bool inline_inline(jitdata *jd)
-{
- inline_node *iln;
-
- DOLOG( printf("==== INLINE ==================================================================\n");
- show_method(jd, SHOW_STACK); );
-
-#if defined(INLINE_STATISTICS)
- inline_stat_roots++;
-#endif
-
- iln = inline_create_root_node(jd);
-
- if (inline_make_inlining_plan(iln)) {
-
- /* add blocks to the root node */
-
- iln->cumul_basicblockcount += iln->cumul_basicblockcount_root;
- iln->cumul_blockmapcount += iln->cumul_basicblockcount_root;
-
- DOLOG( printf("==== INLINE TRANSFORM ========================================================\n"); );
-
- if (iln->children)
- inline_transform(iln, jd);
-
-#if defined(INLINE_STATISTICS)
- inline_gather_statistics(iln);
-#endif
- }
-
- DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
- fflush(stdout); );
-
- return true;
-}
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
--- /dev/null
+/* src/vm/jit/inline/inline.c - method inlining
+
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "threads/lock.hpp"
+#include "threads/mutex.hpp"
+#include "threads/thread.hpp"
+
+#include "toolbox/logging.h"
+
+#include "vm/jit/builtin.hpp"
+#include "vm/class.hpp"
+#include "vm/global.h"
+#include "vm/initialize.hpp"
+#include "vm/method.h"
+#include "vm/options.h"
+#include "vm/statistics.h"
+
+#include "vm/jit/jit.hpp"
+#include "vm/jit/parse.hpp"
+#include "vm/jit/reg.h"
+#include "vm/jit/show.hpp"
+#include "vm/jit/stack.h"
+
+#include "vm/jit/inline/inline.hpp"
+#include "vm/jit/loop/loop.h"
+
+#include "vm/jit/verify/typecheck.h"
+
+
+/* algorithm tuning constants *************************************************/
+
+/* Algorithm Selection */
+/* Define exactly one of the following three to select the inlining */
+/* heuristics. */
+
+/*#define INLINE_DEPTH_FIRST*/
+/*#define INLINE_BREADTH_FIRST*/
+#define INLINE_KNAPSACK
+
+/* Parameters for knapsack heuristics: */
+
+#if defined(INLINE_KNAPSACK)
+
+#define INLINE_COUNTDOWN_INIT 1000
+#define INLINE_COST_OFFSET -16
+#define INLINE_COST_BUDGET 100
+/*#define INLINE_WEIGHT_BUDGET 5.0*/
+/*#define INLINE_ADD_NEGATIVE_TO_BUDGET*/
+/*#define INLINE_MAX_DEPTH 3*/
+/*#define INLINE_DIVIDE_COST_BY_FREQ */
+
+#endif
+
+/* Parameters for depth-first heuristics: */
+
+#if defined(INLINE_DEPTH_FIRST)
+
+#define INLINE_MAX_DEPTH 3
+#define INLINE_MAX_BLOCK_EXPANSION 10
+/*#define INLINE_MAX_ICMD_EXPANSION 10*/
+/*#define INLINE_CANCEL_ON_THRESHOLD*/
+
+#endif
+
+/* Parameters for breadth-first heuristics: */
+
+#if defined(INLINE_BREADTH_FIRST)
+
+/*#define INLINE_MAX_BLOCK_EXPANSION 10*/
+#define INLINE_MAX_ICMD_EXPANSION 5
+
+#endif
+
+
+/* debugging ******************************************************************/
+
+#if !defined(NDEBUG)
+#define INLINE_VERBOSE
+#define DOLOG(code) do{ if (opt_TraceInlining >= 2) { code; } }while(0)
+#define DOLOG_SHORT(code) do{ if (opt_TraceInlining >= 1) { code; } }while(0)
+#else
+#define DOLOG(code)
+#endif
+
+#if defined(ENABLE_VERIFIER) && !defined(NDEBUG)
+/* Define this to verify the resulting code after inlining. */
+/* Note: This is only useful for development and may require patches to the */
+/* verifier code. */
+/* #define INLINE_VERIFY_RESULT */
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* types **********************************************************************/
+
+typedef struct inline_node inline_node;
+typedef struct inline_target_ref inline_target_ref;
+typedef struct inline_context inline_context;
+typedef struct inline_block_map inline_block_map;
+typedef struct inline_site inline_site;
+typedef struct inline_candidate inline_candidate;
+
+struct inline_node {
+ inline_context *ctx;
+
+ jitdata *jd;
+ methodinfo *m;
+ inline_node *children;
+ inline_node *next; /* next node at this depth */
+ inline_node *prev; /* prev node at this depth */
+ int depth; /* inlining depth, 0 for root */
+
+ /* info about the call site (if depth > 0)*/
+ inline_node *parent; /* node of the caller (NULL for root) */
+ basicblock *callerblock; /* original block containing the INVOKE* */
+ instruction *callerins; /* the original INVOKE* instruction */
+ s4 callerpc;
+ s4 *n_passthroughvars;
+ int n_passthroughcount;
+ int n_selfpassthroughcount; /* # of pass-through vars of the call itself */
+ exception_entry **o_handlers;
+ int n_handlercount; /* # of handlers protecting this call */
+ int n_resultlocal;
+ int synclocal; /* variable used for synchr., or UNUSED */
+ bool isstatic; /* this is a static call */
+
+ bool blockbefore; /* block boundary before inlined body? */
+ bool blockafter; /* block boundary after inlined body? */
+
+ /* info about the callee */
+ int localsoffset;
+ int prolog_instructioncount; /* # of ICMDs in the inlining prolog */
+ int epilog_instructioncount; /* # of ICMDs in the inlining epilog */
+ int extra_instructioncount;
+ int extra_exceptiontablelength; /* # of extra handlers to put in caller */
+ bool synchronize; /* do we have to synchronize enter/exit? */
+ basicblock *handler_monitorexit; /* handler for synchronized inlinees */
+ s4 *varmap;
+
+ /* cumulative values */
+ int cumul_instructioncount; /* ICMDs in this node and its children */
+ int cumul_basicblockcount; /* BBs started by this node and its children */
+ int cumul_basicblockcount_root; /* BBs that have to be added to the root */
+ /* node if this node is inlined */
+ int cumul_blockmapcount;
+ int cumul_maxlocals;
+ int cumul_exceptiontablelength;
+
+ /* output */
+ instruction *inlined_iinstr;
+ instruction *inlined_iinstr_cursor;
+ basicblock *inlined_basicblocks;
+ basicblock *inlined_basicblocks_cursor;
+
+ /* register data */
+ registerdata *regdata;
+
+ /* temporary */
+ inline_target_ref *refs;
+ instruction *inline_start_instruction;
+ s4 *javalocals;
+
+ /* XXX debug */
+ char *indent;
+ int debugnr;
+};
+
+struct inline_target_ref {
+ inline_target_ref *next;
+ union {
+ basicblock **block;
+ s4 *nr;
+ } ref;
+ basicblock *target;
+ bool isnumber;
+};
+
+struct inline_block_map {
+ inline_node *iln;
+ basicblock *o_block;
+ basicblock *n_block;
+};
+
+struct inline_context {
+ inline_node *master;
+
+ jitdata *resultjd;
+
+ inline_candidate *candidates;
+
+ int next_block_number;
+ inline_block_map *blockmap;
+ int blockmap_index;
+
+ int maxinoutdepth;
+
+ bool stopped;
+
+ int next_debugnr; /* XXX debug */
+};
+
+struct inline_site {
+ bool speculative; /* true, if inlining would be speculative */
+ bool inlined; /* true, if this site has been inlined */
+
+ basicblock *bptr; /* basic block containing the call site */
+ instruction *iptr; /* the invocation instruction */
+ exception_entry **handlers; /* active handlers at the call site */
+ s4 nhandlers; /* number of active handlers */
+ s4 pc; /* PC of the invocation instruction */
+};
+
+struct inline_candidate {
+ inline_candidate *next;
+ int freq;
+ int cost;
+ double weight;
+ inline_node *caller;
+ methodinfo *callee;
+ inline_site site;
+};
+
+
+/* prototypes *****************************************************************/
+
+static bool inline_analyse_code(inline_node *iln);
+static void inline_post_process(jitdata *jd);
+
+
+/* debug helpers **************************************************************/
+
+#if !defined(NDEBUG)
+#include "inline_debug.inc"
+#endif
+
+
+/* statistics *****************************************************************/
+
+/*#define INLINE_STATISTICS*/
+
+#if !defined(NDEBUG)
+#define INLINE_STATISTICS
+#endif
+
+#if defined(INLINE_STATISTICS)
+int inline_stat_roots = 0;
+int inline_stat_roots_transformed = 0;
+int inline_stat_inlined_nodes = 0;
+int inline_stat_max_depth = 0;
+
+void inline_print_stats()
+{
+ printf("inlining statistics:\n");
+ printf(" roots analysed : %d\n", inline_stat_roots);
+ printf(" roots transformed: %d\n", inline_stat_roots_transformed);
+ printf(" inlined nodes : %d\n", inline_stat_inlined_nodes);
+ printf(" max depth : %d\n", inline_stat_max_depth);
+}
+#endif
+
+
+/* compilation of callees *****************************************************/
+
+static bool inline_jit_compile_intern(jitdata *jd)
+{
+ methodinfo *m;
+
+ /* XXX should share code with jit.c */
+
+ assert(jd);
+
+ /* XXX initialize the static function's class */
+
+ m = jd->m;
+
+ /* call the compiler passes ***********************************************/
+
+ /* call parse pass */
+
+ DOLOG( log_message_class("Parsing ", m->clazz) );
+ if (!parse(jd)) {
+ return false;
+ }
+
+ /* call stack analysis pass */
+
+ if (!stack_analyse(jd)) {
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool inline_jit_compile(inline_node *iln)
+{
+ bool r;
+ methodinfo *m;
+ jitdata *jd;
+
+ /* XXX should share code with jit.c */
+
+ assert(iln);
+ m = iln->m;
+ assert(m);
+
+ /* enter a monitor on the method */
+
+ m->mutex->lock();
+
+ /* allocate jitdata structure and fill it */
+
+ jd = jit_jitdata_new(m);
+ iln->jd = jd;
+
+ jd->flags = 0; /* XXX */
+
+ /* initialize the register allocator */
+
+ reg_setup(jd);
+
+ /* setup the codegendata memory */
+
+ /* XXX do a pseudo setup */
+ jd->cd = (codegendata*) DumpMemory::allocate(sizeof(codegendata));
+ MZERO(jd->cd, codegendata, 1);
+ jd->cd->method = m;
+ /* XXX uses too much dump memory codegen_setup(jd); */
+
+ /* now call internal compile function */
+
+ r = inline_jit_compile_intern(jd);
+
+ if (r) {
+ iln->regdata = jd->rd;
+ }
+
+ /* free some memory */
+#if 0
+
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+ if (!opt_intrp)
+# endif
+ codegen_free(jd);
+#endif
+
+#endif
+
+ /* leave the monitor */
+
+ m->mutex->unlock();
+
+ return r;
+}
+
+
+/* inlining tree handling *****************************************************/
+
+static void inline_insert_inline_node(inline_node *parent, inline_node *child)
+{
+ inline_node *first;
+ inline_node *succ;
+
+ assert(parent && child);
+
+ child->parent = parent;
+
+ child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
+
+ first = parent->children;
+ if (!first) {
+ /* insert as only node */
+ parent->children = child;
+ child->next = child;
+ child->prev = child;
+ return;
+ }
+
+ /* {there is at least one child already there} */
+
+ /* XXX is this search necessary, or could we always add at the end? */
+
+ succ = first;
+ while (succ->callerpc < child->callerpc) {
+ succ = succ->next;
+ if (succ == first) {
+ /* insert as last node */
+ child->prev = first->prev;
+ child->next = first;
+ child->prev->next = child;
+ child->next->prev = child;
+ return;
+ }
+ }
+
+ assert(succ->callerpc > child->callerpc);
+
+ /* insert before succ */
+
+ child->prev = succ->prev;
+ child->next = succ;
+ child->prev->next = child;
+ child->next->prev = child;
+
+ if (parent->children == succ)
+ parent->children = child;
+}
+
+
+static void inline_remove_inline_node(inline_node *parent, inline_node *child)
+{
+ assert(parent);
+ assert(child);
+ assert(child->parent == parent);
+
+ if (child->prev == child) {
+ /* remove the only child node */
+ parent->children = NULL;
+ }
+ else {
+ child->prev->next = child->next;
+ child->next->prev = child->prev;
+
+ if (parent->children == child)
+ parent->children = child->next;
+ }
+}
+
+
+/* inlining candidate handling ************************************************/
+
+#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
+static void inline_add_candidate(inline_context *ctx,
+ inline_node *caller,
+ methodinfo *callee,
+ inline_site *site)
+{
+ inline_candidate **link;
+ inline_candidate *cand;
+
+ cand = (inline_candidate*) DumpMemory::allocate(sizeof(inline_candidate));
+#if defined(INLINE_DIVIDE_COST_BY_FREQ)
+ cand->freq = INLINE_COUNTDOWN_INIT - callee->hitcountdown;
+ if (cand->freq < 1)
+#endif
+ cand->freq = 1;
+#if defined(INLINE_KNAPSACK)
+ cand->cost = callee->jcodelength + INLINE_COST_OFFSET;
+#endif
+#if defined(INLINE_BREADTH_FIRST)
+ cand->cost = caller->depth;
+#endif
+ cand->caller = caller;
+ cand->callee = callee;
+ cand->site = *site;
+
+ cand->weight = (double)cand->cost / cand->freq;
+
+ for (link = &(ctx->candidates); ; link = &((*link)->next)) {
+ if (!*link || (*link)->weight > cand->weight) {
+ cand->next = *link;
+ *link = cand;
+ break;
+ }
+ }
+}
+#endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
+
+#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
+static inline_candidate * inline_pick_best_candidate(inline_context *ctx)
+{
+ inline_candidate *cand;
+
+ cand = ctx->candidates;
+
+ if (cand)
+ ctx->candidates = cand->next;
+
+ return cand;
+}
+#endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
+
+#if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
+static void inline_candidate_println(inline_candidate *cand)
+{
+ printf("%10g (%5d / %5d) depth %2d ",
+ cand->weight, cand->cost, cand->freq, cand->caller->depth + 1);
+ method_println(cand->callee);
+}
+#endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
+
+
+#if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
+static void inline_candidates_println(inline_context *ctx)
+{
+ inline_candidate *cand;
+
+ for (cand = ctx->candidates; cand != NULL; cand = cand->next) {
+ printf(" ");
+ inline_candidate_println(cand);
+ }
+}
+#endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
+
+
+/* variable handling **********************************************************/
+
+static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
+{
+ s4 index;
+ s4 newcount;
+
+ index = jd->vartop++;
+ if (index >= jd->varcount) {
+ newcount = jd->vartop * 2; /* XXX */
+ jd->var = (varinfo*) DumpMemory::reallocate(jd->var, sizeof(varinfo) * jd->varcount, sizeof(varinfo) * newcount);
+ MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
+ jd->varcount = newcount;
+ }
+
+ jd->var[index].type = type;
+ jd->var[index].flags = flags;
+
+ return index;
+}
+
+
+static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
+{
+ varinfo *v;
+ s4 newidx;
+
+ v = &(origjd->var[origidx]);
+
+ newidx = inline_new_variable(jd, v->type, v->flags);
+
+ jd->var[newidx].vv = v->vv;
+
+ return newidx;
+}
+
+
+static s4 inline_new_temp_variable(jitdata *jd, s4 type)
+{
+ return inline_new_variable(jd, type, 0);
+}
+
+
+static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
+{
+ s4 idx;
+
+ idx = varmap[index];
+
+ if (idx < 0) {
+ idx = inline_new_variable_clone(jd, origjd, index);
+ varmap[index] = idx;
+ }
+
+ return idx;
+}
+
+
+static s4 *create_variable_map(inline_node *callee)
+{
+ s4 *varmap;
+ s4 i, t;
+ s4 varindex;
+ s4 n_javaindex;
+ s4 avail;
+ varinfo *v;
+
+ /* create the variable mapping */
+
+ varmap = (s4*) DumpMemory::allocate(sizeof(s4) * callee->jd->varcount);
+ for (i=0; i<callee->jd->varcount; ++i)
+ varmap[i] = -1;
+
+ /* translate local variables */
+
+ for (i=0; i<callee->m->maxlocals; ++i) {
+ for (t=0; t<5; ++t) {
+ varindex = callee->jd->local_map[5*i + t];
+ if (varindex == UNUSED)
+ continue;
+
+ v = &(callee->jd->var[varindex]);
+ assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
+ v->type = t; /* XXX restore if it is TYPE_VOID */
+
+ avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
+
+ if (avail == UNUSED) {
+ avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, varindex);
+ callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
+ }
+
+ varmap[varindex] = avail;
+ }
+ }
+
+ /* for synchronized instance methods we need an extra local */
+
+ if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
+ n_javaindex = callee->localsoffset - 1;
+ assert(n_javaindex >= 0);
+ assert(callee->parent);
+ assert(n_javaindex == callee->parent->localsoffset + callee->parent->m->maxlocals);
+
+ avail = callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR];
+
+ if (avail == UNUSED) {
+ avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
+ callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR] = avail;
+ }
+
+ callee->synclocal = avail;
+ }
+ else {
+ callee->synclocal = UNUSED;
+ }
+
+ return varmap;
+}
+
+
+/* basic block translation ****************************************************/
+
+#define INLINE_RETURN_REFERENCE(callee) \
+ ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
+
+
+static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
+{
+ inline_target_ref *ref;
+
+ ref = (inline_target_ref*) DumpMemory::allocate(sizeof(inline_target_ref));
+ ref->ref.block = blockp;
+ ref->isnumber = false;
+ ref->next = iln->refs;
+ iln->refs = ref;
+}
+
+
+#if 0
+static void inline_add_blocknr_reference(inline_node *iln, s4 *nrp)
+{
+ inline_target_ref *ref;
+
+ ref = (inline_target_ref*) DumpMemory::allocate(inline_target_ref);
+ ref->ref.nr = nrp;
+ ref->isnumber = true;
+ ref->next = iln->refs;
+ iln->refs = ref;
+}
+#endif
+
+
+static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
+{
+ inline_context *ctx;
+
+ ctx = iln->ctx;
+ assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
+
+ ctx->blockmap[ctx->blockmap_index].iln = iln;
+ ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
+ ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
+
+ ctx->blockmap_index++;
+}
+
+
+static basicblock * inline_map_block(inline_node *iln,
+ basicblock *o_block,
+ inline_node *targetiln)
+{
+ inline_block_map *bm;
+ inline_block_map *bmend;
+
+ assert(iln);
+ assert(targetiln);
+
+ if (!o_block)
+ return NULL;
+
+ bm = iln->ctx->blockmap;
+ bmend = bm + iln->ctx->blockmap_index;
+
+ while (bm < bmend) {
+ assert(bm->iln && bm->o_block && bm->n_block);
+ if (bm->o_block == o_block && bm->iln == targetiln)
+ return bm->n_block;
+ bm++;
+ }
+
+ assert(false);
+ return NULL; /* not reached */
+}
+
+
+static void inline_resolve_block_refs(inline_target_ref **refs,
+ basicblock *o_bptr,
+ basicblock *n_bptr,
+ bool returnref)
+{
+ inline_target_ref *ref;
+ inline_target_ref *prev;
+
+ prev = NULL;
+ for (ref = *refs; ref != NULL; ref = ref->next) {
+ if (ref->isnumber && !returnref) {
+ if (*(ref->ref.nr) == JAVALOCAL_FROM_RETADDR(o_bptr->nr)) {
+ *(ref->ref.nr) = JAVALOCAL_FROM_RETADDR(n_bptr->nr);
+ goto remove_ref;
+ }
+ }
+ else {
+ if (*(ref->ref.block) == o_bptr) {
+ *(ref->ref.block) = n_bptr;
+ goto remove_ref;
+ }
+ }
+
+ /* skip this ref */
+
+ prev = ref;
+ continue;
+
+remove_ref:
+ /* remove this ref */
+
+ if (prev) {
+ prev->next = ref->next;
+ }
+ else {
+ *refs = ref->next;
+ }
+ }
+}
+
+
+/* basic block creation *******************************************************/
+
+static basicblock * create_block(inline_node *container,
+ inline_node *iln,
+ inline_node *inner,
+ int indepth)
+{
+ basicblock *n_bptr;
+ inline_node *outer;
+ s4 i;
+ s4 depth;
+ s4 varidx;
+ s4 newvaridx;
+
+ assert(container);
+ assert(iln);
+ assert(inner);
+ assert(indepth >= 0);
+
+ n_bptr = container->inlined_basicblocks_cursor++;
+ assert(n_bptr);
+ assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
+
+ BASICBLOCK_INIT(n_bptr, iln->m);
+
+ n_bptr->iinstr = container->inlined_iinstr_cursor;
+ n_bptr->next = n_bptr + 1;
+ n_bptr->nr = container->ctx->next_block_number++;
+ n_bptr->indepth = indepth;
+ n_bptr->flags = BBFINISHED; /* XXX */
+
+ /* set the inlineinfo of the new block */
+
+ if (iln->inline_start_instruction)
+ n_bptr->inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
+
+ if (indepth > container->ctx->maxinoutdepth)
+ container->ctx->maxinoutdepth = indepth;
+
+ if (indepth) {
+ n_bptr->invars = (s4*) DumpMemory::allocate(sizeof(s4) * indepth);
+
+
+ for (i=0; i<indepth; ++i)
+ n_bptr->invars[i] = -1; /* XXX debug */
+
+ /* pass-through variables enter the block */
+
+ outer = inner->parent;
+ while (outer != NULL) {
+ depth = outer->n_passthroughcount;
+
+ assert(depth + inner->n_selfpassthroughcount <= indepth);
+
+ for (i=0; i<inner->n_selfpassthroughcount; ++i) {
+ varidx = inner->n_passthroughvars[i];
+ newvaridx =
+ inline_new_variable_clone(container->ctx->resultjd,
+ outer->jd,
+ varidx);
+ n_bptr->invars[depth + i] = newvaridx;
+ outer->varmap[varidx] = newvaridx;
+ }
+ inner = outer;
+ outer = outer->parent;
+ }
+ }
+ else {
+ n_bptr->invars = NULL;
+ }
+
+ /* XXX for the verifier. should not be here */
+
+ {
+ varinfo *dv;
+
+ dv = (varinfo*) DumpMemory::allocate(sizeof(varinfo) * (iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS));
+ MZERO(dv, varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
+ n_bptr->inlocals = dv;
+ }
+
+ return n_bptr;
+}
+
+
+static s4 *translate_javalocals(inline_node *iln, s4 *javalocals)
+{
+ s4 *jl;
+ s4 i, j;
+
+ jl = (s4*) DumpMemory::allocate(sizeof(s4) * iln->jd->maxlocals);
+
+ for (i=0; i<iln->jd->maxlocals; ++i) {
+ j = javalocals[i];
+ if (j > UNUSED)
+ j = inline_translate_variable(iln->ctx->resultjd, iln->jd, iln->varmap, j);
+ jl[i] = j;
+
+#if 0
+ if (j < UNUSED) {
+ /* an encoded returnAddress value - must be relocated */
+ inline_add_blocknr_reference(iln, &(jl[i]));
+ }
+#endif
+ }
+
+ return jl;
+}
+
+
+static basicblock * create_body_block(inline_node *iln,
+ basicblock *o_bptr, s4 *varmap)
+{
+ basicblock *n_bptr;
+ s4 i;
+
+ n_bptr = create_block(iln, iln, iln,
+ o_bptr->indepth + iln->n_passthroughcount);
+
+ n_bptr->type = o_bptr->type;
+ n_bptr->flags = o_bptr->flags;
+ n_bptr->bitflags = o_bptr->bitflags;
+
+ /* resolve references to this block */
+
+ inline_resolve_block_refs(&(iln->refs), o_bptr, n_bptr, false);
+
+ /* translate the invars of the original block */
+
+ for (i=0; i<o_bptr->indepth; ++i) {
+ n_bptr->invars[iln->n_passthroughcount + i] =
+ inline_translate_variable(iln->ctx->resultjd, iln->jd,
+ varmap,
+ o_bptr->invars[i]);
+ }
+
+ /* translate javalocals info (not for dead code) */
+
+ if (n_bptr->flags >= BBREACHED)
+ n_bptr->javalocals = translate_javalocals(iln, o_bptr->javalocals);
+
+ return n_bptr;
+}
+
+
+static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
+{
+ basicblock *n_bptr;
+ s4 retcount;
+ s4 idx;
+
+ /* number of return variables */
+
+ retcount = (callee->n_resultlocal == -1
+ && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
+
+ /* start the epilog block */
+
+ n_bptr = create_block(caller, caller, callee,
+ callee->n_passthroughcount + retcount);
+
+ /* resolve references to the return block */
+
+ inline_resolve_block_refs(&(callee->refs),
+ INLINE_RETURN_REFERENCE(callee),
+ n_bptr,
+ true);
+
+ /* return variable */
+
+ if (retcount) {
+ idx = inline_new_variable(caller->ctx->resultjd,
+ callee->m->parseddesc->returntype.type, 0 /* XXX */);
+ n_bptr->invars[callee->n_passthroughcount] = idx;
+ varmap[callee->callerins->dst.varindex] = idx;
+ }
+
+ /* set javalocals */
+
+ n_bptr->javalocals = (s4*) DumpMemory::allocate(sizeof(s4) * caller->jd->maxlocals);
+ MCOPY(n_bptr->javalocals, caller->javalocals, s4, caller->jd->maxlocals);
+
+ /* set block flags & type */
+
+ n_bptr->flags = /* XXX original block flags */ BBFINISHED;
+ n_bptr->type = BBTYPE_STD;
+
+ return n_bptr;
+}
+
+
+static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
+{
+ inline_node *outer;
+ s4 i;
+ s4 depth;
+ s4 varidx;
+
+ n_bptr->outdepth = outdepth;
+ n_bptr->outvars = (s4*) DumpMemory::allocate(sizeof(s4) * outdepth);
+
+ for (i=0; i<outdepth; ++i)
+ n_bptr->outvars[i] = 0; /* XXX debug */
+
+ if (outdepth > iln->ctx->maxinoutdepth)
+ iln->ctx->maxinoutdepth = outdepth;
+
+ /* pass-through variables leave the block */
+
+ outer = inner->parent;
+ while (outer != NULL) {
+ depth = outer->n_passthroughcount;
+
+ assert(depth + inner->n_selfpassthroughcount <= outdepth);
+
+ for (i=0; i<inner->n_selfpassthroughcount; ++i) {
+ varidx = inner->n_passthroughvars[i];
+ n_bptr->outvars[depth + i] =
+ inline_translate_variable(iln->ctx->resultjd,
+ outer->jd,
+ outer->varmap,
+ varidx);
+ }
+ inner = outer;
+ outer = outer->parent;
+ }
+}
+
+
+static void close_prolog_block(inline_node *iln,
+ basicblock *n_bptr,
+ inline_node *nextcall)
+{
+ /* XXX add original outvars! */
+ close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
+
+ /* pass-through variables */
+
+ DOLOG( printf("closed prolog block:\n");
+ show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
+}
+
+
+static void close_body_block(inline_node *iln,
+ basicblock *n_bptr,
+ basicblock *o_bptr,
+ s4 *varmap,
+ s4 retcount,
+ s4 retidx)
+{
+ s4 i;
+
+ close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
+
+ /* translate the outvars of the original block */
+
+ /* XXX reuse code */
+ for (i=0; i<o_bptr->outdepth; ++i) {
+ n_bptr->outvars[iln->n_passthroughcount + i] =
+ inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
+ o_bptr->outvars[i]);
+ }
+
+ /* set the return variable, if any */
+
+ if (retcount) {
+ assert(retidx >= 0);
+ n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
+ }
+}
+
+
+/* inlined code generation ****************************************************/
+
+static instruction * inline_instruction(inline_node *iln,
+ s4 opcode,
+ instruction *o_iptr)
+{
+ instruction *n_iptr;
+
+ n_iptr = (iln->inlined_iinstr_cursor++);
+ assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
+
+ n_iptr->opc = opcode;
+ n_iptr->flags.bits = o_iptr->flags.bits & INS_FLAG_ID_MASK;
+ n_iptr->line = o_iptr->line;
+
+ return n_iptr;
+}
+
+static void inline_generate_sync_builtin(inline_node *iln,
+ inline_node *callee,
+ instruction *o_iptr,
+ s4 instancevar,
+ functionptr func)
+{
+ int syncvar;
+ instruction *n_ins;
+
+ if (callee->m->flags & ACC_STATIC) {
+ /* ACONST */
+ syncvar = inline_new_temp_variable(iln->ctx->resultjd, TYPE_ADR);
+
+ n_ins = inline_instruction(iln, ICMD_ACONST, o_iptr);
+ n_ins->sx.val.c.cls = callee->m->clazz;
+ n_ins->dst.varindex = syncvar;
+ n_ins->flags.bits |= INS_FLAG_CLASS;
+ }
+ else {
+ syncvar = instancevar;
+ }
+
+ assert(syncvar != UNUSED);
+
+ /* MONITORENTER / MONITOREXIT */
+
+ n_ins = inline_instruction(iln, ICMD_BUILTIN, o_iptr);
+ n_ins->sx.s23.s3.bte = builtintable_get_internal(func);
+ n_ins->s1.argcount = 1; /* XXX add through-vars */
+ n_ins->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4));
+ n_ins->sx.s23.s2.args[0] = syncvar;
+}
+
+static s4 emit_inlining_prolog(inline_node *iln,
+ inline_node *callee,
+ instruction *o_iptr,
+ s4 *varmap)
+{
+ methodinfo *calleem;
+ methoddesc *md;
+ int i;
+ int localindex;
+ int type;
+ instruction *n_ins;
+ insinfo_inline *insinfo;
+ s4 varindex;
+
+ assert(iln && callee && o_iptr);
+
+ calleem = callee->m;
+ md = calleem->parseddesc;
+
+ /* INLINE_START instruction */
+
+ n_ins = inline_instruction(iln, ICMD_INLINE_START, o_iptr);
+
+ insinfo = (insinfo_inline*) DumpMemory::allocate(sizeof(insinfo_inline));
+ insinfo->method = callee->m;
+ insinfo->outer = iln->m;
+ insinfo->synclocal = callee->synclocal;
+ insinfo->synchronize = callee->synchronize;
+ insinfo->javalocals_start = NULL;
+ insinfo->javalocals_end = NULL;
+
+ /* info about stack vars live at the INLINE_START */
+
+ insinfo->throughcount = callee->n_passthroughcount;
+ insinfo->paramcount = md->paramcount;
+ insinfo->stackvarscount = o_iptr->s1.argcount;
+ insinfo->stackvars = (s4*) DumpMemory::allocate(sizeof(s4) * insinfo->stackvarscount);
+ for (i=0; i<insinfo->stackvarscount; ++i)
+ insinfo->stackvars[i] = iln->varmap[o_iptr->sx.s23.s2.args[i]];
+
+ /* info about the surrounding inlining */
+
+ if (iln->inline_start_instruction)
+ insinfo->parent = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
+ else
+ insinfo->parent = NULL;
+
+ /* finish the INLINE_START instruction */
+
+ n_ins->sx.s23.s3.inlineinfo = insinfo;
+ callee->inline_start_instruction = n_ins;
+
+ DOLOG( printf("%sprolog: ", iln->indent);
+ show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
+
+ /* handle parameters for the inlined callee */
+
+ localindex = callee->localsoffset + md->paramslots;
+
+ for (i=md->paramcount-1; i>=0; --i) {
+ assert(iln);
+
+ type = md->paramtypes[i].type;
+
+ localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
+ assert(callee->regdata);
+
+ /* translate the argument variable */
+
+ varindex = varmap[o_iptr->sx.s23.s2.args[i]];
+ assert(varindex != UNUSED);
+
+ /* remove preallocation from the argument variable */
+
+ iln->ctx->resultjd->var[varindex].flags &= ~(PREALLOC | INMEMORY);
+
+ /* check the instance slot against NULL */
+ /* we don't need that for <init> methods, as the verifier */
+ /* ensures that they are only called for an uninit. object */
+ /* (which may not be NULL). */
+
+ if (!callee->isstatic && i == 0 && calleem->name != utf_init) {
+ assert(type == TYPE_ADR);
+ n_ins = inline_instruction(iln, ICMD_CHECKNULL, o_iptr);
+ n_ins->s1.varindex = varindex;
+ n_ins->dst.varindex = n_ins->s1.varindex;
+ }
+
+ /* store argument into local variable of inlined callee */
+
+ if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
+ {
+ /* this value is used in the callee */
+
+ if (i == 0 && callee->synclocal != UNUSED) {
+ /* we also need it for synchronization, so copy it */
+ assert(type == TYPE_ADR);
+ n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
+ }
+ else {
+ n_ins = inline_instruction(iln, ICMD_ISTORE + type, o_iptr);
+ n_ins->sx.s23.s3.javaindex = UNUSED;
+ }
+ n_ins->s1.varindex = varindex;
+ n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
+ assert(n_ins->dst.varindex != UNUSED);
+ }
+ else if (i == 0 && callee->synclocal != UNUSED) {
+ /* the value is not used inside the callee, but we need it for */
+ /* synchronization */
+ /* XXX In this case it actually makes no sense to create a */
+ /* separate synchronization variable. */
+
+ n_ins = inline_instruction(iln, ICMD_NOP, o_iptr);
+ }
+ else {
+ /* this value is not used, pop it */
+
+ n_ins = inline_instruction(iln, ICMD_POP, o_iptr);
+ n_ins->s1.varindex = varindex;
+ }
+
+ DOLOG( printf("%sprolog: ", iln->indent);
+ show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
+ }
+
+ /* COPY for synchronized instance methods */
+
+ if (callee->synclocal != UNUSED) {
+ n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
+ n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
+ n_ins->dst.varindex = callee->synclocal;
+
+ assert(n_ins->s1.varindex != UNUSED);
+ }
+
+ if (callee->synchronize) {
+ inline_generate_sync_builtin(iln, callee, o_iptr,
+ (callee->isstatic) ? UNUSED : varmap[o_iptr->sx.s23.s2.args[0]],
+ LOCK_monitor_enter);
+ }
+
+ /* INLINE_BODY instruction */
+
+ n_ins = inline_instruction(iln, ICMD_INLINE_BODY, callee->jd->basicblocks[0].iinstr);
+ n_ins->sx.s23.s3.inlineinfo = insinfo;
+
+ return 0; /* XXX */
+}
+
+
+static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
+{
+ instruction *n_ins;
+ s4 *jl;
+
+ assert(iln && callee && o_iptr);
+ assert(callee->inline_start_instruction);
+
+ if (callee->synchronize) {
+ inline_generate_sync_builtin(iln, callee, o_iptr,
+ callee->synclocal,
+ LOCK_monitor_exit);
+ }
+
+ /* INLINE_END instruction */
+
+ n_ins = inline_instruction(iln, ICMD_INLINE_END, o_iptr);
+ n_ins->sx.s23.s3.inlineinfo = callee->inline_start_instruction->sx.s23.s3.inlineinfo;
+
+ /* set the javalocals */
+
+ jl = (s4*) DumpMemory::allocate(sizeof(s4) * iln->jd->maxlocals);
+ MCOPY(jl, iln->javalocals, s4, iln->jd->maxlocals);
+ n_ins->sx.s23.s3.inlineinfo->javalocals_end = jl;
+
+ DOLOG( printf("%sepilog: ", iln->indent);
+ show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
+}
+
+
+#define TRANSLATE_VAROP(vo) \
+ n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
+
+
+static void inline_clone_instruction(inline_node *iln,
+ jitdata *jd,
+ jitdata *origjd,
+ s4 *varmap,
+ instruction *o_iptr,
+ instruction *n_iptr)
+{
+ icmdtable_entry_t *icmdt;
+ builtintable_entry *bte;
+ methoddesc *md;
+ s4 i, j;
+ branch_target_t *table;
+ lookup_target_t *lookup;
+ inline_node *scope;
+
+ *n_iptr = *o_iptr;
+
+ icmdt = &(icmd_table[o_iptr->opc]);
+
+ switch (icmdt->dataflow) {
+ case DF_0_TO_0:
+ break;
+
+ case DF_3_TO_0:
+ TRANSLATE_VAROP(sx.s23.s3);
+ case DF_2_TO_0:
+ TRANSLATE_VAROP(sx.s23.s2);
+ case DF_1_TO_0:
+ TRANSLATE_VAROP(s1);
+ break;
+
+ case DF_2_TO_1:
+ TRANSLATE_VAROP(sx.s23.s2);
+ case DF_1_TO_1:
+ case DF_COPY:
+ case DF_MOVE:
+ TRANSLATE_VAROP(s1);
+ case DF_0_TO_1:
+ TRANSLATE_VAROP(dst);
+ break;
+
+ case DF_N_TO_1:
+ n_iptr->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4) * n_iptr->s1.argcount);
+ for (i=0; i<n_iptr->s1.argcount; ++i) {
+ n_iptr->sx.s23.s2.args[i] =
+ inline_translate_variable(jd, origjd, varmap,
+ o_iptr->sx.s23.s2.args[i]);
+ }
+ TRANSLATE_VAROP(dst);
+ break;
+
+ case DF_INVOKE:
+ INSTRUCTION_GET_METHODDESC(n_iptr, md);
+clone_call:
+ n_iptr->s1.argcount += iln->n_passthroughcount;
+ n_iptr->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4) * n_iptr->s1.argcount);
+ for (i=0; i<o_iptr->s1.argcount; ++i) {
+ n_iptr->sx.s23.s2.args[i] =
+ inline_translate_variable(jd, origjd, varmap,
+ o_iptr->sx.s23.s2.args[i]);
+ }
+ for (scope = iln; scope != NULL; scope = scope->parent) {
+ for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
+ n_iptr->sx.s23.s2.args[i++] =
+ scope->parent->varmap[scope->n_passthroughvars[j]];
+ }
+ }
+ if (md->returntype.type != TYPE_VOID)
+ TRANSLATE_VAROP(dst);
+ break;
+
+ case DF_BUILTIN:
+ bte = n_iptr->sx.s23.s3.bte;
+ md = bte->md;
+ goto clone_call;
+
+ default:
+ assert(0);
+ }
+
+ switch (icmdt->controlflow) {
+ case CF_RET:
+ TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
+ /* FALLTHROUGH */
+ case CF_IF:
+ case CF_GOTO:
+ inline_add_block_reference(iln, &(n_iptr->dst.block));
+ break;
+
+ case CF_JSR:
+ inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
+ break;
+
+ case CF_TABLE:
+ i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
+
+ table = (branch_target_t*) DumpMemory::allocate(sizeof(branch_target_t) * i);
+ MCOPY(table, o_iptr->dst.table, branch_target_t, i);
+ n_iptr->dst.table = table;
+
+ while (--i >= 0) {
+ inline_add_block_reference(iln, &(table->block));
+ table++;
+ }
+ break;
+
+ case CF_LOOKUP:
+ inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
+
+ i = n_iptr->sx.s23.s2.lookupcount;
+ lookup = (lookup_target_t*) DumpMemory::allocate(sizeof(lookup_target_t) * i);
+ MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
+ n_iptr->dst.lookup = lookup;
+
+ while (--i >= 0) {
+ inline_add_block_reference(iln, &(lookup->target.block));
+ lookup++;
+ }
+ break;
+ }
+
+ /* XXX move this to dataflow section? */
+
+ switch (n_iptr->opc) {
+ case ICMD_ASTORE:
+#if 0
+ if (n_iptr->flags.bits & INS_FLAG_RETADDR)
+ inline_add_blocknr_reference(iln, &(n_iptr->sx.s23.s2.retaddrnr));
+#endif
+ /* FALLTHROUGH! */
+ case ICMD_ISTORE:
+ case ICMD_LSTORE:
+ case ICMD_FSTORE:
+ case ICMD_DSTORE:
+ stack_javalocals_store(n_iptr, iln->javalocals);
+ break;
+ }
+}
+
+
+static void inline_rewrite_method(inline_node *iln)
+{
+ basicblock *o_bptr;
+ s4 len;
+ instruction *o_iptr;
+ instruction *n_iptr;
+ inline_node *nextcall;
+ basicblock *n_bptr;
+ inline_block_map *bm;
+ int i;
+ int icount;
+ jitdata *resultjd;
+ jitdata *origjd;
+ char indent[100]; /* XXX debug */
+ s4 retcount;
+ s4 retidx;
+
+ assert(iln);
+
+ resultjd = iln->ctx->resultjd;
+ origjd = iln->jd;
+
+ n_bptr = NULL;
+ nextcall = iln->children;
+
+ /* XXX debug */
+ for (i=0; i<iln->depth; ++i)
+ indent[i] = '\t';
+ indent[i] = 0;
+ iln->indent = indent;
+
+ DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
+ printf("%s(passthrough: %d+%d)\n",
+ indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
+ iln->n_passthroughcount); );
+
+ /* set memory cursors */
+
+ iln->inlined_iinstr_cursor = iln->inlined_iinstr;
+ iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
+
+ /* allocate temporary buffers */
+
+ iln->javalocals = (s4*) DumpMemory::allocate(sizeof(s4) * iln->jd->maxlocals);
+
+ /* loop over basic blocks */
+
+ o_bptr = iln->jd->basicblocks;
+ for (; o_bptr; o_bptr = o_bptr->next) {
+
+ if (o_bptr->flags < BBREACHED) {
+
+ /* ignore the dummy end block */
+
+ if (o_bptr->icount == 0 && o_bptr->next == NULL) {
+ /* enter the following block as translation, for exception handler ranges */
+ inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
+ continue;
+ }
+
+ DOLOG(
+ printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
+ indent,
+ o_bptr->nr, o_bptr->flags, o_bptr->type,
+ o_bptr->indepth);
+ method_println(iln->m);
+ );
+
+ n_bptr = create_body_block(iln, o_bptr, iln->varmap);
+
+ /* enter it in the blockmap */
+
+ inline_block_translation(iln, o_bptr, n_bptr);
+
+ close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
+ continue;
+ }
+
+ len = o_bptr->icount;
+ o_iptr = o_bptr->iinstr;
+
+ DOLOG(
+ printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
+ indent,
+ o_bptr->nr, o_bptr->flags, o_bptr->type,
+ o_bptr->indepth);
+ method_println(iln->m);
+ show_basicblock(iln->jd, o_bptr, SHOW_STACK);
+ );
+
+ if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
+ /* create an inlined clone of this block */
+
+ n_bptr = create_body_block(iln, o_bptr, iln->varmap);
+ icount = 0;
+
+ /* enter it in the blockmap */
+
+ inline_block_translation(iln, o_bptr, n_bptr);
+
+ /* initialize the javalocals */
+
+ MCOPY(iln->javalocals, n_bptr->javalocals, s4, iln->jd->maxlocals);
+ }
+ else {
+ s4 *jl;
+
+ /* continue caller block */
+
+ n_bptr = iln->inlined_basicblocks_cursor - 1;
+ icount = n_bptr->icount;
+
+ /* translate the javalocals */
+
+ jl = translate_javalocals(iln, o_bptr->javalocals);
+ iln->inline_start_instruction->sx.s23.s3.inlineinfo->javalocals_start = jl;
+
+ MCOPY(iln->javalocals, jl, s4, iln->jd->maxlocals);
+ }
+
+ /* iterate over the ICMDs of this block */
+
+ retcount = 0;
+ retidx = UNUSED;
+
+ while (--len >= 0) {
+
+ DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false, SHOW_STACK);
+ printf("\n") );
+
+ /* handle calls that will be inlined */
+
+ if (nextcall && o_iptr == nextcall->callerins) {
+
+ /* write the inlining prolog */
+
+ (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
+ icount += nextcall->prolog_instructioncount;
+
+ /* end current block, or glue blocks together */
+
+ n_bptr->icount = icount;
+
+ if (nextcall->blockbefore) {
+ close_prolog_block(iln, n_bptr, nextcall);
+ }
+ else {
+ /* XXX */
+ }
+
+ /* check if the result is a local variable */
+
+ if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
+ && o_iptr->dst.varindex < iln->jd->localcount)
+ {
+ nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
+ }
+ else
+ nextcall->n_resultlocal = -1;
+
+ /* set memory pointers in the callee */
+
+ nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
+ nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
+
+ /* recurse */
+
+ DOLOG( printf("%sentering inline ", indent);
+ show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
+
+ inline_rewrite_method(nextcall);
+
+ DOLOG( printf("%sleaving inline ", indent);
+ show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
+
+ /* update memory cursors */
+
+ assert(nextcall->inlined_iinstr_cursor
+ <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
+ assert(nextcall->inlined_basicblocks_cursor
+ == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
+ iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
+ iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
+
+ /* start new block, or glue blocks together */
+
+ if (nextcall->blockafter) {
+ n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
+ icount = 0;
+ }
+ else {
+ n_bptr = iln->inlined_basicblocks_cursor - 1;
+ icount = n_bptr->icount;
+ /* XXX */
+ }
+
+ /* emit inlining epilog */
+
+ emit_inlining_epilog(iln, nextcall, o_iptr);
+ icount += nextcall->epilog_instructioncount;
+
+ /* proceed to next call */
+
+ nextcall = nextcall->next;
+ }
+ else {
+ n_iptr = (iln->inlined_iinstr_cursor++);
+ assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
+
+ switch (o_iptr->opc) {
+ case ICMD_RETURN:
+ if (iln->depth == 0)
+ goto default_clone;
+ goto return_tail;
+
+ case ICMD_IRETURN:
+ case ICMD_ARETURN:
+ case ICMD_LRETURN:
+ case ICMD_FRETURN:
+ case ICMD_DRETURN:
+ if (iln->depth == 0)
+ goto default_clone;
+ retcount = 1;
+ retidx = iln->varmap[o_iptr->s1.varindex];
+ if (iln->n_resultlocal != -1) {
+ /* store result in a local variable */
+
+ DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
+ /* This relies on the same sequence of types for */
+ /* ?STORE and ?RETURN opcodes. */
+ n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
+ n_iptr->s1.varindex = retidx;
+ n_iptr->dst.varindex = iln->n_resultlocal;
+ n_iptr->sx.s23.s3.javaindex = UNUSED; /* XXX set real javaindex? */
+
+ retcount = 0;
+ retidx = UNUSED;
+
+ n_iptr = (iln->inlined_iinstr_cursor++);
+ assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
+ icount++;
+ }
+ else if ((retidx < resultjd->localcount && iln->blockafter)
+ || !iln->blockafter) /* XXX do we really always need the MOVE? */
+ {
+ /* local must not become outvar, insert a MOVE */
+
+ n_iptr->opc = ICMD_MOVE;
+ n_iptr->s1.varindex = retidx;
+ retidx = inline_new_temp_variable(resultjd,
+ resultjd->var[retidx].type);
+ n_iptr->dst.varindex = retidx;
+
+ n_iptr = (iln->inlined_iinstr_cursor++);
+ assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
+ icount++;
+ }
+return_tail:
+ if (iln->blockafter) {
+ n_iptr->opc = ICMD_GOTO;
+ n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
+ inline_add_block_reference(iln, &(n_iptr->dst.block));
+ }
+ else {
+ n_iptr->opc = ICMD_NOP;
+ }
+ break;
+#if 0
+ if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
+ n_iptr->opc = ICMD_NOP;
+ break;
+ }
+ goto default_clone;
+ break;
+#endif
+
+ default:
+default_clone:
+ inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
+ }
+
+ DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
+ printf("\n"););
+
+ icount++;
+ }
+
+ o_iptr++;
+ }
+
+ /* end of basic block */
+
+ if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
+ close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
+ n_bptr->icount = icount;
+
+ DOLOG( printf("closed body block:\n");
+ show_basicblock(resultjd, n_bptr, SHOW_STACK); );
+ }
+ else {
+ n_bptr->icount = icount;
+ assert(iln->parent);
+ if (retidx != UNUSED)
+ iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
+ }
+ }
+
+ bm = iln->ctx->blockmap;
+ for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
+ assert(bm->iln && bm->o_block && bm->n_block);
+ if (bm->iln == iln)
+ inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block, false);
+ }
+
+#if !defined(NDEBUG)
+ if (iln->refs) {
+ inline_target_ref *ref;
+ ref = iln->refs;
+ while (ref) {
+ if (!iln->depth || ref->isnumber || *(ref->ref.block) != INLINE_RETURN_REFERENCE(iln)) {
+ DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
+ (void*)*(ref->ref.block)) );
+ assert(false);
+ }
+ ref = ref->next;
+ }
+ }
+#endif
+}
+
+
+static exception_entry * inline_exception_tables(inline_node *iln,
+ exception_entry *n_extable,
+ exception_entry **prevextable)
+{
+ inline_node *child;
+ inline_node *scope;
+ exception_entry *et;
+
+ assert(iln);
+ assert(n_extable);
+ assert(prevextable);
+
+ child = iln->children;
+ if (child) {
+ do {
+ n_extable = inline_exception_tables(child, n_extable, prevextable);
+ child = child->next;
+ } while (child != iln->children);
+ }
+
+ et = iln->jd->exceptiontable;
+ for (; et != NULL; et = et->down) {
+ assert(et);
+ MZERO(n_extable, exception_entry, 1);
+ n_extable->start = inline_map_block(iln, et->start , iln);
+ n_extable->end = inline_map_block(iln, et->end , iln);
+ n_extable->handler = inline_map_block(iln, et->handler, iln);
+ n_extable->catchtype = et->catchtype;
+
+ if (*prevextable) {
+ (*prevextable)->down = n_extable;
+ }
+ *prevextable = n_extable;
+
+ n_extable++;
+ }
+
+ if (iln->handler_monitorexit) {
+ exception_entry **activehandlers;
+
+ MZERO(n_extable, exception_entry, 1);
+ n_extable->start = iln->inlined_basicblocks;
+ n_extable->end = iln->inlined_basicblocks_cursor;
+ n_extable->handler = iln->handler_monitorexit;
+ n_extable->catchtype.any = NULL; /* finally */
+
+ if (*prevextable) {
+ (*prevextable)->down = n_extable;
+ }
+ *prevextable = n_extable;
+
+ n_extable++;
+
+ /* We have to protect the created handler with the same handlers */
+ /* that protect the method body itself. */
+
+ for (scope = iln; scope->parent != NULL; scope = scope->parent) {
+
+ activehandlers = scope->o_handlers;
+ assert(activehandlers);
+
+ while (*activehandlers) {
+
+ assert(scope->parent);
+
+ MZERO(n_extable, exception_entry, 1);
+ n_extable->start = iln->handler_monitorexit;
+ n_extable->end = iln->handler_monitorexit + 1; /* XXX ok in this case? */
+ n_extable->handler = inline_map_block(scope->parent,
+ (*activehandlers)->handler,
+ scope->parent);
+ n_extable->catchtype = (*activehandlers)->catchtype;
+
+ if (*prevextable) {
+ (*prevextable)->down = n_extable;
+ }
+ *prevextable = n_extable;
+
+ n_extable++;
+ activehandlers++;
+ }
+ }
+ }
+
+ return n_extable;
+}
+
+
+static void inline_locals(inline_node *iln)
+{
+ inline_node *child;
+
+ assert(iln);
+
+ iln->varmap = create_variable_map(iln);
+
+ child = iln->children;
+ if (child) {
+ do {
+ inline_locals(child);
+ child = child->next;
+ } while (child != iln->children);
+ }
+
+ if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
+ iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
+ if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
+ iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
+ if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
+ iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
+}
+
+
+static void inline_interface_variables(inline_node *iln)
+{
+ basicblock *bptr;
+ jitdata *resultjd;
+ s4 i;
+ varinfo *v;
+
+ resultjd = iln->ctx->resultjd;
+
+ resultjd->interface_map = (interface_info*) DumpMemory::allocate(sizeof(interface_info) * 5 * iln->ctx->maxinoutdepth);
+ for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
+ resultjd->interface_map[i].flags = UNUSED;
+
+ for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
+ assert(bptr->indepth <= iln->ctx->maxinoutdepth);
+ assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
+
+ for (i=0; i<bptr->indepth; ++i) {
+ v = &(resultjd->var[bptr->invars[i]]);
+ v->flags |= INOUT;
+ if (v->type == TYPE_RET)
+ v->flags |= PREALLOC;
+ else
+ v->flags &= ~PREALLOC;
+ v->flags &= ~INMEMORY;
+ assert(bptr->invars[i] >= resultjd->localcount);
+
+ if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
+ resultjd->interface_map[5*i + v->type].flags = v->flags;
+ }
+ else {
+ resultjd->interface_map[5*i + v->type].flags |= v->flags;
+ }
+ }
+
+ for (i=0; i<bptr->outdepth; ++i) {
+ v = &(resultjd->var[bptr->outvars[i]]);
+ v->flags |= INOUT;
+ if (v->type == TYPE_RET)
+ v->flags |= PREALLOC;
+ else
+ v->flags &= ~PREALLOC;
+ v->flags &= ~INMEMORY;
+ assert(bptr->outvars[i] >= resultjd->localcount);
+
+ if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
+ resultjd->interface_map[5*i + v->type].flags = v->flags;
+ }
+ else {
+ resultjd->interface_map[5*i + v->type].flags |= v->flags;
+ }
+ }
+ }
+}
+
+
+static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
+{
+ basicblock *n_bptr;
+ instruction *n_ins;
+ inline_node *child;
+ builtintable_entry *bte;
+ s4 exvar;
+ s4 syncvar;
+ s4 i;
+
+ child = iln->children;
+ if (child) {
+ do {
+ inline_write_exception_handlers(master, child);
+ child = child->next;
+ } while (child != iln->children);
+ }
+
+ if (iln->synchronize) {
+ /* create the monitorexit handler */
+ n_bptr = create_block(master, iln, iln,
+ iln->n_passthroughcount + 1);
+ n_bptr->type = BBTYPE_EXH;
+ n_bptr->flags = BBFINISHED;
+
+ exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
+ n_bptr->invars[iln->n_passthroughcount] = exvar;
+
+ iln->handler_monitorexit = n_bptr;
+
+ /* ACONST / ALOAD */
+
+ n_ins = master->inlined_iinstr_cursor++;
+ if (iln->m->flags & ACC_STATIC) {
+ n_ins->opc = ICMD_ACONST;
+ n_ins->sx.val.c.cls = iln->m->clazz;
+ n_ins->flags.bits = INS_FLAG_CLASS;
+ }
+ else {
+ n_ins->opc = ICMD_ALOAD;
+ n_ins->s1.varindex = iln->synclocal;
+ assert(n_ins->s1.varindex != UNUSED);
+ }
+ /* XXX could be PREALLOCed for builtin call */
+ syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
+ n_ins->dst.varindex = syncvar;
+ n_ins->line = 0;
+
+ /* MONITOREXIT */
+
+ bte = builtintable_get_internal(LOCK_monitor_exit);
+
+ n_ins = master->inlined_iinstr_cursor++;
+ n_ins->opc = ICMD_BUILTIN;
+ n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
+ n_ins->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4) * n_ins->s1.argcount);
+ n_ins->sx.s23.s2.args[0] = syncvar;
+ for (i=0; i < iln->n_passthroughcount + 1; ++i) {
+ n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
+ }
+ n_ins->sx.s23.s3.bte = bte;
+ n_ins->line = 0;
+
+ /* ATHROW */
+
+ n_ins = master->inlined_iinstr_cursor++;
+ n_ins->opc = ICMD_ATHROW;
+ n_ins->flags.bits = 0;
+ n_ins->s1.varindex = exvar;
+ n_ins->line = 0;
+
+ /* close basic block */
+
+ close_block(iln, iln, n_bptr, iln->n_passthroughcount);
+ n_bptr->icount = 3;
+ }
+}
+
+
+/* second pass driver *********************************************************/
+
+static bool inline_transform(inline_node *iln, jitdata *jd)
+{
+ instruction *n_ins;
+ basicblock *n_bb;
+ basicblock *n_bptr;
+ exception_entry *n_ext;
+ exception_entry *prevext;
+ codegendata *n_cd;
+ jitdata *n_jd;
+ s4 i;
+#if defined(INLINE_VERIFY_RESULT)
+ static int debug_verify_inlined_code = 1;
+#endif
+#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
+ static int debug_counter = 0;
+#endif
+
+ DOLOG( dump_inline_tree(iln, 0); );
+
+ assert(iln && jd);
+
+ n_ins = (instruction*) DumpMemory::allocate(sizeof(instruction) * iln->cumul_instructioncount);
+ MZERO(n_ins, instruction, iln->cumul_instructioncount);
+ iln->inlined_iinstr = n_ins;
+
+ n_bb = (basicblock*) DumpMemory::allocate(sizeof(basicblock) * iln->cumul_basicblockcount);
+ MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
+ iln->inlined_basicblocks = n_bb;
+
+ iln->ctx->blockmap = (inline_block_map*) DumpMemory::allocate(sizeof(inline_block_map) * iln->cumul_blockmapcount);
+
+ n_jd = jit_jitdata_new(iln->m);
+ n_jd->flags = jd->flags;
+ n_jd->code->optlevel = jd->code->optlevel;
+ iln->ctx->resultjd = n_jd;
+
+ reg_setup(n_jd);
+
+ /* create the local_map */
+
+ n_jd->local_map = (s4*) DumpMemory::allocate(sizeof(s4) * 5 * iln->cumul_maxlocals);
+ for (i=0; i<5*iln->cumul_maxlocals; ++i)
+ n_jd->local_map[i] = UNUSED;
+
+ /* create / coalesce local variables */
+
+ n_jd->varcount = 0;
+ n_jd->vartop = 0;
+ n_jd->var = NULL;
+
+ inline_locals(iln);
+
+ n_jd->localcount = n_jd->vartop;
+
+ /* extra variables for verification (debugging) */
+
+#if defined(INLINE_VERIFY_RESULT)
+ if (debug_verify_inlined_code) {
+ n_jd->vartop += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
+ if (n_jd->vartop > n_jd->varcount) {
+ /* XXX why? */
+ n_jd->var = (varinfo*) DumpMemory::realloc(n_jd->var, sizeof(varinfo) * n_jd->varcount, sizeof(varinfo) * n_jd->vartop);
+ n_jd->varcount = n_jd->vartop;
+ }
+ }
+#endif /* defined(INLINE_VERIFY_RESULT) */
+
+ /* write inlined code */
+
+ inline_rewrite_method(iln);
+
+ /* create exception handlers */
+
+ inline_write_exception_handlers(iln, iln);
+
+ /* write the dummy end block */
+
+ n_bptr = create_block(iln, iln, iln, 0);
+ n_bptr->flags = BBUNDEF;
+ n_bptr->type = BBTYPE_STD;
+
+ /* store created code in jitdata */
+
+ n_jd->basicblocks = iln->inlined_basicblocks;
+ n_jd->instructioncount = iln->cumul_instructioncount;
+ n_jd->instructions = iln->inlined_iinstr;
+
+ /* link the basic blocks (dummy end block is not counted) */
+
+ n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
+ for (i=0; i<n_jd->basicblockcount + 1; ++i)
+ n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
+ if (i)
+ n_jd->basicblocks[i-1].next = NULL;
+
+ /* check basicblock numbers */
+
+#if !defined(NDEBUG)
+ jit_check_basicblock_numbers(n_jd);
+#endif
+
+ /* create the exception table */
+
+ if (iln->cumul_exceptiontablelength) {
+ exception_entry *tableend;
+
+ n_ext = (exception_entry*) DumpMemory::allocate(sizeof(exception_entry) * iln->cumul_exceptiontablelength);
+ prevext = NULL;
+ tableend = inline_exception_tables(iln, n_ext, &prevext);
+ assert(tableend == n_ext + iln->cumul_exceptiontablelength);
+ if (prevext)
+ prevext->down = NULL;
+
+ n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
+ n_jd->exceptiontable = n_ext;
+ }
+ else {
+ n_ext = NULL;
+ }
+
+ /*******************************************************************************/
+
+ n_cd = n_jd->cd;
+ memcpy(n_cd, jd->cd, sizeof(codegendata));
+
+ n_cd->method = NULL; /* XXX */
+ n_jd->maxlocals = iln->cumul_maxlocals;
+ n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
+
+ inline_post_process(n_jd);
+
+ inline_interface_variables(iln);
+
+ /* for debugging, verify the inlined result */
+
+#if defined(INLINE_VERIFY_RESULT)
+ if (debug_verify_inlined_code) {
+ debug_verify_inlined_code = 0;
+ DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
+ if (!typecheck(n_jd)) {
+ exceptions_clear_exception();
+ DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
+ return false;
+ }
+ else {
+ DOLOG( printf("VERIFICATION PASSED.\n") );
+ }
+ debug_verify_inlined_code = 1;
+ }
+#endif /* defined(INLINE_VERIFY_RESULT) */
+
+ /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
+
+ n_jd->rd->freemem = (s4*) DumpMemory::allocate(sizeof(s4) * (iln->ctx->maxinoutdepth + 1000)) /* XXX max vars/block */;
+
+#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
+ if ( (n_jd->instructioncount >= opt_InlineMinSize)
+ && (n_jd->instructioncount <= opt_InlineMaxSize))
+ {
+ if (debug_counter < opt_InlineCount)
+#endif /* defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) */
+ {
+ /* install the inlined result */
+
+ *jd->code = *n_jd->code;
+ n_jd->code = jd->code;
+ *jd = *n_jd;
+
+ /* statistics and logging */
+
+#if !defined(NDEBUG)
+ inline_stat_roots++;
+
+ DOLOG_SHORT(
+ printf("==== %d.INLINE ==================================================================\n",
+ debug_counter);
+ printf("\ninline tree:\n");
+ dump_inline_tree(iln, 0);
+ n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
+ /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
+ printf("-------- DONE -----------------------------------------------------------\n");
+ fflush(stdout);
+ );
+#endif
+ }
+
+#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
+ debug_counter++;
+ }
+#endif
+ return true;
+}
+
+
+/******************************************************************************/
+/* FIRST PASS: build inlining tree */
+/******************************************************************************/
+
+
+/* inline_pre_parse_heuristics *************************************************
+
+ Perform heuristic checks whether a call site should be inlined.
+ These checks are evaluated before the callee has been parsed and analysed.
+
+ IN:
+ caller...........inlining node of the caller
+ callee...........the called method
+ site.............information on the call site
+
+ RETURN VALUE:
+ true........consider for inlining
+ false.......don't inline
+
+*******************************************************************************/
+
+static bool inline_pre_parse_heuristics(const inline_node *caller,
+ const methodinfo *callee,
+ inline_site *site)
+{
+#if defined(INLINE_MAX_DEPTH)
+ if (caller->depth >= INLINE_MAX_DEPTH)
+ return false;
+#endif
+
+ return true;
+}
+
+
+/* inline_post_parse_heuristics ************************************************
+
+ Perform heuristic checks whether a call site should be inlined.
+ These checks are evaluated after the callee has been parsed and analysed.
+
+ IN:
+ caller...........inlining node of the caller (const)
+ callee...........the called method (const)
+
+ RETURN VALUE:
+ true........consider for inlining
+ false.......don't inline
+
+*******************************************************************************/
+
+static bool inline_post_parse_heuristics(const inline_node *caller,
+ const inline_node *callee)
+{
+ return true;
+}
+
+
+/* inline_afterwards_heuristics ************************************************
+
+ Perform heuristic checks whether a call site should be inlined.
+ These checks are evaluated after the inlining plan for the callee has
+ been made.
+
+ IN:
+ caller...........inlining node of the caller (const)
+ callee...........the called method (const)
+
+ RETURN VALUE:
+ true........consider for inlining
+ false.......don't inline
+
+*******************************************************************************/
+
+static bool inline_afterwards_heuristics(const inline_node *caller,
+ const inline_node *callee)
+{
+ inline_node *cumulator;
+
+#if defined(INLINE_DEPTH_FIRST)
+ cumulator = caller;
+#else
+ cumulator = caller->ctx->master;
+#endif
+
+ if (0
+#if defined(INLINE_MAX_BLOCK_EXPANSION)
+ || (cumulator->cumul_basicblockcount + callee->cumul_basicblockcount
+ > INLINE_MAX_BLOCK_EXPANSION*caller->ctx->master->jd->basicblockcount)
+#endif
+#if defined(INLINE_MAX_ICMD_EXPANSION)
+ || (cumulator->cumul_instructioncount + callee->cumul_instructioncount
+ > INLINE_MAX_ICMD_EXPANSION*caller->ctx->master->jd->instructioncount)
+#endif
+ )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+/* inline_is_monomorphic *******************************************************
+
+ Check if the given call site can be proven to be monomorphic.
+
+ IN:
+ callee...........the called method
+ call.............the invocation instruction
+
+ OUT:
+ site->speculative.....flags whether the inlining is speculative
+ (only defined if return value is true)
+
+ RETURN VALUE:
+ true if the call site is (currently) monomorphic,
+ false if not or unknown
+
+*******************************************************************************/
+
+static bool inline_is_monomorphic(const methodinfo *callee,
+ const instruction *call,
+ inline_site *site)
+{
+ if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
+ || call->opc == ICMD_INVOKESPECIAL))
+ {
+ site->speculative = false;
+ return true;
+ }
+
+ /* XXX search single implementation for abstract monomorphics */
+
+ if ((callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED
+ | ACC_ABSTRACT))
+ == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED))
+ {
+ if (1) {
+ DOLOG( printf("SPECULATIVE INLINE: "); method_println((methodinfo*)callee); );
+ site->speculative = true;
+
+ return true;
+ }
+ }
+
+ /* possibly polymorphic call site */
+
+ return false;
+}
+
+
+/* inline_can_inline ***********************************************************
+
+ Check if inlining of the given call site is possible.
+
+ IN:
+ caller...........inlining node of the caller
+ callee...........the called method
+ call.............the invocation instruction
+
+ OUT:
+ site->speculative.....flags whether the inlining is speculative
+ (only defined if return value is true)
+
+ RETURN VALUE:
+ true if inlining is possible, false if not
+
+*******************************************************************************/
+
+static bool inline_can_inline(const inline_node *caller,
+ const methodinfo *callee,
+ const instruction *call,
+ inline_site *site)
+{
+ const inline_node *active;
+
+ /* cannot inline native methods */
+
+ if (callee->flags & ACC_NATIVE)
+ return false;
+
+ /* cannot inline possibly polymorphic calls */
+
+ if (!inline_is_monomorphic(callee, call, site))
+ return false;
+
+ /* cannot inline recursive calls */
+
+ for (active = caller; active; active = active->parent) {
+ if (callee == active->m) {
+ DOLOG( printf("RECURSIVE!\n") );
+ return false;
+ }
+ }
+
+ /* inlining is possible */
+
+ return true;
+}
+
+
+/* inline_create_callee_node ***************************************************
+
+ Create an inlining node for the given callee.
+
+ IN:
+ caller...........inlining node of the caller (const)
+ callee...........the called method
+
+ RETURN VALUE:
+ the new inlining node
+
+*******************************************************************************/
+
+static inline_node * inline_create_callee_node(const inline_node *caller,
+ methodinfo *callee)
+{
+ inline_node *cn; /* the callee inline_node */
+
+ cn = (inline_node*) DumpMemory::allocate(sizeof(inline_node));
+ MZERO(cn, inline_node, 1);
+
+ cn->depth = caller->depth + 1;
+ cn->ctx = caller->ctx;
+ cn->m = callee;
+ cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
+ cn->isstatic = (callee->flags & ACC_STATIC);
+
+ return cn;
+}
+
+
+/* inline_set_callee_properties ************************************************
+
+ Set properties of the inlined call site.
+
+ IN:
+ caller...........inlining node of the caller (const)
+ cn...............the called method
+ site.............info about the call site (const)
+
+ OUT:
+ *cn..............has the properties set
+
+*******************************************************************************/
+
+static void inline_set_callee_properties(const inline_node *caller,
+ inline_node *cn,
+ const inline_site *site)
+{
+ s4 argi;
+ s4 i, j;
+ basicblock *bptr;
+
+ /* set info about the call site */
+
+ cn->callerblock = site->bptr;
+ cn->callerins = site->iptr;
+ cn->callerpc = site->pc;
+ cn->o_handlers = site->handlers;
+ cn->n_handlercount = caller->n_handlercount + site->nhandlers;
+
+ /* determine if we need basic block boundaries before/after */
+
+ cn->blockbefore = false;
+ cn->blockafter = false;
+
+ if (cn->jd->branchtoentry)
+ cn->blockbefore = true;
+
+ if (cn->jd->branchtoend)
+ cn->blockafter = true;
+
+ if (cn->jd->returncount > 1)
+ cn->blockafter = true;
+
+ /* XXX make safer and reusable (maybe store last real block) */
+ for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
+ ;
+
+ if (cn->jd->returnblock != bptr)
+ cn->blockafter = true;
+
+ /* info about the callee */
+
+ cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
+ cn->prolog_instructioncount = cn->m->parseddesc->paramcount + 2;
+ cn->epilog_instructioncount = 1; /* INLINE_END */
+ cn->extra_instructioncount = 0;
+
+ /* we need a CHECKNULL for instance methods, except for <init> */
+
+ if (!cn->isstatic && cn->m->name != utf_init)
+ cn->prolog_instructioncount += 1;
+
+ /* deal with synchronized callees */
+
+ if (cn->synchronize) {
+ methoddesc *md;
+ builtintable_entry *bte;
+
+ /* we need basic block boundaries because of the handler */
+
+ cn->blockbefore = true;
+ cn->blockafter = true;
+
+ /* for synchronized static methods */
+ /* we need an ACONST, MONITORENTER in the prolog */
+ /* and ACONST, MONITOREXIT in the epilog */
+
+ /* for synchronized instance methods */
+ /* we need an COPY, MONITORENTER in the prolog */
+ /* and MONITOREXIT in the epilog */
+
+ if (cn->isstatic) {
+ cn->prolog_instructioncount += 2;
+ cn->epilog_instructioncount += 2;
+ }
+ else {
+ cn->prolog_instructioncount += 2;
+ cn->epilog_instructioncount += 1;
+ cn->localsoffset += 1;
+ }
+
+ /* and exception handler */
+ /* ALOAD, builtin_monitorexit, ATHROW */
+
+ cn->extra_instructioncount += 3;
+
+ /* exception table entries */
+
+ cn->extra_exceptiontablelength = 1 + cn->n_handlercount;
+
+ /* add exception handler block */
+
+ cn->cumul_basicblockcount_root++;
+
+ /* we must call the builtins */
+
+ bte = builtintable_get_internal(LOCK_monitor_enter);
+ md = bte->md;
+ if (md->memuse > cn->regdata->memuse)
+ cn->regdata->memuse = md->memuse;
+ if (md->argintreguse > cn->regdata->argintreguse)
+ cn->regdata->argintreguse = md->argintreguse;
+
+ bte = builtintable_get_internal(LOCK_monitor_exit);
+ md = bte->md;
+ if (md->memuse > cn->regdata->memuse)
+ cn->regdata->memuse = md->memuse;
+ if (md->argintreguse > cn->regdata->argintreguse)
+ cn->regdata->argintreguse = md->argintreguse;
+ }
+
+ /* determine pass-through variables */
+
+ i = site->iptr->s1.argcount - cn->m->parseddesc->paramcount; /* max # of pass-though vars */
+
+ cn->n_passthroughvars = (s4*) DumpMemory::allocate(sizeof(s4) * i);
+ j = 0;
+ for (argi = site->iptr->s1.argcount - 1; argi >= cn->m->parseddesc->paramcount; --argi) {
+ s4 idx = site->iptr->sx.s23.s2.args[argi];
+ if (idx >= caller->jd->localcount) {
+ cn->n_passthroughvars[j] = idx;
+ j++;
+ }
+ else {
+ DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
+ }
+ }
+ assert(j <= i);
+ cn->n_selfpassthroughcount = j;
+ cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
+}
+
+
+/* inline_cumulate_counters ****************************************************
+
+ Cumulate counters after a node has been decided to become inlined.
+
+ IN:
+ caller...........inlining node of the caller
+ callee...........inlining node of the callee (const)
+
+ OUT:
+ *caller..........gets cumulated values added
+
+*******************************************************************************/
+
+static void inline_cumulate_counters(inline_node *caller,
+ const inline_node *cn)
+{
+ caller->cumul_instructioncount += cn->prolog_instructioncount;
+ caller->cumul_instructioncount += cn->epilog_instructioncount;
+ caller->cumul_instructioncount += cn->extra_instructioncount;
+ caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
+
+ caller->cumul_basicblockcount += cn->cumul_basicblockcount;
+ caller->cumul_basicblockcount_root += cn->cumul_basicblockcount_root;
+ caller->cumul_blockmapcount += cn->cumul_blockmapcount;
+ caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
+ caller->cumul_exceptiontablelength += cn->extra_exceptiontablelength;
+
+ if (cn->cumul_maxlocals > caller->cumul_maxlocals)
+ caller->cumul_maxlocals = cn->cumul_maxlocals;
+
+ /* XXX extra block after inlined call */
+ if (cn->blockafter) {
+ caller->cumul_basicblockcount += 1;
+ caller->cumul_blockmapcount += 1;
+ }
+}
+
+
+/* inline_analyse_callee *******************************************************
+
+ Analyse an inlining candidate callee.
+
+ IN:
+ caller...........inlining node of the caller
+ callee...........the called method
+ site.............info about the call site
+
+ OUT:
+ site->inlined....true if the callee has been selected for inlining
+
+ RETURN VALUE:
+ the inline node of the callee, or
+ NULL if an error has occurred (don't use the inlining plan in this case)
+
+*******************************************************************************/
+
+static inline_node * inline_analyse_callee(inline_node *caller,
+ methodinfo *callee,
+ inline_site *site)
+{
+ inline_node *cn; /* the callee inline_node */
+
+ /* create an inline tree node */
+
+ cn = inline_create_callee_node(caller, callee);
+
+ /* get the intermediate representation of the callee */
+
+ if (!inline_jit_compile(cn))
+ return NULL;
+
+ /* evaluate heuristics after parsing the callee */
+
+ if (!inline_post_parse_heuristics(caller, cn))
+ return cn;
+
+ /* the call site will be inlined */
+
+ site->inlined = true;
+
+ /* set info about the call site */
+
+ inline_set_callee_properties(caller, cn, site);
+
+ /* insert the node into the inline tree */
+
+ inline_insert_inline_node(caller, cn);
+
+ /* analyse recursively */
+
+ if (!inline_analyse_code(cn))
+ return NULL;
+
+ if (!inline_afterwards_heuristics(caller, cn)) {
+#if defined(INLINE_CANCEL_ON_THRESHOLD)
+ return NULL;
+#else
+ inline_remove_inline_node(caller, cn);
+ caller->ctx->stopped = true;
+ site->inlined = false;
+ return cn;
+#endif
+ }
+
+ /* cumulate counters */
+
+#if defined(INLINE_DEPTH_FIRST)
+ inline_cumulate_counters(caller, cn);
+#endif
+
+#if defined(INLINE_BREADTH_FIRST)
+ while (caller) {
+ inline_cumulate_counters(caller, cn);
+ caller = caller->parent;
+ }
+#endif
+
+ return cn;
+}
+
+
+/* inline_process_candidate ****************************************************
+
+ Process a selected inlining candidate.
+
+ IN:
+ cand.............the candidate
+
+ RETURN VALUE:
+ true........everything ok
+ false.......an error has occurred, don't use the plan
+
+*******************************************************************************/
+
+static bool inline_process_candidate(inline_candidate *cand)
+{
+ inline_node *cn;
+
+ cn = inline_analyse_callee(cand->caller,
+ cand->callee,
+ &(cand->site));
+
+ if (!cn)
+ return false;
+
+ if (!cand->site.inlined)
+ return true;
+
+ /* store assumptions */
+
+ if (cand->site.speculative)
+ method_add_assumption_monomorphic(cand->callee, cand->caller->ctx->master->m);
+
+ return true;
+}
+
+
+/* inline_analyse_code *********************************************************
+
+ Analyse the intermediate code of the given inlining node.
+
+ IN:
+ iln..............the inlining node
+
+ OUT:
+ *iln.............the inlining plan
+
+ RETURN VALUE:
+ true........everything ok
+ false.......an error has occurred, don't use the plan
+
+*******************************************************************************/
+
+static bool inline_analyse_code(inline_node *iln)
+{
+ methodinfo *m;
+ basicblock *bptr;
+ s4 len;
+ instruction *iptr;
+ methodinfo *callee;
+ exception_entry **handlers;
+ exception_entry *ex;
+ s4 nhandlers;
+ s4 blockendpc;
+ jitdata *mjd;
+ inline_site site;
+
+ assert(iln);
+
+ m = iln->m;
+ mjd = iln->jd;
+
+ /* initialize cumulative counters */
+
+ iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
+ iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
+
+ /* iterate over basic blocks */
+
+ blockendpc = 0;
+
+ for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
+
+ /* count the block */
+ /* ignore dummy end blocks (but count them for the blockmap) */
+
+ iln->cumul_blockmapcount++;
+ if ((bptr != mjd->basicblocks || iln->blockbefore)
+ &&
+ (bptr->icount > 0 || bptr->next != NULL))
+ iln->cumul_basicblockcount++;
+
+ /* skip dead code */
+
+ if (bptr->flags < BBREACHED)
+ continue;
+
+ /* allocate the buffer of active exception handlers */
+ /* XXX this wastes some memory, but probably it does not matter */
+
+ handlers = (exception_entry**) DumpMemory::allocate(sizeof(exception_entry*) * (mjd->exceptiontablelength + 1));
+
+ /* determine the active exception handlers for this block */
+ /* XXX maybe the handlers of a block should be part of our IR */
+ /* XXX this should share code with the type checkers */
+ nhandlers = 0;
+ for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
+ if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
+ handlers[nhandlers++] = ex;
+ }
+ }
+ handlers[nhandlers] = NULL;
+
+ len = bptr->icount;
+ iptr = bptr->iinstr;
+
+ blockendpc += len;
+ iln->cumul_instructioncount += len;
+
+ /* iterate over the instructions of the block */
+
+ for (; --len >= 0; ++iptr) {
+
+ switch (iptr->opc) {
+ case ICMD_INVOKEVIRTUAL:
+ case ICMD_INVOKESPECIAL:
+ case ICMD_INVOKESTATIC:
+ case ICMD_INVOKEINTERFACE:
+
+ if (!INSTRUCTION_IS_UNRESOLVED(iptr) && !iln->ctx->stopped) {
+ callee = iptr->sx.s23.s3.fmiref->p.method;
+
+ if (inline_can_inline(iln, callee, iptr, &site)) {
+ site.inlined = false;
+ site.bptr = bptr;
+ site.iptr = iptr;
+ site.pc = blockendpc - len - 1;
+ site.handlers = handlers;
+ site.nhandlers = nhandlers;
+
+ if (inline_pre_parse_heuristics(iln, callee, &site)) {
+#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
+ inline_add_candidate(iln->ctx, iln, callee, &site);
+#else
+ inline_candidate cand;
+ cand.caller = iln;
+ cand.callee = callee;
+ cand.site = site;
+
+ if (!inline_process_candidate(&cand))
+ return false;
+#endif
+ }
+ }
+ }
+ break;
+
+ case ICMD_RETURN:
+ case ICMD_IRETURN:
+ case ICMD_ARETURN:
+ case ICMD_LRETURN:
+ case ICMD_FRETURN:
+ case ICMD_DRETURN:
+ /* extra ICMD_MOVE may be necessary */
+ iln->cumul_instructioncount++;
+ break;
+ }
+ }
+
+ /* end of basic block */
+ }
+
+ return true;
+}
+
+
+static void inline_cumulate_counters_recursive(inline_node *iln)
+{
+ inline_node *child;
+
+ child = iln->children;
+ if (child) {
+ do {
+ inline_cumulate_counters_recursive(child);
+ inline_cumulate_counters(iln, child);
+ child = child->next;
+ } while (child != iln->children);
+ }
+}
+
+
+/* inline_make_inlining_plan ***************************************************
+
+ Make an inlining plan for the given root node
+
+ IN:
+ iln..............the root node
+
+ OUT:
+ *iln.............the inlining plan
+
+ RETURN VALUE:
+ true........everything ok
+ false.......an error has occurred, don't use the plan
+
+*******************************************************************************/
+
+#if defined(INLINE_KNAPSACK)
+static bool inline_make_inlining_plan(inline_node *iln)
+{
+ inline_candidate *cand;
+#if defined(INLINE_COST_BUDGET)
+ s4 budget = INLINE_COST_BUDGET;
+# define BUDGETMEMBER cost
+#endif
+#if defined(INLINE_WEIGHT_BUDGET)
+ double budget = INLINE_WEIGHT_BUDGET;
+# define BUDGETMEMBER weight
+#endif
+
+ inline_analyse_code(iln);
+
+ DOLOG( printf("candidates in "); method_println(iln->m);
+ inline_candidates_println(iln->ctx); );
+
+ while ((cand = inline_pick_best_candidate(iln->ctx)) != NULL)
+ {
+ if (cand->BUDGETMEMBER <= budget) {
+ DOLOG( printf(" picking: "); inline_candidate_println(cand); );
+
+ if (!inline_process_candidate(cand))
+ return false;
+
+#if !defined(INLINE_ADD_NEGATIVE_TO_BUDGET)
+ if (cand->BUDGETMEMBER > 0)
+#endif
+ budget -= cand->BUDGETMEMBER;
+ }
+ }
+
+ inline_cumulate_counters_recursive(iln);
+
+ return true;
+}
+#endif /* defined(INLINE_KNAPSACK) */
+
+
+#if defined(INLINE_DEPTH_FIRST)
+static bool inline_make_inlining_plan(inline_node *iln)
+{
+ return inline_analyse_code(iln);
+}
+#endif /* defined(INLINE_DEPTH_FIRST) */
+
+
+#if defined(INLINE_BREADTH_FIRST)
+static bool inline_make_inlining_plan(inline_node *iln)
+{
+ inline_candidate *cand;
+
+ inline_analyse_code(iln);
+
+ DOLOG( printf("candidates in "); method_println(iln->m);
+ inline_candidates_println(iln->ctx); );
+
+ while (!iln->ctx->stopped
+ && (cand = inline_pick_best_candidate(iln->ctx)) != NULL)
+ {
+ DOLOG( printf(" picking: "); inline_candidate_println(cand); );
+
+ if (!inline_process_candidate(cand))
+ return false;
+ }
+
+ return true;
+}
+#endif /* defined(INLINE_BREADTH_FIRST) */
+
+
+/* statistics *****************************************************************/
+
+#if defined(INLINE_STATISTICS)
+static void inline_gather_statistics_recursive(inline_node *iln)
+{
+ inline_node *child;
+
+ inline_stat_inlined_nodes++;
+
+ if (iln->depth > inline_stat_max_depth)
+ inline_stat_max_depth++;
+
+ child = iln->children;
+ if (child) {
+ do {
+ inline_gather_statistics_recursive(child);
+ child = child->next;
+ } while (child != iln->children);
+ }
+}
+#endif /* defined(INLINE_STATISTICS) */
+
+
+#if defined(INLINE_STATISTICS)
+static void inline_gather_statistics(inline_node *iln)
+{
+ inline_stat_roots_transformed++;
+
+ inline_gather_statistics_recursive(iln);
+}
+#endif /* defined(INLINE_STATISTICS) */
+
+
+/* post processing ************************************************************/
+
+#define POSTPROCESS_SRC(varindex) live[varindex]--
+#define POSTPROCESS_DST(varindex) live[varindex]++
+
+#define POSTPROCESS_SRCOP(s) POSTPROCESS_SRC(iptr->s.varindex)
+#define POSTPROCESS_DSTOP(d) POSTPROCESS_DST(iptr->d.varindex)
+
+#define MARKSAVED(varindex) jd->var[varindex].flags |= SAVEDVAR
+
+#define MARK_ALL_SAVED \
+ do { \
+ for (i=0; i<jd->vartop; ++i) \
+ if (live[i]) \
+ MARKSAVED(i); \
+ } while (0)
+
+static void inline_post_process(jitdata *jd)
+{
+ codeinfo *code;
+ basicblock *bptr;
+ instruction *iptr;
+ instruction *iend;
+ s4 i;
+ icmdtable_entry_t *icmdt;
+ s4 *live;
+ methoddesc *md;
+ builtintable_entry *bte;
+
+ /* Get required compiler data. */
+
+ code = jd->code;
+
+ /* reset the SAVEDVAR flag of all variables */
+
+ for (i=0; i<jd->vartop; ++i)
+ jd->var[i].flags &= ~SAVEDVAR;
+
+ /* allocate the life counters */
+
+ live = (s4*) DumpMemory::allocate(sizeof(s4) * jd->vartop);
+ MZERO(live, s4, jd->vartop);
+
+ /* iterate over all basic blocks */
+
+ for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
+ if (bptr->flags < BBREACHED)
+ continue;
+
+ /* make invars live */
+
+ for (i=0; i<bptr->indepth; ++i)
+ POSTPROCESS_DST(bptr->invars[i]);
+
+ iptr = bptr->iinstr;
+ iend = iptr + bptr->icount;
+
+ for (; iptr < iend; ++iptr) {
+
+ icmdt = &(icmd_table[iptr->opc]);
+
+ switch (icmdt->dataflow) {
+ case DF_3_TO_0:
+ POSTPROCESS_SRCOP(sx.s23.s3);
+ case DF_2_TO_0:
+ POSTPROCESS_SRCOP(sx.s23.s2);
+ case DF_1_TO_0:
+ POSTPROCESS_SRCOP(s1);
+ case DF_0_TO_0:
+ if (icmdt->flags & ICMDTABLE_CALLS) {
+ code_unflag_leafmethod(code);
+ MARK_ALL_SAVED;
+ }
+ break;
+
+ case DF_2_TO_1:
+ POSTPROCESS_SRCOP(sx.s23.s2);
+ case DF_1_TO_1:
+ case DF_MOVE:
+ POSTPROCESS_SRCOP(s1);
+ case DF_0_TO_1:
+ if (icmdt->flags & ICMDTABLE_CALLS) {
+ code_unflag_leafmethod(code);
+ MARK_ALL_SAVED;
+ }
+ case DF_COPY:
+ POSTPROCESS_DSTOP(dst);
+ break;
+
+ case DF_N_TO_1:
+ for (i=0; i<iptr->s1.argcount; ++i) {
+ POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
+ }
+ if (icmdt->flags & ICMDTABLE_CALLS) {
+ code_unflag_leafmethod(code);
+ MARK_ALL_SAVED;
+ }
+ POSTPROCESS_DSTOP(dst);
+ break;
+
+ case DF_INVOKE:
+ INSTRUCTION_GET_METHODDESC(iptr, md);
+ post_process_call:
+ code_unflag_leafmethod(code);
+ for (i=0; i<md->paramcount; ++i) {
+ POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
+ }
+ for (; i<iptr->s1.argcount; ++i) {
+ MARKSAVED(iptr->sx.s23.s2.args[i]);
+ }
+ if (md->returntype.type != TYPE_VOID)
+ POSTPROCESS_DSTOP(dst);
+ break;
+
+ case DF_BUILTIN:
+ bte = iptr->sx.s23.s3.bte;
+ md = bte->md;
+ goto post_process_call;
+
+ default:
+ assert(0);
+ }
+
+ } /* end instruction loop */
+
+ /* consume outvars */
+
+ for (i=0; i<bptr->outdepth; ++i)
+ POSTPROCESS_SRC(bptr->outvars[i]);
+
+#if !defined(NDEBUG)
+ for (i=jd->localcount; i < jd->vartop; ++i)
+ assert(live[i] == 0);
+#endif
+
+ } /* end basic block loop */
+}
+
+
+/* inline_create_root_node *****************************************************
+
+ Create the root node of the inlining tree.
+
+ IN:
+ jd...............the current jitdata of the root method
+
+ RETURN VALUE:
+ the root node of the inlining tree
+
+*******************************************************************************/
+
+static inline_node * inline_create_root_node(jitdata *jd)
+{
+ inline_node *iln;
+
+ iln = (inline_node*) DumpMemory::allocate(sizeof(inline_node));
+ MZERO(iln, inline_node, 1);
+
+ iln->m = jd->m;
+ iln->jd = jd;
+ iln->regdata = jd->rd;
+
+ iln->blockbefore = true;
+ iln->blockafter = true;
+
+ iln->cumul_instructioncount = 0;
+ iln->cumul_basicblockcount = 1 /* dummy end block */;
+
+ /* create inlining context */
+
+ iln->ctx = (inline_context*) DumpMemory::allocate(sizeof(inline_context));
+ MZERO(iln->ctx, inline_context, 1);
+ iln->ctx->master = iln;
+ iln->ctx->next_debugnr = 1; /* XXX debug */
+
+ return iln;
+}
+
+
+/******************************************************************************/
+/* MAIN DRIVER FUNCTION */
+/******************************************************************************/
+
+bool inline_inline(jitdata *jd)
+{
+ inline_node *iln;
+
+ DOLOG( printf("==== INLINE ==================================================================\n");
+ show_method(jd, SHOW_STACK); );
+
+#if defined(INLINE_STATISTICS)
+ inline_stat_roots++;
+#endif
+
+ iln = inline_create_root_node(jd);
+
+ if (inline_make_inlining_plan(iln)) {
+
+ /* add blocks to the root node */
+
+ iln->cumul_basicblockcount += iln->cumul_basicblockcount_root;
+ iln->cumul_blockmapcount += iln->cumul_basicblockcount_root;
+
+ DOLOG( printf("==== INLINE TRANSFORM ========================================================\n"); );
+
+ if (iln->children)
+ inline_transform(iln, jd);
+
+#if defined(INLINE_STATISTICS)
+ inline_gather_statistics(iln);
+#endif
+ }
+
+ DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
+ fflush(stdout); );
+
+ return true;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
+++ /dev/null
-/* src/vm/jit/inline/inline.h - code inliner
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- 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., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#ifndef _INLINE_H
-#define _INLINE_H
-
-#include "config.h"
-
-#include <stdbool.h>
-
-#include "vm/jit/jit.hpp"
-
-
-/* function prototypes ********************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-bool inline_inline(jitdata *jd);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _INLINE_H */
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
--- /dev/null
+/* src/vm/jit/inline/inline.h - code inliner
+
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#ifndef _INLINE_H
+#define _INLINE_H
+
+#include "config.h"
+
+#include <stdbool.h>
+
+#include "vm/jit/jit.hpp"
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool inline_inline(jitdata *jd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _INLINE_H */
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
#include "vm/jit/codegen-common.hpp"
#include "vm/jit/dseg.h"
#include "vm/jit/jit.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/patcher.h"
#include "vm/jit/stack.h"
#include "vm/jit/stacktrace.hpp"
#include "vm/jit/disass.h"
#include "vm/jit/dseg.h"
#include "vm/jit/jit.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/reg.h"
#include "vm/jit/show.hpp"
#endif
#if defined(ENABLE_INLINING)
-# include "vm/jit/inline/inline.h"
+# include "vm/jit/inline/inline.hpp"
#endif
#include "vm/jit/ir/bytecode.h"
#include "vm/jit/stacktrace.hpp"
#if defined(ENABLE_INLINING)
-# include "vm/jit/inline/inline.h"
+# include "vm/jit/inline/inline.hpp"
#endif
#include "vm/jit/ir/bytecode.h"
#include "vm/jit/emit-common.hpp"
#include "vm/jit/jit.hpp"
#include "vm/jit/abi.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/reg.h"
#include "vm/jit/replace.hpp"
#include "vm/jit/stacktrace.hpp"
M_CMPLT(s1, s2, REG_ITMP3);
M_CMPLT(s2, s1, REG_ITMP1);
M_ISUB(REG_ITMP1, REG_ITMP3, d);
- M_BNEZ(d, 4);
- M_NOP;
+ emit_label_bnez(cd, BRANCH_LABEL_1, d);
s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
M_CMPULT(s1, s2, REG_ITMP3);
M_CMPULT(s2, s1, REG_ITMP1);
M_ISUB(REG_ITMP1, REG_ITMP3, d);
+ emit_label(cd, BRANCH_LABEL_1);
#endif
emit_store_dst(jd, iptr, d);
break;
ICONST(REG_ITMP2, iptr->sx.val.l >> 32);
M_CMPLT(s1, REG_ITMP2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+ emit_label_bne(cd, BRANCH_LABEL_1, s1, REG_ITMP2);
s2 = emit_load_s1_low(jd, iptr, REG_ITMP3);
- M_BNE(s1, REG_ITMP2, 5); /* XXX */
- M_NOP;
ICONST(REG_ITMP2, iptr->sx.val.l & 0xffffffff);
M_CMPULT(s2, REG_ITMP2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+ emit_label(cd, BRANCH_LABEL_1);
}
#endif
break;
#else
if (iptr->sx.val.l == 0) {
s1 = emit_load_s1(jd, iptr, REG_ITMP12_PACKED);
- M_BGTZ(GET_HIGH_REG(s1), 5); /* XXX */
- M_NOP;
+ emit_label_bgtz(cd, BRANCH_LABEL_1, GET_HIGH_REG(s1));
emit_bltz(cd, iptr->dst.block, GET_HIGH_REG(s1));
- emit_beqz(cd, iptr->dst.block, GET_LOW_REG(s1));
+ emit_beqz(cd, iptr->dst.block, GET_LOW_REG(s1));
+ emit_label(cd, BRANCH_LABEL_1);
}
else {
s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
ICONST(REG_ITMP2, iptr->sx.val.l >> 32);
M_CMPLT(s1, REG_ITMP2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+ emit_label_bne(cd, BRANCH_LABEL_1, s1, REG_ITMP2);
s2 = emit_load_s1_low(jd, iptr, REG_ITMP3);
- M_BNE(s1, REG_ITMP2, 5); /* XXX */
- M_NOP;
ICONST(REG_ITMP2, iptr->sx.val.l & 0xffffffff);
M_CMPUGT(s2, REG_ITMP2, REG_ITMP3);
emit_beqz(cd, iptr->dst.block, REG_ITMP3);
+ emit_label(cd, BRANCH_LABEL_1);
}
#endif
break;
if (iptr->sx.val.l == 0) {
s1 = emit_load_s1(jd, iptr, REG_ITMP12_PACKED);
emit_bgtz(cd, iptr->dst.block, GET_HIGH_REG(s1));
- M_BLTZ(GET_HIGH_REG(s1), 3); /* XXX */
- M_NOP;
+ emit_label_bltz(cd, BRANCH_LABEL_1, GET_HIGH_REG(s1));
emit_bnez(cd, iptr->dst.block, GET_LOW_REG(s1));
+ emit_label(cd, BRANCH_LABEL_1);
}
else {
s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
ICONST(REG_ITMP2, iptr->sx.val.l >> 32);
M_CMPGT(s1, REG_ITMP2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+ emit_label_bne(cd, BRANCH_LABEL_1, s1, REG_ITMP2);
s2 = emit_load_s1_low(jd, iptr, REG_ITMP3);
- M_BNE(s1, REG_ITMP2, 5); /* XXX */
- M_NOP;
ICONST(REG_ITMP2, iptr->sx.val.l & 0xffffffff);
M_CMPUGT(s2, REG_ITMP2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+ emit_label(cd, BRANCH_LABEL_1);
}
#endif
break;
ICONST(REG_ITMP2, iptr->sx.val.l >> 32);
M_CMPGT(s1, REG_ITMP2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+ emit_label_bne(cd, BRANCH_LABEL_1, s1, REG_ITMP2);
s2 = emit_load_s1_low(jd, iptr, REG_ITMP3);
- M_BNE(s1, REG_ITMP2, 5); /* XXX */
- M_NOP;
ICONST(REG_ITMP2, iptr->sx.val.l & 0xffffffff);
M_CMPULT(s2, REG_ITMP2, REG_ITMP3);
emit_beqz(cd, iptr->dst.block, REG_ITMP3);
+ emit_label(cd, BRANCH_LABEL_1);
}
#endif
break;
s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
s2 = emit_load_s2_high(jd, iptr, REG_ITMP2);
- M_BNE(s1, s2, 3); /* XXX TWISTI: uff, that is a problem */
- M_NOP;
+ emit_label_bne(cd, BRANCH_LABEL_1, s1, s2);
s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
emit_beq(cd, iptr->dst.block, s1, s2);
+ emit_label(cd, BRANCH_LABEL_1);
break;
#endif
M_CMPLT(s1, s2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
M_CMPGT(s1, s2, REG_ITMP3);
- /* load low-bits before the branch, so we know the distance */
+ emit_label_bnez(cd, BRANCH_LABEL_1, REG_ITMP3);
s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
- M_BNEZ(REG_ITMP3, 4); /* XXX */
- M_NOP;
M_CMPULT(s1, s2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+ emit_label(cd, BRANCH_LABEL_1);
break;
#endif
M_CMPGT(s1, s2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
M_CMPLT(s1, s2, REG_ITMP3);
- /* load low-bits before the branch, so we know the distance */
+ emit_label_bnez(cd, BRANCH_LABEL_1, REG_ITMP3);
s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
- M_BNEZ(REG_ITMP3, 4); /* XXX */
- M_NOP;
M_CMPUGT(s1, s2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+ emit_label(cd, BRANCH_LABEL_1);
break;
#endif
M_CMPLT(s1, s2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
M_CMPGT(s1, s2, REG_ITMP3);
- /* load low-bits before the branch, so we know the distance */
+ emit_label_bnez(cd, BRANCH_LABEL_1, REG_ITMP3);
s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
- M_BNEZ(REG_ITMP3, 4); /* XXX */
- M_NOP;
M_CMPUGT(s1, s2, REG_ITMP3);
emit_beqz(cd, iptr->dst.block, REG_ITMP3);
+ emit_label(cd, BRANCH_LABEL_1);
break;
#endif
M_CMPGT(s1, s2, REG_ITMP3);
emit_bnez(cd, iptr->dst.block, REG_ITMP3);
M_CMPLT(s1, s2, REG_ITMP3);
- /* load low-bits before the branch, so we know the distance */
+ emit_label_bnez(cd, BRANCH_LABEL_1, REG_ITMP3);
s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
- M_BNEZ(REG_ITMP3, 4); /* XXX */
- M_NOP;
M_CMPULT(s1, s2, REG_ITMP3);
emit_beqz(cd, iptr->dst.block, REG_ITMP3);
+ emit_label(cd, BRANCH_LABEL_1);
break;
#endif
+++ /dev/null
-/* src/vm/jit/parse.c - parser for JavaVM to intermediate code translation
-
- Copyright (C) 1996-2005, 2006, 2007, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- 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., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include "vm/types.h"
-
-#include "mm/memory.h"
-
-#include "native/native.hpp"
-
-#include "threads/lock.hpp"
-
-#include "toolbox/logging.h"
-
-#include "vm/jit/builtin.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/global.h"
-#include "vm/linker.h"
-#include "vm/loader.hpp"
-#include "vm/options.h"
-#include "vm/resolve.hpp"
-
-#if defined(ENABLE_STATISTICS)
-# include "vm/statistics.h"
-#endif
-
-#include "vm/string.hpp"
-#include "vm/suck.hpp"
-
-#include "vm/jit/asmpart.h"
-#include "vm/jit/jit.hpp"
-#include "vm/jit/parse.h"
-#include "vm/jit/loop/loop.h"
-
-#include "vm/jit/ir/bytecode.h"
-
-
-#define INSTRUCTIONS_INCREMENT 5 /* number of additional instructions to */
- /* allocate if space runs out */
-
-
-/* local macros ***************************************************************/
-
-#define BYTECODEINDEX_TO_BASICBLOCK(dst) \
- do { \
- (dst).block = \
- parse_bytecodeindex_to_basicblock(jd, &pd, (dst).insindex); \
- } while (0)
-
-
-/* parserdata_t ***************************************************************/
-
-typedef struct parsedata_t parsedata_t;
-
-struct parsedata_t {
- u1 *bytecodestart; /* start of bytecode instructions */
- u1 *basicblockstart; /* start of bytecode basic-blocks */
-
- s4 *bytecodemap; /* bytecode to IR mapping */
-
- instruction *instructions; /* instruction array */
- s4 instructionslength; /* length of the instruction array */
-
- s4 *instructionmap; /* IR to basic-block mapping */
-};
-
-
-/* parse_setup *****************************************************************
-
- Fills the passed parsedata_t structure.
-
-*******************************************************************************/
-
-static void parse_setup(jitdata *jd, parsedata_t *pd)
-{
- methodinfo *m;
-
- /* get required compiler data */
-
- m = jd->m;
-
- /* bytecode start array */
-
- pd->bytecodestart = DMNEW(u1, m->jcodelength + 1);
- MZERO(pd->bytecodestart, u1, m->jcodelength + 1);
-
- /* bytecode basic-block start array */
-
- pd->basicblockstart = DMNEW(u1, m->jcodelength + 1);
- MZERO(pd->basicblockstart, u1, m->jcodelength + 1);
-
- /* bytecode instruction index to IR instruction mapping */
-
- pd->bytecodemap = DMNEW(s4, m->jcodelength + 1);
- MSET(pd->bytecodemap, -1, s4, m->jcodelength + 1);
-
- /* allocate the instruction array */
-
- pd->instructionslength = m->jcodelength + 1;
- pd->instructions = DMNEW(instruction, pd->instructionslength);
-
- /* Zero the intermediate instructions array so we don't have any
- invalid pointers in it if we cannot finish stack_analyse(). */
-
- MZERO(pd->instructions, instruction, pd->instructionslength);
-
- /* The instructionmap is allocated later when we know the count of
- instructions. */
-
- pd->instructionmap = NULL;
-}
-
-
-/* parse_realloc_instructions **************************************************
-
- Reallocate the instructions array so there is room for at least N
- additional instructions.
-
- RETURN VALUE:
- the new value for iptr
-
-*******************************************************************************/
-
-static instruction *parse_realloc_instructions(parsedata_t *pd, s4 icount, s4 n)
-{
- /* increase the size of the instruction array */
-
- pd->instructionslength += (n + INSTRUCTIONS_INCREMENT);
-
- /* reallocate the array */
-
- pd->instructions = DMREALLOC(pd->instructions, instruction, icount,
- pd->instructionslength);
- MZERO(pd->instructions + icount, instruction,
- (pd->instructionslength - icount));
-
- /* return the iptr */
-
- return pd->instructions + icount;
-}
-
-
-/* parse_bytecodeindex_to_basicblock *******************************************
-
- Resolves a bytecode index to the corresponding basic block.
-
-*******************************************************************************/
-
-static basicblock *parse_bytecodeindex_to_basicblock(jitdata *jd,
- parsedata_t *pd,
- s4 bcindex)
-{
- s4 irindex;
- basicblock *bb;
-
- irindex = pd->bytecodemap[bcindex];
- bb = jd->basicblocks + pd->instructionmap[irindex];
-
- return bb;
-}
-
-
-/* parse_mark_exception_boundaries *********************************************
-
- Mark exception handlers and the boundaries of the handled regions as
- basic block boundaries.
-
- IN:
- jd...............current jitdata
-
- RETURN VALUE:
- true.............everything ok
- false............an exception has been thrown
-
-*******************************************************************************/
-
-static bool parse_mark_exception_boundaries(jitdata *jd, parsedata_t *pd)
-{
- s4 bcindex;
- s4 i;
- s4 len;
- raw_exception_entry *rex;
- methodinfo *m;
-
- m = jd->m;
-
- len = m->rawexceptiontablelength;
-
- if (len == 0)
- return true;
-
- rex = m->rawexceptiontable;
-
- for (i = 0; i < len; ++i, ++rex) {
-
- /* the start of the handled region becomes a basic block start */
-
- bcindex = rex->startpc;
- CHECK_BYTECODE_INDEX(bcindex);
- MARK_BASICBLOCK(pd, bcindex);
-
- bcindex = rex->endpc; /* see JVM Spec 4.7.3 */
- CHECK_BYTECODE_INDEX_EXCLUSIVE(bcindex);
-
- /* check that the range is valid */
-
-#if defined(ENABLE_VERIFIER)
- if (bcindex <= rex->startpc) {
- exceptions_throw_verifyerror(m, "Invalid exception handler range");
- return false;
- }
-#endif
-
- /* End of handled region becomes a basic block boundary (if it
- is the bytecode end, we'll use the special end block that
- is created anyway). */
-
- if (bcindex < m->jcodelength)
- MARK_BASICBLOCK(pd, bcindex);
- else
- jd->branchtoend = true;
-
- /* the start of the handler becomes a basic block start */
-
- bcindex = rex->handlerpc;
- CHECK_BYTECODE_INDEX(bcindex);
- MARK_BASICBLOCK(pd, bcindex);
- }
-
- /* everything ok */
-
- return true;
-
-#if defined(ENABLE_VERIFIER)
-throw_invalid_bytecode_index:
- exceptions_throw_verifyerror(m,
- "Illegal bytecode index in exception table");
- return false;
-#endif
-}
-
-
-/* parse_resolve_exception_table ***********************************************
-
- Enter the exception handlers and their ranges, resolved to basicblock *s,
- in the jitdata.
-
- IN:
- jd...............current jitdata
-
- RETURN VALUE:
- true.............everything ok
- false............an exception has been thrown
-
-*******************************************************************************/
-
-static bool parse_resolve_exception_table(jitdata *jd, parsedata_t *pd)
-{
- methodinfo *m;
- raw_exception_entry *rex;
- exception_entry *ex;
- s4 i;
- s4 len;
- classinfo *exclass;
-
- m = jd->m;
-
- len = m->rawexceptiontablelength;
-
- /* common case: no handler entries */
-
- if (len == 0)
- return true;
-
- /* allocate the exception table */
-
- jd->exceptiontablelength = len;
- jd->exceptiontable = DMNEW(exception_entry, len + 1); /* XXX why +1? */
-
- /* copy and resolve the entries */
-
- ex = jd->exceptiontable;
- rex = m->rawexceptiontable;
-
- for (i = 0; i < len; ++i, ++rex, ++ex) {
- /* resolve instruction indices to basic blocks */
-
- ex->start = parse_bytecodeindex_to_basicblock(jd, pd, rex->startpc);
- ex->end = parse_bytecodeindex_to_basicblock(jd, pd, rex->endpc);
- ex->handler = parse_bytecodeindex_to_basicblock(jd, pd, rex->handlerpc);
-
- /* lazily resolve the catchtype */
-
- if (rex->catchtype.any != NULL) {
- if (!resolve_classref_or_classinfo(m,
- rex->catchtype,
- resolveLazy, true, false,
- &exclass))
- return false;
-
- /* if resolved, enter the result of resolution in the table */
-
- if (exclass != NULL)
- rex->catchtype.cls = exclass;
- }
-
- ex->catchtype = rex->catchtype;
- ex->next = NULL; /* set by loop analysis */
- ex->down = ex + 1; /* link to next exception entry */
- }
-
- /* terminate the ->down linked list */
-
- assert(ex != jd->exceptiontable);
- ex[-1].down = NULL;
-
- return true;
-}
-
-
-/*******************************************************************************
-
- function 'parse' scans the JavaVM code and generates intermediate code
-
- During parsing the block index table is used to store at bit pos 0
- a flag which marks basic block starts and at position 1 to 31 the
- intermediate instruction index. After parsing the block index table
- is scanned, for marked positions a block is generated and the block
- number is stored in the block index table.
-
-*******************************************************************************/
-
-/*** macro for checking the length of the bytecode ***/
-
-#if defined(ENABLE_VERIFIER)
-#define CHECK_END_OF_BYTECODE(neededlength) \
- do { \
- if ((neededlength) > m->jcodelength) \
- goto throw_unexpected_end_of_bytecode; \
- } while (0)
-#else /* !ENABLE_VERIFIER */
-#define CHECK_END_OF_BYTECODE(neededlength)
-#endif /* ENABLE_VERIFIER */
-
-bool parse(jitdata *jd)
-{
- methodinfo *m; /* method being parsed */
- codeinfo *code;
- parsedata_t pd;
- instruction *iptr; /* current ptr into instruction array */
-
- s4 bcindex; /* bytecode instruction index */
- s4 nextbc; /* start of next bytecode instruction */
- s4 opcode; /* bytecode instruction opcode */
-
- s4 irindex; /* IR instruction index */
- s4 ircount; /* IR instruction count */
-
- s4 bbcount; /* basic block count */
-
- int s_count = 0; /* stack element counter */
- bool blockend; /* true if basic block end has been reached */
- bool iswide; /* true if last instruction was a wide */
-
- constant_classref *cr;
- constant_classref *compr;
- classinfo *c;
- builtintable_entry *bte;
- constant_FMIref *fmi;
- methoddesc *md;
- unresolved_method *um;
- unresolved_field *uf;
-
- resolve_result_t result;
- u2 lineindex = 0;
- u2 currentline = 0;
- u2 linepcchange = 0;
- u4 flags;
- basicblock *bptr;
-
- int *local_map; /* local pointer to renaming map */
- /* is assigned to rd->local_map at the end */
- branch_target_t *table;
- lookup_target_t *lookup;
- s4 i;
- s4 j;
-
- /* get required compiler data */
-
- m = jd->m;
- code = jd->code;
-
- /* allocate buffers for local variable renaming */
-
- local_map = DMNEW(int, m->maxlocals * 5);
-
- for (i = 0; i < m->maxlocals; i++) {
- local_map[i * 5 + 0] = 0;
- local_map[i * 5 + 1] = 0;
- local_map[i * 5 + 2] = 0;
- local_map[i * 5 + 3] = 0;
- local_map[i * 5 + 4] = 0;
- }
-
- /* initialize the parse data structures */
-
- parse_setup(jd, &pd);
-
- /* initialize local variables */
-
- iptr = pd.instructions;
- ircount = 0;
- bbcount = 0;
- blockend = false;
- iswide = false;
-
- /* mark basic block boundaries for exception table */
-
- if (!parse_mark_exception_boundaries(jd, &pd))
- return false;
-
- /* initialize stack element counter */
-
- s_count = 1 + m->rawexceptiontablelength;
-
- /* setup line number info */
-
- currentline = 0;
- linepcchange = 0;
-
- if (m->linenumbercount == 0) {
- lineindex = 0;
- }
- else {
- linepcchange = m->linenumbers[0].start_pc;
- }
-
- /*** LOOP OVER ALL BYTECODE INSTRUCTIONS **********************************/
-
- for (bcindex = 0; bcindex < m->jcodelength; bcindex = nextbc) {
-
- /* mark this position as a valid bytecode instruction start */
-
- pd.bytecodestart[bcindex] = 1;
-
- /* change the current line number, if necessary */
-
- /* XXX rewrite this using pointer arithmetic */
-
- if (linepcchange == bcindex) {
- if (m->linenumbercount > lineindex) {
-next_linenumber:
- currentline = m->linenumbers[lineindex].line_number;
- lineindex++;
- if (lineindex < m->linenumbercount) {
- linepcchange = m->linenumbers[lineindex].start_pc;
- if (linepcchange == bcindex)
- goto next_linenumber;
- }
- }
- }
-
-fetch_opcode:
- /* fetch next opcode */
-
- opcode = SUCK_BE_U1(m->jcode + bcindex);
-
- /* If the previous instruction was a block-end instruction,
- mark the current bytecode instruction as basic-block
- starting instruction. */
-
- /* NOTE: Some compilers put a BC_nop after a blockend
- instruction. */
-
- if (blockend && (opcode != BC_nop)) {
- MARK_BASICBLOCK(&pd, bcindex);
- blockend = false;
- }
-
- /* If the current bytecode instruction was marked as
- basic-block starting instruction before (e.g. blockend,
- forward-branch target), mark the current IR instruction
- too. */
-
- if (pd.basicblockstart[bcindex] != 0) {
- /* We need a NOP as last instruction in each basic block
- for basic block reordering (may be replaced with a GOTO
- later). */
-
- INSTRUCTIONS_CHECK(1);
- OP(ICMD_NOP);
- }
-
- /* store intermediate instruction count (bit 0 mark block starts) */
-
- pd.bytecodemap[bcindex] = ircount;
-
- /* compute next instruction start */
-
- nextbc = bcindex + bytecode[opcode].length;
-
- CHECK_END_OF_BYTECODE(nextbc);
-
- /* add stack elements produced by this instruction */
-
- s_count += bytecode[opcode].slots;
-
- /* We check here for the space of 1 instruction in the
- instruction array. If an opcode is converted to more than
- 1 instruction, this is checked in the corresponding
- case. */
-
- INSTRUCTIONS_CHECK(1);
-
- /* translate this bytecode instruction */
- switch (opcode) {
-
- case BC_nop:
- break;
-
- /* pushing constants onto the stack ***********************************/
-
- case BC_bipush:
- OP_LOADCONST_I(SUCK_BE_S1(m->jcode + bcindex + 1));
- break;
-
- case BC_sipush:
- OP_LOADCONST_I(SUCK_BE_S2(m->jcode + bcindex + 1));
- break;
-
- case BC_ldc1:
- i = SUCK_BE_U1(m->jcode + bcindex + 1);
- goto pushconstantitem;
-
- case BC_ldc2:
- case BC_ldc2w:
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
-
- pushconstantitem:
-
-#if defined(ENABLE_VERIFIER)
- if (i >= m->clazz->cpcount) {
- exceptions_throw_verifyerror(m,
- "Attempt to access constant outside range");
- return false;
- }
-#endif
-
- switch (m->clazz->cptags[i]) {
- case CONSTANT_Integer:
- OP_LOADCONST_I(((constant_integer *) (m->clazz->cpinfos[i]))->value);
- break;
- case CONSTANT_Long:
- OP_LOADCONST_L(((constant_long *) (m->clazz->cpinfos[i]))->value);
- break;
- case CONSTANT_Float:
- OP_LOADCONST_F(((constant_float *) (m->clazz->cpinfos[i]))->value);
- break;
- case CONSTANT_Double:
- OP_LOADCONST_D(((constant_double *) (m->clazz->cpinfos[i]))->value);
- break;
- case CONSTANT_String:
- OP_LOADCONST_STRING(literalstring_new((utf *) (m->clazz->cpinfos[i])));
- break;
- case CONSTANT_Class:
- cr = (constant_classref *) (m->clazz->cpinfos[i]);
-
- if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
- return false;
-
- /* if not resolved, c == NULL */
-
- OP_LOADCONST_CLASSINFO_OR_CLASSREF_CHECK(c, cr);
-
- break;
-
-#if defined(ENABLE_VERIFIER)
- default:
- exceptions_throw_verifyerror(m,
- "Invalid constant type to push");
- return false;
-#endif
- }
- break;
-
- case BC_aconst_null:
- OP_LOADCONST_NULL();
- break;
-
- case BC_iconst_m1:
- case BC_iconst_0:
- case BC_iconst_1:
- case BC_iconst_2:
- case BC_iconst_3:
- case BC_iconst_4:
- case BC_iconst_5:
- OP_LOADCONST_I(opcode - BC_iconst_0);
- break;
-
- case BC_lconst_0:
- case BC_lconst_1:
- OP_LOADCONST_L(opcode - BC_lconst_0);
- break;
-
- case BC_fconst_0:
- case BC_fconst_1:
- case BC_fconst_2:
- OP_LOADCONST_F(opcode - BC_fconst_0);
- break;
-
- case BC_dconst_0:
- case BC_dconst_1:
- OP_LOADCONST_D(opcode - BC_dconst_0);
- break;
-
- /* stack operations ***************************************************/
-
- /* We need space for additional instruction so we can
- translate these instructions to sequences of ICMD_COPY and
- ICMD_MOVE instructions. */
-
- case BC_dup_x1:
- INSTRUCTIONS_CHECK(4);
- OP(opcode);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- break;
-
- case BC_dup_x2:
- INSTRUCTIONS_CHECK(6);
- OP(opcode);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- break;
-
- case BC_dup2:
- INSTRUCTIONS_CHECK(2);
- OP(opcode);
- OP(ICMD_NOP);
- break;
-
- case BC_dup2_x1:
- INSTRUCTIONS_CHECK(7);
- OP(opcode);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- break;
-
- case BC_dup2_x2:
- INSTRUCTIONS_CHECK(9);
- OP(opcode);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- break;
-
- case BC_swap:
- INSTRUCTIONS_CHECK(3);
- OP(opcode);
- OP(ICMD_NOP);
- OP(ICMD_NOP);
- break;
-
- /* local variable access instructions *********************************/
-
- case BC_iload:
- case BC_fload:
- case BC_aload:
- if (iswide == false) {
- i = SUCK_BE_U1(m->jcode + bcindex + 1);
- }
- else {
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- nextbc = bcindex + 3;
- iswide = false;
- }
- OP_LOAD_ONEWORD(opcode, i, opcode - BC_iload);
- break;
-
- case BC_lload:
- case BC_dload:
- if (iswide == false) {
- i = SUCK_BE_U1(m->jcode + bcindex + 1);
- }
- else {
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- nextbc = bcindex + 3;
- iswide = false;
- }
- OP_LOAD_TWOWORD(opcode, i, opcode - BC_iload);
- break;
-
- case BC_iload_0:
- case BC_iload_1:
- case BC_iload_2:
- case BC_iload_3:
- OP_LOAD_ONEWORD(ICMD_ILOAD, opcode - BC_iload_0, TYPE_INT);
- break;
-
- case BC_lload_0:
- case BC_lload_1:
- case BC_lload_2:
- case BC_lload_3:
- OP_LOAD_TWOWORD(ICMD_LLOAD, opcode - BC_lload_0, TYPE_LNG);
- break;
-
- case BC_fload_0:
- case BC_fload_1:
- case BC_fload_2:
- case BC_fload_3:
- OP_LOAD_ONEWORD(ICMD_FLOAD, opcode - BC_fload_0, TYPE_FLT);
- break;
-
- case BC_dload_0:
- case BC_dload_1:
- case BC_dload_2:
- case BC_dload_3:
- OP_LOAD_TWOWORD(ICMD_DLOAD, opcode - BC_dload_0, TYPE_DBL);
- break;
-
- case BC_aload_0:
- case BC_aload_1:
- case BC_aload_2:
- case BC_aload_3:
- OP_LOAD_ONEWORD(ICMD_ALOAD, opcode - BC_aload_0, TYPE_ADR);
- break;
-
- case BC_istore:
- case BC_fstore:
- case BC_astore:
- if (iswide == false) {
- i = SUCK_BE_U1(m->jcode + bcindex + 1);
- }
- else {
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- nextbc = bcindex + 3;
- iswide = false;
- }
- OP_STORE_ONEWORD(opcode, i, opcode - BC_istore);
- break;
-
- case BC_lstore:
- case BC_dstore:
- if (iswide == false) {
- i = SUCK_BE_U1(m->jcode + bcindex + 1);
- }
- else {
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- nextbc = bcindex + 3;
- iswide = false;
- }
- OP_STORE_TWOWORD(opcode, i, opcode - BC_istore);
- break;
-
- case BC_istore_0:
- case BC_istore_1:
- case BC_istore_2:
- case BC_istore_3:
- OP_STORE_ONEWORD(ICMD_ISTORE, opcode - BC_istore_0, TYPE_INT);
- break;
-
- case BC_lstore_0:
- case BC_lstore_1:
- case BC_lstore_2:
- case BC_lstore_3:
- OP_STORE_TWOWORD(ICMD_LSTORE, opcode - BC_lstore_0, TYPE_LNG);
- break;
-
- case BC_fstore_0:
- case BC_fstore_1:
- case BC_fstore_2:
- case BC_fstore_3:
- OP_STORE_ONEWORD(ICMD_FSTORE, opcode - BC_fstore_0, TYPE_FLT);
- break;
-
- case BC_dstore_0:
- case BC_dstore_1:
- case BC_dstore_2:
- case BC_dstore_3:
- OP_STORE_TWOWORD(ICMD_DSTORE, opcode - BC_dstore_0, TYPE_DBL);
- break;
-
- case BC_astore_0:
- case BC_astore_1:
- case BC_astore_2:
- case BC_astore_3:
- OP_STORE_ONEWORD(ICMD_ASTORE, opcode - BC_astore_0, TYPE_ADR);
- break;
-
- case BC_iinc:
- {
- int v;
-
- if (iswide == false) {
- i = SUCK_BE_U1(m->jcode + bcindex + 1);
- v = SUCK_BE_S1(m->jcode + bcindex + 2);
- }
- else {
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- v = SUCK_BE_S2(m->jcode + bcindex + 3);
- nextbc = bcindex + 5;
- iswide = false;
- }
- INDEX_ONEWORD(i);
- LOCALTYPE_USED(i, TYPE_INT);
- OP_LOCALINDEX_I(opcode, i, v);
- }
- break;
-
- /* wider index for loading, storing and incrementing ******************/
-
- case BC_wide:
- bcindex++;
- iswide = true;
- goto fetch_opcode;
-
- /* managing arrays ****************************************************/
-
- case BC_newarray:
- switch (SUCK_BE_S1(m->jcode + bcindex + 1)) {
- case 4:
- bte = builtintable_get_internal(BUILTIN_newarray_boolean);
- break;
- case 5:
- bte = builtintable_get_internal(BUILTIN_newarray_char);
- break;
- case 6:
- bte = builtintable_get_internal(BUILTIN_newarray_float);
- break;
- case 7:
- bte = builtintable_get_internal(BUILTIN_newarray_double);
- break;
- case 8:
- bte = builtintable_get_internal(BUILTIN_newarray_byte);
- break;
- case 9:
- bte = builtintable_get_internal(BUILTIN_newarray_short);
- break;
- case 10:
- bte = builtintable_get_internal(BUILTIN_newarray_int);
- break;
- case 11:
- bte = builtintable_get_internal(BUILTIN_newarray_long);
- break;
-#if defined(ENABLE_VERIFIER)
- default:
- exceptions_throw_verifyerror(m, "Invalid array-type to create");
- return false;
-#endif
- }
- OP_BUILTIN_CHECK_EXCEPTION(bte);
- break;
-
- case BC_anewarray:
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- compr = (constant_classref *) class_getconstant(m->clazz, i, CONSTANT_Class);
- if (compr == NULL)
- return false;
-
- if (!(cr = class_get_classref_multiarray_of(1, compr)))
- return false;
-
- if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
- return false;
-
- INSTRUCTIONS_CHECK(2);
- OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
- bte = builtintable_get_internal(BUILTIN_newarray);
- OP_BUILTIN_CHECK_EXCEPTION(bte);
- s_count++;
- break;
-
- case BC_multianewarray:
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- j = SUCK_BE_U1(m->jcode + bcindex + 3);
-
- cr = (constant_classref *) class_getconstant(m->clazz, i, CONSTANT_Class);
- if (cr == NULL)
- return false;
-
- if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
- return false;
-
- /* if unresolved, c == NULL */
-
- iptr->s1.argcount = j;
- OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, INS_FLAG_CHECK);
- code_unflag_leafmethod(code);
- break;
-
- /* control flow instructions ******************************************/
-
- case BC_ifeq:
- case BC_iflt:
- case BC_ifle:
- case BC_ifne:
- case BC_ifgt:
- case BC_ifge:
- case BC_ifnull:
- case BC_ifnonnull:
- case BC_if_icmpeq:
- case BC_if_icmpne:
- case BC_if_icmplt:
- case BC_if_icmpgt:
- case BC_if_icmple:
- case BC_if_icmpge:
- case BC_if_acmpeq:
- case BC_if_acmpne:
- case BC_goto:
- i = bcindex + SUCK_BE_S2(m->jcode + bcindex + 1);
- CHECK_BYTECODE_INDEX(i);
- MARK_BASICBLOCK(&pd, i);
- blockend = true;
- OP_INSINDEX(opcode, i);
- break;
-
- case BC_goto_w:
- i = bcindex + SUCK_BE_S4(m->jcode + bcindex + 1);
- CHECK_BYTECODE_INDEX(i);
- MARK_BASICBLOCK(&pd, i);
- blockend = true;
- OP_INSINDEX(ICMD_GOTO, i);
- break;
-
- case BC_jsr:
- i = bcindex + SUCK_BE_S2(m->jcode + bcindex + 1);
-jsr_tail:
- CHECK_BYTECODE_INDEX(i);
- MARK_BASICBLOCK(&pd, i);
- blockend = true;
- OP_PREPARE_ZEROFLAGS(BC_jsr);
- iptr->sx.s23.s3.jsrtarget.insindex = i;
- PINC;
- break;
-
- case BC_jsr_w:
- i = bcindex + SUCK_BE_S4(m->jcode + bcindex + 1);
- goto jsr_tail;
-
- case BC_ret:
- if (iswide == false) {
- i = SUCK_BE_U1(m->jcode + bcindex + 1);
- }
- else {
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- nextbc = bcindex + 3;
- iswide = false;
- }
- blockend = true;
-
- OP_LOAD_ONEWORD(opcode, i, TYPE_ADR);
- break;
-
- case BC_ireturn:
- case BC_lreturn:
- case BC_freturn:
- case BC_dreturn:
- case BC_areturn:
- case BC_return:
- blockend = true;
- /* XXX ARETURN will need a flag in the typechecker */
- OP(opcode);
- break;
-
- case BC_athrow:
- blockend = true;
- /* XXX ATHROW will need a flag in the typechecker */
- OP(opcode);
- break;
-
-
- /* table jumps ********************************************************/
-
- case BC_lookupswitch:
- {
- s4 num, j;
- lookup_target_t *lookup;
-#if defined(ENABLE_VERIFIER)
- s4 prevvalue = 0;
-#endif
- blockend = true;
- nextbc = MEMORY_ALIGN((bcindex + 1), 4);
-
- CHECK_END_OF_BYTECODE(nextbc + 8);
-
- OP_PREPARE_ZEROFLAGS(opcode);
-
- /* default target */
-
- j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
- iptr->sx.s23.s3.lookupdefault.insindex = j;
- nextbc += 4;
- CHECK_BYTECODE_INDEX(j);
- MARK_BASICBLOCK(&pd, j);
-
- /* number of pairs */
-
- num = SUCK_BE_U4(m->jcode + nextbc);
- iptr->sx.s23.s2.lookupcount = num;
- nextbc += 4;
-
- /* allocate the intermediate code table */
-
- lookup = DMNEW(lookup_target_t, num);
- iptr->dst.lookup = lookup;
-
- /* iterate over the lookup table */
-
- CHECK_END_OF_BYTECODE(nextbc + 8 * num);
-
- for (i = 0; i < num; i++) {
- /* value */
-
- j = SUCK_BE_S4(m->jcode + nextbc);
- lookup->value = j;
-
- nextbc += 4;
-
-#if defined(ENABLE_VERIFIER)
- /* check if the lookup table is sorted correctly */
-
- if (i && (j <= prevvalue)) {
- exceptions_throw_verifyerror(m, "Unsorted lookup switch");
- return false;
- }
- prevvalue = j;
-#endif
- /* target */
-
- j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
- lookup->target.insindex = j;
- lookup++;
- nextbc += 4;
- CHECK_BYTECODE_INDEX(j);
- MARK_BASICBLOCK(&pd, j);
- }
-
- PINC;
- break;
- }
-
- case BC_tableswitch:
- {
- s4 num, j;
- s4 deftarget;
- branch_target_t *table;
-
- blockend = true;
- nextbc = MEMORY_ALIGN((bcindex + 1), 4);
-
- CHECK_END_OF_BYTECODE(nextbc + 12);
-
- OP_PREPARE_ZEROFLAGS(opcode);
-
- /* default target */
-
- deftarget = bcindex + SUCK_BE_S4(m->jcode + nextbc);
- nextbc += 4;
- CHECK_BYTECODE_INDEX(deftarget);
- MARK_BASICBLOCK(&pd, deftarget);
-
- /* lower bound */
-
- j = SUCK_BE_S4(m->jcode + nextbc);
- iptr->sx.s23.s2.tablelow = j;
- nextbc += 4;
-
- /* upper bound */
-
- num = SUCK_BE_S4(m->jcode + nextbc);
- iptr->sx.s23.s3.tablehigh = num;
- nextbc += 4;
-
- /* calculate the number of table entries */
-
- num = num - j + 1;
-
-#if defined(ENABLE_VERIFIER)
- if (num < 1) {
- exceptions_throw_verifyerror(m,
- "invalid TABLESWITCH: upper bound < lower bound");
- return false;
- }
-#endif
- /* create the intermediate code table */
- /* the first entry is the default target */
-
- table = DMNEW(branch_target_t, 1 + num);
- iptr->dst.table = table;
- (table++)->insindex = deftarget;
-
- /* iterate over the target table */
-
- CHECK_END_OF_BYTECODE(nextbc + 4 * num);
-
- for (i = 0; i < num; i++) {
- j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
- (table++)->insindex = j;
- nextbc += 4;
- CHECK_BYTECODE_INDEX(j);
- MARK_BASICBLOCK(&pd, j);
- }
-
- PINC;
- break;
- }
-
-
- /* load and store of object fields ************************************/
-
- case BC_aastore:
- OP(opcode);
- code_unflag_leafmethod(code);
- break;
-
- case BC_getstatic:
- case BC_putstatic:
- case BC_getfield:
- case BC_putfield:
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- fmi = class_getconstant(m->clazz, i, CONSTANT_Fieldref);
-
- if (fmi == NULL)
- return false;
-
- OP_PREPARE_ZEROFLAGS(opcode);
- iptr->sx.s23.s3.fmiref = fmi;
-
- /* only with -noverify, otherwise the typechecker does this */
-
-#if defined(ENABLE_VERIFIER)
- if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
-#endif
- result = resolve_field_lazy(m, fmi);
-
- if (result == resolveFailed)
- return false;
-
- if (result != resolveSucceeded) {
- uf = resolve_create_unresolved_field(m->clazz, m, iptr);
-
- if (uf == NULL)
- return false;
-
- /* store the unresolved_field pointer */
-
- iptr->sx.s23.s3.uf = uf;
- iptr->flags.bits |= INS_FLAG_UNRESOLVED;
- }
-#if defined(ENABLE_VERIFIER)
- }
-#endif
- PINC;
- break;
-
-
- /* method invocation **************************************************/
-
- case BC_invokestatic:
- OP_PREPARE_ZEROFLAGS(opcode);
-
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- fmi = class_getconstant(m->clazz, i, CONSTANT_Methodref);
-
- if (fmi == NULL)
- return false;
-
- md = fmi->parseddesc.md;
-
- if (md->params == NULL)
- if (!descriptor_params_from_paramtypes(md, ACC_STATIC))
- return false;
-
- goto invoke_method;
-
- case BC_invokespecial:
- OP_PREPARE_FLAGS(opcode, INS_FLAG_CHECK);
-
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- fmi = class_getconstant(m->clazz, i, CONSTANT_Methodref);
-
- goto invoke_nonstatic_method;
-
- case BC_invokeinterface:
- OP_PREPARE_ZEROFLAGS(opcode);
-
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- fmi = class_getconstant(m->clazz, i, CONSTANT_InterfaceMethodref);
-
- goto invoke_nonstatic_method;
-
- case BC_invokevirtual:
- OP_PREPARE_ZEROFLAGS(opcode);
-
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- fmi = class_getconstant(m->clazz, i, CONSTANT_Methodref);
-
-invoke_nonstatic_method:
- if (fmi == NULL)
- return false;
-
- md = fmi->parseddesc.md;
-
- if (md->params == NULL)
- if (!descriptor_params_from_paramtypes(md, 0))
- return false;
-
-invoke_method:
- code_unflag_leafmethod(code);
-
- iptr->sx.s23.s3.fmiref = fmi;
-
- /* only with -noverify, otherwise the typechecker does this */
-
-#if defined(ENABLE_VERIFIER)
- if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
-#endif
- result = resolve_method_lazy(m, fmi,
- (opcode == BC_invokespecial));
-
- if (result == resolveFailed)
- return false;
-
- if (result == resolveSucceeded) {
- methodinfo *mi = iptr->sx.s23.s3.fmiref->p.method;
-
- /* if this call is monomorphic, turn it into an
- INVOKESPECIAL */
-
- assert(IS_FMIREF_RESOLVED(iptr->sx.s23.s3.fmiref));
-
- if ((iptr->opc == ICMD_INVOKEVIRTUAL)
- && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
- {
- iptr->opc = ICMD_INVOKESPECIAL;
- iptr->flags.bits |= INS_FLAG_CHECK;
- }
- }
- else {
- um = resolve_create_unresolved_method(m->clazz, m, fmi,
- (opcode == BC_invokestatic),
- (opcode == BC_invokespecial));
-
- if (um == NULL)
- return false;
-
- /* store the unresolved_method pointer */
-
- iptr->sx.s23.s3.um = um;
- iptr->flags.bits |= INS_FLAG_UNRESOLVED;
- }
-#if defined(ENABLE_VERIFIER)
- }
-#endif
- PINC;
- break;
-
- /* instructions taking class arguments ********************************/
-
- case BC_new:
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- cr = class_getconstant(m->clazz, i, CONSTANT_Class);
-
- if (cr == NULL)
- return false;
-
- if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
- return false;
-
- INSTRUCTIONS_CHECK(2);
- OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
- bte = builtintable_get_internal(BUILTIN_new);
- OP_BUILTIN_CHECK_EXCEPTION(bte);
- s_count++;
- break;
-
- case BC_checkcast:
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- cr = class_getconstant(m->clazz, i, CONSTANT_Class);
-
- if (cr == NULL)
- return false;
-
- if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
- return false;
-
- if (cr->name->text[0] == '[') {
- /* array type cast-check */
- flags = INS_FLAG_CHECK | INS_FLAG_ARRAY;
- code_unflag_leafmethod(code);
- }
- else {
- /* object type cast-check */
- flags = INS_FLAG_CHECK;
- }
- OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, flags);
- break;
-
- case BC_instanceof:
- i = SUCK_BE_U2(m->jcode + bcindex + 1);
- cr = class_getconstant(m->clazz, i, CONSTANT_Class);
-
- if (cr == NULL)
- return false;
-
- if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
- return false;
-
- if (cr->name->text[0] == '[') {
- /* array type cast-check */
- INSTRUCTIONS_CHECK(2);
- OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
- bte = builtintable_get_internal(BUILTIN_arrayinstanceof);
- OP_BUILTIN_NO_EXCEPTION(bte);
- s_count++;
- }
- else {
- /* object type cast-check */
- OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, 0 /* flags*/);
- }
- break;
-
- /* synchronization instructions ***************************************/
-
- case BC_monitorenter:
-#if defined(ENABLE_THREADS)
- if (checksync) {
- bte = builtintable_get_internal(LOCK_monitor_enter);
- OP_BUILTIN_CHECK_EXCEPTION(bte);
- }
- else
-#endif
- {
- OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
- OP(ICMD_POP);
- }
- break;
-
- case BC_monitorexit:
-#if defined(ENABLE_THREADS)
- if (checksync) {
- bte = builtintable_get_internal(LOCK_monitor_exit);
- OP_BUILTIN_CHECK_EXCEPTION(bte);
- }
- else
-#endif
- {
- OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
- OP(ICMD_POP);
- }
- break;
-
- /* arithmetic instructions that may become builtin functions **********/
-
- case BC_idiv:
-#if !SUPPORT_DIVISION
- bte = builtintable_get_internal(BUILTIN_idiv);
- OP_BUILTIN_ARITHMETIC(opcode, bte);
-#else
-# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
- OP(opcode);
-# else
- OP_CHECK_EXCEPTION(opcode);
-# endif
-#endif
- break;
-
- case BC_irem:
-#if !SUPPORT_DIVISION
- bte = builtintable_get_internal(BUILTIN_irem);
- OP_BUILTIN_ARITHMETIC(opcode, bte);
-#else
-# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
- OP(opcode);
-# else
- OP_CHECK_EXCEPTION(opcode);
-# endif
-#endif
- break;
-
- case BC_ldiv:
-#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV)
- bte = builtintable_get_internal(BUILTIN_ldiv);
- OP_BUILTIN_ARITHMETIC(opcode, bte);
-#else
-# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
- OP(opcode);
-# else
- OP_CHECK_EXCEPTION(opcode);
-# endif
-#endif
- break;
-
- case BC_lrem:
-#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV)
- bte = builtintable_get_internal(BUILTIN_lrem);
- OP_BUILTIN_ARITHMETIC(opcode, bte);
-#else
-# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
- OP(opcode);
-# else
- OP_CHECK_EXCEPTION(opcode);
-# endif
-#endif
- break;
-
- case BC_frem:
-#if defined(__I386__)
- OP(opcode);
-#else
- bte = builtintable_get_internal(BUILTIN_frem);
- OP_BUILTIN_NO_EXCEPTION(bte);
-#endif
- break;
-
- case BC_drem:
-#if defined(__I386__)
- OP(opcode);
-#else
- bte = builtintable_get_internal(BUILTIN_drem);
- OP_BUILTIN_NO_EXCEPTION(bte);
-#endif
- break;
-
- case BC_f2i:
-#if defined(__ALPHA__)
- bte = builtintable_get_internal(BUILTIN_f2i);
- OP_BUILTIN_NO_EXCEPTION(bte);
-#else
- OP(opcode);
-#endif
- break;
-
- case BC_f2l:
-#if defined(__ALPHA__)
- bte = builtintable_get_internal(BUILTIN_f2l);
- OP_BUILTIN_NO_EXCEPTION(bte);
-#else
- OP(opcode);
-#endif
- break;
-
- case BC_d2i:
-#if defined(__ALPHA__)
- bte = builtintable_get_internal(BUILTIN_d2i);
- OP_BUILTIN_NO_EXCEPTION(bte);
-#else
- OP(opcode);
-#endif
- break;
-
- case BC_d2l:
-#if defined(__ALPHA__)
- bte = builtintable_get_internal(BUILTIN_d2l);
- OP_BUILTIN_NO_EXCEPTION(bte);
-#else
- OP(opcode);
-#endif
- break;
-
-
- /* invalid opcodes ****************************************************/
-
- /* check for invalid opcodes if the verifier is enabled */
-#if defined(ENABLE_VERIFIER)
- case BC_breakpoint:
- exceptions_throw_verifyerror(m, "Quick instructions shouldn't appear, yet.");
- return false;
-
-
- /* Unused opcodes ************************************************** */
-
- case 186:
- case 203:
- case 204:
- case 205:
- case 206:
- case 207:
- case 208:
- case 209:
- case 210:
- case 211:
- case 212:
- case 213:
- case 214:
- case 215:
- case 216:
- case 217:
- case 218:
- case 219:
- case 220:
- case 221:
- case 222:
- case 223:
- case 224:
- case 225:
- case 226:
- case 227:
- case 228:
- case 229:
- case 230:
- case 231:
- case 232:
- case 233:
- case 234:
- case 235:
- case 236:
- case 237:
- case 238:
- case 239:
- case 240:
- case 241:
- case 242:
- case 243:
- case 244:
- case 245:
- case 246:
- case 247:
- case 248:
- case 249:
- case 250:
- case 251:
- case 252:
- case 253:
- case 254:
- case 255:
- exceptions_throw_verifyerror(m, "Illegal opcode %d at instr %d\n",
- opcode, ircount);
- return false;
- break;
-#endif /* defined(ENABLE_VERIFIER) */
-
- /* opcodes that don't require translation *****************************/
-
- default:
- /* Straight-forward translation to HIR. */
- OP(opcode);
- break;
-
- } /* end switch */
-
- /* verifier checks ****************************************************/
-
-#if defined(ENABLE_VERIFIER)
- /* If WIDE was used correctly, iswide should have been reset by now. */
- if (iswide) {
- exceptions_throw_verifyerror(m,
- "Illegal instruction: WIDE before incompatible opcode");
- return false;
- }
-#endif /* defined(ENABLE_VERIFIER) */
-
- } /* end for */
-
- if (JITDATA_HAS_FLAG_REORDER(jd)) {
- /* add a NOP to the last basic block */
-
- INSTRUCTIONS_CHECK(1);
- OP(ICMD_NOP);
- }
-
- /*** END OF LOOP **********************************************************/
-
- /* assert that we did not write more ICMDs than allocated */
-
- assert(ircount <= pd.instructionslength);
- assert(ircount == (iptr - pd.instructions));
-
- /*** verifier checks ******************************************************/
-
-#if defined(ENABLE_VERIFIER)
- if (bcindex != m->jcodelength) {
- exceptions_throw_verifyerror(m,
- "Command-sequence crosses code-boundary");
- return false;
- }
-
- if (!blockend) {
- exceptions_throw_verifyerror(m, "Falling off the end of the code");
- return false;
- }
-#endif /* defined(ENABLE_VERIFIER) */
-
- /*** setup the methodinfo, allocate stack and basic blocks ****************/
-
- /* identify basic blocks */
-
- /* check if first instruction is a branch target */
-
- if (pd.basicblockstart[0] == 1) {
- jd->branchtoentry = true;
- }
- else {
- /* first instruction always starts a basic block */
-
- iptr = pd.instructions;
-
- iptr->flags.bits |= INS_FLAG_BASICBLOCK;
- }
-
- /* Iterate over all bytecode instructions and set missing
- basic-block starts in IR instructions. */
-
- for (bcindex = 0; bcindex < m->jcodelength; bcindex++) {
- /* Does the current bytecode instruction start a basic
- block? */
-
- if (pd.basicblockstart[bcindex] == 1) {
-#if defined(ENABLE_VERIFIER)
- /* Check if this bytecode basic-block start at the
- beginning of a bytecode instruction. */
-
- if (pd.bytecodestart[bcindex] == 0) {
- exceptions_throw_verifyerror(m,
- "Branch into middle of instruction");
- return false;
- }
-#endif
-
- /* Get the IR instruction mapped to the bytecode
- instruction and set the basic block flag. */
-
- irindex = pd.bytecodemap[bcindex];
- iptr = pd.instructions + irindex;
-
- iptr->flags.bits |= INS_FLAG_BASICBLOCK;
- }
- }
-
- /* IR instruction index to basic-block index mapping */
-
- pd.instructionmap = DMNEW(s4, ircount);
- MZERO(pd.instructionmap, s4, ircount);
-
- /* Iterate over all IR instructions and count the basic blocks. */
-
- iptr = pd.instructions;
-
- bbcount = 0;
-
- for (i = 0; i < ircount; i++, iptr++) {
- if (INSTRUCTION_STARTS_BASICBLOCK(iptr)) {
- /* store the basic-block number in the IR instruction
- map */
-
- pd.instructionmap[i] = bbcount;
-
- /* post-increment the basic-block count */
-
- bbcount++;
- }
- }
-
- /* Allocate basic block array (one more for end ipc). */
-
- jd->basicblocks = DMNEW(basicblock, bbcount + 1);
- MZERO(jd->basicblocks, basicblock, bbcount + 1);
-
- /* Now iterate again over all IR instructions and initialize the
- basic block structures and, in the same loop, resolve the
- branch-target instruction indices to basic blocks. */
-
- iptr = pd.instructions;
- bptr = jd->basicblocks;
-
- bbcount = 0;
-
- for (i = 0; i < ircount; i++, iptr++) {
- /* check for basic block */
-
- if (INSTRUCTION_STARTS_BASICBLOCK(iptr)) {
- /* intialize the basic block */
-
- BASICBLOCK_INIT(bptr, m);
-
- bptr->iinstr = iptr;
-
- if (bbcount > 0) {
- bptr[-1].icount = bptr->iinstr - bptr[-1].iinstr;
- }
-
- /* bptr->icount is set when the next block is allocated */
-
- bptr->nr = bbcount++;
- bptr++;
- bptr[-1].next = bptr;
- }
-
- /* resolve instruction indices to basic blocks */
-
- switch (iptr->opc) {
- case ICMD_IFEQ:
- case ICMD_IFLT:
- case ICMD_IFLE:
- case ICMD_IFNE:
- case ICMD_IFGT:
- case ICMD_IFGE:
- case ICMD_IFNULL:
- case ICMD_IFNONNULL:
- case ICMD_IF_ICMPEQ:
- case ICMD_IF_ICMPNE:
- case ICMD_IF_ICMPLT:
- case ICMD_IF_ICMPGT:
- case ICMD_IF_ICMPLE:
- case ICMD_IF_ICMPGE:
- case ICMD_IF_ACMPEQ:
- case ICMD_IF_ACMPNE:
- case ICMD_GOTO:
- BYTECODEINDEX_TO_BASICBLOCK(iptr->dst);
- break;
-
- case ICMD_JSR:
- BYTECODEINDEX_TO_BASICBLOCK(iptr->sx.s23.s3.jsrtarget);
- break;
-
- case ICMD_TABLESWITCH:
- table = iptr->dst.table;
-
- BYTECODEINDEX_TO_BASICBLOCK(*table);
- table++;
-
- j = iptr->sx.s23.s3.tablehigh - iptr->sx.s23.s2.tablelow + 1;
-
- while (--j >= 0) {
- BYTECODEINDEX_TO_BASICBLOCK(*table);
- table++;
- }
- break;
-
- case ICMD_LOOKUPSWITCH:
- BYTECODEINDEX_TO_BASICBLOCK(iptr->sx.s23.s3.lookupdefault);
-
- lookup = iptr->dst.lookup;
-
- j = iptr->sx.s23.s2.lookupcount;
-
- while (--j >= 0) {
- BYTECODEINDEX_TO_BASICBLOCK(lookup->target);
- lookup++;
- }
- break;
- }
- }
-
- /* set instruction count of last real block */
-
- if (bbcount > 0) {
- bptr[-1].icount = (pd.instructions + ircount) - bptr[-1].iinstr;
- }
-
- /* allocate additional block at end */
-
- BASICBLOCK_INIT(bptr, m);
- bptr->nr = bbcount;
-
- /* set basicblock pointers in exception table */
-
- if (!parse_resolve_exception_table(jd, &pd))
- return false;
-
- /* store the local map */
-
- jd->local_map = local_map;
-
- /* calculate local variable renaming */
-
- {
- s4 nlocals = 0;
- s4 i;
- s4 t;
- s4 varindex;
- s4 *mapptr;
- s4 *reversemap;
-
- mapptr = local_map;
-
- /* iterate over local_map[0..m->maxlocals*5-1] and allocate a unique */
- /* variable index for each _used_ (javaindex,type) pair. */
- /* (local_map[javaindex*5+type] = cacaoindex) */
- /* Unused (javaindex,type) pairs are marked with UNUSED. */
-
- for (i = 0; i < (m->maxlocals * 5); i++, mapptr++) {
- if (*mapptr)
- *mapptr = nlocals++;
- else
- *mapptr = UNUSED;
- }
-
- jd->localcount = nlocals;
-
- /* calculate the (maximum) number of variables needed */
-
- jd->varcount =
- nlocals /* local variables */
- + bbcount * m->maxstack /* invars */
- + s_count; /* variables created within blocks (non-invar) */
-
- /* reserve the first indices for local variables */
-
- jd->vartop = nlocals;
-
- /* reserve extra variables needed by stack analyse */
-
- jd->varcount += STACK_EXTRA_VARS;
- jd->vartop += STACK_EXTRA_VARS;
-
- /* The verifier needs space for saving invars in some cases and */
- /* extra variables. */
-
-#if defined(ENABLE_VERIFIER)
- jd->varcount += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
- jd->vartop += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
-#endif
- /* allocate and initialize the variable array */
-
- jd->var = DMNEW(varinfo, jd->varcount);
- MZERO(jd->var, varinfo, jd->varcount);
-
- /* set types of all locals in jd->var */
- /* and fill the reverselocalmap */
-
- reversemap = DMNEW(s4, nlocals);
-
- for (i = 0; i < m->maxlocals; i++)
- for (t=0; t<5; t++) {
- varindex = local_map[5*i + t];
- if (varindex != UNUSED) {
- VAR(varindex)->type = t;
- reversemap[varindex] = i;
- }
- }
-
- jd->reverselocalmap = reversemap;
- }
-
- /* assign local variables to method variables */
-
- jd->instructions = pd.instructions;
- jd->instructioncount = ircount;
- jd->basicblockcount = bbcount;
- jd->stackcount = s_count + bbcount * m->maxstack; /* in-stacks */
-
- /* allocate stack table */
-
- jd->stack = DMNEW(stackelement_t, jd->stackcount);
-
- /* everything's ok */
-
- return true;
-
- /*** goto labels for throwing verifier exceptions *************************/
-
-#if defined(ENABLE_VERIFIER)
-
-throw_unexpected_end_of_bytecode:
- exceptions_throw_verifyerror(m, "Unexpected end of bytecode");
- return false;
-
-throw_invalid_bytecode_index:
- exceptions_throw_verifyerror(m, "Illegal target of branch instruction");
- return false;
-
-throw_illegal_local_variable_number:
- exceptions_throw_verifyerror(m, "Illegal local variable number");
- return false;
-
-#endif /* ENABLE_VERIFIER */
-}
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
--- /dev/null
+/* src/vm/jit/parse.c - parser for JavaVM to intermediate code translation
+
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "native/native.hpp"
+
+#include "threads/lock.hpp"
+
+#include "toolbox/logging.h"
+
+#include "vm/jit/builtin.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/global.h"
+#include "vm/linker.h"
+#include "vm/loader.hpp"
+#include "vm/options.h"
+#include "vm/resolve.hpp"
+
+#if defined(ENABLE_STATISTICS)
+# include "vm/statistics.h"
+#endif
+
+#include "vm/string.hpp"
+#include "vm/suck.hpp"
+
+#include "vm/jit/asmpart.h"
+#include "vm/jit/jit.hpp"
+#include "vm/jit/parse.hpp"
+#include "vm/jit/loop/loop.h"
+
+#include "vm/jit/ir/bytecode.h"
+
+
+#define INSTRUCTIONS_INCREMENT 5 /* number of additional instructions to */
+ /* allocate if space runs out */
+
+
+/* local macros ***************************************************************/
+
+#define BYTECODEINDEX_TO_BASICBLOCK(dst) \
+ do { \
+ (dst).block = \
+ parse_bytecodeindex_to_basicblock(jd, &pd, (dst).insindex); \
+ } while (0)
+
+
+/* parserdata_t ***************************************************************/
+
+typedef struct parsedata_t parsedata_t;
+
+struct parsedata_t {
+ u1 *bytecodestart; /* start of bytecode instructions */
+ u1 *basicblockstart; /* start of bytecode basic-blocks */
+
+ s4 *bytecodemap; /* bytecode to IR mapping */
+
+ instruction *instructions; /* instruction array */
+ s4 instructionslength; /* length of the instruction array */
+
+ s4 *instructionmap; /* IR to basic-block mapping */
+};
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* parse_setup *****************************************************************
+
+ Fills the passed parsedata_t structure.
+
+*******************************************************************************/
+
+static void parse_setup(jitdata *jd, parsedata_t *pd)
+{
+ methodinfo *m;
+
+ /* get required compiler data */
+
+ m = jd->m;
+
+ /* bytecode start array */
+
+ pd->bytecodestart = (u1*) DumpMemory::allocate(sizeof(u1) * (m->jcodelength + 1));
+ MZERO(pd->bytecodestart, u1, m->jcodelength + 1);
+
+ /* bytecode basic-block start array */
+
+ pd->basicblockstart = (u1*) DumpMemory::allocate(sizeof(u1) *(m->jcodelength + 1));
+ MZERO(pd->basicblockstart, u1, m->jcodelength + 1);
+
+ /* bytecode instruction index to IR instruction mapping */
+
+ pd->bytecodemap = (s4*) DumpMemory::allocate(sizeof(s4) * (m->jcodelength + 1));
+ MSET(pd->bytecodemap, -1, s4, m->jcodelength + 1);
+
+ /* allocate the instruction array */
+
+ pd->instructionslength = m->jcodelength + 1;
+ pd->instructions = (instruction*) DumpMemory::allocate(sizeof(instruction) * pd->instructionslength);
+
+ /* Zero the intermediate instructions array so we don't have any
+ invalid pointers in it if we cannot finish stack_analyse(). */
+
+ MZERO(pd->instructions, instruction, pd->instructionslength);
+
+ /* The instructionmap is allocated later when we know the count of
+ instructions. */
+
+ pd->instructionmap = NULL;
+}
+
+
+/* parse_realloc_instructions **************************************************
+
+ Reallocate the instructions array so there is room for at least N
+ additional instructions.
+
+ RETURN VALUE:
+ the new value for iptr
+
+*******************************************************************************/
+
+static instruction *parse_realloc_instructions(parsedata_t *pd, s4 icount, s4 n)
+{
+ /* increase the size of the instruction array */
+
+ pd->instructionslength += (n + INSTRUCTIONS_INCREMENT);
+
+ /* reallocate the array */
+
+ pd->instructions = (instruction*) DumpMemory::reallocate(pd->instructions, sizeof(instruction) * icount,
+ sizeof(instruction) * pd->instructionslength);
+ MZERO(pd->instructions + icount, instruction,
+ (pd->instructionslength - icount));
+
+ /* return the iptr */
+
+ return pd->instructions + icount;
+}
+
+
+/* parse_bytecodeindex_to_basicblock *******************************************
+
+ Resolves a bytecode index to the corresponding basic block.
+
+*******************************************************************************/
+
+static basicblock *parse_bytecodeindex_to_basicblock(jitdata *jd,
+ parsedata_t *pd,
+ s4 bcindex)
+{
+ s4 irindex;
+ basicblock *bb;
+
+ irindex = pd->bytecodemap[bcindex];
+ bb = jd->basicblocks + pd->instructionmap[irindex];
+
+ return bb;
+}
+
+
+/* parse_mark_exception_boundaries *********************************************
+
+ Mark exception handlers and the boundaries of the handled regions as
+ basic block boundaries.
+
+ IN:
+ jd...............current jitdata
+
+ RETURN VALUE:
+ true.............everything ok
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+static bool parse_mark_exception_boundaries(jitdata *jd, parsedata_t *pd)
+{
+ s4 bcindex;
+ s4 i;
+ s4 len;
+ raw_exception_entry *rex;
+ methodinfo *m;
+
+ m = jd->m;
+
+ len = m->rawexceptiontablelength;
+
+ if (len == 0)
+ return true;
+
+ rex = m->rawexceptiontable;
+
+ for (i = 0; i < len; ++i, ++rex) {
+
+ /* the start of the handled region becomes a basic block start */
+
+ bcindex = rex->startpc;
+ CHECK_BYTECODE_INDEX(bcindex);
+ MARK_BASICBLOCK(pd, bcindex);
+
+ bcindex = rex->endpc; /* see JVM Spec 4.7.3 */
+ CHECK_BYTECODE_INDEX_EXCLUSIVE(bcindex);
+
+ /* check that the range is valid */
+
+#if defined(ENABLE_VERIFIER)
+ if (bcindex <= rex->startpc) {
+ exceptions_throw_verifyerror(m, "Invalid exception handler range");
+ return false;
+ }
+#endif
+
+ /* End of handled region becomes a basic block boundary (if it
+ is the bytecode end, we'll use the special end block that
+ is created anyway). */
+
+ if (bcindex < m->jcodelength)
+ MARK_BASICBLOCK(pd, bcindex);
+ else
+ jd->branchtoend = true;
+
+ /* the start of the handler becomes a basic block start */
+
+ bcindex = rex->handlerpc;
+ CHECK_BYTECODE_INDEX(bcindex);
+ MARK_BASICBLOCK(pd, bcindex);
+ }
+
+ /* everything ok */
+
+ return true;
+
+#if defined(ENABLE_VERIFIER)
+throw_invalid_bytecode_index:
+ exceptions_throw_verifyerror(m,
+ "Illegal bytecode index in exception table");
+ return false;
+#endif
+}
+
+
+/* parse_resolve_exception_table ***********************************************
+
+ Enter the exception handlers and their ranges, resolved to basicblock *s,
+ in the jitdata.
+
+ IN:
+ jd...............current jitdata
+
+ RETURN VALUE:
+ true.............everything ok
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+static bool parse_resolve_exception_table(jitdata *jd, parsedata_t *pd)
+{
+ methodinfo *m;
+ raw_exception_entry *rex;
+ exception_entry *ex;
+ s4 i;
+ s4 len;
+ classinfo *exclass;
+
+ m = jd->m;
+
+ len = m->rawexceptiontablelength;
+
+ /* common case: no handler entries */
+
+ if (len == 0)
+ return true;
+
+ /* allocate the exception table */
+
+ jd->exceptiontablelength = len;
+ jd->exceptiontable = (exception_entry*) DumpMemory::allocate(sizeof(exception_entry) * (len + 1)); /* XXX why +1? */
+
+ /* copy and resolve the entries */
+
+ ex = jd->exceptiontable;
+ rex = m->rawexceptiontable;
+
+ for (i = 0; i < len; ++i, ++rex, ++ex) {
+ /* resolve instruction indices to basic blocks */
+
+ ex->start = parse_bytecodeindex_to_basicblock(jd, pd, rex->startpc);
+ ex->end = parse_bytecodeindex_to_basicblock(jd, pd, rex->endpc);
+ ex->handler = parse_bytecodeindex_to_basicblock(jd, pd, rex->handlerpc);
+
+ /* lazily resolve the catchtype */
+
+ if (rex->catchtype.any != NULL) {
+ if (!resolve_classref_or_classinfo(m,
+ rex->catchtype,
+ resolveLazy, true, false,
+ &exclass))
+ return false;
+
+ /* if resolved, enter the result of resolution in the table */
+
+ if (exclass != NULL)
+ rex->catchtype.cls = exclass;
+ }
+
+ ex->catchtype = rex->catchtype;
+ ex->next = NULL; /* set by loop analysis */
+ ex->down = ex + 1; /* link to next exception entry */
+ }
+
+ /* terminate the ->down linked list */
+
+ assert(ex != jd->exceptiontable);
+ ex[-1].down = NULL;
+
+ return true;
+}
+
+
+/*******************************************************************************
+
+ function 'parse' scans the JavaVM code and generates intermediate code
+
+ During parsing the block index table is used to store at bit pos 0
+ a flag which marks basic block starts and at position 1 to 31 the
+ intermediate instruction index. After parsing the block index table
+ is scanned, for marked positions a block is generated and the block
+ number is stored in the block index table.
+
+*******************************************************************************/
+
+/*** macro for checking the length of the bytecode ***/
+
+#if defined(ENABLE_VERIFIER)
+#define CHECK_END_OF_BYTECODE(neededlength) \
+ do { \
+ if ((neededlength) > m->jcodelength) \
+ goto throw_unexpected_end_of_bytecode; \
+ } while (0)
+#else /* !ENABLE_VERIFIER */
+#define CHECK_END_OF_BYTECODE(neededlength)
+#endif /* ENABLE_VERIFIER */
+
+bool parse(jitdata *jd)
+{
+ methodinfo *m; /* method being parsed */
+ codeinfo *code;
+ parsedata_t pd;
+ instruction *iptr; /* current ptr into instruction array */
+
+ s4 bcindex; /* bytecode instruction index */
+ s4 nextbc; /* start of next bytecode instruction */
+ s4 opcode; /* bytecode instruction opcode */
+
+ s4 irindex; /* IR instruction index */
+ s4 ircount; /* IR instruction count */
+
+ s4 bbcount; /* basic block count */
+
+ int s_count = 0; /* stack element counter */
+ bool blockend; /* true if basic block end has been reached */
+ bool iswide; /* true if last instruction was a wide */
+
+ constant_classref *cr;
+ constant_classref *compr;
+ classinfo *c;
+ builtintable_entry *bte;
+ constant_FMIref *fmi;
+ methoddesc *md;
+ unresolved_method *um;
+ unresolved_field *uf;
+
+ resolve_result_t result;
+ u2 lineindex = 0;
+ u2 currentline = 0;
+ u2 linepcchange = 0;
+ u4 flags;
+ basicblock *bptr;
+
+ int *local_map; /* local pointer to renaming map */
+ /* is assigned to rd->local_map at the end */
+ branch_target_t *table;
+ lookup_target_t *lookup;
+ s4 i;
+ s4 j;
+
+ /* get required compiler data */
+
+ m = jd->m;
+ code = jd->code;
+
+ /* allocate buffers for local variable renaming */
+
+ local_map = (int*) DumpMemory::allocate(sizeof(int) * m->maxlocals * 5);
+
+ for (i = 0; i < m->maxlocals; i++) {
+ local_map[i * 5 + 0] = 0;
+ local_map[i * 5 + 1] = 0;
+ local_map[i * 5 + 2] = 0;
+ local_map[i * 5 + 3] = 0;
+ local_map[i * 5 + 4] = 0;
+ }
+
+ /* initialize the parse data structures */
+
+ parse_setup(jd, &pd);
+
+ /* initialize local variables */
+
+ iptr = pd.instructions;
+ ircount = 0;
+ bbcount = 0;
+ blockend = false;
+ iswide = false;
+
+ /* mark basic block boundaries for exception table */
+
+ if (!parse_mark_exception_boundaries(jd, &pd))
+ return false;
+
+ /* initialize stack element counter */
+
+ s_count = 1 + m->rawexceptiontablelength;
+
+ /* setup line number info */
+
+ currentline = 0;
+ linepcchange = 0;
+
+ if (m->linenumbercount == 0) {
+ lineindex = 0;
+ }
+ else {
+ linepcchange = m->linenumbers[0].start_pc;
+ }
+
+ /*** LOOP OVER ALL BYTECODE INSTRUCTIONS **********************************/
+
+ for (bcindex = 0; bcindex < m->jcodelength; bcindex = nextbc) {
+
+ /* mark this position as a valid bytecode instruction start */
+
+ pd.bytecodestart[bcindex] = 1;
+
+ /* change the current line number, if necessary */
+
+ /* XXX rewrite this using pointer arithmetic */
+
+ if (linepcchange == bcindex) {
+ if (m->linenumbercount > lineindex) {
+next_linenumber:
+ currentline = m->linenumbers[lineindex].line_number;
+ lineindex++;
+ if (lineindex < m->linenumbercount) {
+ linepcchange = m->linenumbers[lineindex].start_pc;
+ if (linepcchange == bcindex)
+ goto next_linenumber;
+ }
+ }
+ }
+
+fetch_opcode:
+ /* fetch next opcode */
+
+ opcode = SUCK_BE_U1(m->jcode + bcindex);
+
+ /* If the previous instruction was a block-end instruction,
+ mark the current bytecode instruction as basic-block
+ starting instruction. */
+
+ /* NOTE: Some compilers put a BC_nop after a blockend
+ instruction. */
+
+ if (blockend && (opcode != BC_nop)) {
+ MARK_BASICBLOCK(&pd, bcindex);
+ blockend = false;
+ }
+
+ /* If the current bytecode instruction was marked as
+ basic-block starting instruction before (e.g. blockend,
+ forward-branch target), mark the current IR instruction
+ too. */
+
+ if (pd.basicblockstart[bcindex] != 0) {
+ /* We need a NOP as last instruction in each basic block
+ for basic block reordering (may be replaced with a GOTO
+ later). */
+
+ INSTRUCTIONS_CHECK(1);
+ OP(ICMD_NOP);
+ }
+
+ /* store intermediate instruction count (bit 0 mark block starts) */
+
+ pd.bytecodemap[bcindex] = ircount;
+
+ /* compute next instruction start */
+
+ nextbc = bcindex + bytecode[opcode].length;
+
+ CHECK_END_OF_BYTECODE(nextbc);
+
+ /* add stack elements produced by this instruction */
+
+ s_count += bytecode[opcode].slots;
+
+ /* We check here for the space of 1 instruction in the
+ instruction array. If an opcode is converted to more than
+ 1 instruction, this is checked in the corresponding
+ case. */
+
+ INSTRUCTIONS_CHECK(1);
+
+ /* translate this bytecode instruction */
+ switch (opcode) {
+
+ case BC_nop:
+ break;
+
+ /* pushing constants onto the stack ***********************************/
+
+ case BC_bipush:
+ OP_LOADCONST_I(SUCK_BE_S1(m->jcode + bcindex + 1));
+ break;
+
+ case BC_sipush:
+ OP_LOADCONST_I(SUCK_BE_S2(m->jcode + bcindex + 1));
+ break;
+
+ case BC_ldc1:
+ i = SUCK_BE_U1(m->jcode + bcindex + 1);
+ goto pushconstantitem;
+
+ case BC_ldc2:
+ case BC_ldc2w:
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+
+ pushconstantitem:
+
+#if defined(ENABLE_VERIFIER)
+ if (i >= m->clazz->cpcount) {
+ exceptions_throw_verifyerror(m,
+ "Attempt to access constant outside range");
+ return false;
+ }
+#endif
+
+ switch (m->clazz->cptags[i]) {
+ case CONSTANT_Integer:
+ OP_LOADCONST_I(((constant_integer *) (m->clazz->cpinfos[i]))->value);
+ break;
+ case CONSTANT_Long:
+ OP_LOADCONST_L(((constant_long *) (m->clazz->cpinfos[i]))->value);
+ break;
+ case CONSTANT_Float:
+ OP_LOADCONST_F(((constant_float *) (m->clazz->cpinfos[i]))->value);
+ break;
+ case CONSTANT_Double:
+ OP_LOADCONST_D(((constant_double *) (m->clazz->cpinfos[i]))->value);
+ break;
+ case CONSTANT_String:
+ OP_LOADCONST_STRING(literalstring_new((utf *) (m->clazz->cpinfos[i])));
+ break;
+ case CONSTANT_Class:
+ cr = (constant_classref *) (m->clazz->cpinfos[i]);
+
+ if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+ return false;
+
+ /* if not resolved, c == NULL */
+
+ OP_LOADCONST_CLASSINFO_OR_CLASSREF_CHECK(c, cr);
+
+ break;
+
+#if defined(ENABLE_VERIFIER)
+ default:
+ exceptions_throw_verifyerror(m,
+ "Invalid constant type to push");
+ return false;
+#endif
+ }
+ break;
+
+ case BC_aconst_null:
+ OP_LOADCONST_NULL();
+ break;
+
+ case BC_iconst_m1:
+ case BC_iconst_0:
+ case BC_iconst_1:
+ case BC_iconst_2:
+ case BC_iconst_3:
+ case BC_iconst_4:
+ case BC_iconst_5:
+ OP_LOADCONST_I(opcode - BC_iconst_0);
+ break;
+
+ case BC_lconst_0:
+ case BC_lconst_1:
+ OP_LOADCONST_L(opcode - BC_lconst_0);
+ break;
+
+ case BC_fconst_0:
+ case BC_fconst_1:
+ case BC_fconst_2:
+ OP_LOADCONST_F(opcode - BC_fconst_0);
+ break;
+
+ case BC_dconst_0:
+ case BC_dconst_1:
+ OP_LOADCONST_D(opcode - BC_dconst_0);
+ break;
+
+ /* stack operations ***************************************************/
+
+ /* We need space for additional instruction so we can
+ translate these instructions to sequences of ICMD_COPY and
+ ICMD_MOVE instructions. */
+
+ case BC_dup_x1:
+ INSTRUCTIONS_CHECK(4);
+ OP(opcode);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ break;
+
+ case BC_dup_x2:
+ INSTRUCTIONS_CHECK(6);
+ OP(opcode);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ break;
+
+ case BC_dup2:
+ INSTRUCTIONS_CHECK(2);
+ OP(opcode);
+ OP(ICMD_NOP);
+ break;
+
+ case BC_dup2_x1:
+ INSTRUCTIONS_CHECK(7);
+ OP(opcode);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ break;
+
+ case BC_dup2_x2:
+ INSTRUCTIONS_CHECK(9);
+ OP(opcode);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ break;
+
+ case BC_swap:
+ INSTRUCTIONS_CHECK(3);
+ OP(opcode);
+ OP(ICMD_NOP);
+ OP(ICMD_NOP);
+ break;
+
+ /* local variable access instructions *********************************/
+
+ case BC_iload:
+ case BC_fload:
+ case BC_aload:
+ if (iswide == false) {
+ i = SUCK_BE_U1(m->jcode + bcindex + 1);
+ }
+ else {
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ nextbc = bcindex + 3;
+ iswide = false;
+ }
+ OP_LOAD_ONEWORD(opcode, i, opcode - BC_iload);
+ break;
+
+ case BC_lload:
+ case BC_dload:
+ if (iswide == false) {
+ i = SUCK_BE_U1(m->jcode + bcindex + 1);
+ }
+ else {
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ nextbc = bcindex + 3;
+ iswide = false;
+ }
+ OP_LOAD_TWOWORD(opcode, i, opcode - BC_iload);
+ break;
+
+ case BC_iload_0:
+ case BC_iload_1:
+ case BC_iload_2:
+ case BC_iload_3:
+ OP_LOAD_ONEWORD(ICMD_ILOAD, opcode - BC_iload_0, TYPE_INT);
+ break;
+
+ case BC_lload_0:
+ case BC_lload_1:
+ case BC_lload_2:
+ case BC_lload_3:
+ OP_LOAD_TWOWORD(ICMD_LLOAD, opcode - BC_lload_0, TYPE_LNG);
+ break;
+
+ case BC_fload_0:
+ case BC_fload_1:
+ case BC_fload_2:
+ case BC_fload_3:
+ OP_LOAD_ONEWORD(ICMD_FLOAD, opcode - BC_fload_0, TYPE_FLT);
+ break;
+
+ case BC_dload_0:
+ case BC_dload_1:
+ case BC_dload_2:
+ case BC_dload_3:
+ OP_LOAD_TWOWORD(ICMD_DLOAD, opcode - BC_dload_0, TYPE_DBL);
+ break;
+
+ case BC_aload_0:
+ case BC_aload_1:
+ case BC_aload_2:
+ case BC_aload_3:
+ OP_LOAD_ONEWORD(ICMD_ALOAD, opcode - BC_aload_0, TYPE_ADR);
+ break;
+
+ case BC_istore:
+ case BC_fstore:
+ case BC_astore:
+ if (iswide == false) {
+ i = SUCK_BE_U1(m->jcode + bcindex + 1);
+ }
+ else {
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ nextbc = bcindex + 3;
+ iswide = false;
+ }
+ OP_STORE_ONEWORD(opcode, i, opcode - BC_istore);
+ break;
+
+ case BC_lstore:
+ case BC_dstore:
+ if (iswide == false) {
+ i = SUCK_BE_U1(m->jcode + bcindex + 1);
+ }
+ else {
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ nextbc = bcindex + 3;
+ iswide = false;
+ }
+ OP_STORE_TWOWORD(opcode, i, opcode - BC_istore);
+ break;
+
+ case BC_istore_0:
+ case BC_istore_1:
+ case BC_istore_2:
+ case BC_istore_3:
+ OP_STORE_ONEWORD(ICMD_ISTORE, opcode - BC_istore_0, TYPE_INT);
+ break;
+
+ case BC_lstore_0:
+ case BC_lstore_1:
+ case BC_lstore_2:
+ case BC_lstore_3:
+ OP_STORE_TWOWORD(ICMD_LSTORE, opcode - BC_lstore_0, TYPE_LNG);
+ break;
+
+ case BC_fstore_0:
+ case BC_fstore_1:
+ case BC_fstore_2:
+ case BC_fstore_3:
+ OP_STORE_ONEWORD(ICMD_FSTORE, opcode - BC_fstore_0, TYPE_FLT);
+ break;
+
+ case BC_dstore_0:
+ case BC_dstore_1:
+ case BC_dstore_2:
+ case BC_dstore_3:
+ OP_STORE_TWOWORD(ICMD_DSTORE, opcode - BC_dstore_0, TYPE_DBL);
+ break;
+
+ case BC_astore_0:
+ case BC_astore_1:
+ case BC_astore_2:
+ case BC_astore_3:
+ OP_STORE_ONEWORD(ICMD_ASTORE, opcode - BC_astore_0, TYPE_ADR);
+ break;
+
+ case BC_iinc:
+ {
+ int v;
+
+ if (iswide == false) {
+ i = SUCK_BE_U1(m->jcode + bcindex + 1);
+ v = SUCK_BE_S1(m->jcode + bcindex + 2);
+ }
+ else {
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ v = SUCK_BE_S2(m->jcode + bcindex + 3);
+ nextbc = bcindex + 5;
+ iswide = false;
+ }
+ INDEX_ONEWORD(i);
+ LOCALTYPE_USED(i, TYPE_INT);
+ OP_LOCALINDEX_I(opcode, i, v);
+ }
+ break;
+
+ /* wider index for loading, storing and incrementing ******************/
+
+ case BC_wide:
+ bcindex++;
+ iswide = true;
+ goto fetch_opcode;
+
+ /* managing arrays ****************************************************/
+
+ case BC_newarray:
+ switch (SUCK_BE_S1(m->jcode + bcindex + 1)) {
+ case 4:
+ bte = builtintable_get_internal(BUILTIN_newarray_boolean);
+ break;
+ case 5:
+ bte = builtintable_get_internal(BUILTIN_newarray_char);
+ break;
+ case 6:
+ bte = builtintable_get_internal(BUILTIN_newarray_float);
+ break;
+ case 7:
+ bte = builtintable_get_internal(BUILTIN_newarray_double);
+ break;
+ case 8:
+ bte = builtintable_get_internal(BUILTIN_newarray_byte);
+ break;
+ case 9:
+ bte = builtintable_get_internal(BUILTIN_newarray_short);
+ break;
+ case 10:
+ bte = builtintable_get_internal(BUILTIN_newarray_int);
+ break;
+ case 11:
+ bte = builtintable_get_internal(BUILTIN_newarray_long);
+ break;
+#if defined(ENABLE_VERIFIER)
+ default:
+ exceptions_throw_verifyerror(m, "Invalid array-type to create");
+ return false;
+#endif
+ }
+ OP_BUILTIN_CHECK_EXCEPTION(bte);
+ break;
+
+ case BC_anewarray:
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ compr = (constant_classref *) class_getconstant(m->clazz, i, CONSTANT_Class);
+ if (compr == NULL)
+ return false;
+
+ if (!(cr = class_get_classref_multiarray_of(1, compr)))
+ return false;
+
+ if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+ return false;
+
+ INSTRUCTIONS_CHECK(2);
+ OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
+ bte = builtintable_get_internal(BUILTIN_newarray);
+ OP_BUILTIN_CHECK_EXCEPTION(bte);
+ s_count++;
+ break;
+
+ case BC_multianewarray:
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ j = SUCK_BE_U1(m->jcode + bcindex + 3);
+
+ cr = (constant_classref *) class_getconstant(m->clazz, i, CONSTANT_Class);
+ if (cr == NULL)
+ return false;
+
+ if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+ return false;
+
+ /* if unresolved, c == NULL */
+
+ iptr->s1.argcount = j;
+ OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, INS_FLAG_CHECK);
+ code_unflag_leafmethod(code);
+ break;
+
+ /* control flow instructions ******************************************/
+
+ case BC_ifeq:
+ case BC_iflt:
+ case BC_ifle:
+ case BC_ifne:
+ case BC_ifgt:
+ case BC_ifge:
+ case BC_ifnull:
+ case BC_ifnonnull:
+ case BC_if_icmpeq:
+ case BC_if_icmpne:
+ case BC_if_icmplt:
+ case BC_if_icmpgt:
+ case BC_if_icmple:
+ case BC_if_icmpge:
+ case BC_if_acmpeq:
+ case BC_if_acmpne:
+ case BC_goto:
+ i = bcindex + SUCK_BE_S2(m->jcode + bcindex + 1);
+ CHECK_BYTECODE_INDEX(i);
+ MARK_BASICBLOCK(&pd, i);
+ blockend = true;
+ OP_INSINDEX(opcode, i);
+ break;
+
+ case BC_goto_w:
+ i = bcindex + SUCK_BE_S4(m->jcode + bcindex + 1);
+ CHECK_BYTECODE_INDEX(i);
+ MARK_BASICBLOCK(&pd, i);
+ blockend = true;
+ OP_INSINDEX(ICMD_GOTO, i);
+ break;
+
+ case BC_jsr:
+ i = bcindex + SUCK_BE_S2(m->jcode + bcindex + 1);
+jsr_tail:
+ CHECK_BYTECODE_INDEX(i);
+ MARK_BASICBLOCK(&pd, i);
+ blockend = true;
+ OP_PREPARE_ZEROFLAGS(BC_jsr);
+ iptr->sx.s23.s3.jsrtarget.insindex = i;
+ PINC;
+ break;
+
+ case BC_jsr_w:
+ i = bcindex + SUCK_BE_S4(m->jcode + bcindex + 1);
+ goto jsr_tail;
+
+ case BC_ret:
+ if (iswide == false) {
+ i = SUCK_BE_U1(m->jcode + bcindex + 1);
+ }
+ else {
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ nextbc = bcindex + 3;
+ iswide = false;
+ }
+ blockend = true;
+
+ OP_LOAD_ONEWORD(opcode, i, TYPE_ADR);
+ break;
+
+ case BC_ireturn:
+ case BC_lreturn:
+ case BC_freturn:
+ case BC_dreturn:
+ case BC_areturn:
+ case BC_return:
+ blockend = true;
+ /* XXX ARETURN will need a flag in the typechecker */
+ OP(opcode);
+ break;
+
+ case BC_athrow:
+ blockend = true;
+ /* XXX ATHROW will need a flag in the typechecker */
+ OP(opcode);
+ break;
+
+
+ /* table jumps ********************************************************/
+
+ case BC_lookupswitch:
+ {
+ s4 num, j;
+ lookup_target_t *lookup;
+#if defined(ENABLE_VERIFIER)
+ s4 prevvalue = 0;
+#endif
+ blockend = true;
+ nextbc = MEMORY_ALIGN((bcindex + 1), 4);
+
+ CHECK_END_OF_BYTECODE(nextbc + 8);
+
+ OP_PREPARE_ZEROFLAGS(opcode);
+
+ /* default target */
+
+ j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
+ iptr->sx.s23.s3.lookupdefault.insindex = j;
+ nextbc += 4;
+ CHECK_BYTECODE_INDEX(j);
+ MARK_BASICBLOCK(&pd, j);
+
+ /* number of pairs */
+
+ num = SUCK_BE_U4(m->jcode + nextbc);
+ iptr->sx.s23.s2.lookupcount = num;
+ nextbc += 4;
+
+ /* allocate the intermediate code table */
+
+ lookup = (lookup_target_t*) DumpMemory::allocate(sizeof(lookup_target_t) * num);
+ iptr->dst.lookup = lookup;
+
+ /* iterate over the lookup table */
+
+ CHECK_END_OF_BYTECODE(nextbc + 8 * num);
+
+ for (i = 0; i < num; i++) {
+ /* value */
+
+ j = SUCK_BE_S4(m->jcode + nextbc);
+ lookup->value = j;
+
+ nextbc += 4;
+
+#if defined(ENABLE_VERIFIER)
+ /* check if the lookup table is sorted correctly */
+
+ if (i && (j <= prevvalue)) {
+ exceptions_throw_verifyerror(m, "Unsorted lookup switch");
+ return false;
+ }
+ prevvalue = j;
+#endif
+ /* target */
+
+ j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
+ lookup->target.insindex = j;
+ lookup++;
+ nextbc += 4;
+ CHECK_BYTECODE_INDEX(j);
+ MARK_BASICBLOCK(&pd, j);
+ }
+
+ PINC;
+ break;
+ }
+
+ case BC_tableswitch:
+ {
+ s4 num, j;
+ s4 deftarget;
+ branch_target_t *table;
+
+ blockend = true;
+ nextbc = MEMORY_ALIGN((bcindex + 1), 4);
+
+ CHECK_END_OF_BYTECODE(nextbc + 12);
+
+ OP_PREPARE_ZEROFLAGS(opcode);
+
+ /* default target */
+
+ deftarget = bcindex + SUCK_BE_S4(m->jcode + nextbc);
+ nextbc += 4;
+ CHECK_BYTECODE_INDEX(deftarget);
+ MARK_BASICBLOCK(&pd, deftarget);
+
+ /* lower bound */
+
+ j = SUCK_BE_S4(m->jcode + nextbc);
+ iptr->sx.s23.s2.tablelow = j;
+ nextbc += 4;
+
+ /* upper bound */
+
+ num = SUCK_BE_S4(m->jcode + nextbc);
+ iptr->sx.s23.s3.tablehigh = num;
+ nextbc += 4;
+
+ /* calculate the number of table entries */
+
+ num = num - j + 1;
+
+#if defined(ENABLE_VERIFIER)
+ if (num < 1) {
+ exceptions_throw_verifyerror(m,
+ "invalid TABLESWITCH: upper bound < lower bound");
+ return false;
+ }
+#endif
+ /* create the intermediate code table */
+ /* the first entry is the default target */
+
+ table = (branch_target_t*) DumpMemory::allocate(sizeof(branch_target_t) * (1 + num));
+ iptr->dst.table = table;
+ (table++)->insindex = deftarget;
+
+ /* iterate over the target table */
+
+ CHECK_END_OF_BYTECODE(nextbc + 4 * num);
+
+ for (i = 0; i < num; i++) {
+ j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
+ (table++)->insindex = j;
+ nextbc += 4;
+ CHECK_BYTECODE_INDEX(j);
+ MARK_BASICBLOCK(&pd, j);
+ }
+
+ PINC;
+ break;
+ }
+
+
+ /* load and store of object fields ************************************/
+
+ case BC_aastore:
+ OP(opcode);
+ code_unflag_leafmethod(code);
+ break;
+
+ case BC_getstatic:
+ case BC_putstatic:
+ case BC_getfield:
+ case BC_putfield:
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ fmi = (constant_FMIref*) class_getconstant(m->clazz, i, CONSTANT_Fieldref);
+
+ if (fmi == NULL)
+ return false;
+
+ OP_PREPARE_ZEROFLAGS(opcode);
+ iptr->sx.s23.s3.fmiref = fmi;
+
+ /* only with -noverify, otherwise the typechecker does this */
+
+#if defined(ENABLE_VERIFIER)
+ if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
+#endif
+ result = resolve_field_lazy(m, fmi);
+
+ if (result == resolveFailed)
+ return false;
+
+ if (result != resolveSucceeded) {
+ uf = resolve_create_unresolved_field(m->clazz, m, iptr);
+
+ if (uf == NULL)
+ return false;
+
+ /* store the unresolved_field pointer */
+
+ iptr->sx.s23.s3.uf = uf;
+ iptr->flags.bits |= INS_FLAG_UNRESOLVED;
+ }
+#if defined(ENABLE_VERIFIER)
+ }
+#endif
+ PINC;
+ break;
+
+
+ /* method invocation **************************************************/
+
+ case BC_invokestatic:
+ OP_PREPARE_ZEROFLAGS(opcode);
+
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ fmi = (constant_FMIref*) class_getconstant(m->clazz, i, CONSTANT_Methodref);
+
+ if (fmi == NULL)
+ return false;
+
+ md = fmi->parseddesc.md;
+
+ if (md->params == NULL)
+ if (!descriptor_params_from_paramtypes(md, ACC_STATIC))
+ return false;
+
+ goto invoke_method;
+
+ case BC_invokespecial:
+ OP_PREPARE_FLAGS(opcode, INS_FLAG_CHECK);
+
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ fmi = (constant_FMIref*) class_getconstant(m->clazz, i, CONSTANT_Methodref);
+
+ goto invoke_nonstatic_method;
+
+ case BC_invokeinterface:
+ OP_PREPARE_ZEROFLAGS(opcode);
+
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ fmi = (constant_FMIref*) class_getconstant(m->clazz, i, CONSTANT_InterfaceMethodref);
+
+ goto invoke_nonstatic_method;
+
+ case BC_invokevirtual:
+ OP_PREPARE_ZEROFLAGS(opcode);
+
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ fmi = (constant_FMIref*) class_getconstant(m->clazz, i, CONSTANT_Methodref);
+
+invoke_nonstatic_method:
+ if (fmi == NULL)
+ return false;
+
+ md = fmi->parseddesc.md;
+
+ if (md->params == NULL)
+ if (!descriptor_params_from_paramtypes(md, 0))
+ return false;
+
+invoke_method:
+ code_unflag_leafmethod(code);
+
+ iptr->sx.s23.s3.fmiref = fmi;
+
+ /* only with -noverify, otherwise the typechecker does this */
+
+#if defined(ENABLE_VERIFIER)
+ if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
+#endif
+ result = resolve_method_lazy(m, fmi,
+ (opcode == BC_invokespecial));
+
+ if (result == resolveFailed)
+ return false;
+
+ if (result == resolveSucceeded) {
+ methodinfo *mi = iptr->sx.s23.s3.fmiref->p.method;
+
+ /* if this call is monomorphic, turn it into an
+ INVOKESPECIAL */
+
+ assert(IS_FMIREF_RESOLVED(iptr->sx.s23.s3.fmiref));
+
+ if ((iptr->opc == ICMD_INVOKEVIRTUAL)
+ && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
+ {
+ iptr->opc = ICMD_INVOKESPECIAL;
+ iptr->flags.bits |= INS_FLAG_CHECK;
+ }
+ }
+ else {
+ um = resolve_create_unresolved_method(m->clazz, m, fmi,
+ (opcode == BC_invokestatic),
+ (opcode == BC_invokespecial));
+
+ if (um == NULL)
+ return false;
+
+ /* store the unresolved_method pointer */
+
+ iptr->sx.s23.s3.um = um;
+ iptr->flags.bits |= INS_FLAG_UNRESOLVED;
+ }
+#if defined(ENABLE_VERIFIER)
+ }
+#endif
+ PINC;
+ break;
+
+ /* instructions taking class arguments ********************************/
+
+ case BC_new:
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ cr = (constant_classref*) class_getconstant(m->clazz, i, CONSTANT_Class);
+
+ if (cr == NULL)
+ return false;
+
+ if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+ return false;
+
+ INSTRUCTIONS_CHECK(2);
+ OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
+ bte = builtintable_get_internal(BUILTIN_new);
+ OP_BUILTIN_CHECK_EXCEPTION(bte);
+ s_count++;
+ break;
+
+ case BC_checkcast:
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ cr = (constant_classref*) class_getconstant(m->clazz, i, CONSTANT_Class);
+
+ if (cr == NULL)
+ return false;
+
+ if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+ return false;
+
+ if (cr->name->text[0] == '[') {
+ /* array type cast-check */
+ flags = INS_FLAG_CHECK | INS_FLAG_ARRAY;
+ code_unflag_leafmethod(code);
+ }
+ else {
+ /* object type cast-check */
+ flags = INS_FLAG_CHECK;
+ }
+ OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, flags);
+ break;
+
+ case BC_instanceof:
+ i = SUCK_BE_U2(m->jcode + bcindex + 1);
+ cr = (constant_classref*) class_getconstant(m->clazz, i, CONSTANT_Class);
+
+ if (cr == NULL)
+ return false;
+
+ if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+ return false;
+
+ if (cr->name->text[0] == '[') {
+ /* array type cast-check */
+ INSTRUCTIONS_CHECK(2);
+ OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
+ bte = builtintable_get_internal(BUILTIN_arrayinstanceof);
+ OP_BUILTIN_NO_EXCEPTION(bte);
+ s_count++;
+ }
+ else {
+ /* object type cast-check */
+ OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, 0 /* flags*/);
+ }
+ break;
+
+ /* synchronization instructions ***************************************/
+
+ case BC_monitorenter:
+#if defined(ENABLE_THREADS)
+ if (checksync) {
+ bte = builtintable_get_internal(LOCK_monitor_enter);
+ OP_BUILTIN_CHECK_EXCEPTION(bte);
+ }
+ else
+#endif
+ {
+ OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
+ OP(ICMD_POP);
+ }
+ break;
+
+ case BC_monitorexit:
+#if defined(ENABLE_THREADS)
+ if (checksync) {
+ bte = builtintable_get_internal(LOCK_monitor_exit);
+ OP_BUILTIN_CHECK_EXCEPTION(bte);
+ }
+ else
+#endif
+ {
+ OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
+ OP(ICMD_POP);
+ }
+ break;
+
+ /* arithmetic instructions that may become builtin functions **********/
+
+ case BC_idiv:
+#if !SUPPORT_DIVISION
+ bte = builtintable_get_internal(BUILTIN_idiv);
+ OP_BUILTIN_ARITHMETIC(opcode, bte);
+#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
+ OP(opcode);
+# else
+ OP_CHECK_EXCEPTION(opcode);
+# endif
+#endif
+ break;
+
+ case BC_irem:
+#if !SUPPORT_DIVISION
+ bte = builtintable_get_internal(BUILTIN_irem);
+ OP_BUILTIN_ARITHMETIC(opcode, bte);
+#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
+ OP(opcode);
+# else
+ OP_CHECK_EXCEPTION(opcode);
+# endif
+#endif
+ break;
+
+ case BC_ldiv:
+#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV)
+ bte = builtintable_get_internal(BUILTIN_ldiv);
+ OP_BUILTIN_ARITHMETIC(opcode, bte);
+#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
+ OP(opcode);
+# else
+ OP_CHECK_EXCEPTION(opcode);
+# endif
+#endif
+ break;
+
+ case BC_lrem:
+#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV)
+ bte = builtintable_get_internal(BUILTIN_lrem);
+ OP_BUILTIN_ARITHMETIC(opcode, bte);
+#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
+ OP(opcode);
+# else
+ OP_CHECK_EXCEPTION(opcode);
+# endif
+#endif
+ break;
+
+ case BC_frem:
+#if defined(__I386__)
+ OP(opcode);
+#else
+ bte = builtintable_get_internal(BUILTIN_frem);
+ OP_BUILTIN_NO_EXCEPTION(bte);
+#endif
+ break;
+
+ case BC_drem:
+#if defined(__I386__)
+ OP(opcode);
+#else
+ bte = builtintable_get_internal(BUILTIN_drem);
+ OP_BUILTIN_NO_EXCEPTION(bte);
+#endif
+ break;
+
+ case BC_f2i:
+#if defined(__ALPHA__)
+ bte = builtintable_get_internal(BUILTIN_f2i);
+ OP_BUILTIN_NO_EXCEPTION(bte);
+#else
+ OP(opcode);
+#endif
+ break;
+
+ case BC_f2l:
+#if defined(__ALPHA__)
+ bte = builtintable_get_internal(BUILTIN_f2l);
+ OP_BUILTIN_NO_EXCEPTION(bte);
+#else
+ OP(opcode);
+#endif
+ break;
+
+ case BC_d2i:
+#if defined(__ALPHA__)
+ bte = builtintable_get_internal(BUILTIN_d2i);
+ OP_BUILTIN_NO_EXCEPTION(bte);
+#else
+ OP(opcode);
+#endif
+ break;
+
+ case BC_d2l:
+#if defined(__ALPHA__)
+ bte = builtintable_get_internal(BUILTIN_d2l);
+ OP_BUILTIN_NO_EXCEPTION(bte);
+#else
+ OP(opcode);
+#endif
+ break;
+
+
+ /* invalid opcodes ****************************************************/
+
+ /* check for invalid opcodes if the verifier is enabled */
+#if defined(ENABLE_VERIFIER)
+ case BC_breakpoint:
+ exceptions_throw_verifyerror(m, "Quick instructions shouldn't appear, yet.");
+ return false;
+
+
+ /* Unused opcodes ************************************************** */
+
+ case 186:
+ case 203:
+ case 204:
+ case 205:
+ case 206:
+ case 207:
+ case 208:
+ case 209:
+ case 210:
+ case 211:
+ case 212:
+ case 213:
+ case 214:
+ case 215:
+ case 216:
+ case 217:
+ case 218:
+ case 219:
+ case 220:
+ case 221:
+ case 222:
+ case 223:
+ case 224:
+ case 225:
+ case 226:
+ case 227:
+ case 228:
+ case 229:
+ case 230:
+ case 231:
+ case 232:
+ case 233:
+ case 234:
+ case 235:
+ case 236:
+ case 237:
+ case 238:
+ case 239:
+ case 240:
+ case 241:
+ case 242:
+ case 243:
+ case 244:
+ case 245:
+ case 246:
+ case 247:
+ case 248:
+ case 249:
+ case 250:
+ case 251:
+ case 252:
+ case 253:
+ case 254:
+ case 255:
+ exceptions_throw_verifyerror(m, "Illegal opcode %d at instr %d\n",
+ opcode, ircount);
+ return false;
+ break;
+#endif /* defined(ENABLE_VERIFIER) */
+
+ /* opcodes that don't require translation *****************************/
+
+ default:
+ /* Straight-forward translation to HIR. */
+ OP(opcode);
+ break;
+
+ } /* end switch */
+
+ /* verifier checks ****************************************************/
+
+#if defined(ENABLE_VERIFIER)
+ /* If WIDE was used correctly, iswide should have been reset by now. */
+ if (iswide) {
+ exceptions_throw_verifyerror(m,
+ "Illegal instruction: WIDE before incompatible opcode");
+ return false;
+ }
+#endif /* defined(ENABLE_VERIFIER) */
+
+ } /* end for */
+
+ if (JITDATA_HAS_FLAG_REORDER(jd)) {
+ /* add a NOP to the last basic block */
+
+ INSTRUCTIONS_CHECK(1);
+ OP(ICMD_NOP);
+ }
+
+ /*** END OF LOOP **********************************************************/
+
+ /* assert that we did not write more ICMDs than allocated */
+
+ assert(ircount <= pd.instructionslength);
+ assert(ircount == (iptr - pd.instructions));
+
+ /*** verifier checks ******************************************************/
+
+#if defined(ENABLE_VERIFIER)
+ if (bcindex != m->jcodelength) {
+ exceptions_throw_verifyerror(m,
+ "Command-sequence crosses code-boundary");
+ return false;
+ }
+
+ if (!blockend) {
+ exceptions_throw_verifyerror(m, "Falling off the end of the code");
+ return false;
+ }
+#endif /* defined(ENABLE_VERIFIER) */
+
+ /*** setup the methodinfo, allocate stack and basic blocks ****************/
+
+ /* identify basic blocks */
+
+ /* check if first instruction is a branch target */
+
+ if (pd.basicblockstart[0] == 1) {
+ jd->branchtoentry = true;
+ }
+ else {
+ /* first instruction always starts a basic block */
+
+ iptr = pd.instructions;
+
+ iptr->flags.bits |= INS_FLAG_BASICBLOCK;
+ }
+
+ /* Iterate over all bytecode instructions and set missing
+ basic-block starts in IR instructions. */
+
+ for (bcindex = 0; bcindex < m->jcodelength; bcindex++) {
+ /* Does the current bytecode instruction start a basic
+ block? */
+
+ if (pd.basicblockstart[bcindex] == 1) {
+#if defined(ENABLE_VERIFIER)
+ /* Check if this bytecode basic-block start at the
+ beginning of a bytecode instruction. */
+
+ if (pd.bytecodestart[bcindex] == 0) {
+ exceptions_throw_verifyerror(m,
+ "Branch into middle of instruction");
+ return false;
+ }
+#endif
+
+ /* Get the IR instruction mapped to the bytecode
+ instruction and set the basic block flag. */
+
+ irindex = pd.bytecodemap[bcindex];
+ iptr = pd.instructions + irindex;
+
+ iptr->flags.bits |= INS_FLAG_BASICBLOCK;
+ }
+ }
+
+ /* IR instruction index to basic-block index mapping */
+
+ pd.instructionmap = (s4*) DumpMemory::allocate(sizeof(s4) * ircount);
+ MZERO(pd.instructionmap, s4, ircount);
+
+ /* Iterate over all IR instructions and count the basic blocks. */
+
+ iptr = pd.instructions;
+
+ bbcount = 0;
+
+ for (i = 0; i < ircount; i++, iptr++) {
+ if (INSTRUCTION_STARTS_BASICBLOCK(iptr)) {
+ /* store the basic-block number in the IR instruction
+ map */
+
+ pd.instructionmap[i] = bbcount;
+
+ /* post-increment the basic-block count */
+
+ bbcount++;
+ }
+ }
+
+ /* Allocate basic block array (one more for end ipc). */
+
+ jd->basicblocks = (basicblock*) DumpMemory::allocate(sizeof(basicblock) * (bbcount + 1));
+ MZERO(jd->basicblocks, basicblock, bbcount + 1);
+
+ /* Now iterate again over all IR instructions and initialize the
+ basic block structures and, in the same loop, resolve the
+ branch-target instruction indices to basic blocks. */
+
+ iptr = pd.instructions;
+ bptr = jd->basicblocks;
+
+ bbcount = 0;
+
+ for (i = 0; i < ircount; i++, iptr++) {
+ /* check for basic block */
+
+ if (INSTRUCTION_STARTS_BASICBLOCK(iptr)) {
+ /* intialize the basic block */
+
+ BASICBLOCK_INIT(bptr, m);
+
+ bptr->iinstr = iptr;
+
+ if (bbcount > 0) {
+ bptr[-1].icount = bptr->iinstr - bptr[-1].iinstr;
+ }
+
+ /* bptr->icount is set when the next block is allocated */
+
+ bptr->nr = bbcount++;
+ bptr++;
+ bptr[-1].next = bptr;
+ }
+
+ /* resolve instruction indices to basic blocks */
+
+ switch (iptr->opc) {
+ case ICMD_IFEQ:
+ case ICMD_IFLT:
+ case ICMD_IFLE:
+ case ICMD_IFNE:
+ case ICMD_IFGT:
+ case ICMD_IFGE:
+ case ICMD_IFNULL:
+ case ICMD_IFNONNULL:
+ case ICMD_IF_ICMPEQ:
+ case ICMD_IF_ICMPNE:
+ case ICMD_IF_ICMPLT:
+ case ICMD_IF_ICMPGT:
+ case ICMD_IF_ICMPLE:
+ case ICMD_IF_ICMPGE:
+ case ICMD_IF_ACMPEQ:
+ case ICMD_IF_ACMPNE:
+ case ICMD_GOTO:
+ BYTECODEINDEX_TO_BASICBLOCK(iptr->dst);
+ break;
+
+ case ICMD_JSR:
+ BYTECODEINDEX_TO_BASICBLOCK(iptr->sx.s23.s3.jsrtarget);
+ break;
+
+ case ICMD_TABLESWITCH:
+ table = iptr->dst.table;
+
+ BYTECODEINDEX_TO_BASICBLOCK(*table);
+ table++;
+
+ j = iptr->sx.s23.s3.tablehigh - iptr->sx.s23.s2.tablelow + 1;
+
+ while (--j >= 0) {
+ BYTECODEINDEX_TO_BASICBLOCK(*table);
+ table++;
+ }
+ break;
+
+ case ICMD_LOOKUPSWITCH:
+ BYTECODEINDEX_TO_BASICBLOCK(iptr->sx.s23.s3.lookupdefault);
+
+ lookup = iptr->dst.lookup;
+
+ j = iptr->sx.s23.s2.lookupcount;
+
+ while (--j >= 0) {
+ BYTECODEINDEX_TO_BASICBLOCK(lookup->target);
+ lookup++;
+ }
+ break;
+ }
+ }
+
+ /* set instruction count of last real block */
+
+ if (bbcount > 0) {
+ bptr[-1].icount = (pd.instructions + ircount) - bptr[-1].iinstr;
+ }
+
+ /* allocate additional block at end */
+
+ BASICBLOCK_INIT(bptr, m);
+ bptr->nr = bbcount;
+
+ /* set basicblock pointers in exception table */
+
+ if (!parse_resolve_exception_table(jd, &pd))
+ return false;
+
+ /* store the local map */
+
+ jd->local_map = local_map;
+
+ /* calculate local variable renaming */
+
+ {
+ s4 nlocals = 0;
+ s4 i;
+ s4 t;
+ s4 varindex;
+ s4 *mapptr;
+ s4 *reversemap;
+
+ mapptr = local_map;
+
+ /* iterate over local_map[0..m->maxlocals*5-1] and allocate a unique */
+ /* variable index for each _used_ (javaindex,type) pair. */
+ /* (local_map[javaindex*5+type] = cacaoindex) */
+ /* Unused (javaindex,type) pairs are marked with UNUSED. */
+
+ for (i = 0; i < (m->maxlocals * 5); i++, mapptr++) {
+ if (*mapptr)
+ *mapptr = nlocals++;
+ else
+ *mapptr = UNUSED;
+ }
+
+ jd->localcount = nlocals;
+
+ /* calculate the (maximum) number of variables needed */
+
+ jd->varcount =
+ nlocals /* local variables */
+ + bbcount * m->maxstack /* invars */
+ + s_count; /* variables created within blocks (non-invar) */
+
+ /* reserve the first indices for local variables */
+
+ jd->vartop = nlocals;
+
+ /* reserve extra variables needed by stack analyse */
+
+ jd->varcount += STACK_EXTRA_VARS;
+ jd->vartop += STACK_EXTRA_VARS;
+
+ /* The verifier needs space for saving invars in some cases and */
+ /* extra variables. */
+
+#if defined(ENABLE_VERIFIER)
+ jd->varcount += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
+ jd->vartop += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
+#endif
+ /* allocate and initialize the variable array */
+
+ jd->var = (varinfo*) DumpMemory::allocate(sizeof(varinfo) * jd->varcount);
+ MZERO(jd->var, varinfo, jd->varcount);
+
+ /* set types of all locals in jd->var */
+ /* and fill the reverselocalmap */
+
+ reversemap = (s4*) DumpMemory::allocate(sizeof(s4) * nlocals);
+
+ for (i = 0; i < m->maxlocals; i++)
+ for (t=0; t<5; t++) {
+ varindex = local_map[5*i + t];
+ if (varindex != UNUSED) {
+ VAR(varindex)->type = t;
+ reversemap[varindex] = i;
+ }
+ }
+
+ jd->reverselocalmap = reversemap;
+ }
+
+ /* assign local variables to method variables */
+
+ jd->instructions = pd.instructions;
+ jd->instructioncount = ircount;
+ jd->basicblockcount = bbcount;
+ jd->stackcount = s_count + bbcount * m->maxstack; /* in-stacks */
+
+ /* allocate stack table */
+
+ jd->stack = (stackelement_t*) DumpMemory::allocate(sizeof(stackelement_t) * jd->stackcount);
+
+ /* everything's ok */
+
+ return true;
+
+ /*** goto labels for throwing verifier exceptions *************************/
+
+#if defined(ENABLE_VERIFIER)
+
+throw_unexpected_end_of_bytecode:
+ exceptions_throw_verifyerror(m, "Unexpected end of bytecode");
+ return false;
+
+throw_invalid_bytecode_index:
+ exceptions_throw_verifyerror(m, "Illegal target of branch instruction");
+ return false;
+
+throw_illegal_local_variable_number:
+ exceptions_throw_verifyerror(m, "Illegal local variable number");
+ return false;
+
+#endif /* ENABLE_VERIFIER */
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
+++ /dev/null
-/* src/vm/jit/parse.h - parser header
-
- Copyright (C) 1996-2005, 2006, 2008
- CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
- This file is part of CACAO.
-
- 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., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
-*/
-
-
-#ifndef _PARSE_H
-#define _PARSE_H
-
-#include "config.h"
-#include "vm/types.h"
-
-#include "vm/global.h"
-#include "vm/jit/codegen-common.hpp"
-
-
-/* macros for verifier checks during parsing **********************************/
-
-#if defined(ENABLE_VERIFIER)
-
-/* We have to check local variables indices here because they are */
-/* used in stack.c to index the locals array. */
-
-#define INDEX_ONEWORD(num) \
- do { \
- if (((num) < 0) || ((num) >= m->maxlocals)) \
- goto throw_illegal_local_variable_number; \
- } while (0)
-
-#define INDEX_TWOWORD(num) \
- do { \
- if (((num) < 0) || (((num) + 1) >= m->maxlocals)) \
- goto throw_illegal_local_variable_number; \
- } while (0)
-
-/* CHECK_BYTECODE_INDEX(i) checks whether i is a valid bytecode index. */
-/* The end of the bytecode (i == m->jcodelength) is considered valid. */
-
-#define CHECK_BYTECODE_INDEX(i) \
- do { \
- if (((i) < 0) || ((i) >= m->jcodelength)) \
- goto throw_invalid_bytecode_index; \
- } while (0)
-
-/* CHECK_BYTECODE_INDEX_EXCLUSIVE is used for the exclusive ends */
-/* of exception handler ranges. */
-#define CHECK_BYTECODE_INDEX_EXCLUSIVE(i) \
- do { \
- if ((i) < 0 || (i) > m->jcodelength) \
- goto throw_invalid_bytecode_index; \
- } while (0)
-
-#else /* !defined(ENABLE_VERIFIER) */
-
-#define INDEX_ONEWORD(num)
-#define INDEX_TWOWORD(num)
-#define CHECK_BYTECODE_INDEX(i)
-#define CHECK_BYTECODE_INDEX_EXCLUSIVE(i)
-
-#endif /* defined(ENABLE_VERIFIER) */
-
-
-/* basic block generating macro ***********************************************/
-
-#define MARK_BASICBLOCK(pd, i) \
- do { \
- (pd)->basicblockstart[(i)] = 1; \
- } while (0)
-
-#define INSTRUCTIONS_CHECK(i) \
- if ((ircount + (i)) > pd.instructionslength) \
- iptr = parse_realloc_instructions(&pd, ircount, (i))
-
-
-/* intermediate code generating macros ****************************************/
-
-/* These macros ALWAYS set the following fields of *iptr to valid values: */
-/* iptr->opc */
-/* iptr->flags */
-/* iptr->line */
-
-/* These macros do NOT touch the following fields of *iptr, unless a value is */
-/* given for them: */
-/* iptr->s1 */
-/* iptr->sx */
-/* iptr->dst */
-
-/* The _PREPARE macros omit the PINC, so you can set additional fields */
-/* afterwards. */
-
-#define PINC \
- iptr++; ircount++
-
-#define OP_PREPARE_FLAGS(o, f) \
- iptr->opc = (o); \
- iptr->line = currentline; \
- iptr->flags.bits |= (f) | (ircount << INS_FLAG_ID_SHIFT);
-
-#define OP_PREPARE_ZEROFLAGS(o) \
- OP_PREPARE_FLAGS(o, 0)
-
-#define OP_PREPARE(o) \
- OP_PREPARE_ZEROFLAGS(o)
-
-#define OP(o) \
- OP_PREPARE_ZEROFLAGS(o); \
- PINC
-
-#define OP_CHECK_EXCEPTION(o) \
- OP_PREPARE_FLAGS(o, INS_FLAG_CHECK); \
- PINC
-
-#define OP_LOADCONST_I(v) \
- OP_PREPARE_ZEROFLAGS(ICMD_ICONST); \
- iptr->sx.val.i = (v); \
- PINC
-
-#define OP_LOADCONST_L(v) \
- OP_PREPARE_ZEROFLAGS(ICMD_LCONST); \
- iptr->sx.val.l = (v); \
- PINC
-
-#define OP_LOADCONST_F(v) \
- OP_PREPARE_ZEROFLAGS(ICMD_FCONST); \
- iptr->sx.val.f = (v); \
- PINC
-
-#define OP_LOADCONST_D(v) \
- OP_PREPARE_ZEROFLAGS(ICMD_DCONST); \
- iptr->sx.val.d = (v); \
- PINC
-
-#define OP_LOADCONST_NULL() \
- OP_PREPARE_FLAGS(ICMD_ACONST, INS_FLAG_CHECK); \
- iptr->sx.val.anyptr = NULL; \
- PINC
-
-#define OP_LOADCONST_STRING(v) \
- OP_PREPARE_FLAGS(ICMD_ACONST, INS_FLAG_CHECK); \
- iptr->sx.val.stringconst = (v); \
- PINC
-
-#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS(cl, cr, extraflags) \
- OP_PREPARE(ICMD_ACONST); \
- if (cl) { \
- iptr->sx.val.c.cls = (cl); \
- iptr->flags.bits |= INS_FLAG_CLASS | (extraflags); \
- } \
- else { \
- iptr->sx.val.c.ref = (cr); \
- iptr->flags.bits |= INS_FLAG_CLASS | INS_FLAG_UNRESOLVED \
- | (extraflags); \
- } \
- PINC
-
-#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_CHECK(c, cr) \
- OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS((c), (cr), INS_FLAG_CHECK)
-
-#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr) \
- OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS((c), (cr), 0)
-
-#define OP_S3_CLASSINFO_OR_CLASSREF(o, c, cr, extraflags) \
- OP_PREPARE(o); \
- if (c) { \
- iptr->sx.s23.s3.c.cls= (c); \
- iptr->flags.bits |= (extraflags); \
- } \
- else { \
- iptr->sx.s23.s3.c.ref= (cr); \
- iptr->flags.bits |= INS_FLAG_UNRESOLVED | (extraflags); \
- } \
- PINC
-
-#define OP_INSINDEX(o, iindex) \
- OP_PREPARE_ZEROFLAGS(o); \
- iptr->dst.insindex = (iindex); \
- PINC
-
-# define OP_LOCALINDEX(o,index) \
- OP_PREPARE_ZEROFLAGS(o); \
- iptr->s1.varindex = (index); \
- PINC
-
-# define OP_LOCALINDEX_I(o,index,v) \
- OP_PREPARE_ZEROFLAGS(o); \
- iptr->s1.varindex = (index); \
- iptr->sx.val.i = (v); \
- PINC
-
-# define LOCALTYPE_USED(index,type) \
- do { \
- local_map[(index) * 5 + (type)] = 1; \
- } while (0)
-
-#define OP_LOAD_ONEWORD(o,index,type) \
- do { \
- INDEX_ONEWORD(index); \
- OP_LOCALINDEX(o,index); \
- LOCALTYPE_USED(index,type); \
- } while (0)
-
-#define OP_LOAD_TWOWORD(o,index,type) \
- do { \
- INDEX_TWOWORD(index); \
- OP_LOCALINDEX(o,index); \
- LOCALTYPE_USED(index,type); \
- } while (0)
-
-# define OP_STORE_ONEWORD(o,index,type) \
- do { \
- INDEX_ONEWORD(index); \
- OP_PREPARE_ZEROFLAGS(o); \
- iptr->dst.varindex = (index); \
- LOCALTYPE_USED(index,type); \
- PINC; \
- } while (0)
-
-# define OP_STORE_TWOWORD(o,index,type) \
- do { \
- INDEX_TWOWORD(index); \
- OP_PREPARE_ZEROFLAGS(o); \
- iptr->dst.varindex = (index); \
- LOCALTYPE_USED(index,type); \
- PINC; \
- } while (0)
-
-#define OP_BUILTIN_CHECK_EXCEPTION(bte) \
- code_unflag_leafmethod(code); \
- OP_PREPARE_FLAGS(ICMD_BUILTIN, INS_FLAG_CHECK); \
- iptr->sx.s23.s3.bte = (bte); \
- PINC
-
-#define OP_BUILTIN_NO_EXCEPTION(bte) \
- code_unflag_leafmethod(code); \
- OP_PREPARE_ZEROFLAGS(ICMD_BUILTIN); \
- iptr->sx.s23.s3.bte = (bte); \
- PINC
-
-#define OP_BUILTIN_ARITHMETIC(opcode, bte) \
- code_unflag_leafmethod(code); \
- OP_PREPARE_FLAGS(opcode, INS_FLAG_CHECK); \
- iptr->sx.s23.s3.bte = (bte); \
- PINC
-
-/* CAUTION: You must set iptr->flags yourself when using this! */
-#define OP_FMIREF_PREPARE(o, fmiref) \
- OP_PREPARE(o); \
- iptr->sx.s23.s3.fmiref = (fmiref);
-
-
-/* function prototypes ********************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-bool parse(jitdata *jd);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PARSE_H */
-
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
-
--- /dev/null
+/* src/vm/jit/parse.h - parser header
+
+ Copyright (C) 1996-2005, 2006, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#ifndef _PARSE_H
+#define _PARSE_H
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "vm/global.h"
+#include "vm/jit/codegen-common.hpp"
+
+
+/* macros for verifier checks during parsing **********************************/
+
+#if defined(ENABLE_VERIFIER)
+
+/* We have to check local variables indices here because they are */
+/* used in stack.c to index the locals array. */
+
+#define INDEX_ONEWORD(num) \
+ do { \
+ if (((num) < 0) || ((num) >= m->maxlocals)) \
+ goto throw_illegal_local_variable_number; \
+ } while (0)
+
+#define INDEX_TWOWORD(num) \
+ do { \
+ if (((num) < 0) || (((num) + 1) >= m->maxlocals)) \
+ goto throw_illegal_local_variable_number; \
+ } while (0)
+
+/* CHECK_BYTECODE_INDEX(i) checks whether i is a valid bytecode index. */
+/* The end of the bytecode (i == m->jcodelength) is considered valid. */
+
+#define CHECK_BYTECODE_INDEX(i) \
+ do { \
+ if (((i) < 0) || ((i) >= m->jcodelength)) \
+ goto throw_invalid_bytecode_index; \
+ } while (0)
+
+/* CHECK_BYTECODE_INDEX_EXCLUSIVE is used for the exclusive ends */
+/* of exception handler ranges. */
+#define CHECK_BYTECODE_INDEX_EXCLUSIVE(i) \
+ do { \
+ if ((i) < 0 || (i) > m->jcodelength) \
+ goto throw_invalid_bytecode_index; \
+ } while (0)
+
+#else /* !defined(ENABLE_VERIFIER) */
+
+#define INDEX_ONEWORD(num)
+#define INDEX_TWOWORD(num)
+#define CHECK_BYTECODE_INDEX(i)
+#define CHECK_BYTECODE_INDEX_EXCLUSIVE(i)
+
+#endif /* defined(ENABLE_VERIFIER) */
+
+
+/* basic block generating macro ***********************************************/
+
+#define MARK_BASICBLOCK(pd, i) \
+ do { \
+ (pd)->basicblockstart[(i)] = 1; \
+ } while (0)
+
+#define INSTRUCTIONS_CHECK(i) \
+ if ((ircount + (i)) > pd.instructionslength) \
+ iptr = parse_realloc_instructions(&pd, ircount, (i))
+
+
+/* intermediate code generating macros ****************************************/
+
+/* These macros ALWAYS set the following fields of *iptr to valid values: */
+/* iptr->opc */
+/* iptr->flags */
+/* iptr->line */
+
+/* These macros do NOT touch the following fields of *iptr, unless a value is */
+/* given for them: */
+/* iptr->s1 */
+/* iptr->sx */
+/* iptr->dst */
+
+/* The _PREPARE macros omit the PINC, so you can set additional fields */
+/* afterwards. */
+
+#define PINC \
+ iptr++; ircount++
+
+#define OP_PREPARE_FLAGS(o, f) \
+ iptr->opc = (o); \
+ iptr->line = currentline; \
+ iptr->flags.bits |= (f) | (ircount << INS_FLAG_ID_SHIFT);
+
+#define OP_PREPARE_ZEROFLAGS(o) \
+ OP_PREPARE_FLAGS(o, 0)
+
+#define OP_PREPARE(o) \
+ OP_PREPARE_ZEROFLAGS(o)
+
+#define OP(o) \
+ OP_PREPARE_ZEROFLAGS(o); \
+ PINC
+
+#define OP_CHECK_EXCEPTION(o) \
+ OP_PREPARE_FLAGS(o, INS_FLAG_CHECK); \
+ PINC
+
+#define OP_LOADCONST_I(v) \
+ OP_PREPARE_ZEROFLAGS(ICMD_ICONST); \
+ iptr->sx.val.i = (v); \
+ PINC
+
+#define OP_LOADCONST_L(v) \
+ OP_PREPARE_ZEROFLAGS(ICMD_LCONST); \
+ iptr->sx.val.l = (v); \
+ PINC
+
+#define OP_LOADCONST_F(v) \
+ OP_PREPARE_ZEROFLAGS(ICMD_FCONST); \
+ iptr->sx.val.f = (v); \
+ PINC
+
+#define OP_LOADCONST_D(v) \
+ OP_PREPARE_ZEROFLAGS(ICMD_DCONST); \
+ iptr->sx.val.d = (v); \
+ PINC
+
+#define OP_LOADCONST_NULL() \
+ OP_PREPARE_FLAGS(ICMD_ACONST, INS_FLAG_CHECK); \
+ iptr->sx.val.anyptr = NULL; \
+ PINC
+
+#define OP_LOADCONST_STRING(v) \
+ OP_PREPARE_FLAGS(ICMD_ACONST, INS_FLAG_CHECK); \
+ iptr->sx.val.stringconst = (v); \
+ PINC
+
+#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS(cl, cr, extraflags) \
+ OP_PREPARE(ICMD_ACONST); \
+ if (cl) { \
+ iptr->sx.val.c.cls = (cl); \
+ iptr->flags.bits |= INS_FLAG_CLASS | (extraflags); \
+ } \
+ else { \
+ iptr->sx.val.c.ref = (cr); \
+ iptr->flags.bits |= INS_FLAG_CLASS | INS_FLAG_UNRESOLVED \
+ | (extraflags); \
+ } \
+ PINC
+
+#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_CHECK(c, cr) \
+ OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS((c), (cr), INS_FLAG_CHECK)
+
+#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr) \
+ OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS((c), (cr), 0)
+
+#define OP_S3_CLASSINFO_OR_CLASSREF(o, c, cr, extraflags) \
+ OP_PREPARE(o); \
+ if (c) { \
+ iptr->sx.s23.s3.c.cls= (c); \
+ iptr->flags.bits |= (extraflags); \
+ } \
+ else { \
+ iptr->sx.s23.s3.c.ref= (cr); \
+ iptr->flags.bits |= INS_FLAG_UNRESOLVED | (extraflags); \
+ } \
+ PINC
+
+#define OP_INSINDEX(o, iindex) \
+ OP_PREPARE_ZEROFLAGS(o); \
+ iptr->dst.insindex = (iindex); \
+ PINC
+
+# define OP_LOCALINDEX(o,index) \
+ OP_PREPARE_ZEROFLAGS(o); \
+ iptr->s1.varindex = (index); \
+ PINC
+
+# define OP_LOCALINDEX_I(o,index,v) \
+ OP_PREPARE_ZEROFLAGS(o); \
+ iptr->s1.varindex = (index); \
+ iptr->sx.val.i = (v); \
+ PINC
+
+# define LOCALTYPE_USED(index,type) \
+ do { \
+ local_map[(index) * 5 + (type)] = 1; \
+ } while (0)
+
+#define OP_LOAD_ONEWORD(o,index,type) \
+ do { \
+ INDEX_ONEWORD(index); \
+ OP_LOCALINDEX(o,index); \
+ LOCALTYPE_USED(index,type); \
+ } while (0)
+
+#define OP_LOAD_TWOWORD(o,index,type) \
+ do { \
+ INDEX_TWOWORD(index); \
+ OP_LOCALINDEX(o,index); \
+ LOCALTYPE_USED(index,type); \
+ } while (0)
+
+# define OP_STORE_ONEWORD(o,index,type) \
+ do { \
+ INDEX_ONEWORD(index); \
+ OP_PREPARE_ZEROFLAGS(o); \
+ iptr->dst.varindex = (index); \
+ LOCALTYPE_USED(index,type); \
+ PINC; \
+ } while (0)
+
+# define OP_STORE_TWOWORD(o,index,type) \
+ do { \
+ INDEX_TWOWORD(index); \
+ OP_PREPARE_ZEROFLAGS(o); \
+ iptr->dst.varindex = (index); \
+ LOCALTYPE_USED(index,type); \
+ PINC; \
+ } while (0)
+
+#define OP_BUILTIN_CHECK_EXCEPTION(bte) \
+ code_unflag_leafmethod(code); \
+ OP_PREPARE_FLAGS(ICMD_BUILTIN, INS_FLAG_CHECK); \
+ iptr->sx.s23.s3.bte = (bte); \
+ PINC
+
+#define OP_BUILTIN_NO_EXCEPTION(bte) \
+ code_unflag_leafmethod(code); \
+ OP_PREPARE_ZEROFLAGS(ICMD_BUILTIN); \
+ iptr->sx.s23.s3.bte = (bte); \
+ PINC
+
+#define OP_BUILTIN_ARITHMETIC(opcode, bte) \
+ code_unflag_leafmethod(code); \
+ OP_PREPARE_FLAGS(opcode, INS_FLAG_CHECK); \
+ iptr->sx.s23.s3.bte = (bte); \
+ PINC
+
+/* CAUTION: You must set iptr->flags yourself when using this! */
+#define OP_FMIREF_PREPARE(o, fmiref) \
+ OP_PREPARE(o); \
+ iptr->sx.s23.s3.fmiref = (fmiref);
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool parse(jitdata *jd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PARSE_H */
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
+
#include "vm/jit/jit.hpp"
#include "vm/jit/linenumbertable.hpp"
#include "vm/jit/methodheader.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/patcher-common.hpp"
#include "vm/jit/reg.h"
#include "vm/jit/replace.hpp"
#include "vm/jit/emit-common.hpp"
#include "vm/jit/jit.hpp"
#include "vm/jit/linenumbertable.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/patcher-common.hpp"
#include "vm/jit/reg.h"
#include "vm/jit/replace.hpp"
#include "vm/jit/jit.hpp"
#include "vm/jit/linenumbertable.hpp"
#include "vm/jit/methodheader.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/patcher-common.hpp"
#include "vm/jit/reg.h"
#include "vm/jit/replace.hpp"
#include "vm/jit/show.hpp"
#include "vm/jit/disass.h"
#include "vm/jit/stack.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#if defined(ENABLE_DEBUG_FILTER)
# include <sys/types.h>
#include "vm/jit/emit-common.hpp"
#include "vm/jit/jit.hpp"
#include "vm/jit/linenumbertable.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/patcher.h"
#include "vm/jit/reg.h"
#include "vm/jit/replace.hpp"
#include "vm/jit/abi.h"
#include "vm/jit/cfg.h"
#include "vm/jit/codegen-common.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/show.hpp"
#if defined(ENABLE_DISASSEMBLER)
#include "vm/globals.hpp"
#include "vm/primitive.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/show.hpp"
#include "vm/jit/stack.h"
#include "vm/jit/verify/typecheck-common.h"
#include "vm/jit/jit.hpp"
#include "vm/jit/show.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/verify/typecheck-typeinferer.h"
#include "vm/resolve.hpp"
#include "vm/jit/jit.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/show.hpp"
#include <typecheck-common.h>
#include "vm/jit/jit.hpp"
#include "vm/jit/linenumbertable.hpp"
#include "vm/jit/methodheader.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
#include "vm/jit/patcher-common.hpp"
#include "vm/jit/reg.h"
#include "vm/jit/replace.hpp"