* configure.ac [ENABLE_STATICVM] (AC_CHECK_LIB(dl)): Only perform the
authortwisti <none@none>
Thu, 11 Jan 2007 14:19:48 +0000 (14:19 +0000)
committertwisti <none@none>
Thu, 11 Jan 2007 14:19:48 +0000 (14:19 +0000)
check if we want a static VM.
(AC_CONFIG_FILES): Added src/vm/jit/arm/Makefile and
src/vm/jit/arm/linux/Makefile.
* src/vm/jit/Makefile.am (DIST_SUBDIRS): Added arm.

19 files changed:
configure.ac
src/vm/jit/Makefile.am
src/vm/jit/arm/.cvsignore [new file with mode: 0644]
src/vm/jit/arm/Makefile.am [new file with mode: 0644]
src/vm/jit/arm/arch.h [new file with mode: 0644]
src/vm/jit/arm/asmpart.S [new file with mode: 0644]
src/vm/jit/arm/codegen.c [new file with mode: 0644]
src/vm/jit/arm/codegen.h [new file with mode: 0644]
src/vm/jit/arm/disass.c [new file with mode: 0644]
src/vm/jit/arm/emit.c [new file with mode: 0644]
src/vm/jit/arm/linux/.cvsignore [new file with mode: 0644]
src/vm/jit/arm/linux/Makefile.am [new file with mode: 0644]
src/vm/jit/arm/linux/md-os.c [new file with mode: 0644]
src/vm/jit/arm/machine-instr.h [new file with mode: 0644]
src/vm/jit/arm/md-abi.c [new file with mode: 0644]
src/vm/jit/arm/md-abi.h [new file with mode: 0644]
src/vm/jit/arm/md-asm.h [new file with mode: 0644]
src/vm/jit/arm/md.c [new file with mode: 0644]
src/vm/jit/arm/patcher.c [new file with mode: 0644]

index db0e9e436b87d5ebf30cea5463b3abf214597420..3d5348993ec316cf7fce84d68efa4ca4b898fcce 100644 (file)
@@ -22,7 +22,7 @@ dnl along with this program; if not, write to the Free Software
 dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 dnl 02110-1301, USA.
 dnl 
-dnl $Id: configure.ac 6283 2007-01-08 23:49:11Z twisti $
+dnl $Id: configure.ac 6595 2007-01-11 14:19:48Z twisti $
 
 dnl Process this file with autoconf to produce a configure script.
 
@@ -976,7 +976,9 @@ if test x"${WITH_STATIC_CLASSPATH}" = "xyes"; then
     AM_ICONV_LINK
 else
     dnl we need this check for --enable-staticvm, otherwise ltdl can't find dlopen
-    AC_CHECK_LIB(dl, dlopen,, [AC_MSG_ERROR(cannot find libdl)])
+    if test x"${ENABLE_STATICVM}" = "xyes"; then
+        AC_CHECK_LIB(dl, dlopen,, [AC_MSG_ERROR(cannot find libdl)])
+    fi
 
     AC_CHECK_HEADERS([ltdl.h],, [AC_MSG_ERROR(cannot find ltdl.h)])
     AC_CHECK_LIB(ltdl, lt_dlopen,, [AC_MSG_ERROR(cannot find libltdl)])
@@ -1029,6 +1031,8 @@ AC_CONFIG_FILES([Makefile]
                [src/vm/jit/alpha/Makefile]
                [src/vm/jit/alpha/freebsd/Makefile]
                [src/vm/jit/alpha/linux/Makefile]
+               [src/vm/jit/arm/Makefile]
+               [src/vm/jit/arm/linux/Makefile]
                [src/vm/jit/i386/Makefile]
                [src/vm/jit/i386/cygwin/Makefile]
                [src/vm/jit/i386/darwin/Makefile]
index 616397159c8358aaaff774525bfc594bbc662e41..0dfa665f9ba6493bd941be6b3523977074418cef 100644 (file)
@@ -28,7 +28,7 @@
 ##
 ## Changes: Edwin Steiner
 ##
-## $Id: Makefile.am 6265 2007-01-02 20:40:57Z edwin $
+## $Id: Makefile.am 6595 2007-01-11 14:19:48Z twisti $
 
 ## Process this file with automake to produce Makefile.in
 
@@ -47,6 +47,7 @@ DIST_SUBDIRS = \
        \
        intrp \
        alpha \
+       arm \
        i386 \
        mips \
        parisc \
diff --git a/src/vm/jit/arm/.cvsignore b/src/vm/jit/arm/.cvsignore
new file mode 100644 (file)
index 0000000..1f83cf9
--- /dev/null
@@ -0,0 +1,10 @@
+*.a
+*.o
+*.la
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
+TAGS
+offsets.h
diff --git a/src/vm/jit/arm/Makefile.am b/src/vm/jit/arm/Makefile.am
new file mode 100644 (file)
index 0000000..9a1cfb4
--- /dev/null
@@ -0,0 +1,85 @@
+## src/vm/jit/arm/Makefile.am
+##
+## Copyright (C) 1996-2005, 2006 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
+##
+## 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.
+##
+## Contact: cacao@cacaojvm.org
+##
+## Authors: Christian Thalinger
+##
+## Changes: Michael Starzinger
+##
+## $Id: Makefile.am 6527 2006-05-09 17:55:18Z twisti $
+
+## Process this file with automake to produce Makefile.in
+
+DIST_SUBDIRS = \
+       linux
+
+SUBDIRS = $(OS_DIR)
+
+AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir) -I$(top_builddir)/src
+AM_CCASFLAGS = $(AM_CPPFLAGS)
+
+BUILT_SOURCES = offsets.h
+
+CLEANFILES = offsets.h
+
+noinst_HEADERS = \
+       arch.h \
+       machine-instr.h \
+       md-asm.h
+
+noinst_LTLIBRARIES = libarch.la
+
+if ENABLE_DISASSEMBLER
+DISASS_SOURCES = \
+       disass.c
+endif
+
+libarch_la_SOURCES = \
+       asmpart.S \
+       codegen.c \
+       codegen.h \
+       $(DISASS_SOURCES) \
+       emit.c \
+       md.c \
+       md-abi.c \
+       md-abi.h \
+       patcher.c
+
+libarch_la_LIBADD = \
+       $(OS_DIR)/libmd.la
+
+$(srcdir)/asmpart.S: $(top_builddir)/config.h offsets.h
+
+offsets.h: $(top_builddir)/src/vm/jit/tools/genoffsets $(top_builddir)/config.h
+       $(top_builddir)/src/vm/jit/tools/genoffsets > offsets.h
+
+
+## Local variables:
+## mode: Makefile
+## indent-tabs-mode: t
+## c-basic-offset: 4
+## tab-width: 8
+## compile-command: "automake --add-missing"
+## End:
diff --git a/src/vm/jit/arm/arch.h b/src/vm/jit/arm/arch.h
new file mode 100644 (file)
index 0000000..992d902
--- /dev/null
@@ -0,0 +1,117 @@
+/* src/vm/jit/arm/arch.h - architecture defines for arm
+
+   Copyright (C) 1996-2005, 2006 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Michael Starzinger
+            Christian Thalinger
+
+   $Id: arch.h 6591 2007-01-02 19:14:25Z twisti $
+
+*/
+
+
+#ifndef _ARCH_H
+#define _ARCH_H
+
+/* define architecture features ***********************************************/
+
+#define U8_AVAILABLE                     1
+
+#define USEBUILTINTABLE
+
+#define SUPPORT_DIVISION                 0
+#define SUPPORT_LONG                     1
+#if defined(ENABLE_SOFTFLOAT)
+# define SUPPORT_FLOAT                   0
+# define SUPPORT_DOUBLE                  0
+#else
+# define SUPPORT_FLOAT                   1
+# define SUPPORT_DOUBLE                  1
+#endif /* defined(ENABLE_SOFTFLOAT) */
+
+#define SUPPORT_I2F                      1
+#define SUPPORT_I2D                      1
+#define SUPPORT_L2F                      0
+#define SUPPORT_L2D                      0
+
+#define SUPPORT_F2I                      1
+#define SUPPORT_F2L                      0
+#define SUPPORT_D2I                      1
+#define SUPPORT_D2L                      0
+
+#define SUPPORT_LONG_ADD                 1
+#define SUPPORT_LONG_CMP                 1
+#define SUPPORT_LONG_CMP_CONST           1
+#define SUPPORT_LONG_LOGICAL             1
+#define SUPPORT_LONG_SHIFT               0
+#define SUPPORT_LONG_MUL                 0
+#define SUPPORT_LONG_DIV                 0
+
+#define SUPPORT_LONG_DIV_POW2            0
+#define SUPPORT_LONG_REM_POW2            0
+
+#define SUPPORT_CONST_LOGICAL            0  /* AND, OR, XOR with immediates   */
+#define SUPPORT_CONST_MUL                0  /* mutiply with immediate         */
+#define SUPPORT_CONST_STORE              0  /* do we support const stores     */
+#define SUPPORT_CONST_STORE_ZERO_ONLY    0  /* on some risc machines we can   */
+                                            /* only store REG_ZERO            */
+
+#define HAS_4BYTE_STACKSLOT
+#define SUPPORT_COMBINE_INTEGER_REGISTERS
+#define SUPPORT_PASS_FLOATARGS_IN_INTREGS
+
+#define ALIGN_LONGS_IN_MEMORY       /* Align Longs and/or Doubles at          */
+#define ALIGN_DOUBLES_IN_MEMORY     /* 2*Stackslotsize relativ to stackframe  */
+/* Memory Positions for not Interface Stackslots (allocate_scratch_registers) */
+/* are not properly aligned in case HAS_4_BYTE_STACKSLOT is not defined!      */
+/* For HAS_4_BYTE_STACKSLOT archs no distinction is made between long and     */
+/* define SUPPORT_COMBINE_INTEGER_REGISTERS                                   */
+
+
+/* exceptions *****************************************************************/
+
+#define SUPPORT_HARDWARE_DIVIDE_BY_ZERO  0
+
+
+/* replacement ****************************************************************/
+
+#define REPLACEMENT_PATCH_SIZE           4 /* bytes */
+#define REPLACEMENT_STUB_SIZE            5 /* words */
+
+#endif /* _ARCH_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:
+ */
diff --git a/src/vm/jit/arm/asmpart.S b/src/vm/jit/arm/asmpart.S
new file mode 100644 (file)
index 0000000..694a5e4
--- /dev/null
@@ -0,0 +1,471 @@
+/* src/vm/jit/arm/asmpart.S - Java-C interface functions for ARM
+
+   Copyright (C) 1996-2005, 2006 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Michael Starzinger
+
+   Changes: Christian Thalinger
+
+   $Id: asmpart.S 6541 2006-08-22 14:48:01Z twisti $
+
+*/
+
+
+#include "config.h"
+
+#include "vm/jit/arm/offsets.h"
+#include "vm/jit/arm/md-asm.h"
+
+#include "vm/jit/methodheader.h"
+
+
+       .file "asmpart.S"
+       .text
+       .align 2
+
+
+/* export functions ***********************************************************/
+
+       .globl asm_vm_call_method
+       .globl asm_vm_call_method_int
+       .globl asm_vm_call_method_long
+       .globl asm_vm_call_method_float
+       .globl asm_vm_call_method_double
+       .globl asm_vm_call_method_exception_handler
+
+       .globl asm_call_jit_compiler
+
+       .globl asm_handle_exception
+       .globl asm_handle_nat_exception
+
+       .globl asm_abstractmethoderror
+
+       .globl asm_patcher_wrapper
+
+       .globl asm_cacheflush
+
+       .globl asm_getclassvalues_atomic
+       .globl asm_criticalsections
+
+
+#if !defined(ENABLE_THREADS)
+asm_exceptionptr:
+       .word _no_threads_exceptionptr
+#endif
+
+asm_jitcompilerptr:
+       .word asm_call_jit_compiler
+
+asm_criticalsections:
+#if defined(ENABLE_THREADS)
+       .word _crit_begin
+       .word _crit_end
+       .word _crit_restart
+#endif
+       .word 0
+
+
+/* asm_vm_call_method **********************************************************
+
+   This function calls a Java-method (which possibly needs compilation)
+   with up to 4 address parameters.
+
+   This functions calls the JIT-compiler which eventually translates the
+   method into machine code.
+
+*******************************************************************************/
+
+       .align  2
+
+       .word   0                           /* catch type all                     */
+       .word   0                           /* handler pc                         */
+       .word   0                           /* end pc                             */
+       .word   0                           /* start pc                           */
+       .word   1                           /* extable size                       */
+       .word   0                           /* line number table start            */
+       .word   0                           /* line number table size             */
+       .word   0                           /* FltSave                            */
+       .word   0                           /* IntSave                            */
+       .word   0                           /* IsLeaf                             */
+       .word   0                           /* IsSync                             */
+       .word   0                           /* FrameSize                          */
+       .word   0                           /* CodeinfoPointer                    */
+
+asm_vm_call_method:
+asm_vm_call_method_int:
+asm_vm_call_method_long:
+/* asm_vm_call_method_float:
+asm_vm_call_method_double: */
+       SAVE_SCRATCH_REGISTERS            /* save our personal scratch regs   */
+       stmfd sp!, {v1}                   /* V1 is used to recompute SP ...   */
+       mov   v1, #0                      /* ... when using stack arguments   */
+       ldr   ip, asm_jitcompilerptr
+       str   ip, [sp, #-4]!              /* store fake address               */
+       mov   mptr, sp                    /* set method pointer               */
+
+       mov   itmp1, a1                   /* pass methodinfo* via ITMP1       */
+
+       cmp   a2, #0                      /* do we have arguments?            */
+       ble   asm_calljava_copyfinish     /* no -> do not care :-)            */
+
+       /* REMEMBER: stack space for arguments is reserved here! */
+       /* TODO: we possibly reserve to much here */
+       mov   v1, a2, lsl #3              /* how much stack do we alloc?      */
+       sub   sp, sp, v1                  /* allocate stack for arguments!    */
+
+       mov   itmp3, #0                   /* stack position                   */
+asm_calljava_copyloop:                /* reorder stack arguments!         */
+#if defined(__ARMEL__)
+       ldr   ip, [a3,#offvmargdata]      /* get LOW word of argument         */
+       str   ip, [sp, itmp3]
+       add   itmp3, itmp3, #4
+       ldr   ip, [a3,#offvmargtype]      /* is it a 2_WORD_TYPE?             */
+       tst   ip, #1
+       ldrne ip, [a3,#offvmargdata + 4]  /* yes -> get HIGH word of argument */
+       strne ip, [sp, itmp3]
+       addne itmp3, itmp3, #4
+#else /* defined(__ARMEB__) */
+       ldr   ip, [a3,#offvmargtype + 4]  /* get our item type (it is u8)    */
+       teq   ip, #2                      /* is it a TYPE_FLOAT?              */
+       ldreq ip, [a3,#offvmargdata]      /* yes -> get LOW word of float     */
+       streq ip, [sp, itmp3]
+       addeq itmp3, itmp3, #4
+       beq   asm_calljava_copydone
+       tst   ip, #1                      /* is it a 2_WORD_TYPE?             */
+       ldrne ip, [a3,#offvmargdata]      /* yes -> get HIGH word of argument */
+       strne ip, [sp, itmp3]
+       addne itmp3, itmp3, #4
+       ldr   ip, [a3,#offvmargdata + 4]  /* get LOW word of argument         */
+       str   ip, [sp, itmp3]
+       add   itmp3, itmp3, #4
+asm_calljava_copydone:
+#endif
+       add   a3, a3, #sizevmarg          /* next argument block              */
+       subs  a2, a2, #1
+       bgt   asm_calljava_copyloop
+
+       /* REMEMBER: first four args are passed in regs, take them out again  */
+       ldmfd sp, {a1, a2, a3, a4}        /* load first four args to register */
+       cmp   v1, #16                     /* do we have four arguments?       */
+       addlt sp, sp, v1
+       movlt v1, #0
+       addge sp, sp, #16
+       subge v1, v1, #16
+
+asm_calljava_copyfinish:
+       /* REMEMBER: do the method call just like in java! */
+       ldr   ip, [mptr]                  /* fake virtual function call       */
+       mov   lr, pc 
+       mov   pc, ip 
+fake2:
+       sub   ip, pc, #(fake2 - asm_vm_call_method)+8
+
+       add   sp, sp, v1                  /* free stack arguments!            */
+       add   sp, sp, #4                  /* free fake address                */
+       ldmfd sp!, {v1}
+       RESTORE_SCRATCH_REGS_AND_RETURN   /* return to caller, restore regs   */
+
+asm_vm_call_method_exception_handler:
+       mov   a1, xptr                    /* exception pointer is arg1        */
+       bl    builtin_throw_exception     /* throw the exception              */
+       mov   res1, #0                    /* return NULL                      */
+       mov   res2, #0                    /* return NULL                      */
+       add   sp, sp, v1                  /* free stack arguments!            */
+       add   sp, sp, #4                  /* free fake address                */
+       ldmfd sp!, {v1}
+       RESTORE_SCRATCH_REGS_AND_RETURN   /* return to caller, restore regs   */
+
+asm_vm_call_method_float:
+        mov a1,#0x51
+        b asm_debug
+asm_vm_call_method_double:
+        mov a1,#0x52
+        b asm_debug
+
+
+/****************** function asm_call_jit_compiler *****************************
+*                                                                              *
+*   Invokes the compiler for untranslated JavaVM methods.                      *
+*   What this method does:                                                     *
+*    - save args and LR                                                        *
+*    - fire up jit_compile (pass methodinfo pointer)                           *
+*    - try to find out where to write back the new method pointer              *
+*    - restore args and LR                                                     *
+*    - check for exceptions                                                    *
+*    - eventually write back new method pointer                                *
+*    - call jit code (wich will then return to caller)                         *
+*                                                                              *
+*   These methods can call us: codegen_compilerstub & asm_calljavafunction     *
+*   ATTENTION: use REG_ITMP1 to pass methodinfo pointer to me!                 *
+*                                                                              *
+*******************************************************************************/
+
+#define MYSTACKSIZE (5*4)
+
+asm_call_jit_compiler:
+       SAVE_ARGUMENT_REGISTERS             /* save our argument registers & LR   */
+
+       mov   a1, itmp1                     /* pass methodinfo pointer            */
+       mov   a2, mptr                      /* pass method pointer                */
+       add   a3, sp, #MYSTACKSIZE          /* pass Java sp                       */
+       mov   a4, lr                        /* pass Java RA (correct for leafs)   */
+       bl    jit_asm_compile
+       mov   itmp1, res1                   /* save pointer to new jit-code       */
+
+       tst   itmp1,itmp1                   /* check for exeption                 */
+       beq   L_asm_call_jit_compiler_exception
+
+       RESTORE_ARGUMENT_REGISTERS          /* load our argument registers & LR   */
+
+       mov   ip, itmp1
+       mov   pc, ip                        /* call jit-code                      */
+
+L_asm_call_jit_compiler_exception:
+       bl    exceptions_get_and_clear_exception
+       mov   xptr, res1                    /* get exception                      */
+
+       RESTORE_ARGUMENT_REGISTERS          /* load LR                            */
+
+       sub   xpc, lr, #4                   /* xpc = instruction that called us   */
+       b     asm_handle_nat_exception
+
+
+/********************* function asm_handle_exception ***************************
+*                                                                              *
+*   This function handles an exception. It does not use the usual calling      *
+*   conventions. The exception pointer is passed in REG_ITMP1 and the          *
+*   pc from the exception raising position is passed in REG_ITMP2. It searches *
+*   the local exception table for a handler. If no one is found, it unwinds    *
+*   stacks and continues searching the callers.                                *
+*                                                                              *
+*   void asm_handle_exception (exceptionptr, exceptionpc);                     *
+*                                                                              *
+*******************************************************************************/
+
+asm_handle_nat_exception:
+       /*TODO:maybe make a macro out of it!!!*/
+       SAVE_ARGUMENT_REGISTERS  
+       mov   a1, lr
+       bl    md_codegen_get_pv_from_pc
+       mov   ip, res1
+       RESTORE_ARGUMENT_REGISTERS  
+       /* fall through */
+
+asm_handle_exception:
+       stmfd sp!, {r0 - r3}               /* save possible used registers    */
+       mov   itmp3, #1                    /* set maybe-leaf flag             */
+       mov   a4, #(4*4)                   /* prepare a4 for handle_exception */
+
+asm_handle_exception_loop:
+       stmfd sp!, {ip,lr}                 /* call exception helper here!     */
+       mov   a1, xptr                     /* pass exception pointer          */
+       mov   a2, xpc                      /* pass exception pointer          */
+       mov   a3, ip                       /* pass data segment pointer       */
+       add   a4, sp, a4                   /* calculate Java sp into a4...    */
+       add   a4, a4, #(2*4)
+       bl    exceptions_handle_exception
+       ldmfd sp!, {ip,lr}
+
+       tst   a1, a1
+       beq   asm_handle_exception_not_catched
+
+       mov   xpc, a1                      /* move handlerpc into xpc         */
+       tst   itmp3,itmp3                  /* if this is a lead method ...    */
+       ldmnefd sp!, {r0 - r3}             /* restore argument registers      */
+
+       mov   pc, xpc                      /* jump to handler                 */
+
+asm_handle_exception_not_catched:
+       tst   itmp3,itmp3                  /* if this is a lead method ...    */
+       addne sp, sp, #(4*4)               /* remove maybe-leaf stackframe    */
+       movne itmp3, #0                    /* remove maybe-leaf flag          */
+
+       ldr   a3, [ip, #FrameSize]         /* t2 = frame size                 */
+       add   a1, sp, a3                   /* t0 = pointer to save area       */
+       ldr   a2, [ip, #IsLeaf]            /* t1 = is leaf procedure          */
+       tst   a2, a2                       /* if is leaf ...                  */
+       ldreq lr, [a1, #-4]!               /* ... restore RA                  */
+       mov   xpc, lr                      /* the new xpc is RA               */
+
+       ldr   a2, [ip, #IntSave]           /* t1 = saved int register count   */
+       rsb   a2, a2, #5                   /* t1 = count of unsaved registers */
+       sub   a2, a2, #1
+       add   pc, pc, a2, lsl #2           /* do not load unsaved registers   */
+       ldr   v1, [a1, #-20]               /* ... but restore the other ones  */
+       ldr   v2, [a1, #-16]
+       ldr   v3, [a1, #-12]
+       ldr   v4, [a1, #- 8]
+       ldr   v5, [a1, #- 4]
+
+       add   sp, sp, a3                   /* unwind stack (using t2)         */
+       mov   a4, #0                       /* prepare a4 for handle_exception */
+
+       /*TODO:maybe make a macro out of it!!!*/
+       SAVE_ARGUMENT_REGISTERS  
+       mov   a1, lr
+       bl    md_codegen_get_pv_from_pc
+       mov   ip, res1
+       RESTORE_ARGUMENT_REGISTERS  
+
+       b     asm_handle_exception_loop
+
+
+/* asm_patcher_wrapper *********************************************************
+*                                                                              *
+*   TODO: document me                                                          *
+*                                                                              *
+*   Stack layout when calling patcher function:                                *
+*    24   saved REG_ITMP3, should be restored                ( -4)             *
+*    20   data segment displacement from load instructions   ( -8)             *
+*    16   return address into JIT code (patch position)      (-12)             *
+*    12   pointer to virtual java_objectheader                                 *
+*     8   machine code (which is patched back later)                           *
+*   [ 8   result of patcher function (indicates exception)  ]                  *
+*     4   unresolved class/method/field reference                              *
+*   [ 0   patcher function pointer to call                  ]                  *
+*     0   saved IP of caller (caller needs it!)                                *
+*                                                                              *
+*******************************************************************************/
+
+#define PATCHSTACKSIZE 7*4
+
+asm_patcher_wrapper:
+       mov   itmp3, sp                     /* preserve original SP in ITMP3      */
+
+       SAVE_ARGUMENT_REGISTERS_IP          /* save our argument registers & LR   */
+       SAVE_FLOAT_REGISTERS                /* save our float registers here      */
+
+       mov   a1, itmp3                     /* pass SP of patcher stub            */
+       mov   a2, ip                        /* pass PV                            */
+       mov   a3, lr                        /* pass RA (correct for leafs)        */
+       bl    patcher_wrapper
+       mov   itmp3, res1                   /* save return value                  */
+
+       RESTORE_FLOAT_REGISTERS             /* restore our float registers here   */
+       RESTORE_ARGUMENT_REGISTERS_IP       /* load our argument registers & LR   */
+
+       tst   itmp3, itmp3                  /* check for an exception             */
+       bne   L_asm_patcher_wrapper_exception
+
+       add   sp, sp, #PATCHSTACKSIZE       /* remove patcher stack frame         */
+
+       ldr   itmp3, [sp, #-4]              /* restore ITMP3 for calling method   */
+       ldr   pc, [sp, #-12]                /* jump to new patched code           */
+
+L_asm_patcher_wrapper_exception:
+       mov   xptr, itmp3                   /* get exception                      */
+       ldr   xpc, [sp, #16]                /* RA is xpc                          */
+
+       add   sp, sp, #PATCHSTACKSIZE       /* remove patcher stack frame         */
+
+       b     asm_handle_exception
+
+
+/* asm_abstractmethoderror *****************************************************
+
+   Creates and throws an AbstractMethodError.
+
+*******************************************************************************/
+
+asm_abstractmethoderror:
+       stmfd sp!, {lr}                     /* save return address                */
+       add   a1, sp, #(1*4)                /* pass java sp                       */
+       mov   a2, lr                        /* pass exception address             */
+       bl    exceptions_asm_new_abstractmethoderror
+       ldmfd sp!, {lr}                     /* restore return address             */
+
+       mov   xptr, res1                    /* get exception pointer              */
+       sub   xpc, lr, #4                   /* exception address is ra - 4        */
+       b     asm_handle_nat_exception
+
+               
+/********************* function asm_cacheflush *********************************
+*                                                                              *
+*   TODO: document me                                                          *
+*                                                                              *
+*   void asm_cacheflush(void *p, s4 size);                                     *
+*                                                                              *
+*******************************************************************************/
+
+#if 1
+.equ sys_cacheflush, 0x9f0002
+asm_cacheflush:
+       add   a2, a1, a2
+       mov   a3, #0
+       #if 1
+         /* TODO: repeair this! */
+         /* cacheflush is messed up beyond all repair! */
+         mov a1, #0x0
+         mov a2, #0xff000000
+       #endif
+       swi   #sys_cacheflush
+       mov   pc, lr
+#else
+.equ IMBa, 0xf00000
+.equ IMBb, 0xf00001
+asm_cacheflush:
+       /* clean and invalidate the entire cache!!! */
+       swi   #IMBa
+       mov   pc, lr
+#endif
+
+
+/********************* function asm_getclassvalues_atomic *********************/
+
+asm_getclassvalues_atomic:
+       stmfd sp!, {r4, r5, r6}
+_crit_restart:
+_crit_begin:
+       ldr   r4,[a1,#offbaseval]
+       ldr   r5,[a1,#offdiffval]
+       ldr   r6,[a2,#offbaseval]
+_crit_end:
+       str   r4,[a3,#offcast_super_baseval]
+       str   r5,[a3,#offcast_super_diffval]
+       str   r6,[a3,#offcast_sub_baseval]
+       ldmfd sp!, {r4, r5, r6}
+       mov   pc, lr
+
+
+/* Disable exec-stacks, required for Gentoo ***********************************/
+
+#if defined(__GCC__) && defined(__ELF__)
+       .section .note.GNU-stack,"",@progbits
+#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: asm
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
diff --git a/src/vm/jit/arm/codegen.c b/src/vm/jit/arm/codegen.c
new file mode 100644 (file)
index 0000000..3db469a
--- /dev/null
@@ -0,0 +1,3091 @@
+/* src/vm/jit/arm/codegen.c - machine code generator for Arm
+
+   Copyright (C) 1996-2005, 2006 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Michael Starzinger
+
+   Changes: Christian Thalinger
+                       Edwin Steiner
+
+   $Id: codegen.c 6591 2007-01-02 19:14:25Z twisti $
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "vm/types.h"
+
+#include "md-abi.h"
+
+#include "vm/jit/arm/arch.h"
+#include "vm/jit/arm/codegen.h"
+
+#include "mm/memory.h"
+#include "native/native.h"
+
+#if defined(ENABLE_THREADS)
+# include "threads/native/lock.h"
+#endif
+
+#include "vm/builtin.h"
+#include "vm/exceptions.h"
+#include "vm/global.h"
+#include "vm/loader.h"
+#include "vm/options.h"
+#include "vm/stringlocal.h"
+#include "vm/vm.h"
+#include "vm/jit/asmpart.h"
+#include "vm/jit/codegen-common.h"
+#include "vm/jit/dseg.h"
+#include "vm/jit/emit-common.h"
+#include "vm/jit/jit.h"
+#include "vm/jit/methodheader.h"
+#include "vm/jit/parse.h"
+#include "vm/jit/patcher.h"
+#include "vm/jit/reg.h"
+
+#if defined(ENABLE_LSRA)
+#include "vm/jit/allocator/lsra.h"
+#endif
+
+
+/* codegen *********************************************************************
+
+   Generates machine code.
+
+*******************************************************************************/
+
+bool codegen(jitdata *jd)
+{
+       methodinfo         *m;
+       codeinfo           *code;
+       codegendata        *cd;
+       registerdata       *rd;
+       s4              i, t, len;
+       s4              s1, s2, s3, d;
+       s4              disp;
+       varinfo        *var;
+       basicblock     *bptr;
+       instruction    *iptr;
+       exception_entry *ex;
+       s4              fieldtype;
+       s4              varindex;
+
+       s4              spilledregs_num;
+       s4              savedregs_num;
+       u2              savedregs_bitmask;
+       u2              currentline;
+
+       methodinfo         *lm;             /* local methodinfo for ICMD_INVOKE* */
+       unresolved_method  *um;
+       builtintable_entry *bte;
+       methoddesc         *md;
+
+       /* get required compiler data */
+
+       m    = jd->m;
+       code = jd->code;
+       cd   = jd->cd;
+       rd   = jd->rd;
+
+       /* prevent compiler warnings */
+
+       lm  = NULL;
+       um  = NULL;
+       bte = NULL;
+
+       fieldtype = -1;
+       
+       /* space to save used callee saved registers */
+       savedregs_num = (jd->isleafmethod) ? 0 : 1;       /* space to save the LR */
+       savedregs_num += (INT_SAV_CNT - rd->savintreguse);
+       savedregs_num += (FLT_SAV_CNT - rd->savfltreguse);
+       spilledregs_num = rd->memuse;
+
+#if defined(ENABLE_THREADS)        /* space to save argument of monitor_enter */
+       if (checksync && (m->flags & ACC_SYNCHRONIZED))
+               spilledregs_num++;
+#endif
+
+       cd->stackframesize = spilledregs_num + savedregs_num;
+
+       /* SECTION: Method Header */
+       /* create method header */
+
+       (void) dseg_add_unique_address(cd, code);              /* CodeinfoPointer */
+       (void) dseg_add_unique_s4(cd, cd->stackframesize * 4); /* FrameSize       */
+
+#if defined(ENABLE_THREADS)
+       /* IsSync contains the offset relative to the stack pointer for the
+          argument of monitor_exit used in the exception handler. Since the
+          offset could be zero and give a wrong meaning of the flag it is
+          offset by one.
+       */
+
+       if (checksync && (m->flags & ACC_SYNCHRONIZED))
+               (void) dseg_add_unique_s4(cd, (rd->memuse + 1) * 4);/* IsSync         */
+       else
+#endif
+               (void) dseg_add_unique_s4(cd, 0);                  /* IsSync          */
+
+       (void) dseg_add_unique_s4(cd, jd->isleafmethod);       /* IsLeaf          */
+       (void) dseg_add_unique_s4(cd, INT_SAV_CNT - rd->savintreguse); /* IntSave */
+       (void) dseg_add_unique_s4(cd, FLT_SAV_CNT - rd->savfltreguse); /* FltSave */
+       (void) dseg_addlinenumbertablesize(cd);
+       (void) dseg_add_unique_s4(cd, jd->exceptiontablelength); /* ExTableSize   */
+
+       /* create exception table */
+
+       for (ex = jd->exceptiontable; ex != NULL; ex = ex->down) {
+               dseg_add_target(cd, ex->start);
+               dseg_add_target(cd, ex->end);
+               dseg_add_target(cd, ex->handler);
+               (void) dseg_add_unique_address(cd, ex->catchtype.any);
+       }
+
+       /* save return address and used callee saved registers */
+       savedregs_bitmask = 0;
+       if (!jd->isleafmethod)
+               savedregs_bitmask = (1<<REG_LR);
+       for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--)
+               savedregs_bitmask |= (1<<(rd->savintregs[i]));
+#if !defined(NDEBUG)
+       for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) {
+               log_text("!!! CODEGEN: floating-point callee saved registers are not saved to stack (SEVERE! STACK IS MESSED UP!)");
+               /* TODO: floating-point */
+       }
+#endif
+       if (savedregs_bitmask) {
+               M_STMFD(savedregs_bitmask, REG_SP);
+       }
+
+       /* create additional stack frame for spilled variables (if necessary) */
+       if (spilledregs_num) {
+               M_SUB_IMM_EXT_MUL4(REG_SP, REG_SP, spilledregs_num);
+       }
+
+       /* take arguments out of register or stack frame */
+       md = m->parseddesc;
+       for (i = 0, len = 0; i < md->paramcount; i++) {
+               s1 = md->params[i].regoff;
+               t = md->paramtypes[i].type;
+
+               varindex = jd->local_map[len * 5 + t];
+
+               len += (IS_2_WORD_TYPE(t)) ? 2 : 1;          /* 2 word type arguments */
+
+               if (varindex == UNUSED)
+                       continue;
+
+               var = VAR(varindex);
+
+               /* ATTENTION: we use interger registers for all arguments (even float) */
+#if !defined(ENABLE_SOFTFLOAT)
+               if (IS_INT_LNG_TYPE(t)) {                    /* integer args          */
+#endif
+                       if (!md->params[i].inmemory) {           /* register arguments    */
+                               s2 = ARGUMENT_REGS(t, s1);           /* get argument register */
+                               if (!(var->flags & INMEMORY)) {      /* reg arg -> register   */
+                                       if (GET_LOW_REG(var->vv.regoff) == REG_SPLIT || GET_HIGH_REG(var->vv.regoff) == REG_SPLIT) {
+                                               /* TODO: remove this!!! */
+                                               dolog("SPLIT in local var: %x>%x (%s.%s)", s2, var->vv.regoff, m->class->name->text, m->name->text);
+                                               assert(s2 == var->vv.regoff);
+                                       }
+                                       s3 = var->vv.regoff;
+                                       SPLIT_OPEN(t, s2, REG_ITMP1);
+                                       SPLIT_LOAD(t, s2, cd->stackframesize);
+                                       SPLIT_OPEN(t, s3, REG_ITMP1);
+
+                                       if (IS_2_WORD_TYPE(t))
+                                               M_LNGMOVE(s2, s3);
+                                       else
+                                               M_INTMOVE(s2, s3);
+
+                                       SPLIT_STORE_AND_CLOSE(t, s3, cd->stackframesize);
+                               }
+                               else {                               /* reg arg -> spilled    */
+                                       SPLIT_OPEN(t, s2, REG_ITMP1);
+                                       SPLIT_LOAD(t, s2, cd->stackframesize);
+
+                                       if (IS_2_WORD_TYPE(t))
+                                               M_LST(s2, REG_SP, var->vv.regoff * 4);
+                                       else
+                                               M_IST(s2, REG_SP, var->vv.regoff * 4);
+                                       /* no SPLIT_CLOSE here because arg is fully spilled now */
+                               }
+                       }
+                       else {                                   /* stack arguments       */
+                               if (!(var->flags & INMEMORY)) {      /* stack arg -> register */
+                                       if (IS_2_WORD_TYPE(t))
+                                               M_LLD(var->vv.regoff, REG_SP, (cd->stackframesize + s1) * 4);
+                                       else
+                                               M_ILD(var->vv.regoff, REG_SP, (cd->stackframesize + s1) * 4);
+                               }
+                               else {                               /* stack arg -> spilled  */
+                                       /* Reuse Memory Position on Caller Stack */
+                                       var->vv.regoff = cd->stackframesize + s1;
+                               }
+                       }
+#if !defined(ENABLE_SOFTFLOAT)
+               } else {                                     /* floating args         */
+                       if (!md->params[i].inmemory) {           /* register arguments    */
+                               s2 = ARGUMENT_REGS(t, s1);           /* get argument register */
+                               if (!(var->flags & INMEMORY)) {      /* reg arg -> register   */
+                                       SPLIT_OPEN(t, s2, REG_ITMP1);
+                                       SPLIT_LOAD(t, s2, cd->stackframesize);
+                                       M_CAST_INT_TO_FLT_TYPED(t, s2, var->vv.regoff);
+                               }
+                               else {                               /* reg arg -> spilled    */
+                                       SPLIT_OPEN(t, s2, REG_ITMP1);
+                                       SPLIT_LOAD(t, s2, cd->stackframesize);
+
+                                       if (IS_2_WORD_TYPE(t))
+                                               M_LST(s2, REG_SP, var->vv.regoff * 4);
+                                       else
+                                               M_IST(s2, REG_SP, var->vv.regoff * 4);
+                                       /* no SPLIT_CLOSE here because arg is fully spilled now */
+                               }
+                       }
+                       else {                                   /* stack arguments       */
+                               if (!(var->flags & INMEMORY)) {      /* stack arg -> register */
+                                       M_STACK_LOAD_FLT_TYPED(t, var->vv.regoff, cd->stackframesize + s1);
+                               } else {                             /* stack arg -> spilled  */
+                                       /* Reuse Memory Position on Caller Stack */
+                                       var->vv.regoff = cd->stackframesize + s1;
+                               }
+                       }
+               }
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+       }
+
+#if defined(ENABLE_THREADS)
+       /* call monitorenter function */
+
+       if (checksync && (m->flags & ACC_SYNCHRONIZED)) {
+               /* stack offset for monitor argument */
+
+               s1 = rd->memuse;
+
+# if !defined(NDEBUG)
+               if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) {
+                       M_STMFD(BITMASK_ARGS, REG_SP);
+                       s1 += 4;
+               }
+# endif
+
+               /* get the correct lock object */
+
+               if (m->flags & ACC_STATIC) {
+                       disp = dseg_add_address(cd, &m->class->object.header);
+                       M_DSEG_LOAD(REG_A0, disp);
+               }
+               else {
+                       M_TST(REG_A0, REG_A0);
+                       M_BEQ(0);
+                       codegen_add_nullpointerexception_ref(cd);
+               }
+
+               M_STR(REG_A0, REG_SP, s1 * 4);
+               disp = dseg_add_functionptr(cd, LOCK_monitor_enter);
+               M_DSEG_BRANCH(disp);
+               s1 = (s4) (cd->mcodeptr - cd->mcodebase);
+               M_RECOMPUTE_IP(s1);
+
+# if !defined(NDEBUG)
+               if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
+                       M_LDMFD(BITMASK_ARGS, REG_SP);
+# endif
+       }
+#endif
+
+#if !defined(NDEBUG)
+       /* call trace function */
+
+       if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
+               emit_verbosecall_enter(jd);
+#endif
+
+       /* end of header generation */
+
+       /* SECTION: ICMD Code Generation */
+       /* for all basic blocks */
+       for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next)
+       {
+               bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase);
+
+               /* is this basic block reached? */
+               if (bptr->flags < BBREACHED)
+                       continue;
+
+               /* branch resolving */
+               {
+               branchref *brefs;
+               for (brefs = bptr->branchrefs; brefs != NULL; brefs = brefs->next) {
+                       gen_resolvebranch(cd->mcodebase + brefs->branchpos, 
+                                         brefs->branchpos, bptr->mpc);
+               }
+               }
+
+               /* copy interface registers to their destination */
+               len = bptr->indepth;
+
+               MCODECHECK(64+len);
+
+#if defined(ENABLE_LSRA)
+               if (opt_lsra) {
+               while (len) {
+                       len--;
+                       var = VAR(bptr->invars[len]);
+                       if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) {
+                               if (!(var->flags & INMEMORY))
+                                       d= var->vv.regoff;
+                               else
+                                       d=REG_ITMP1;
+                               M_INTMOVE(REG_ITMP1, d);
+                               emit_store(jd, NULL, var, d);   
+                       }
+               }
+               } else {
+#endif
+               while (len) {
+                       len--;
+                       var = VAR(bptr->invars[len]);
+
+                       if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) {
+                               d = codegen_reg_of_var(0, var, REG_ITMP1);
+                               M_INTMOVE(REG_ITMP1, d);
+                               emit_store(jd, NULL, var, d);
+                       }
+                       else {
+                               assert((var->flags & INOUT));
+                       }
+               }
+#if defined(ENABLE_LSRA)
+               }
+#endif
+
+               /* for all instructions */
+               len = bptr->icount;
+               currentline = 0;
+               for (iptr = bptr->iinstr; len > 0; len--, iptr++) {
+
+                       /* add line number */
+                       if (iptr->line != currentline) {
+                               dseg_addlinenumber(cd, iptr->line);
+                               currentline = iptr->line;
+                       }
+
+                       MCODECHECK(64);   /* an instruction usually needs < 64 words      */
+
+                       /* the big switch */
+                       switch (iptr->opc) {
+               case ICMD_NOP:        /* ... ==> ...                                  */
+                       break;
+
+       /* constant operations ************************************************/
+
+               case ICMD_ICONST:     /* ...  ==> ..., constant                       */
+
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       ICONST(d, iptr->sx.val.i);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_ACONST:     /* ... ==> ..., constant                        */
+
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               disp = dseg_add_unique_address(cd, NULL);
+
+                               codegen_addpatchref(cd, PATCHER_aconst,
+                                                   iptr->sx.val.c.ref,
+                                                                       disp);
+
+                               if (opt_showdisassemble)
+                                       M_NOP;
+
+                               M_DSEG_LOAD(d, disp);
+                       }
+                       else {
+                               ICONST(d, (u4) iptr->sx.val.anyptr);
+                       }
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_LCONST:     /* ...  ==> ..., constant                       */
+
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       LCONST(d, iptr->sx.val.l);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_FCONST:     /* ...  ==> ..., constant                       */
+
+#if defined(ENABLE_SOFTFLOAT)
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       ICONST(d, iptr->sx.val.i);
+                       emit_store_dst(jd, iptr, d);
+#else
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       FCONST(d, iptr->sx.val.f);
+                       emit_store_dst(jd, iptr, d);
+#endif
+                       break;
+
+               case ICMD_DCONST:     /* ...  ==> ..., constant                       */
+
+#if defined(ENABLE_SOFTFLOAT)
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       LCONST(d, iptr->sx.val.l);
+                       emit_store_dst(jd, iptr, d);
+#else
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       DCONST(d, iptr->sx.val.d);
+                       emit_store_dst(jd, iptr, d);
+#endif
+                       break;
+
+
+               /* load/store/copy/move operations ************************************/
+
+               case ICMD_ILOAD:      /* ...  ==> ..., content of local variable      */
+               case ICMD_ALOAD:      /* op1 = local variable                         */
+               case ICMD_FLOAD:
+               case ICMD_LLOAD:
+               case ICMD_DLOAD:
+               case ICMD_ISTORE:     /* ..., value  ==> ...                          */
+               case ICMD_FSTORE:
+               case ICMD_LSTORE:
+               case ICMD_DSTORE:
+               case ICMD_COPY:
+               case ICMD_MOVE:
+
+                       emit_copy(jd, iptr, VAROP(iptr->s1), VAROP(iptr->dst));
+                       break;
+
+               case ICMD_ASTORE:
+                       if (!(iptr->flags.bits & INS_FLAG_RETADDR))
+                               emit_copy(jd, iptr, VAROP(iptr->s1), VAROP(iptr->dst));
+                       break;
+
+               /* pop operations *****************************************************/
+
+               /* attention: double and longs are only one entry in CACAO ICMDs      */
+
+               case ICMD_POP:        /* ..., value  ==> ...                          */
+               case ICMD_POP2:       /* ..., value, value  ==> ...                   */
+
+                       break;
+
+
+               /* integer operations *************************************************/
+
+               case ICMD_INT2BYTE:   /* ..., value  ==> ..., value                   */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+                       M_MOV(d, REG_LSL(s1, 24));
+                       M_MOV(d, REG_ASR(d, 24));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_INT2CHAR:   /* ..., value  ==> ..., value                   */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+                       M_MOV(d, REG_LSL(s1, 16));
+                       M_MOV(d, REG_LSR(d, 16)); /* ATTENTION: char is unsigned */
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_INT2SHORT:  /* ..., value  ==> ..., value                   */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+                       M_MOV(d, REG_LSL(s1, 16));
+                       M_MOV(d, REG_ASR(d, 16));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_I2L:        /* ..., value  ==> ..., value                   */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       M_INTMOVE(s1, GET_LOW_REG(d));
+                       M_MOV(GET_HIGH_REG(d), REG_ASR(s1, 31));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_L2I:        /* ..., value  ==> ..., value                   */
+
+                       s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_INTMOVE(s1, d);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_INEG:       /* ..., value  ==> ..., - value                 */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1); 
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+                       M_RSB_IMM(d, s1, 0);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_LNEG:       /* ..., value  ==> ..., - value                 */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP12_PACKED);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       M_RSB_IMMS(GET_LOW_REG(d), GET_LOW_REG(s1), 0);
+                       M_RSC_IMM(GET_HIGH_REG(d), GET_HIGH_REG(s1), 0);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IADD:       /* ..., val1, val2  ==> ..., val1 + val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_ADD(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_LADD:       /* ..., val1, val2  ==> ..., val1 + val2        */
+
+                       s1 = emit_load_s1_low(jd, iptr, REG_ITMP3);
+                       s2 = emit_load_s2_low(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       M_ADD_S(GET_LOW_REG(d), s1, s2);
+                       s1 = emit_load_s1_high(jd, iptr, REG_ITMP3);
+                       s2 = emit_load_s2_high(jd, iptr, REG_ITMP2);
+                       M_ADC(GET_HIGH_REG(d), s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IADDCONST:
+               case ICMD_IINC:
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+
+                       if (IS_IMM(iptr->sx.val.i)) {
+                               M_ADD_IMM(d, s1, iptr->sx.val.i);
+                       } else if (IS_IMM(-iptr->sx.val.i)) {
+                               M_SUB_IMM(d, s1, (-iptr->sx.val.i));
+                       } else {
+                               ICONST(REG_ITMP3, iptr->sx.val.i);
+                               M_ADD(d, s1, REG_ITMP3);
+                       }
+
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_LADDCONST:  /* ..., value  ==> ..., value + constant        */
+                                     /* sx.val.l = constant                          */
+
+                       s3 = iptr->sx.val.l & 0xffffffff;
+                       s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       if (IS_IMM(s3))
+                               M_ADD_IMMS(GET_LOW_REG(d), s1, s3);
+                       else {
+                               ICONST(REG_ITMP3, s3);
+                               M_ADD_S(GET_LOW_REG(d), s1, REG_ITMP3);
+                       }
+                       s3 = iptr->sx.val.l >> 32;
+                       s1 = emit_load_s1_high(jd, iptr, REG_ITMP2);
+                       if (IS_IMM(s3))
+                               M_ADC_IMM(GET_HIGH_REG(d), s1, s3);
+                       else {
+                               ICONST(REG_ITMP3, s3);
+                               M_ADC(GET_HIGH_REG(d), s1, REG_ITMP3);
+                       }
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_ISUB:       /* ..., val1, val2  ==> ..., val1 - val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_SUB(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_LSUB:       /* ..., val1, val2  ==> ..., val1 - val2        */
+
+                       s1 = emit_load_s1_low(jd, iptr, REG_ITMP3);
+                       s2 = emit_load_s2_low(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       M_SUB_S(GET_LOW_REG(d), s1, s2);
+                       s1 = emit_load_s1_high(jd, iptr, REG_ITMP3);
+                       s2 = emit_load_s2_high(jd, iptr, REG_ITMP2);
+                       M_SBC(GET_HIGH_REG(d), s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_ISUBCONST:  /* ..., value  ==> ..., value + constant        */
+                                     /* sx.val.i = constant                          */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+                       if (IS_IMM(iptr->sx.val.i))
+                               M_SUB_IMM(d, s1, iptr->sx.val.i);
+                       else {
+                               ICONST(REG_ITMP3, iptr->sx.val.i);
+                               M_SUB(d, s1, REG_ITMP3);
+                       }
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_LSUBCONST:  /* ..., value  ==> ..., value - constant        */
+                                     /* sx.val.l = constant                          */
+
+                       s3 = iptr->sx.val.l & 0xffffffff;
+                       s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       if (IS_IMM(s3))
+                               M_SUB_IMMS(GET_LOW_REG(d), s1, s3);
+                       else {
+                               ICONST(REG_ITMP3, s3);
+                               M_SUB_S(GET_LOW_REG(d), s1, REG_ITMP3);
+                       }
+                       s3 = iptr->sx.val.l >> 32;
+                       s1 = emit_load_s1_high(jd, iptr, REG_ITMP2);
+                       if (IS_IMM(s3))
+                               M_SBC_IMM(GET_HIGH_REG(d), s1, s3);
+                       else {
+                               ICONST(REG_ITMP3, s3);
+                               M_SBC(GET_HIGH_REG(d), s1, REG_ITMP3);
+                       }
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IMUL:       /* ..., val1, val2  ==> ..., val1 * val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_MUL(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IDIV:       /* ..., val1, val2  ==> ..., val1 / val2        */
+               case ICMD_IREM:       /* ..., val1, val2  ==> ..., val1 % val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_A0);
+                       s2 = emit_load_s2(jd, iptr, REG_A1);
+                       gen_div_check(VAROP(iptr->sx.s23.s2)->type, s2);
+
+                       /* move arguments into argument registers */
+                       M_INTMOVE(s1, REG_A0);
+                       M_INTMOVE(s2, REG_A1);
+
+                       /* call builtin function */
+                       bte = iptr->sx.s23.s3.bte;
+                       disp = dseg_add_functionptr(cd, bte->fp);
+                       M_DSEG_BRANCH(disp);
+
+                       /* recompute ip */
+                       s1 = (s4) (cd->mcodeptr - cd->mcodebase);
+                       M_RECOMPUTE_IP(s1);
+
+                       /* move result into destination register */
+                       d = codegen_reg_of_dst(jd, iptr, REG_RESULT);
+                       M_INTMOVE(REG_RESULT, d);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_LDIV:       /* ..., val1, val2  ==> ..., val1 / val2        */
+               case ICMD_LREM:       /* ..., val1, val2  ==> ..., val1 % val2        */
+
+                       /* move arguments into argument registers */
+
+                       s1 = emit_load_s1(jd, iptr, REG_A0_A1_PACKED);
+                       M_LNGMOVE(s1, REG_A0_A1_PACKED);
+
+                       s2 = emit_load_s2(jd, iptr, REG_A2_A3_PACKED);
+                       M_LNGMOVE(s2, REG_A2_A3_PACKED);
+
+                       gen_div_check(VAROP(iptr->sx.s23.s2)->type, s2);
+
+                       /* call builtin function */
+                       bte = iptr->sx.s23.s3.bte;
+                       disp = dseg_add_functionptr(cd, bte->fp);
+                       M_DSEG_BRANCH(disp);
+
+                       /* recompute ip */
+                       s1 = (s4) (cd->mcodeptr - cd->mcodebase);
+                       M_RECOMPUTE_IP(s1);
+
+                       /* move result into destination register */
+                       d = codegen_reg_of_dst(jd, iptr, REG_RESULT_PACKED);
+                       M_LNGMOVE(REG_RESULT_PACKED, d);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IMULPOW2:   /* ..., value  ==> ..., value * (2 ^ constant)  */
+                                     /* sx.val.i = constant                          */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+                       M_MOV(d, REG_LSL(s1, iptr->sx.val.i));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IDIVPOW2:   /* ..., value  ==> ..., value / (2 ^ constant)  */
+                                     /* sx.val.i = constant                          */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+                       /* this rounds towards 0 as java likes it */
+                       M_MOV(REG_ITMP3, REG_ASR(s1, 31));
+                       M_ADD(REG_ITMP3, s1, REG_LSR(REG_ITMP3, 32 - iptr->sx.val.i));
+                       M_MOV(d, REG_ASR(REG_ITMP3, iptr->sx.val.i));
+                       /* this rounds towards nearest, not java style */
+                       /*M_MOV_S(d, REG_ASR(s1, iptr->sx.val.i));
+                       M_ADCMI_IMM(d, d, 0);*/
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IREMPOW2:   /* ..., value  ==> ..., value % constant        */
+                                     /* sx.val.i = constant [ (2 ^ x) - 1 ]          */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+                       M_MOV_S(REG_ITMP1, s1);
+                       M_RSBMI_IMM(REG_ITMP1, REG_ITMP1, 0);
+                       if (IS_IMM(iptr->sx.val.i))
+                               M_AND_IMM(d, REG_ITMP1, iptr->sx.val.i);
+                       else {
+                               ICONST(REG_ITMP3, iptr->sx.val.i);
+                               M_AND(d, REG_ITMP1, REG_ITMP3);
+                       }
+                       M_RSBMI_IMM(d, d, 0);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_ISHL:       /* ..., val1, val2  ==> ..., val1 << val2       */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_AND_IMM(REG_ITMP2, s2, 0x1f);
+                       M_MOV(d, REG_LSL_REG(s1, REG_ITMP2));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_ISHR:       /* ..., val1, val2  ==> ..., val1 >> val2       */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_AND_IMM(REG_ITMP2, s2, 0x1f);
+                       M_MOV(d, REG_ASR_REG(s1, REG_ITMP2));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IUSHR:      /* ..., val1, val2  ==> ..., val1 >>> val2      */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_AND_IMM(REG_ITMP2, s2, 0x1f);
+                       M_MOV(d, REG_LSR_REG(s1, REG_ITMP2));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_ISHLCONST:  /* ..., value  ==> ..., value << constant       */
+                                     /* sx.val.i = constant                          */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+                       M_MOV(d, REG_LSL(s1, iptr->sx.val.i & 0x1f));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_ISHRCONST:  /* ..., value  ==> ..., value >> constant       */
+                                     /* sx.val.i = constant                          */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       /* we need to check for zero here because arm interprets it as SHR by 32 */
+                       if ((iptr->sx.val.i & 0x1f) == 0) {
+                               M_INTMOVE(s1, d);
+                       } else {
+                               M_MOV(d, REG_ASR(s1, iptr->sx.val.i & 0x1f));
+                       }
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IUSHRCONST: /* ..., value  ==> ..., value >>> constant      */
+                                     /* sx.val.i = constant                          */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       /* we need to check for zero here because arm interprets it as SHR by 32 */
+                       if ((iptr->sx.val.i & 0x1f) == 0)
+                               M_INTMOVE(s1, d);
+                       else
+                               M_MOV(d, REG_LSR(s1, iptr->sx.val.i & 0x1f));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IAND:       /* ..., val1, val2  ==> ..., val1 & val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_AND(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_LAND:       /* ..., val1, val2  ==> ..., val1 & val2        */
+
+                       s1 = emit_load_s1_low(jd, iptr, REG_ITMP3);
+                       s2 = emit_load_s2_low(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       M_AND(GET_LOW_REG(d), s1, s2);
+                       s1 = emit_load_s1_high(jd, iptr, REG_ITMP3);
+                       s2 = emit_load_s2_high(jd, iptr, REG_ITMP2);
+                       M_AND(GET_HIGH_REG(d), s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IOR:        /* ..., val1, val2  ==> ..., val1 | val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_ORR(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_LOR:       /* ..., val1, val2  ==> ..., val1 | val2        */ 
+
+                       s1 = emit_load_s1_low(jd, iptr, REG_ITMP3);
+                       s2 = emit_load_s2_low(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       M_ORR(GET_LOW_REG(d), s1, s2);
+                       s1 = emit_load_s1_high(jd, iptr, REG_ITMP3);
+                       s2 = emit_load_s2_high(jd, iptr, REG_ITMP2);
+                       M_ORR(GET_HIGH_REG(d), s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IXOR:       /* ..., val1, val2  ==> ..., val1 ^ val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_EOR(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_LXOR:       /* ..., val1, val2  ==> ..., val1 ^ val2        */
+
+                       s1 = emit_load_s1_low(jd, iptr, REG_ITMP3);
+                       s2 = emit_load_s2_low(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       M_EOR(GET_LOW_REG(d), s1, s2);
+                       s1 = emit_load_s1_high(jd, iptr, REG_ITMP3);
+                       s2 = emit_load_s2_high(jd, iptr, REG_ITMP2);
+                       M_EOR(GET_HIGH_REG(d), s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+
+       /* floating operations ************************************************/
+
+#if !defined(ENABLE_SOFTFLOAT)
+
+               case ICMD_FNEG:       /* ..., value  ==> ..., - value                 */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_MNFS(d, s1);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_FADD:       /* ..., val1, val2  ==> ..., val1 + val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_ADFS(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_FSUB:       /* ..., val1, val2  ==> ..., val1 - val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_SUFS(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_FMUL:       /* ..., val1, val2  ==> ..., val1 * val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_MUFS(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_FDIV:       /* ..., val1, val2  ==> ..., val1 / val2        */
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_DVFS(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               /* ATTENTION: Jave does not want IEEE behaviour in FREM, do
+                  not use this */
+
+               case ICMD_FREM:       /* ..., val1, val2  ==> ..., val1 % val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_RMFS(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_DNEG:       /* ..., value  ==> ..., - value                 */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_MNFD(d, s1);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_DADD:       /* ..., val1, val2  ==> ..., val1 + val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_ADFD(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_DSUB:       /* ..., val1, val2  ==> ..., val1 - val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_SUFD(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_DMUL:       /* ..., val1, val2  ==> ..., val1 * val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_MUFD(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_DDIV:       /* ..., val1, val2  ==> ..., val1 / val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_DVFD(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               /* ATTENTION: Jave does not want IEEE behaviour in DREM, do
+                  not use this */
+
+               case ICMD_DREM:       /* ..., val1, val2  ==> ..., val1 % val2        */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_RMFD(d, s1, s2);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_I2F:       /* ..., value  ==> ..., (float) value            */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_FLTS(d, s1);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_I2D:       /* ..., value  ==> ..., (double) value           */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_FLTD(d, s1);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_F2I:       /* ..., value  ==> ..., (int) value              */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       /* this uses round towards zero, as Java likes it */
+                       M_FIX(d, s1);
+                       /* this checks for NaN; to return zero as Java likes it */
+                       M_CMF(s1, 0x8);
+                       M_MOVVS_IMM(d, 0);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_D2I:       /* ..., value  ==> ..., (int) value              */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       /* this uses round towards zero, as Java likes it */
+                       M_FIX(d, s1);
+                       /* this checks for NaN; to return zero as Java likes it */
+                       M_CMF(s1, 0x8);
+                       M_MOVVS_IMM(d, 0);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_D2F:       /* ..., value  ==> ..., (float) value            */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
+                       M_MVFS(d,s1);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_F2D:       /* ..., value  ==> ..., (double) value           */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
+                       M_MVFD(d,s1);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_FCMPG:      /* ..., val1, val2  ==> ..., val1 fcmpg val2    */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_CMF(s2, s1);
+                       M_MOV_IMM(d, 0);
+                       M_SUBGT_IMM(d, d, 1);
+                       M_ADDLT_IMM(d, d, 1);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_DCMPG:      /* ..., val1, val2  ==> ..., val1 dcmpg val2    */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_CMF(s2, s1);
+                       M_MOV_IMM(d, 0);
+                       M_SUBGT_IMM(d, d, 1);
+                       M_ADDLT_IMM(d, d, 1);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_FCMPL:      /* ..., val1, val2  ==> ..., val1 fcmpl val2    */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_CMF(s1, s2);
+                       M_MOV_IMM(d, 0);
+                       M_SUBLT_IMM(d, d, 1);
+                       M_ADDGT_IMM(d, d, 1);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_DCMPL:      /* ..., val1, val2  ==> ..., val1 dcmpl val2    */
+
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_CMF(s1, s2);
+                       M_MOV_IMM(d, 0);
+                       M_SUBLT_IMM(d, d, 1);
+                       M_ADDGT_IMM(d, d, 1);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+
+
+               /* memory operations **************************************************/
+
+               case ICMD_ARRAYLENGTH: /* ..., arrayref  ==> ..., length              */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+                       gen_nullptr_check(s1);
+                       M_ILD_INTERN(d, s1, OFFSET(java_arrayheader, size));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_AALOAD:     /* ..., arrayref, index  ==> ..., value         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       M_ADD(REG_ITMP1, s1, REG_LSL(s2, 2)); /* REG_ITMP1 = s1 + 4 * s2 */
+                       M_LDR_INTERN(d, REG_ITMP1, OFFSET(java_objectarray, data[0]));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_IALOAD:     /* ..., arrayref, index  ==> ..., value         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       M_ADD(REG_ITMP1, s1, REG_LSL(s2, 2)); /* REG_ITMP1 = s1 + 4 * s2 */
+                       M_ILD_INTERN(d, REG_ITMP1, OFFSET(java_intarray, data[0]));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_BALOAD:     /* ..., arrayref, index  ==> ..., value         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       M_ADD(REG_ITMP1, s1, s2); /* REG_ITMP1 = s1 + 1 * s2 */
+                       M_LDRSB(d, REG_ITMP1, OFFSET(java_bytearray, data[0]));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_CALOAD:     /* ..., arrayref, index  ==> ..., value         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       M_ADD(REG_ITMP1, s1, REG_LSL(s2, 1)); /* REG_ITMP1 = s1 + 2 * s2 */
+                       M_LDRH(d, REG_ITMP1, OFFSET(java_chararray, data[0]));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_SALOAD:     /* ..., arrayref, index  ==> ..., value         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       M_ADD(REG_ITMP1, s1, REG_LSL(s2, 1)); /* REG_ITMP1 = s1 + 2 * s2 */
+                       M_LDRSH(d, REG_ITMP1, OFFSET(java_shortarray, data[0]));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_LALOAD:     /* ..., arrayref, index  ==> ..., value         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       M_ADD(REG_ITMP3, s1, REG_LSL(s2, 3)); /* REG_ITMP3 = s1 + 8 * s2 */
+                       M_LLD_INTERN(d, REG_ITMP3, OFFSET(java_longarray, data[0]));
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_FALOAD:     /* ..., arrayref, index  ==> ..., value         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       M_ADD(REG_ITMP1, s1, REG_LSL(s2, 2)); /* REG_ITMP1 = s1 + 4 * s2 */
+#if !defined(ENABLE_SOFTFLOAT)
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_FLD_INTERN(d, REG_ITMP1, OFFSET(java_floatarray, data[0]));
+#else
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       M_ILD_INTERN(d, REG_ITMP1, OFFSET(java_floatarray, data[0]));
+#endif
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_DALOAD:     /* ..., arrayref, index  ==> ..., value         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       M_ADD(REG_ITMP3, s1, REG_LSL(s2, 3)); /* REG_ITMP3 = s1 + 8 * s2 */
+#if !defined(ENABLE_SOFTFLOAT)
+                       d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                       M_DLD_INTERN(d, REG_ITMP3, OFFSET(java_doublearray, data[0]));
+#else
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                       M_LLD_INTERN(d, REG_ITMP3, OFFSET(java_doublearray, data[0]));
+#endif
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_AASTORE:    /* ..., arrayref, index, value  ==> ...         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_A0);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP1);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       s3 = emit_load_s3(jd, iptr, REG_A1);
+
+                       /* move arguments to argument registers */
+                       M_INTMOVE(s1, REG_A0);
+                       M_INTMOVE(s3, REG_A1);
+
+                       /* call builtin function */
+                       disp = dseg_add_functionptr(cd, BUILTIN_canstore);
+                       M_DSEG_BRANCH(disp);
+
+                       /* recompute ip */
+                       s1 = (s4) (cd->mcodeptr - cd->mcodebase);
+                       M_RECOMPUTE_IP(s1);
+
+                       /* check resturn value of builtin */
+                       M_TST(REG_RESULT, REG_RESULT);
+                       M_BEQ(0);
+                       codegen_add_arraystoreexception_ref(cd);
+
+                       /* finally store address into array */
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+                       M_ADD(REG_ITMP1, s1, REG_LSL(s2, 2)); /* REG_ITMP1 = s1 + 4 * s2 */
+                       M_STR_INTERN(s3, REG_ITMP1, OFFSET(java_objectarray, data[0]));
+                       break;
+
+               case ICMD_IASTORE:    /* ..., arrayref, index, value  ==> ...         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+                       M_ADD(REG_ITMP1, s1, REG_LSL(s2, 2)); /* REG_ITMP1 = s1 + 4 * s2 */
+                       M_IST_INTERN(s3, REG_ITMP1, OFFSET(java_intarray, data[0]));
+                       break;
+
+               case ICMD_BASTORE:    /* ..., arrayref, index, value  ==> ...         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+                       M_ADD(REG_ITMP1, s1, s2); /* REG_ITMP1 = s1 + 1 * s2 */
+                       M_STRB(s3, REG_ITMP1, OFFSET(java_bytearray, data[0]));
+                       break;
+
+               case ICMD_CASTORE:    /* ..., arrayref, index, value  ==> ...         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+                       M_ADD(REG_ITMP1, s1, REG_LSL(s2, 1)); /* REG_ITMP1 = s1 + 2 * s2 */
+                       M_STRH(s3, REG_ITMP1, OFFSET(java_chararray, data[0]));
+                       break;
+
+               case ICMD_SASTORE:    /* ..., arrayref, index, value  ==> ...         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+                       M_ADD(REG_ITMP1, s1, REG_LSL(s2, 1)); /* REG_ITMP1 = s1 + 2 * s2 */
+                       M_STRH(s3, REG_ITMP1, OFFSET(java_shortarray, data[0]));
+                       break;
+
+               case ICMD_LASTORE:    /* ..., arrayref, index, value  ==> ...         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       M_ADD(REG_ITMP3, s1, REG_LSL(s2, 3)); /* REG_ITMP3 = s1 + 8 * s2 */
+                       s3 = emit_load_s3(jd, iptr, REG_ITMP12_PACKED);
+                       M_LST_INTERN(s3, REG_ITMP3, OFFSET(java_longarray, data[0]));
+                       break;
+
+               case ICMD_FASTORE:    /* ..., arrayref, index, value  ==> ...         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       M_ADD(REG_ITMP1, s1, REG_LSL(s2, 2)); /* REG_ITMP1 = s1 + 4 * s2 */
+#if !defined(ENABLE_SOFTFLOAT)
+                       s3 = emit_load_s3(jd, iptr, REG_FTMP1);
+                       M_FST_INTERN(s3, REG_ITMP1, OFFSET(java_floatarray, data[0]));
+#else
+                       s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+                       M_IST_INTERN(s3, REG_ITMP1, OFFSET(java_floatarray, data[0]));
+#endif
+                       break;
+
+               case ICMD_DASTORE:    /* ..., arrayref, index, value  ==> ...         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               gen_nullptr_check(s1);
+                               gen_bound_check(s1, s2);
+                       }
+                       M_ADD(REG_ITMP1, s1, REG_LSL(s2, 3)); /* REG_ITMP1 = s1 + 8 * s2 */
+#if !defined(ENABLE_SOFTFLOAT)
+                       s3 = emit_load_s3(jd, iptr, REG_FTMP1);
+                       M_DST_INTERN(s3, REG_ITMP1, OFFSET(java_doublearray, data[0]));
+#else
+                       s3 = emit_load_s3(jd, iptr, VAROP(iptr->sx.s23.s3), REG_ITMP23_PACKED);
+                       M_LST_INTERN(s3, REG_ITMP1, OFFSET(java_doublearray, data[0]));
+#endif
+                       break;
+
+               case ICMD_GETSTATIC:  /* ...  ==> ..., value                          */
+
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               unresolved_field *uf = iptr->sx.s23.s3.uf;
+
+                               fieldtype = uf->fieldref->parseddesc.fd->type;
+
+                               disp = dseg_add_unique_address(cd, NULL);
+
+                               codegen_addpatchref(cd, PATCHER_get_putstatic, uf, disp);
+
+                               if (opt_showdisassemble)
+                                       M_NOP;
+                       }
+                       else {
+                               fieldinfo *fi = iptr->sx.s23.s3.fmiref->p.field;
+
+                               fieldtype = fi->type;
+
+                               if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
+                                       codegen_addpatchref(cd, PATCHER_clinit, fi->class, 0);
+
+                                       if (opt_showdisassemble)
+                                               M_NOP;
+                               }
+
+                               disp = dseg_add_address(cd, &(fi->value));
+                       }
+
+                       M_DSEG_LOAD(REG_ITMP3, disp);
+                       switch (fieldtype) {
+                       case TYPE_INT:
+#if defined(ENABLE_SOFTFLOAT)
+                       case TYPE_FLT:
+#endif
+                       case TYPE_ADR:
+                               d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                               M_ILD_INTERN(d, REG_ITMP3, 0);
+                               break;
+                       case TYPE_LNG:
+#if defined(ENABLE_SOFTFLOAT)
+                       case TYPE_DBL:
+#endif
+                               d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                               M_LLD_INTERN(d, REG_ITMP3, 0);
+                               break;
+#if !defined(ENABLE_SOFTFLOAT)
+                       case TYPE_FLT:
+                               d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                               M_FLD_INTERN(d, REG_ITMP3, 0);
+                               break;
+                       case TYPE_DBL:
+                               d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                               M_DLD_INTERN(d, REG_ITMP3, 0);
+                               break;
+#endif
+                       default:
+                               assert(0);
+                       }
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_PUTSTATIC:  /* ..., value  ==> ...                          */
+
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               unresolved_field *uf = iptr->sx.s23.s3.uf;
+
+                               fieldtype = uf->fieldref->parseddesc.fd->type;
+
+                               disp = dseg_add_unique_address(cd, NULL);
+
+                               codegen_addpatchref(cd, PATCHER_get_putstatic, uf, disp);
+
+                               if (opt_showdisassemble)
+                                       M_NOP;
+                       }
+                       else {
+                               fieldinfo *fi = iptr->sx.s23.s3.fmiref->p.field;
+
+                               fieldtype = fi->type;
+
+                               if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
+                                       codegen_addpatchref(cd, PATCHER_clinit, fi->class, 0);
+
+                                       if (opt_showdisassemble)
+                                               M_NOP;
+                               }
+
+                               disp = dseg_add_address(cd, &(fi->value));
+                       }
+
+                       M_DSEG_LOAD(REG_ITMP3, disp);
+                       switch (fieldtype) {
+                       case TYPE_INT:
+#if defined(ENABLE_SOFTFLOAT)
+                       case TYPE_FLT:
+#endif
+                       case TYPE_ADR:
+                               s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                               M_IST_INTERN(s1, REG_ITMP3, 0);
+                               break;
+                       case TYPE_LNG:
+#if defined(ENABLE_SOFTFLOAT)
+                       case TYPE_DBL:
+#endif
+                               s1 = emit_load_s1(jd, iptr, REG_ITMP12_PACKED);
+                               M_LST_INTERN(s1, REG_ITMP3, 0);
+                               break;
+#if !defined(ENABLE_SOFTFLOAT)
+                       case TYPE_FLT:
+                               s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                               M_FST_INTERN(s1, REG_ITMP3, 0);
+                               break;
+                       case TYPE_DBL:
+                               s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                               M_DST_INTERN(s1, REG_ITMP3, 0);
+                               break;
+#endif
+                       default:
+                               assert(0);
+                       }
+                       break;
+
+               case ICMD_GETFIELD:   /* ..., objectref, value  ==> ...               */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP3);
+                       gen_nullptr_check(s1);
+#if !defined(ENABLE_SOFTFLOAT)
+                       /* HACK: softnull checks on floats */
+                       if (!checknull && IS_FLT_DBL_TYPE(fieldtype))
+                               gen_nullptr_check_intern(s1);
+#endif
+
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               unresolved_field *uf = iptr->sx.s23.s3.uf;
+
+                               fieldtype = uf->fieldref->parseddesc.fd->type;
+
+                               codegen_addpatchref(cd, PATCHER_get_putfield,
+                                                                       iptr->sx.s23.s3.uf, 0);
+
+                               if (opt_showdisassemble)
+                                       M_NOP;
+
+                               disp = 0;
+                       }
+                       else {
+                               fieldinfo *fi = iptr->sx.s23.s3.fmiref->p.field;
+
+                               fieldtype = fi->type;
+                               disp      = fi->offset;
+                       }
+
+                       switch (fieldtype) {
+                       case TYPE_INT:
+#if defined(ENABLE_SOFTFLOAT)
+                       case TYPE_FLT:
+#endif
+                       case TYPE_ADR:
+                               d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                               M_ILD(d, s1, disp);
+                               break;
+                       case TYPE_LNG:
+#if defined(ENABLE_SOFTFLOAT)
+                       case TYPE_DBL:
+#endif
+                               d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+                               M_LLD(d, s1, disp);
+                               break;
+#if !defined(ENABLE_SOFTFLOAT)
+                       case TYPE_FLT:
+                               d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                               M_FLD(d, s1, disp);
+                               break;
+                       case TYPE_DBL:
+                               d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                               M_DLD(d, s1, disp);
+                               break;
+#endif
+                       default:
+                               assert(0);
+                       }
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_PUTFIELD:   /* ..., objectref, value  ==> ...               */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP3);
+                       gen_nullptr_check(s1);
+
+#if !defined(ENABLE_SOFTFLOAT)
+                       /* HACK: softnull checks on floats */
+                       if (!checknull && IS_FLT_DBL_TYPE(fieldtype))
+                               gen_nullptr_check_intern(s1);
+#endif
+
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               unresolved_field *uf = iptr->sx.s23.s3.uf;
+
+                               fieldtype = uf->fieldref->parseddesc.fd->type;
+                       }
+                       else {
+                               fieldinfo *fi = iptr->sx.s23.s3.fmiref->p.field;
+
+                               fieldtype = fi->type;
+                               disp      = fi->offset;
+                       }
+
+                       switch (fieldtype) {
+                       case TYPE_INT:
+#if defined(ENABLE_SOFTFLOAT)
+                       case TYPE_FLT:
+#endif
+                       case TYPE_ADR:
+                               s2 = emit_load_s2(jd, iptr, REG_ITMP1);
+                               break;
+#if defined(ENABLE_SOFTFLOAT)
+                       case TYPE_DBL: /* fall through */
+#endif
+                       case TYPE_LNG:
+                               s2 = emit_load_s2(jd, iptr, REG_ITMP12_PACKED);
+                               break;
+#if !defined(ENABLE_SOFTFLOAT)
+                       case TYPE_FLT:
+                       case TYPE_DBL:
+                               s2 = emit_load_s2(jd, iptr, REG_FTMP1);
+                               break;
+#endif
+                       default:
+                               assert(0);
+                       }
+
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               unresolved_field *uf = iptr->sx.s23.s3.uf;
+
+                               codegen_addpatchref(cd, PATCHER_get_putfield, uf, 0);
+
+                               if (opt_showdisassemble)
+                                       M_NOP;
+
+                               disp = 0;
+                       }
+
+                       switch (fieldtype) {
+                       case TYPE_INT:
+#if defined(ENABLE_SOFTFLOAT)
+                       case TYPE_FLT:
+#endif
+                       case TYPE_ADR:
+                               M_IST(s2, s1, disp);
+                               break;
+                       case TYPE_LNG:
+#if defined(ENABLE_SOFTFLOAT)
+                       case TYPE_DBL:
+#endif
+                               M_LST(s2, s1, disp);
+                               break;
+#if !defined(ENABLE_SOFTFLOAT)
+                       case TYPE_FLT:
+                               M_FST(s2, s1, disp);
+                               break;
+                       case TYPE_DBL:
+                               M_DST(s2, s1, disp);
+                               break;
+#endif
+                       default:
+                               assert(0);
+                       }
+                       break;
+
+
+               /* branch operations **************************************************/
+
+               case ICMD_ATHROW:       /* ..., objectref ==> ... (, objectref)       */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       M_INTMOVE(s1, REG_ITMP1_XPTR);
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               codegen_addpatchref(cd, PATCHER_athrow_areturn,
+                                                                       iptr->sx.s23.s2.uc, 0);
+
+                               if (opt_showdisassemble)
+                                       M_NOP;
+                       }
+                       disp = dseg_add_functionptr(cd, asm_handle_exception);
+                       M_DSEG_LOAD(REG_ITMP3, disp);
+                       M_MOV(REG_ITMP2_XPC, REG_PC);
+                       M_MOV(REG_PC, REG_ITMP3);
+                       M_NOP;              /* nop ensures that XPC is less than the end  */
+                                           /* of basic block                             */
+                       break;
+
+               case ICMD_GOTO:         /* ... ==> ...                                */
+               case ICMD_RET:
+
+                       M_B(0);
+                       codegen_addreference(cd, iptr->dst.block);
+                       break;
+
+               case ICMD_JSR:          /* ... ==> ...                                */
+
+                       M_B(0);
+                       codegen_addreference(cd, iptr->sx.s23.s3.jsrtarget.block);
+                       break;
+               
+               case ICMD_IFNULL:       /* ..., value ==> ...                         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       M_TEQ_IMM(s1, 0);
+                       M_BEQ(0);
+                       codegen_addreference(cd, iptr->dst.block);
+                       break;
+
+               case ICMD_IFNONNULL:    /* ..., value ==> ...                         */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       M_TEQ_IMM(s1, 0);
+                       M_BNE(0);
+                       codegen_addreference(cd, iptr->dst.block);
+                       break;
+
+               case ICMD_IFLT:         /* ..., value ==> ...                         */
+               case ICMD_IFLE:         /* op1 = target JavaVM pc, val.i = constant   */
+               case ICMD_IFGT:
+               case ICMD_IFGE:
+               case ICMD_IFEQ:
+               case ICMD_IFNE:
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       M_COMPARE(s1, iptr->sx.val.i, UNCOND, 0);
+
+                       switch(iptr->opc) {
+                       case ICMD_IFLT:
+                               M_BLT(0);
+                               break;
+                       case ICMD_IFLE:
+                               M_BLE(0);
+                               break;
+                       case ICMD_IFGT:
+                               M_BGT(0);
+                               break;
+                       case ICMD_IFGE:
+                               M_BGE(0);
+                               break;
+                       case ICMD_IFEQ:
+                               M_BEQ(0);
+                               break;
+                       case ICMD_IFNE:
+                               M_BNE(0);
+                               break;
+                       default:
+                               assert(0);
+                       }
+                       codegen_addreference(cd, iptr->dst.block);
+                       break;
+
+               case ICMD_IF_LLT:       /* ..., value ==> ...                         */
+               case ICMD_IF_LLE:       /* op1 = target JavaVM pc, val.l = constant   */
+               case ICMD_IF_LGT:
+               case ICMD_IF_LGE:
+               case ICMD_IF_LEQ:
+               case ICMD_IF_LNE:
+
+                       /* ATTENTION: compare high words signed and low words unsigned */
+
+                       s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
+                       M_COMPARE(s1, (iptr->sx.val.l >> 32), UNCOND, 0);
+
+                       switch(iptr->opc) {
+                       case ICMD_IF_LLT:
+                       case ICMD_IF_LLE:
+                               M_BLT(0);
+                               codegen_addreference(cd, iptr->dst.block);
+                               break;
+                       case ICMD_IF_LGT:
+                       case ICMD_IF_LGE:
+                               M_BGT(0);
+                               codegen_addreference(cd, iptr->dst.block);
+                               break;
+                       case ICMD_IF_LEQ: /* EQ and NE are the same for unsigned */
+                       case ICMD_IF_LNE:
+                               break;
+                       default:
+                               assert(0);
+                       }
+
+                       s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
+
+                       switch(iptr->opc) {
+                       case ICMD_IF_LLT:
+                               M_COMPARE(s1, (iptr->sx.val.l & 0xffffffff), COND_EQ, 1);
+                               M_BLO(0);
+                               break;
+                       case ICMD_IF_LLE:
+                               M_COMPARE(s1, (iptr->sx.val.l & 0xffffffff), COND_EQ, 1);
+                               M_BLS(0);
+                               break;
+                       case ICMD_IF_LGT:
+                               M_COMPARE(s1, (iptr->sx.val.l & 0xffffffff), COND_EQ, 1);
+                               M_BHI(0);
+                               break;
+                       case ICMD_IF_LGE:
+                               M_COMPARE(s1, (iptr->sx.val.l & 0xffffffff), COND_EQ, 1);
+                               M_BHS(0);
+                               break;
+                       case ICMD_IF_LEQ:
+                               M_COMPARE(s1, (iptr->sx.val.l & 0xffffffff), COND_EQ, 0);
+                               M_BEQ(0);
+                               break;
+                       case ICMD_IF_LNE:
+                               M_COMPARE(s1, (iptr->sx.val.l & 0xffffffff), COND_EQ, 0);
+                               M_BNE(0);
+                               break;
+                       default:
+                               assert(0);
+                       }
+                       codegen_addreference(cd, iptr->dst.block);
+                       break;
+
+               case ICMD_IF_ICMPEQ:    /* ..., value, value ==> ...                  */
+               case ICMD_IF_ACMPEQ:    /* op1 = target JavaVM pc                     */
+               case ICMD_IF_ICMPNE:
+               case ICMD_IF_ACMPNE:
+               case ICMD_IF_ICMPLT:
+               case ICMD_IF_ICMPLE:
+               case ICMD_IF_ICMPGT:
+               case ICMD_IF_ICMPGE:
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+                       M_CMP(s1, s2);
+                       switch(iptr->opc) {
+                       case ICMD_IF_ICMPLT:
+                               M_BLT(0);
+                               break;
+                       case ICMD_IF_ICMPLE:
+                               M_BLE(0);
+                               break;
+                       case ICMD_IF_ICMPGT:
+                               M_BGT(0);
+                               break;
+                       case ICMD_IF_ICMPGE:
+                               M_BGE(0);
+                               break;
+                       case ICMD_IF_ICMPEQ:
+                       case ICMD_IF_ACMPEQ:
+                               M_BEQ(0);
+                               break;
+                       case ICMD_IF_ICMPNE:
+                       case ICMD_IF_ACMPNE:
+                               M_BNE(0);
+                               break;
+                       default:
+                               assert(0);
+                       }
+                       codegen_addreference(cd, iptr->dst.block);
+                       break;
+
+               case ICMD_IF_LCMPEQ:    /* ..., value, value ==> ...                  */
+               case ICMD_IF_LCMPNE:    /* op1 = target JavaVM pc                     */
+               case ICMD_IF_LCMPLT:
+               case ICMD_IF_LCMPLE:
+               case ICMD_IF_LCMPGT:
+               case ICMD_IF_LCMPGE:
+
+                       /* ATTENTION: compare high words signed and low words unsigned */
+                       s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2_high(jd, iptr, REG_ITMP2);
+                       M_CMP(s1, s2);
+
+                       switch(iptr->opc) {
+                       case ICMD_IF_LCMPEQ: /* EQ and NE are the same for unsigned */
+                       case ICMD_IF_LCMPNE:
+                               break;
+                       case ICMD_IF_LCMPLT:
+                       case ICMD_IF_LCMPLE:
+                               M_BLT(0);
+                               codegen_addreference(cd, iptr->dst.block);
+                               break;
+                       case ICMD_IF_LCMPGT:
+                       case ICMD_IF_LCMPGE:
+                               M_BGT(0);
+                               codegen_addreference(cd, iptr->dst.block);
+                               break;
+                       default:
+                               assert(0);
+                       }
+
+                       s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
+                       s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
+
+                       switch(iptr->opc) {
+                       case ICMD_IF_LCMPEQ:
+                               M_DAT(COND_EQ,0x0a,0,s1,1,0,s2);
+                               M_BEQ(0);
+                               break;
+                       case ICMD_IF_LCMPNE:
+                               M_DAT(COND_EQ,0x0a,0,s1,1,0,s2);
+                               M_BNE(0);
+                               break;
+                       case ICMD_IF_LCMPLT:
+                               M_BNE(1);
+                               M_CMP(s1, s2);
+                               M_BLO(0);
+                               break;
+                       case ICMD_IF_LCMPLE:
+                               M_BNE(1);
+                               M_CMP(s1, s2);
+                               M_BLS(0);
+                               break;
+                       case ICMD_IF_LCMPGT:
+                               M_BNE(1);
+                               M_CMP(s1, s2);
+                               M_BHI(0);
+                               break;
+                       case ICMD_IF_LCMPGE:
+                               M_BNE(1);
+                               M_CMP(s1, s2);
+                               M_BHS(0);
+                               break;
+                       default:
+                               assert(0);
+                       }
+                       codegen_addreference(cd, iptr->dst.block);
+                       break;
+
+               case ICMD_TABLESWITCH:  /* ..., index ==> ...                         */
+                       {
+                       s4 i, l;
+                       branch_target_t *table;
+
+                       table = iptr->dst.table;
+
+                       l = iptr->sx.s23.s2.tablelow;
+                       i = iptr->sx.s23.s3.tablehigh;
+
+                       /* calculate new index (index - low) */
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       if (l  == 0) {
+                               M_INTMOVE(s1, REG_ITMP1);
+                       } else if (IS_IMM(l)) {
+                               M_SUB_IMM(REG_ITMP1, s1, l);
+                       } else {
+                               ICONST(REG_ITMP2, l);
+                               M_SUB(REG_ITMP1, s1, REG_ITMP2);
+                       }
+
+                       /* range check (index <= high-low) */
+                       i = i - l + 1;
+                       M_COMPARE(REG_ITMP1, i-1, UNCOND, 0);
+                       M_BHI(0); /* unsigned greater than */
+                       codegen_addreference(cd, table[0].block);
+
+                       /* build jump table top down and use address of lowest entry */
+
+                       table += i;
+
+                       while (--i >= 0) {
+                               dseg_add_target(cd, table->block);
+                               --table;
+                       }
+                       }
+
+                       /* length of dataseg after last dseg_add_target is used by load */
+                       /* TODO: this loads from data-segment */
+                       M_ADD(REG_ITMP2, REG_IP, REG_LSL(REG_ITMP1, 2));
+                       M_LDR(REG_PC, REG_ITMP2, -(cd->dseglen));
+                       break;
+
+               case ICMD_LOOKUPSWITCH: /* ..., key ==> ...                           */
+                       {
+                       s4 i;
+                       lookup_target_t *lookup;
+
+                       lookup = iptr->dst.lookup;
+
+                       i = iptr->sx.s23.s2.lookupcount;
+                       
+                       /* compare keys */
+                       MCODECHECK((i<<2)+8);
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+
+                       while (--i >= 0) {
+                               M_COMPARE(s1, lookup->value, UNCOND, 0);
+                               M_BEQ(0);
+                               codegen_addreference(cd, lookup->target.block);
+                               lookup++;
+                       }
+
+                       /* default branch */
+                       M_B(0);
+                       codegen_addreference(cd, iptr->sx.s23.s3.lookupdefault.block);
+                       }
+                       break;
+
+               case ICMD_FRETURN:      /* ..., retvalue ==> ...                      */
+
+#if !defined(ENABLE_SOFTFLOAT)
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       M_CAST_FLT_TO_INT_TYPED(VAROP(iptr->s1)->type, s1, REG_RESULT);
+                       goto ICMD_RETURN_do;
+#endif
+
+               case ICMD_IRETURN:      /* ..., retvalue ==> ...                      */
+
+                       s1 = emit_load_s1(jd, iptr, REG_RESULT);
+                       M_INTMOVE(s1, REG_RESULT);
+                       goto ICMD_RETURN_do;
+
+               case ICMD_DRETURN:      /* ..., retvalue ==> ...                      */
+
+#if !defined(ENABLE_SOFTFLOAT)
+                       s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+                       M_CAST_FLT_TO_INT_TYPED(VAROP(iptr->s1)->type, s1, REG_RESULT_PACKED);
+                       goto ICMD_RETURN_do;
+#endif
+
+               case ICMD_LRETURN:      /* ..., retvalue ==> ...                      */
+
+                       s1 = emit_load_s1(jd, iptr, REG_RESULT_PACKED);
+                       M_LNGMOVE(s1, REG_RESULT_PACKED);
+                       goto ICMD_RETURN_do;
+
+               case ICMD_ARETURN:      /* ..., retvalue ==> ...                      */
+
+                       s1 = emit_load_s1(jd, iptr, REG_RESULT);
+                       M_INTMOVE(s1, REG_RESULT);
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               codegen_addpatchref(cd, PATCHER_athrow_areturn,
+                                                                       iptr->sx.s23.s2.uc, 0);
+
+                               if (opt_showdisassemble)
+                                       M_NOP;
+                       }
+                       goto ICMD_RETURN_do;
+
+               case ICMD_RETURN:       /* ...  ==> ...                               */
+                       ICMD_RETURN_do:
+
+#if !defined(NDEBUG)
+                       if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
+                               emit_verbosecall_exit(jd);
+#endif
+
+#if defined(ENABLE_THREADS)
+                       /* call monitorexit function */
+
+                       if (checksync && (m->flags & ACC_SYNCHRONIZED)) {
+                               /* stack offset for monitor argument */
+
+                               s1 = rd->memuse;
+
+                               /* we need to save the proper return value */
+
+                               switch (iptr->opc) {
+                               case ICMD_IRETURN:
+                               case ICMD_ARETURN:
+                               case ICMD_LRETURN:
+                               case ICMD_FRETURN: /* XXX TWISTI: is that correct? */
+                               case ICMD_DRETURN:
+                                       M_STMFD(BITMASK_RESULT, REG_SP);
+                                       s1 += 2;
+                                       break;
+                               }
+
+                               M_LDR(REG_A0, REG_SP, s1 * 4);
+                               disp = dseg_add_functionptr(cd, LOCK_monitor_exit);
+                               M_DSEG_BRANCH(disp);
+
+                               /* we no longer need IP here, no more loading */
+                               /*s1 = (s4) (cd->mcodeptr - cd->mcodebase);
+                               M_RECOMPUTE_IP(s1);*/
+
+                               switch (iptr->opc) {
+                               case ICMD_IRETURN:
+                               case ICMD_ARETURN:
+                               case ICMD_LRETURN:
+                               case ICMD_FRETURN: /* XXX TWISTI: is that correct? */
+                               case ICMD_DRETURN:
+                                       M_LDMFD(BITMASK_RESULT, REG_SP);
+                                       break;
+                               }
+                       }
+#endif
+
+                       /* deallocate stackframe for spilled variables */
+                       if (spilledregs_num) {
+                               M_ADD_IMM_EXT_MUL4(REG_SP, REG_SP, spilledregs_num);
+                       }
+
+                       /* restore callee saved registers + do return */
+                       if (savedregs_bitmask) {
+                               if (!jd->isleafmethod) {
+                                       savedregs_bitmask &= ~(1<<REG_LR);
+                                       savedregs_bitmask |= (1<<REG_PC);
+                               }
+                               M_LDMFD(savedregs_bitmask, REG_SP);
+                       }
+
+                       /* if LR was not on stack, we need to return manually */
+                       if (jd->isleafmethod)
+                               M_MOV(REG_PC, REG_LR);
+                       break;
+
+               case ICMD_BUILTIN:      /* ..., arg1, arg2, arg3 ==> ...              */
+
+                       bte = iptr->sx.s23.s3.bte;
+                       md  = bte->md;
+                       goto ICMD_INVOKE_do;
+
+               case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ...            */
+               case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */
+               case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer    */
+               case ICMD_INVOKEINTERFACE:
+
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               lm = NULL;
+                               um = iptr->sx.s23.s3.um;
+                               md = um->methodref->parseddesc.md;
+                       }
+                       else {
+                               lm = iptr->sx.s23.s3.fmiref->p.method;
+                               um = NULL;
+                               md = lm->parseddesc;
+                       }
+
+               ICMD_INVOKE_do:
+                       /* copy arguments to registers or stack location */
+
+                       s3 = md->paramcount;
+
+                       MCODECHECK((s3 << 1) + 64);
+
+                       for (s3 = s3 - 1; s3 >= 0; s3--) {
+                               var = VAR(iptr->sx.s23.s2.args[s3]);
+
+                               if (var->flags & PREALLOC) /* argument was precolored? */
+                                       continue;
+
+                               /* TODO: document me */
+#if !defined(ENABLE_SOFTFLOAT)
+                               if (IS_INT_LNG_TYPE(var->type)) {
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+                                       if (!md->params[s3].inmemory) {
+                                               s1 = ARGUMENT_REGS(var->type, md->params[s3].regoff);
+                                               SPLIT_OPEN(var->type, s1, REG_ITMP2);
+                                               d = emit_load(jd, iptr, var, s1);
+
+                                               if (IS_2_WORD_TYPE(var->type))
+                                                       M_LNGMOVE(d, s1);
+                                               else
+                                                       M_INTMOVE(d, s1);
+
+                                               SPLIT_STORE_AND_CLOSE(var->type, s1, 0);
+                                       }
+                                       else {
+                                               if (IS_2_WORD_TYPE(var->type)) {
+                                                       d = emit_load(jd, iptr, var, REG_ITMP12_PACKED);
+                                                       M_LST(d, REG_SP, md->params[s3].regoff * 4);
+                                               }
+                                               else {
+                                                       d = emit_load(jd, iptr, var, REG_ITMP1);
+                                                       M_IST(d, REG_SP, md->params[s3].regoff * 4);
+                                               }
+                                       }
+#if !defined(ENABLE_SOFTFLOAT)
+                               }
+                               else {
+                                       if (!md->params[s3].inmemory) {
+                                               s1 = ARGUMENT_REGS(var->type, md->params[s3].regoff);
+                                               d = emit_load(jd, iptr, var, REG_FTMP1);
+                                               SPLIT_OPEN(var->type, s1, REG_ITMP1);
+                                               M_CAST_FLT_TO_INT_TYPED(var->type, d, s1);
+                                               SPLIT_STORE_AND_CLOSE(var->type, s1, 0);
+                                       }
+                                       else {
+                                               d = emit_load(jd, iptr, var, REG_FTMP1);
+                                               M_STACK_STORE_FLT_TYPED(var->type, d, md->params[s3].regoff);
+                                       }
+                               }
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+                       }
+
+                       switch (iptr->opc) {
+                       case ICMD_BUILTIN:
+                               disp = dseg_add_functionptr(cd, bte->fp);
+
+                               M_DSEG_LOAD(REG_IP, disp); /* Pointer to built-in-function */
+                               break;
+
+                       case ICMD_INVOKESPECIAL:
+                               M_TST(REG_A0, REG_A0);
+                               M_BEQ(0);
+                               codegen_add_nullpointerexception_ref(cd);
+                               /* fall through */
+
+                       case ICMD_INVOKESTATIC:
+                               if (lm == NULL) {
+                                       disp = dseg_add_unique_address(cd, NULL);
+
+                                       codegen_addpatchref(cd, PATCHER_invokestatic_special,
+                                                                               um, disp);
+
+                                       if (opt_showdisassemble)
+                                               M_NOP;
+                               }
+                               else
+                                       disp = dseg_add_address(cd, lm->stubroutine);
+
+                               M_DSEG_LOAD(REG_IP, disp);            /* Pointer to method */
+                               break;
+
+                       case ICMD_INVOKEVIRTUAL:
+                               gen_nullptr_check(REG_A0);
+
+                               if (lm == NULL) {
+                                       codegen_addpatchref(cd, PATCHER_invokevirtual, um, 0);
+
+                                       if (opt_showdisassemble)
+                                               M_NOP;
+
+                                       s1 = 0;
+                               }
+                               else
+                                       s1 = OFFSET(vftbl_t, table[0]) +
+                                               sizeof(methodptr) * lm->vftblindex;
+
+                               M_LDR_INTERN(REG_METHODPTR, REG_A0,
+                                                        OFFSET(java_objectheader, vftbl));
+                               M_LDR_INTERN(REG_IP, REG_METHODPTR, s1);
+                               break;
+
+                       case ICMD_INVOKEINTERFACE:
+                               gen_nullptr_check(REG_A0);
+
+                               if (lm == NULL) {
+                                       codegen_addpatchref(cd, PATCHER_invokeinterface, um, 0);
+
+                                       if (opt_showdisassemble)
+                                               M_NOP;
+
+                                       s1 = 0;
+                                       s2 = 0;
+                               }
+                               else {
+                                       s1 = OFFSET(vftbl_t, interfacetable[0]) -
+                                               sizeof(methodptr*) * lm->class->index;
+                                       s2 = sizeof(methodptr) * (lm - lm->class->methods);
+                               }
+
+                               M_LDR_INTERN(REG_METHODPTR, REG_A0,
+                                                        OFFSET(java_objectheader, vftbl));
+                               M_LDR_INTERN(REG_METHODPTR, REG_METHODPTR, s1);
+                               M_LDR_INTERN(REG_IP, REG_METHODPTR, s2);
+                               break;
+                       }
+
+                       /* generate the actual call */
+
+                       M_MOV(REG_LR, REG_PC);               /* save return address in LR */
+                       M_MOV(REG_PC, REG_IP);               /* branch to method          */
+                       s1 = (s4) (cd->mcodeptr - cd->mcodebase);
+                       M_RECOMPUTE_IP(s1);
+
+                       /* actually only used for ICMD_BUILTIN */
+
+                       if (INSTRUCTION_MUST_CHECK(iptr)) {
+                               M_TST(REG_RESULT, REG_RESULT);
+                               M_BEQ(0);
+                               codegen_add_fillinstacktrace_ref(cd);
+                       }
+
+                       /* store return value */
+
+                       d = md->returntype.type;
+
+#if !defined(__SOFTFP__)
+                       /* TODO: this is only a hack, since we use R0/R1 for float
+                          return!  this depends on gcc; it is independent from
+                          our ENABLE_SOFTFLOAT define */
+                       if (iptr->opc == ICMD_BUILTIN && d != TYPE_VOID && IS_FLT_DBL_TYPE(d)) {
+#if 0 && !defined(NDEBUG)
+                               dolog("BUILTIN that returns float or double (%s.%s)", m->class->name->text, m->name->text);
+#endif
+                               /* we cannot use this macro, since it is not defined
+                                  in ENABLE_SOFTFLOAT M_CAST_FLT_TO_INT_TYPED(d,
+                                  REG_FRESULT, REG_RESULT_TYPED(d)); */
+                               if (IS_2_WORD_TYPE(d)) {
+                                       DCD(0xed2d8102); /* stfd    f0, [sp, #-8]! */
+                                       M_LDRD_UPDATE(REG_RESULT_PACKED, REG_SP, 8);
+                               } else {
+                                       DCD(0xed2d0101); /* stfs    f0, [sp, #-4]!*/
+                                       M_LDR_UPDATE(REG_RESULT, REG_SP, 4);
+                               }
+                       }
+#endif
+
+                       if (d != TYPE_VOID) {
+#if !defined(ENABLE_SOFTFLOAT)
+                               if (IS_INT_LNG_TYPE(d)) {
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+                                       if (IS_2_WORD_TYPE(d)) {
+                                               s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT_PACKED);
+                                               M_LNGMOVE(REG_RESULT_PACKED, s1);
+                                       }
+                                       else {
+                                               s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT);
+                                               M_INTMOVE(REG_RESULT, s1);
+                                       }
+
+#if !defined(ENABLE_SOFTFLOAT)
+                               } else {
+                                       s1 = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+                                       M_CAST_INT_TO_FLT_TYPED(VAROP(iptr->dst)->type, REG_RESULT_TYPED(VAROP(iptr->dst)->type), s1);
+                               }
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+
+                               emit_store_dst(jd, iptr, s1);
+                       }
+                       break;
+
+               case ICMD_CHECKCAST:  /* ..., objectref ==> ..., objectref            */
+                                     /* val.a: (classinfo*) superclass               */
+                       if (!(iptr->flags.bits & INS_FLAG_ARRAY)) {
+                               /* object type cast-check */
+
+                       classinfo *super;
+                       s4         superindex;
+                       u1        *branch1 = NULL;
+                       u1        *branch2 = NULL;
+                       u1        *branch3 = NULL;
+
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               super      = NULL;
+                               superindex = 0;
+                       }
+                       else {
+                               super      = iptr->sx.s23.s3.c.cls;
+                               superindex = super->index;
+                       }
+
+#if defined(ENABLE_THREADS)
+                       codegen_threadcritrestart(cd, cd->mcodeptr - cd->mcodebase);
+#endif
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+
+                       /* if class is not resolved, check which code to call */
+
+                       if (super == NULL) {
+                               M_TST(s1, s1);
+                               M_BEQ(0);
+                               branch1 = cd->mcodeptr;
+
+                               disp = dseg_add_unique_s4(cd, 0); /* super->flags */
+                               codegen_addpatchref(cd, PATCHER_checkcast_instanceof_flags,
+                                                   iptr->sx.s23.s3.c.ref, disp);
+
+                               if (opt_showdisassemble)
+                                       M_NOP;
+
+                               M_DSEG_LOAD(REG_ITMP2, disp);
+                               disp = dseg_add_s4(cd, ACC_INTERFACE);
+                               M_DSEG_LOAD(REG_ITMP3, disp);
+                               M_TST(REG_ITMP2, REG_ITMP3);
+                               M_BEQ(0);
+                               branch2 = cd->mcodeptr;
+                       }
+
+                       /* interface checkcast code */
+
+                       if ((super == NULL) || (super->flags & ACC_INTERFACE)) {
+                               if (super == NULL) {
+                                       codegen_addpatchref(cd,
+                                                           PATCHER_checkcast_instanceof_interface,
+                                                           iptr->sx.s23.s3.c.ref, 0);
+
+                                       if (opt_showdisassemble)
+                                               M_NOP;
+                               }
+                               else {
+                                       M_TST(s1, s1);
+                                       M_BEQ(0);
+                                       branch1 = cd->mcodeptr;
+                               }
+
+                               M_LDR_INTERN(REG_ITMP2, s1, OFFSET(java_objectheader, vftbl));
+                               M_LDR_INTERN(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, interfacetablelength));
+                               assert(IS_IMM(superindex));
+                               M_CMP_IMM(REG_ITMP3, superindex);
+                               M_BLE(0);
+                               codegen_add_classcastexception_ref(cd, s1);
+
+                               s2 = OFFSET(vftbl_t, interfacetable[0]) -
+                                       superindex * sizeof(methodptr*);
+
+                               M_LDR_INTERN(REG_ITMP3, REG_ITMP2, s2);
+                               M_TST(REG_ITMP3, REG_ITMP3);
+                               M_BEQ(0);
+                               codegen_add_classcastexception_ref(cd, s1);
+
+                               if (super == NULL) {
+                                       M_B(0);
+                                       branch3 = cd->mcodeptr;
+                               }
+                       }
+
+                       if (branch2) {
+                               gen_resolvebranch(branch2, branch2 - cd->mcodebase,
+                                                                 cd->mcodeptr - cd->mcodebase);
+                       }
+
+                       /* class checkcast code */
+
+
+                       if ((super == NULL) || !(super->flags & ACC_INTERFACE)) {
+                               if (super == NULL) {
+                                       disp = dseg_add_unique_address(cd, NULL);
+
+                                       codegen_addpatchref(cd, PATCHER_checkcast_instanceof_class,
+                                                           iptr->sx.s23.s3.c.ref,
+                                                                               disp);
+
+                                       if (opt_showdisassemble)
+                                               M_NOP;
+                               }
+                               else {
+                                       disp = dseg_add_address(cd, super->vftbl);
+
+                                       M_TST(s1, s1);
+                                       M_BEQ(0);
+                                       branch1 = cd->mcodeptr;
+                               }
+
+                               M_LDR_INTERN(REG_ITMP2, s1, OFFSET(java_objectheader, vftbl));
+                               M_DSEG_LOAD(REG_ITMP3, disp);
+#if defined(ENABLE_THREADS)
+                               codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase);
+#endif
+                               M_LDR_INTERN(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
+                               M_LDR_INTERN(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval));
+                               M_SUB(REG_ITMP2, REG_ITMP2, REG_ITMP3);
+                               M_DSEG_LOAD(REG_ITMP3, disp);
+                               M_LDR_INTERN(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval));
+#if defined(ENABLE_THREADS)
+                               codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase);
+#endif
+                               M_CMP(REG_ITMP2, REG_ITMP3);
+                               M_BHI(0);
+                               codegen_add_classcastexception_ref(cd, s1);
+                       }
+
+                       if (branch1) {
+                               gen_resolvebranch(branch1, branch1 - cd->mcodebase,
+                                                                 cd->mcodeptr - cd->mcodebase);
+                       }
+
+                       if (branch3) {
+                               gen_resolvebranch(branch3, branch3 - cd->mcodebase,
+                                                                 cd->mcodeptr - cd->mcodebase);
+                       }
+
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+                       }
+                       else {
+                               /* array type cast-check */
+
+                               s1 = emit_load_s1(jd, iptr, REG_A0);
+                               M_INTMOVE(s1, REG_A0);
+
+                               if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                                       disp = dseg_add_unique_address(cd, NULL);
+
+                                       codegen_addpatchref(cd, PATCHER_builtin_arraycheckcast,
+                                                                               iptr->sx.s23.s3.c.ref,
+                                                                               disp);
+
+                                       if (opt_showdisassemble)
+                                               M_NOP;
+                               }
+                               else
+                                       disp = dseg_add_address(cd, iptr->sx.s23.s3.c.cls);
+
+                               M_DSEG_LOAD(REG_A1, disp);
+                               disp = dseg_add_functionptr(cd, BUILTIN_arraycheckcast);
+                               M_DSEG_BRANCH(disp);
+
+                               /* recompute ip */
+                               disp = (s4) (cd->mcodeptr - cd->mcodebase);
+                               M_RECOMPUTE_IP(disp);
+
+                               s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                               M_TST(REG_RESULT, REG_RESULT);
+                               M_BEQ(0);
+                               codegen_add_classcastexception_ref(cd, s1);
+
+                               d = codegen_reg_of_dst(jd, iptr, s1);
+                       }
+
+                       M_INTMOVE(s1, d);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult            */
+                                     /* val.a: (classinfo*) superclass               */
+                       {
+                       classinfo *super;
+                       s4         superindex;
+                       u1        *branch1 = NULL;
+                       u1        *branch2 = NULL;
+                       u1        *branch3 = NULL;
+
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               super      = NULL;
+                               superindex = 0;
+                       }
+                       else {
+                               super      = iptr->sx.s23.s3.c.cls;
+                               superindex = super->index;
+                       }
+
+#if defined(ENABLE_THREADS)
+                       codegen_threadcritrestart(cd, cd->mcodeptr - cd->mcodebase);
+#endif
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+                       if (s1 == d) {
+                               M_MOV(REG_ITMP1, s1);
+                               s1 = REG_ITMP1;
+                       }
+
+                       /* if class is not resolved, check which code to call */
+
+                       if (super == NULL) {
+                               M_EOR(d, d, d);
+                               M_TST(s1, s1);
+                               M_BEQ(0);
+                               branch1 = cd->mcodeptr;
+
+                               disp = dseg_add_unique_s4(cd, 0); /* super->flags */
+                               codegen_addpatchref(cd, PATCHER_checkcast_instanceof_flags,
+                                                   iptr->sx.s23.s3.c.ref, disp);
+
+                               if (opt_showdisassemble)
+                                       M_NOP;
+
+                               M_DSEG_LOAD(REG_ITMP2, disp);
+                               disp = dseg_add_s4(cd, ACC_INTERFACE);
+                               M_DSEG_LOAD(REG_ITMP3, disp);
+                               M_TST(REG_ITMP2, REG_ITMP3);
+                               M_BEQ(0);
+                               branch2 = cd->mcodeptr;
+                       }
+
+                       /* interface checkcast code */
+
+                       if ((super == NULL) || (super->flags & ACC_INTERFACE)) {
+                               if (super == NULL) {
+                                       /* If d == REG_ITMP2, then it's destroyed in check
+                                          code above.  */
+                                       if (d == REG_ITMP2)
+                                               M_EOR(d, d, d);
+
+                                       codegen_addpatchref(cd,
+                                                           PATCHER_checkcast_instanceof_interface,
+                                                           iptr->sx.s23.s3.c.ref, 0);
+
+                                       if (opt_showdisassemble)
+                                               M_NOP;
+                               }
+                               else {
+                                       M_EOR(d, d, d);
+                                       M_TST(s1, s1);
+                                       M_BEQ(0);
+                                       branch1 = cd->mcodeptr;
+                               }
+
+                               M_LDR_INTERN(REG_ITMP1, s1, OFFSET(java_objectheader, vftbl));
+                               M_LDR_INTERN(REG_ITMP3,
+                                                        REG_ITMP1, OFFSET(vftbl_t, interfacetablelength));
+                               assert(IS_IMM(superindex));
+                               M_CMP_IMM(REG_ITMP3, superindex);
+                               M_BLE(2);
+
+                               s2 = OFFSET(vftbl_t, interfacetable[0]) -
+                                       superindex * sizeof(methodptr*);
+
+                               M_LDR_INTERN(REG_ITMP3, REG_ITMP1, s2);
+                               M_TST(REG_ITMP3, REG_ITMP3);
+                               M_MOVNE_IMM(d, 1);
+
+                               if (super == NULL) {
+                                       M_B(0);
+                                       branch3 = cd->mcodeptr;
+                               }
+                       }
+
+                       if (branch2) {
+                               gen_resolvebranch(branch2, branch2 - cd->mcodebase,
+                                                                 cd->mcodeptr - cd->mcodebase);
+                       }
+
+                       /* class checkcast code */
+
+                       if ((super == NULL) || !(super->flags & ACC_INTERFACE)) {
+                               if (super == NULL) {
+                                       disp = dseg_add_unique_address(cd, NULL);
+
+                                       codegen_addpatchref(cd, PATCHER_checkcast_instanceof_class,
+                                                           iptr->sx.s23.s3.c.ref,
+                                                                               disp);
+
+                                       if (opt_showdisassemble)
+                                               M_NOP;
+                               }
+                               else {
+                                       disp = dseg_add_address(cd, super->vftbl);
+
+                                       M_EOR(d, d, d);
+                                       M_TST(s1, s1);
+                                       M_BEQ(0);
+                                       branch1 = cd->mcodeptr;
+                               }
+
+                               M_LDR_INTERN(REG_ITMP1, s1, OFFSET(java_objectheader, vftbl));
+                               M_DSEG_LOAD(REG_ITMP2, disp);
+#if defined(ENABLE_THREADS)
+                               codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase);
+#endif
+                               M_LDR_INTERN(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval));
+                               M_LDR_INTERN(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, baseval));
+                               M_LDR_INTERN(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, diffval));
+#if defined(ENABLE_THREADS)
+                               codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase);
+#endif
+                               M_SUB(REG_ITMP1, REG_ITMP1, REG_ITMP3);
+                               M_CMP(REG_ITMP1, REG_ITMP2);
+                               /* If d == REG_ITMP2, then it's destroyed */
+                               if (d == REG_ITMP2)
+                                       M_EOR(d, d, d);
+                               M_MOVLS_IMM(d, 1);
+                       }
+
+                       if (branch1) {
+                               gen_resolvebranch(branch1, branch1 - cd->mcodebase,
+                                                                 cd->mcodeptr - cd->mcodebase);
+                       }
+
+                       if (branch3) {
+                               gen_resolvebranch(branch3, branch3 - cd->mcodebase,
+                                                                 cd->mcodeptr - cd->mcodebase);
+                       }
+
+                       }
+
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_MULTIANEWARRAY:/* ..., cnt1, [cnt2, ...] ==> ..., arrayref  */
+
+                       /* copy sizes to stack if necessary  */
+
+                       MCODECHECK((iptr->s1.argcount << 1) + 64);
+
+                       for (s1 = iptr->s1.argcount; --s1 >= 0; ) {
+
+                               var = VAR(iptr->sx.s23.s2.args[s1]);
+       
+                               /* copy SAVEDVAR sizes to stack */
+
+                               if (!(var->flags & PREALLOC)) {
+                                       s2 = emit_load(jd, iptr, var, REG_ITMP1);
+                                       M_STR(s2, REG_SP, s1 * 4);
+                               }
+                       }
+
+                       /* a0 = dimension count */
+
+                       assert(IS_IMM(iptr->s1.argcount));
+                       M_MOV_IMM(REG_A0, iptr->s1.argcount);
+
+                       /* is patcher function set? */
+
+                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                               disp = dseg_add_unique_address(cd, NULL);
+
+                               codegen_addpatchref(cd, PATCHER_builtin_multianewarray,
+                                                                       iptr->sx.s23.s3.c.ref, disp);
+
+                               if (opt_showdisassemble)
+                                       M_NOP;
+                       }
+                       else
+                               disp = dseg_add_address(cd, iptr->sx.s23.s3.c.cls);
+
+                       /* a1 = arraydescriptor */
+
+                       M_DSEG_LOAD(REG_A1, disp);
+
+                       /* a2 = pointer to dimensions = stack pointer */
+
+                       M_INTMOVE(REG_SP, REG_A2);
+
+                       /* call builtin_multianewarray here */
+
+                       disp = dseg_add_functionptr(cd, BUILTIN_multianewarray);
+                       M_DSEG_BRANCH(disp);
+
+                       /* recompute ip (pv) */
+
+                       s1 = (s4) (cd->mcodeptr - cd->mcodebase);
+                       M_RECOMPUTE_IP(s1);
+
+                       /* check for exception before result assignment */
+
+                       M_TST(REG_RESULT, REG_RESULT);
+                       M_BEQ(0);
+                       codegen_add_fillinstacktrace_ref(cd);
+
+                       /* get arrayref */
+
+                       d = codegen_reg_of_dst(jd, iptr, REG_RESULT);
+                       M_INTMOVE(REG_RESULT, d);
+                       emit_store_dst(jd, iptr, d);
+                       break;
+
+               case ICMD_CHECKNULL:  /* ..., objectref  ==> ..., objectref           */
+
+                       s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+                       M_TST(s1, s1);
+                       M_BEQ(0);
+                       codegen_add_nullpointerexception_ref(cd);
+                       break;
+
+               default:
+                       *exceptionptr = new_internalerror("Unknown ICMD %d", iptr->opc);
+                       return false;
+               } /* the big switch */
+
+               } /* for all instructions */
+
+       } /* for all basic blocks */
+
+       dseg_createlinenumbertable(cd);
+
+
+       /* generate exception and patcher stubs */
+
+       emit_exception_stubs(jd);
+       emit_patcher_stubs(jd);
+
+       codegen_finish(jd);
+
+       /* everything's ok */
+
+       return true;
+}
+
+
+/* createcompilerstub **********************************************************
+
+   creates a stub routine which calls the compiler
+
+*******************************************************************************/
+
+#define COMPILERSTUB_DATASIZE    3 * SIZEOF_VOID_P
+#define COMPILERSTUB_CODESIZE    2 * 4
+
+#define COMPILERSTUB_SIZE        COMPILERSTUB_DATASIZE + COMPILERSTUB_CODESIZE
+
+
+u1 *createcompilerstub(methodinfo *m)
+{
+       u1          *s;                     /* memory to hold the stub            */
+       ptrint      *d;
+       codeinfo    *code;
+       codegendata *cd;
+       s4           dumpsize;              /* code generation pointer            */
+
+       s = CNEW(u1, COMPILERSTUB_SIZE);
+
+       /* set data pointer and code pointer */
+
+       d = (ptrint *) s;
+       s = s + COMPILERSTUB_DATASIZE;
+
+       /* mark start of dump memory area */
+
+       dumpsize = dump_size();
+
+       cd = DNEW(codegendata);
+       cd->mcodeptr = s;
+
+       /* Store the codeinfo pointer in the same place as in the
+          methodheader for compiled methods. */
+
+       code = code_codeinfo_new(m);
+
+       d[0] = (ptrint) asm_call_jit_compiler;
+       d[1] = (ptrint) m;
+       d[2] = (ptrint) code;
+
+       /* code for the stub */
+
+       M_LDR_INTERN(REG_ITMP1, REG_PC, -(2 * 4 + 2 * SIZEOF_VOID_P));
+       M_LDR_INTERN(REG_PC, REG_PC, -(3 * 4 + 3 * SIZEOF_VOID_P));
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               count_cstub_len += COMPILERSTUB_SIZE * 4;
+#endif
+
+       /* release dump area */
+
+       dump_release(dumpsize);
+
+       /* synchronize instruction and data cache */
+
+       md_cacheflush(s, cd->mcodeptr - (u1 *) d);
+
+       return s;
+}
+
+
+/* createnativestub ************************************************************
+
+   Creates a stub routine which calls a native method.
+
+*******************************************************************************/
+
+u1 *createnativestub(functionptr f, jitdata *jd, methoddesc *nmd)
+{
+       methodinfo   *m;
+       codeinfo     *code;
+       codegendata  *cd;
+       registerdata *rd;
+       s4            nativeparams;
+       methoddesc   *md;
+       s4            i, j;
+       s4            t;
+       s4            disp, funcdisp, s1, s2;
+
+       /* get required compiler data */
+
+       m    = jd->m;
+       code = jd->code;
+       cd   = jd->cd;
+       rd   = jd->rd;
+
+       /* initialize variables */
+
+       md = m->parseddesc;
+       nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
+
+       /* calculate stackframe size */
+
+       cd->stackframesize = 
+               1 +                                                /* return address  */
+               sizeof(stackframeinfo) / SIZEOF_VOID_P +           /* stackframeinfo  */
+               sizeof(localref_table) / SIZEOF_VOID_P +           /* localref_table  */
+               nmd->memuse;                                       /* stack arguments */
+
+       /* create method header */
+
+       (void) dseg_add_unique_address(cd, code);              /* CodeinfoPointer */
+       (void) dseg_add_unique_s4(cd, cd->stackframesize * 4); /* FrameSize       */
+       (void) dseg_add_unique_s4(cd, 0);                      /* IsSync          */
+       (void) dseg_add_unique_s4(cd, 0);                      /* IsLeaf          */
+       (void) dseg_add_unique_s4(cd, 0);                      /* IntSave         */
+       (void) dseg_add_unique_s4(cd, 0);                      /* FltSave         */
+       (void) dseg_addlinenumbertablesize(cd);
+       (void) dseg_add_unique_s4(cd, 0);                      /* ExTableSize     */
+
+       /* generate stub code */
+       /* TODO: don't forget ... there is a M_ADD_IMM at the end of this stub!!! */
+       M_STMFD(1<<REG_LR, REG_SP);
+       if (cd->stackframesize - 1) {
+               M_SUB_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize - 1);
+       }
+
+#if !defined(NDEBUG)
+       if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
+               emit_verbosecall_enter(jd);
+#endif
+
+       /* get function address (this must happen before the stackframeinfo) */
+
+       funcdisp = dseg_add_functionptr(cd, f);
+
+#if !defined(WITH_STATIC_CLASSPATH)
+       if (f == NULL) {
+               codegen_addpatchref(cd, PATCHER_resolve_native, m, funcdisp);
+
+               if (opt_showdisassemble)
+                       M_NOP;
+       }
+#endif
+
+       /* save integer and float argument registers */
+       M_STMFD(BITMASK_ARGS | (1<<REG_IP), REG_SP);
+       /* TODO: floating point */
+
+       /* create native stackframe info */
+       assert(IS_IMM(20 + cd->stackframesize * 4));
+       M_ADD_IMM(REG_A0, REG_SP, 20 + cd->stackframesize * 4 - SIZEOF_VOID_P);
+       M_MOV(REG_A1, REG_IP);
+       M_ADD_IMM(REG_A2, REG_SP, 20 + cd->stackframesize * 4);
+       M_LDR_INTERN(REG_A3, REG_SP, 20 + cd->stackframesize * 4 - SIZEOF_VOID_P);
+       disp = dseg_add_functionptr(cd, codegen_start_native_call);
+       M_DSEG_BRANCH(disp);
+
+       /* recompute ip */
+       /*s1 = (s4) (cd->mcodeptr - cd->mcodebase);
+       M_RECOMPUTE_IP(s1);*/
+
+       /* restore integer and float argument registers */
+       M_LDMFD(BITMASK_ARGS | (1<<REG_IP), REG_SP);
+       /* TODO: floating point */
+
+       /* copy or spill arguments to new locations */
+       /* ATTENTION: the ARM has only integer argument registers! */
+
+       for (i = md->paramcount - 1, j = i + nativeparams; i >= 0; i--, j--) {
+               t = md->paramtypes[i].type;
+
+               if (!md->params[i].inmemory) {
+                       s1 = ARGUMENT_REGS(t, md->params[i].regoff);
+
+                       if (!nmd->params[j].inmemory) {
+                               s2 = ARGUMENT_REGS(t, nmd->params[j].regoff);
+                               SPLIT_OPEN(t, s1, REG_ITMP1);
+                               SPLIT_LOAD(t, s1, cd->stackframesize);
+                               SPLIT_OPEN(t, s2, REG_ITMP1);
+
+                               if (IS_2_WORD_TYPE(t))
+                                       M_LNGMOVE(s1, s2);
+                               else
+                                       M_INTMOVE(s1, s2);
+
+                               SPLIT_STORE_AND_CLOSE(t, s2, 0);
+                       }
+                       else {
+                               s2 = nmd->params[j].regoff;
+                               SPLIT_OPEN(t, s1, REG_ITMP1);
+                               SPLIT_LOAD(t, s1, cd->stackframesize);
+
+                               if (IS_2_WORD_TYPE(t))
+                                       M_LST(s1, REG_SP, s2 * 4);
+                               else
+                                       M_IST(s1, REG_SP, s2 * 4);
+                               /* no SPLIT_CLOSE here because argument is fully on stack now */
+                       }
+               }
+               else {
+                       s1 = md->params[i].regoff + cd->stackframesize;
+                       s2 = nmd->params[j].regoff;
+
+                       if (IS_2_WORD_TYPE(t)) {
+                               M_LLD(REG_ITMP12_PACKED, REG_SP, s1 * 4);
+                               M_LST(REG_ITMP12_PACKED, REG_SP, s2 * 4);
+                       }
+                       else {
+                               M_ILD(REG_ITMP1, REG_SP, s1 * 4);
+                               M_IST(REG_ITMP1, REG_SP, s2 * 4);
+                       }
+               }
+       }
+
+       /* put class into second argument register */
+       if (m->flags & ACC_STATIC) {
+               disp = dseg_add_address(cd, m->class);
+               M_DSEG_LOAD(REG_A1, disp);
+       }
+
+       /* put env into first argument register */
+       disp = dseg_add_address(cd, _Jv_env);
+       M_DSEG_LOAD(REG_A0, disp);
+
+       /* do the native function call */
+       M_DSEG_BRANCH(funcdisp);            /* call native method                 */
+
+       /* recompute ip from pc */
+       /* TODO: this is only needed because of the tracer ... do we
+          really need it? */
+       s1 = (s4) (cd->mcodeptr - cd->mcodebase);
+       M_RECOMPUTE_IP(s1);
+
+#if !defined(__SOFTFP__)
+       /* TODO: this is only a hack, since we use R0/R1 for float return! */
+       /* this depends on gcc; it is independent from our ENABLE_SOFTFLOAT define */
+       if (md->returntype.type != TYPE_VOID && IS_FLT_DBL_TYPE(md->returntype.type)) {
+#if 0 && !defined(NDEBUG)
+               dolog("NATIVESTUB that returns float or double (%s.%s)", m->class->name->text, m->name->text);
+#endif
+               /* we cannot use this macro, since it is not defined in ENABLE_SOFTFLOAT */
+               /* M_CAST_FLT_TO_INT_TYPED(md->returntype.type, REG_FRESULT, REG_RESULT_TYPED(md->returntype.type)); */
+               if (IS_2_WORD_TYPE(md->returntype.type)) {
+                       DCD(0xed2d8102); /* stfd    f0, [sp, #-8]! */
+                       M_LDRD_UPDATE(REG_RESULT_PACKED, REG_SP, 8);
+               } else {
+                       DCD(0xed2d0101); /* stfs    f0, [sp, #-4]!*/
+                       M_LDR_UPDATE(REG_RESULT, REG_SP, 4);
+               }
+       }
+#endif
+
+#if !defined(NDEBUG)
+       if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
+               emit_verbosecall_exit(jd);
+#endif
+
+       /* remove native stackframe info */
+       /* TODO: improve this store/load */
+
+       M_STMFD(BITMASK_RESULT | (1<<REG_IP), REG_SP);
+       M_ADD_IMM(REG_A0, REG_SP, 12 + cd->stackframesize * 4 - SIZEOF_VOID_P);
+       disp = dseg_add_functionptr(cd, codegen_finish_native_call);
+       M_DSEG_BRANCH(disp);
+       M_MOV(REG_ITMP1_XPTR, REG_RESULT);
+       M_LDMFD(BITMASK_RESULT | (1<<REG_IP), REG_SP);
+
+       /* finish stub code, but do not yet return to caller */
+
+       if (cd->stackframesize - 1)
+               M_ADD_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize - 1);
+
+       M_LDMFD(1<<REG_LR, REG_SP);
+
+       /* check for exception */
+
+       M_TST(REG_ITMP1_XPTR, REG_ITMP1_XPTR);
+       M_MOVEQ(REG_PC, REG_LR);            /* if no exception, return to caller  */
+
+       /* handle exception here */
+
+       M_SUB_IMM(REG_ITMP2_XPC, REG_LR, 4);/* move fault address into xpc        */
+
+       disp = dseg_add_functionptr(cd, asm_handle_nat_exception);
+       M_DSEG_LOAD(REG_ITMP3, disp);       /* load asm exception handler address */
+       M_MOV(REG_PC, REG_ITMP3);           /* jump to asm exception handler      */
+
+       /* generate patcher stubs */
+
+       emit_patcher_stubs(jd);
+
+       codegen_finish(jd);
+
+       return code->entrypoint;
+}
+
+
+/* asm_debug *******************************************************************
+
+   Lazy debugger!
+
+*******************************************************************************/
+
+void asm_debug(int a1, int a2, int a3, int a4)
+{
+       printf("===> i am going to exit after this debugging message!\n");
+       printf("got asm_debug(%p, %p, %p, %p)\n",(void*)a1,(void*)a2,(void*)a3,(void*)a4);
+       throw_cacao_exception_exit(string_java_lang_InternalError, "leave you now");
+}
+
+
+/*
+ * 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:
+ */
diff --git a/src/vm/jit/arm/codegen.h b/src/vm/jit/arm/codegen.h
new file mode 100644 (file)
index 0000000..5cca083
--- /dev/null
@@ -0,0 +1,1244 @@
+/* src/vm/jit/arm/codegen.h - code generation macros and definitions for ARM
+
+   Copyright (C) 1996-2005, 2006 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Michael Starzinger
+            Christian Thalinger
+
+   $Id: codegen.h 6591 2007-01-02 19:14:25Z twisti $
+
+*/
+
+
+#ifndef _CODEGEN_H
+#define _CODEGEN_H
+
+#include "config.h"
+
+
+/* helper macros for generating code ******************************************/
+
+/* load_var_to_reg_xxx:
+   this function generates code to fetch data from a pseudo-register
+   into a real register. 
+   If the pseudo-register has actually been assigned to a real 
+   register, no code will be emitted, since following operations
+   can use this register directly.
+   v:      pseudoregister to be fetched from
+   tempnr: temporary register to be used if v is actually spilled to ram
+   regnr:  the register number, where the operand can be found after 
+           fetching (this wil be either tempregnum or the register
+           number allready given to v)
+*/
+
+#if defined(__ARMEL__)
+#define load_var_to_reg_lng(regnr,v,tempnr) { \
+       if ((v)->flags & INMEMORY) { \
+               COUNT_SPILLS; \
+               M_STACK_LOAD_LNG(tempnr, (v)->regoff); \
+               regnr = tempnr; \
+       } else if (GET_HIGH_REG((v)->regoff)==REG_SPLIT) { \
+               M_LDR_INTERN(GET_HIGH_REG(tempnr), REG_SP, 0); /* TODO: where to load? */ \
+               regnr = PACK_REGS(GET_LOW_REG((v)->regoff), GET_HIGH_REG(tempnr)); \
+       } else regnr = (v)->regoff; \
+}
+#else /* defined(__ARMEB__) */
+#define load_var_to_reg_lng(regnr,v,tempnr) { \
+        if ((v)->flags & INMEMORY) { \
+                COUNT_SPILLS; \
+                M_STACK_LOAD_LNG(tempnr, (v)->regoff); \
+                regnr = tempnr; \
+        } else if (GET_LOW_REG((v)->regoff)==REG_SPLIT) { \
+                M_LDR_INTERN(GET_LOW_REG(tempnr), REG_SP, 0); /* TODO: where to load? */ \
+                regnr = PACK_REGS(GET_LOW_REG(tempnr), GET_HIGH_REG((v)->regoff)); \
+        } else regnr = (v)->regoff; \
+}
+#endif
+
+
+/* store_reg_to_var_xxx:
+   This function generates the code to store the result of an operation
+   back into a spilled pseudo-variable.
+   If the pseudo-variable has not been spilled in the first place, this 
+   function will generate nothing.
+   v:      Pseudovariable
+   tempnr: Number of the temporary registers as returned by
+           reg_of_var.
+*/
+
+#if defined(__ARMEL__)
+#define store_reg_to_var_lng(v,tempnr) { \
+       if ((v)->flags & INMEMORY) { \
+               COUNT_SPILLS; \
+               M_STACK_STORE_LNG(tempnr, (v)->regoff); \
+       } else if (GET_HIGH_REG((v)->regoff)==REG_SPLIT) { \
+               M_STR_INTERN(GET_HIGH_REG(tempnr), REG_SP, 0); /* TODO: where to store? */ \
+       } \
+}
+#else /* defined(__ARMEB__) */
+#define store_reg_to_var_lng(v,tempnr) { \
+        if ((v)->flags & INMEMORY) { \
+                COUNT_SPILLS; \
+                M_STACK_STORE_LNG(tempnr, (v)->regoff); \
+        } else if (GET_LOW_REG((v)->regoff)==REG_SPLIT) { \
+                M_STR_INTERN(GET_LOW_REG(tempnr), REG_SP, 0); /* TODO: where to store? */ \
+        } \
+}
+#endif
+
+#if defined(__ARMEL__)
+#define SPLIT_OPEN(type, reg, tmpreg) \
+       if (IS_2_WORD_TYPE(type) && GET_HIGH_REG(reg)==REG_SPLIT) { \
+               /*dolog("SPLIT_OPEN({R%d;SPL} > {R%d;R%d})", GET_LOW_REG(reg), GET_LOW_REG(reg), tmpreg);*/ \
+               /*assert(GET_LOW_REG(reg) == 3);*/ \
+               (reg) = PACK_REGS(GET_LOW_REG(reg), tmpreg); \
+       }
+#define SPLIT_LOAD(type, reg, offset) \
+       if (IS_2_WORD_TYPE(type) && GET_LOW_REG(reg)==3) { \
+               /*dolog("SPLIT_LOAD({R%d;R%d} from [%x])", GET_LOW_REG(reg), GET_HIGH_REG(reg), offset);*/ \
+               M_LDR(GET_HIGH_REG(reg), REG_SP, 4 * (offset)); \
+       }
+#define SPLIT_STORE_AND_CLOSE(type, reg, offset) \
+       if (IS_2_WORD_TYPE(type) && GET_LOW_REG(reg)==3) { \
+               /*dolog("SPLIT_STORE({R%d;R%d} to [%x])", GET_LOW_REG(reg), GET_HIGH_REG(reg), offset);*/ \
+               M_STR(GET_HIGH_REG(reg), REG_SP, 4 * (offset)); \
+               (reg) = PACK_REGS(GET_LOW_REG(reg), REG_SPLIT); \
+       }
+#else /* defined(__ARMEB__) */
+#define SPLIT_OPEN(type, reg, tmpreg) \
+       if (IS_2_WORD_TYPE(type) && GET_LOW_REG(reg)==REG_SPLIT) { \
+               /*dolog("SPLIT_OPEN({SPL;R%d} > {R%d;R%d})", GET_HIGH_REG(reg), tmpreg, GET_HIGH_REG(reg));*/ \
+               /*assert(GET_HIGH_REG(reg) == 3);*/ \
+               (reg) = PACK_REGS(tmpreg, GET_HIGH_REG(reg)); \
+       }
+#define SPLIT_LOAD(type, reg, offset) \
+       if (IS_2_WORD_TYPE(type) && GET_HIGH_REG(reg)==3) { \
+               /*dolog("SPLIT_LOAD({R%d;R%d} from [%x])", GET_LOW_REG(reg), GET_HIGH_REG(reg), offset);*/ \
+               M_LDR(GET_LOW_REG(reg), REG_SP, 4 * (offset)); \
+       }
+#define SPLIT_STORE_AND_CLOSE(type, reg, offset) \
+       if (IS_2_WORD_TYPE(type) && GET_HIGH_REG(reg)==3) { \
+               /*dolog("SPLIT_STORE({R%d;R%d} to [%x])", GET_LOW_REG(reg), GET_HIGH_REG(reg), offset);*/ \
+               M_STR(GET_LOW_REG(reg), REG_SP, 4 * (offset)); \
+               (reg) = PACK_REGS(REG_SPLIT, GET_HIGH_REG(reg)); \
+       }
+#endif
+
+
+#define MCODECHECK(icnt) \
+    do { \
+        if ((cd->mcodeptr + (icnt) * 4) > cd->mcodeend) \
+            codegen_increase(cd); \
+    } while (0)
+
+
+/* TODO: correct this! */
+#define IS_IMM(val) ( ((val) >= 0) && ((val) <= 255) )
+#define IS_OFFSET(off,max) ((s4)(off) <= (max) && (s4)(off) >= -(max))
+
+#if !defined(NDEBUG)
+# define CHECK_INT_REG(r) if ((r)<0 || (r)>15) printf("CHECK_INT_REG: this is not an integer register: %d\n", r); assert((r)>=0 && (r)<=15)
+# define CHECK_FLT_REG(r) if ((r)<0 || (r)>7) printf("CHECK_FLT_REG: this is not an float register: %d\n", r); assert((r)>=0 && (r)<=7)
+# define CHECK_OFFSET(off,max) \
+       if (!IS_OFFSET(off,max)) printf("CHECK_OFFSET: offset out of range: %x (>%x) SEVERE ERROR!!!\n", ((off)<0)?-(off):off, max); \
+       assert(IS_OFFSET(off,max))
+#else
+# define CHECK_INT_REG(r)
+# define CHECK_FLT_REG(r)
+# define CHECK_OFFSET(off,max)
+#endif
+
+
+/* branch defines *************************************************************/
+
+#define BRANCH_NOPS \
+    do { \
+        M_NOP; \
+    } while (0)
+
+
+/* patcher defines ************************************************************/
+
+#define PATCHER_CALL_SIZE    1 * 4      /* an instruction is 4-bytes long     */
+
+#define PATCHER_NOPS \
+    do { \
+        M_NOP; \
+    } while (0)
+
+
+/* lazy debugger **************************************************************/
+
+#if !defined(NDEBUG)
+void asm_debug(int a1, int a2, int a3, int a4);
+void asm_debug_intern(int a1, int a2, int a3, int a4);
+
+/* if called with this macros, it can be placed nearly anywhere */
+/* almost all registers are saved and restored afterwards       */
+/* it uses a long branch to call the asm_debug_intern (no exit) */
+#define ASM_DEBUG_PREPARE \
+       M_STMFD(0x7fff, REG_SP)
+#define ASM_DEBUG_EXECUTE \
+       M_LONGBRANCH(asm_debug_intern); \
+       M_LDMFD(0x7fff, REG_SP)
+#endif
+
+
+/* macros to create code ******************************************************/
+
+/* the condition field */
+#define COND_EQ 0x0  /* Equal        Z set   */
+#define COND_NE 0x1  /* Not equal    Z clear */
+#define COND_CS 0x2  /* Carry set    C set   */
+#define COND_CC 0x3  /* Carry clear  C clear */
+#define COND_MI 0x4  /* Negative     N set   */
+#define COND_PL 0x5  /* Positive     N clear */
+#define COND_VS 0x6  /* Overflow     V set   */
+#define COND_VC 0x7  /* No overflow  V clear */
+#define COND_HI 0x8  /* Unsigned higher      */
+#define COND_LS 0x9  /* Unsigned lower, same */
+#define COND_GE 0xA  /* Sig. greater, equal  */
+#define COND_LT 0xB  /* Sig. less than       */
+#define COND_GT 0xC  /* Sig. greater than    */
+#define COND_LE 0xD  /* Sig. less, equal     */
+#define COND_AL 0xE  /* Always               */
+#define CONDNV  0xF  /* Special (see A3-5)   */
+#define UNCOND COND_AL
+
+/* data processing operation: M_DAT
+   cond ... conditional execution
+   op ..... opcode
+   d ...... destination reg
+   n ...... source reg
+   S ...... update condition codes
+   I ...... switch to immediate mode
+   shift .. shifter operand
+*/
+
+#define M_DAT(cond,op,d,n,S,I,shift) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | ((op) << 21) | ((d) << 12) | ((n) << 16) | ((I) << 25) | ((S) << 20) | ((shift) & 0x00000fff)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+/* load and store instruction: M_MEM
+   cond ... conditional execution
+   L ...... load (L=1) or store (L=0)
+   B ...... unsigned byte (B=1) or word (B=0)
+   d ...... destination reg
+   n ...... base reg for addressing
+   adr .... addressing mode specific
+*/
+
+#define M_MEM(cond,L,B,d,n,adr,I,P,U,W) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | (1 << 26) | ((L) << 20) | ((B) << 22) | ((d) << 12) | ((n) << 16) | ((adr) & 0x0fff) | ((I) << 25) | ((P) << 24) | ((U) << 23) | ((W) << 21)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+/* load and store instruction: M_MEM2
+   cond ... conditional execution
+   L ...... load (L=1) or store (L=0)
+   H ...... halfword (H=1) or signed byte (H=0)
+   S ...... signed (S=1) or unsigned (S=0) halfword
+   d ...... destination reg
+   n ...... base reg for addressing
+   adr .... addressing mode specific
+*/
+
+#define M_MEM2(cond,L,H,S,d,n,adr,I,P,U,W) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | (1 << 22) | (0x9 << 4) | ((L) << 20) | ((H) << 5) | ((S) << 6) | ((d) << 12) | ((n) << 16) | ((adr) & 0x0f) | (((adr) & 0xf0) << (8-4)) | ((I) << 22) | ((P) << 24) | ((U) << 23) | ((W) << 21)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+/* load and store multiple instruction: M_MEM_MULTI
+   cond ... conditional execution
+   L ...... load (L=1) or store (L=0)
+   S ...... special (see "The ARM ARM A3-21")
+   regs ... register list
+   n ...... base reg for addressing
+*/
+
+#define M_MEM_MULTI(cond,L,S,regs,n,P,U,W) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | (1 << 27) | ((L) << 20) | ((S) << 22) | ((n) << 16) | ((regs) & 0xffff) | ((P) << 24) | ((U) << 23) | ((W) << 21)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+/* branch and branch with link: M_BRA
+   cond ... conditional execution
+   L ...... branch with link (L=1)
+   offset . 24bit offset
+*/
+
+#define M_BRA(cond,L,offset) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x5 << 25) | ((L) << 24) | ((offset) & 0x00ffffff)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+/* multiplies: M_MULT
+   cond ... conditional execution
+   d ...... destination register
+   n, m ... source registers
+   S ...... update conditional codes
+   A ...... accumulate flag (enables third source)
+   s ...... third source register
+*/
+
+#define M_MULT(cond,d,n,m,S,A,s) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | ((d) << 16) | ((n) << 8) | (m) | (0x09 << 4) | ((S) << 20) | ((A) << 21) | ((s) << 12)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+/* no operation (mov r0,r0): M_NOP */
+
+#define M_NOP \
+    do { \
+        *((u4 *) cd->mcodeptr) = (0xe1a00000); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+/* software breakpoint (only v5 and above): M_BREAKPOINT */
+
+#define M_BREAKPOINT(imm) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (0x0e12 << 20) | (0x07 << 4) | (((imm) & 0xfff0) << (8-4)) | ((imm) & 0x0f); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+#if !defined(ENABLE_SOFTFLOAT)
+
+/* M_CPDO **********************************************************************
+
+   Floating-Point Coprocessor Data Operations
+
+   cond ... conditional execution
+   op ..... opcode
+   D ...... dyadic (D=0) or monadic (D=1) instruction
+   Fd ..... destination float-register
+   Fn ..... source float-register
+   Fm ..... source float-register or immediate
+
+*******************************************************************************/
+
+#define M_CPDOS(cond,op,D,Fd,Fn,Fm) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | ((op) << 20) | ((D) << 15) | ((Fd) << 12) | ((Fn) << 16) | ((Fm) & 0x0f)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+#define M_CPDOD(cond,op,D,Fd,Fn,Fm) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | ((op) << 20) | ((D) << 15) | ((Fd) << 12) | ((Fn) << 16) | ((Fm) & 0x0f) | (1 << 7)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+/* M_CPDT **********************************************************************
+
+   Floating-Point Coprocessor Data Transfer
+
+   cond ... conditional execution
+   L ...... load (L=1) or store (L=0)
+   Fd ..... destination float-register
+   n ...... base reg for addressing
+
+*******************************************************************************/
+
+#define M_CPDT(cond,L,T1,T0,Fd,n,off,P,U,W) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0c << 24) | (1 << 8) | ((L) << 20) | ((T1) << 22) | ((T0) << 15) | ((Fd) << 12) | ((n) << 16) | ((off) & 0xff) | ((P) << 24) | ((U) << 23) | ((W) << 21)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+/* M_CPRT **********************************************************************
+
+   Floating-Point Coprocessor Register Transfer
+
+   XXX
+
+*******************************************************************************/
+
+#define M_CPRTS(cond,L,d,Fn,Fm) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+#define M_CPRTD(cond,L,d,Fn,Fm) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (1 << 7)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+#define M_CPRTI(cond,L,d,Fn,Fm) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (3 << 5)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+/* XXX TWISTI: replace X by something useful */
+
+#define M_CPRTX(cond,L,d,Fn,Fm) \
+    do { \
+        *((u4 *) cd->mcodeptr) = (((cond) << 28) | (0x0e << 24) | (1 << 8) | (1 << 4) | ((L) << 20) | ((d) << 12) | ((Fn) << 16) | (Fm) | (1 << 23)); \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+
+
+/* used to store values! */
+#define DCD(val) \
+    do { \
+        *((u4 *) cd->mcodeptr) = val; \
+        cd->mcodeptr += 4; \
+    } while (0)
+
+
+/* used to directly access shifter; insert this as shifter operand! */
+#define REG_LSL(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) )
+#define REG_LSR(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) | (1 << 5) )
+#define REG_ASR(reg, shift) ( (((shift) & 0x1f) << 7) | ((reg) & 0x0f) | (1 << 6) )
+#define REG_LSL_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) )
+#define REG_LSR_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) | (1 << 5) )
+#define REG_ASR_REG(reg, s) ( (((s) & 0x0f) << 8) | ((reg) & 0x0f) | (1 << 4) | (1 << 6) )
+
+/* used to directly rotate immediate values; insert this as immediate! */
+/* ATTENTION: this rotates the immediate right by (2 * rot) bits */
+#define IMM_ROTR(imm, rot) ( ((imm) & 0xff) | (((rot) & 0x0f) << 8) )
+#define IMM_ROTL(imm, rot) IMM_ROTR(imm, 16-(rot))
+
+/* macros for all arm instructions ********************************************/
+
+#define M_ADD(d,a,b)       M_DAT(UNCOND,0x04,d,a,0,0,b)         /* d = a +  b */
+#define M_ADC(d,a,b)       M_DAT(UNCOND,0x05,d,a,0,0,b)         /* d = a +  b (with Carry) */
+#define M_SUB(d,a,b)       M_DAT(UNCOND,0x02,d,a,0,0,b)         /* d = a -  b */
+#define M_SBC(d,a,b)       M_DAT(UNCOND,0x06,d,a,0,0,b)         /* d = a -  b (with Carry) */
+#define M_AND(d,a,b)       M_DAT(UNCOND,0x00,d,a,0,0,b)         /* d = a &  b */
+#define M_ORR(d,a,b)       M_DAT(UNCOND,0x0c,d,a,0,0,b)         /* d = a |  b */
+#define M_EOR(d,a,b)       M_DAT(UNCOND,0x01,d,a,0,0,b)         /* d = a ^  b */
+#define M_TST(a,b)         M_DAT(UNCOND,0x08,0,a,1,0,b)         /* TST a &  b */
+#define M_TEQ(a,b)         M_DAT(UNCOND,0x09,0,a,1,0,b)         /* TST a ^  b */
+#define M_CMP(a,b)         M_DAT(UNCOND,0x0a,0,a,1,0,b)         /* TST a -  b */
+#define M_MOV(d,b)         M_DAT(UNCOND,0x0d,d,0,0,0,b)         /* d =      b */
+#define M_ADD_S(d,a,b)     M_DAT(UNCOND,0x04,d,a,1,0,b)         /* d = a +  b (update Flags) */
+#define M_SUB_S(d,a,b)     M_DAT(UNCOND,0x02,d,a,1,0,b)         /* d = a -  b (update Flags) */
+#define M_MOV_S(d,b)       M_DAT(UNCOND,0x0d,d,0,1,0,b)         /* d =      b (update Flags) */
+
+#define M_ADD_IMM(d,a,i)   M_DAT(UNCOND,0x04,d,a,0,1,i)         /* d = a +  i */
+#define M_ADC_IMM(d,a,i)   M_DAT(UNCOND,0x05,d,a,0,1,i)         /* d = a +  i (with Carry) */
+#define M_SUB_IMM(d,a,i)   M_DAT(UNCOND,0x02,d,a,0,1,i)         /* d = a -  i */
+#define M_SBC_IMM(d,a,i)   M_DAT(UNCOND,0x06,d,a,0,1,i)         /* d = a -  i (with Carry) */
+#define M_RSB_IMM(d,a,i)   M_DAT(UNCOND,0x03,d,a,0,1,i)         /* d = -a + i */
+#define M_RSC_IMM(d,a,i)   M_DAT(UNCOND,0x07,d,a,0,1,i)         /* d = -a + i (with Carry) */
+#define M_AND_IMM(d,a,i)   M_DAT(UNCOND,0x00,d,a,0,1,i)         /* d = a &  i */
+#define M_TST_IMM(a,i)     M_DAT(UNCOND,0x08,0,a,1,1,i)         /* TST a &  i */
+#define M_TEQ_IMM(a,i)     M_DAT(UNCOND,0x09,0,a,1,1,i)         /* TST a ^  i */
+#define M_CMP_IMM(a,i)     M_DAT(UNCOND,0x0a,0,a,1,1,i)         /* TST a -  i */
+#define M_CMN_IMM(a,i)     M_DAT(UNCOND,0x0b,0,a,1,1,i)         /* TST a +  i */
+#define M_MOV_IMM(d,i)     M_DAT(UNCOND,0x0d,d,0,0,1,i)         /* d =      i */
+#define M_ADD_IMMS(d,a,i)  M_DAT(UNCOND,0x04,d,a,1,1,i)         /* d = a +  i (update Flags) */
+#define M_SUB_IMMS(d,a,i)  M_DAT(UNCOND,0x02,d,a,1,1,i)         /* d = a -  i (update Flags) */
+#define M_RSB_IMMS(d,a,i)  M_DAT(UNCOND,0x03,d,a,1,1,i)         /* d = -a + i (update Flags) */
+
+#define M_ADDSUB_IMM(d,a,i) if((i)>=0) M_ADD_IMM(d,a,i); else M_SUB_IMM(d,a,-(i))
+#define M_MOVEQ(d,b)       M_DAT(COND_EQ,0x0d,d,0,0,0,b)
+#define M_MOVVS_IMM(d,i)   M_DAT(COND_VS,0x0d,d,0,0,1,i)
+#define M_MOVNE_IMM(d,i)   M_DAT(COND_NE,0x0d,d,0,0,1,i)
+#define M_MOVLS_IMM(d,i)   M_DAT(COND_LS,0x0d,d,0,0,1,i)
+#define M_ADDLT_IMM(d,a,i) M_DAT(COND_LT,0x04,d,a,0,1,i)
+#define M_ADDGT_IMM(d,a,i) M_DAT(COND_GT,0x04,d,a,0,1,i)
+#define M_SUBLT_IMM(d,a,i) M_DAT(COND_LT,0x02,d,a,0,1,i)
+#define M_SUBGT_IMM(d,a,i) M_DAT(COND_GT,0x02,d,a,0,1,i)
+#define M_RSBMI_IMM(d,a,i) M_DAT(COND_MI,0x03,d,a,0,1,i)
+#define M_ADCMI_IMM(d,a,i) M_DAT(COND_MI,0x05,d,a,0,1,i)
+
+#define M_MUL(d,a,b)       M_MULT(UNCOND,d,a,b,0,0,0x0)         /* d = a *  b */
+
+
+#define M_LDMFD(regs,base) M_MEM_MULTI(UNCOND,1,0,regs,base,0,1,1)
+#define M_STMFD(regs,base) M_MEM_MULTI(UNCOND,0,0,regs,base,1,0,1)
+
+#define M_LDR_INTERN(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x0fff); \
+        M_MEM(UNCOND,1,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),0); \
+    } while (0)
+
+#define M_STR_INTERN(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x0fff); \
+        M_MEM(UNCOND,0,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),0); \
+    } while (0)
+
+#define M_LDR_UPDATE(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x0fff); \
+        M_MEM(UNCOND,1,0,d,base,(((off) < 0) ? -(off) : off),0,0,(((off) < 0) ? 0 : 1),0); \
+    } while (0)
+
+#define M_STR_UPDATE(d,base,off) \
+    do { \
+        CHECK_OFFSET(off,0x0fff); \
+        M_MEM(UNCOND,0,0,d,base,(((off) < 0) ? -(off) : off),0,1,(((off) < 0) ? 0 : 1),1); \
+    } while (0)
+
+
+#define M_LDRH(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x00ff); \
+        assert(off >= 0); \
+        M_MEM2(UNCOND,1,1,0,d,base,off,1,1,1,0); \
+    } while (0)
+
+#define M_LDRSH(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x00ff); \
+        assert(off >= 0); \
+        M_MEM2(UNCOND,1,1,1,d,base,off,1,1,1,0); \
+    } while (0)
+
+#define M_LDRSB(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x00ff); \
+        assert(off >= 0); \
+        M_MEM2(UNCOND,1,0,1,d,base,off,1,1,1,0); \
+    } while (0)
+
+#define M_STRH(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x00ff); \
+        assert(off >= 0); \
+        M_MEM2(UNCOND,0,1,0,d,base,off,1,1,1,0); \
+    } while (0)
+
+#define M_STRB(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x0fff); \
+        assert(off >= 0); \
+        M_MEM(UNCOND,0,1,d,base,off,0,1,1,0); \
+    } while (0)
+
+                                                                                                     
+#if !defined(ENABLE_SOFTFLOAT)
+
+#define M_LDFS_INTERN(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x03ff); \
+        M_CPDT(UNCOND,1,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
+    } while (0)
+
+#define M_LDFD_INTERN(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x03ff); \
+        M_CPDT(UNCOND,1,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
+    } while (0)
+
+#define M_STFS_INTERN(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x03ff); \
+        M_CPDT(UNCOND,0,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
+    } while (0)
+
+#define M_STFD_INTERN(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x03ff); \
+        M_CPDT(UNCOND,0,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),0); \
+    } while (0)
+
+#define M_LDFS_UPDATE(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x03ff); \
+        M_CPDT(UNCOND,1,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),0,(((off) < 0) ? 0 : 1),1); \
+    } while (0)
+
+#define M_LDFD_UPDATE(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x03ff); \
+        M_CPDT(UNCOND,1,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),0,(((off) < 0) ? 0 : 1),1); \
+    } while (0)
+
+#define M_STFS_UPDATE(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x03ff); \
+        M_CPDT(UNCOND,0,0,0,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),1); \
+    } while (0)
+
+#define M_STFD_UPDATE(d,base,off) \
+    do { \
+        CHECK_OFFSET(off, 0x03ff); \
+        M_CPDT(UNCOND,0,0,1,d,base,(((off) < 0) ? -(off) >> 2 : (off) >> 2),1,(((off) < 0) ? 0 : 1),1); \
+    } while (0)
+
+#define M_ADFS(d,a,b)      M_CPDOS(UNCOND,0x00,0,d,a,b)         /* d = a +  b */
+#define M_SUFS(d,a,b)      M_CPDOS(UNCOND,0x02,0,d,a,b)         /* d = a -  b */
+#define M_RSFS(d,a,b)      M_CPDOS(UNCOND,0x03,0,d,a,b)         /* d = b -  a */
+#define M_MUFS(d,a,b)      M_CPDOS(UNCOND,0x01,0,d,a,b)         /* d = a *  b */
+#define M_DVFS(d,a,b)      M_CPDOS(UNCOND,0x04,0,d,a,b)         /* d = a /  b */
+#define M_RMFS(d,a,b)      M_CPDOS(UNCOND,0x08,0,d,a,b)         /* d = a %  b */
+#define M_ADFD(d,a,b)      M_CPDOD(UNCOND,0x00,0,d,a,b)         /* d = a +  b */
+#define M_SUFD(d,a,b)      M_CPDOD(UNCOND,0x02,0,d,a,b)         /* d = a -  b */
+#define M_RSFD(d,a,b)      M_CPDOD(UNCOND,0x03,0,d,a,b)         /* d = b -  a */
+#define M_MUFD(d,a,b)      M_CPDOD(UNCOND,0x01,0,d,a,b)         /* d = a *  b */
+#define M_DVFD(d,a,b)      M_CPDOD(UNCOND,0x04,0,d,a,b)         /* d = a /  b */
+#define M_RMFD(d,a,b)      M_CPDOD(UNCOND,0x08,0,d,a,b)         /* d = a %  b */
+#define M_MVFS(d,a)        M_CPDOS(UNCOND,0x00,1,d,0,a)         /* d =      a */
+#define M_MVFD(d,a)        M_CPDOD(UNCOND,0x00,1,d,0,a)         /* d =      a */
+#define M_MNFS(d,a)        M_CPDOS(UNCOND,0x01,1,d,0,a)         /* d =    - a */
+#define M_MNFD(d,a)        M_CPDOD(UNCOND,0x01,1,d,0,a)         /* d =    - a */
+#define M_CMF(a,b)         M_CPRTX(UNCOND,1,0x0f,a,b)           /* COMPARE a;  b */
+#define M_FLTS(d,a)        M_CPRTS(UNCOND,0,a,d,0)              /* d = (float) a */
+#define M_FLTD(d,a)        M_CPRTD(UNCOND,0,a,d,0)              /* d = (float) a */
+#define M_FIX(d,a)         M_CPRTI(UNCOND,1,d,0,a)              /* d = (int)   a */
+
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+
+
+#define M_B(off)           M_BRA(UNCOND,0,off)    /* unconditional branch */
+#define M_BL(off)          M_BRA(UNCOND,1,off)    /* branch and link      */
+#define M_BEQ(off)         M_BRA(COND_EQ,0,off)   /* conditional branches */
+#define M_BNE(off)         M_BRA(COND_NE,0,off)
+#define M_BGE(off)         M_BRA(COND_GE,0,off)
+#define M_BGT(off)         M_BRA(COND_GT,0,off)
+#define M_BLT(off)         M_BRA(COND_LT,0,off)
+#define M_BLE(off)         M_BRA(COND_LE,0,off)
+#define M_BHI(off)         M_BRA(COND_HI,0,off)   /* unsigned conditional */
+#define M_BHS(off)         M_BRA(COND_CS,0,off)
+#define M_BLO(off)         M_BRA(COND_CC,0,off)
+#define M_BLS(off)         M_BRA(COND_LS,0,off)
+
+
+#define M_FMOV(a,b)        M_MVFS(b,a)
+#define M_DMOV(a,b)        M_MVFD(b,a)
+
+
+/* if we do not have double-word load/store command, we can fake them */
+/* ATTENTION: the original LDRD/STRD of ARMv5e would always use (Rd/Rd+1),
+   so these faked versions are more "powerful" */
+
+#if defined(__ARMEL__)
+
+#define M_LDRD_INTERN(d,base,off) \
+    do { \
+        M_LDR_INTERN(GET_LOW_REG(d), base, off); \
+        M_LDR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
+    } while (0)
+
+#define M_STRD_INTERN(d,base,off) \
+    do { \
+        M_STR_INTERN(GET_LOW_REG(d), base, off); \
+        M_STR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
+    } while (0)
+
+#define M_LDRD_ALTERN(d,base,off) \
+    do { \
+        M_LDR_INTERN(GET_HIGH_REG(d), base, (off) + 4); \
+        M_LDR_INTERN(GET_LOW_REG(d), base, off); \
+    } while (0)
+
+#define M_LDRD_UPDATE(d,base,off) \
+    do { \
+        assert((off) == +8); \
+        M_LDR_UPDATE(GET_LOW_REG(d), base, 4); \
+        M_LDR_UPDATE(GET_HIGH_REG(d), base, 4); \
+    } while (0)
+
+#define M_STRD_UPDATE(d,base,off) \
+    do { \
+        assert((off) == -8); \
+        M_STR_UPDATE(GET_HIGH_REG(d), base, -4); \
+        M_STR_UPDATE(GET_LOW_REG(d), base, -4); \
+    } while (0)
+
+#define GET_FIRST_REG(d)  GET_LOW_REG(d)
+#define GET_SECOND_REG(d) GET_HIGH_REG(d)
+
+#else /* defined(__ARMEB__) */
+
+#define M_LDRD_INTERN(d,base,off) \
+    do { \
+        M_LDR_INTERN(GET_HIGH_REG(d), base, off); \
+        M_LDR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
+    } while (0)
+
+#define M_STRD_INTERN(d,base,off) \
+    do { \
+        M_STR_INTERN(GET_HIGH_REG(d), base, off); \
+        M_STR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
+    } while (0)
+
+#define M_LDRD_ALTERN(d,base,off) \
+    do { \
+        M_LDR_INTERN(GET_LOW_REG(d), base, (off) + 4); \
+        M_LDR_INTERN(GET_HIGH_REG(d), base, off); \
+    } while (0)
+
+#define M_LDRD_UPDATE(d,base,off) \
+    do { \
+        assert((off) == +8); \
+        M_LDR_UPDATE(GET_HIGH_REG(d), base, 4); \
+        M_LDR_UPDATE(GET_LOW_REG(d), base, 4); \
+    } while (0)
+
+#define M_STRD_UPDATE(d,base,off) \
+    do { \
+        assert((off) == -8); \
+        M_STR_UPDATE(GET_LOW_REG(d), base, -4); \
+        M_STR_UPDATE(GET_HIGH_REG(d) ,base, -4); \
+    } while (0)
+
+#define GET_FIRST_REG(d)  GET_HIGH_REG(d)
+#define GET_SECOND_REG(d) GET_LOW_REG(d)
+
+#endif /* defined(__ARMEB__) */
+
+
+/* M_LDR/M_STR:
+   these are replacements for the original LDR/STR instructions, which can
+   handle longer offsets (up to 20bits). the original functions are now
+   called M_xxx_INTERN.
+*/
+/* ATTENTION: We use ITMP3 here, take into account that it gets destroyed.
+   This means that only ITMP1 and ITMP2 can be used in reg_of_var()!!!
+*/
+/* ATTENTION2: It is possible to use ITMP3 as base reg. Remember that when
+   changing these macros!!!
+*/
+
+#define M_LDR(d, base, offset) \
+do { \
+       CHECK_OFFSET(offset, 0x0fffff); \
+       if (IS_OFFSET(offset, 0x000fff)) { \
+               M_LDR_INTERN(d, base, offset); \
+       } else { \
+               /* we cannot handle REG_PC here */ \
+               assert((d) != REG_PC); \
+               if ((offset) > 0) { \
+                       M_ADD_IMM(d, base, IMM_ROTL((offset) >> 12, 6)); \
+                       M_LDR_INTERN(d, d, (offset) & 0x000fff); \
+               } else { \
+                       M_SUB_IMM(d, base, IMM_ROTL((-(offset)) >> 12, 6)); \
+                       M_LDR_INTERN(d, d, -(-(offset) & 0x000fff)); \
+               } \
+       } \
+} while (0)
+
+#define M_LDR_NEGATIVE(d, base, offset) { \
+       /*assert((offset) <= 0);*/ \
+       if (IS_OFFSET(offset, 0x000fff)) { \
+               M_LDR_INTERN(d, base, offset); \
+       } else { \
+               /* we cannot handle REG_PC here */ \
+               assert((d) != REG_PC); \
+               M_SUB_IMM(d, base, IMM_ROTL((-(offset)) >> 12, 6)); \
+               M_LDR_INTERN(d, d, -(-(offset) & 0x000fff)); \
+       } \
+}
+
+#define M_LDRD(d, base, offset) \
+do { \
+       CHECK_OFFSET(offset, 0x0fffff - 4); \
+       if (IS_OFFSET(offset, 0x000fff - 4)) { \
+               if (GET_FIRST_REG(d) != (base)) { \
+                       M_LDRD_INTERN(d, base, offset); \
+               } else { \
+                       M_LDRD_ALTERN(d, base, offset); \
+               } \
+       } else if (IS_OFFSET(offset, 0x000fff)) { \
+               dolog("M_LDRD: this offset seems to be complicated (%d)", offset); \
+               assert(0); \
+       } else { \
+               if ((offset) > 0) { \
+                       M_ADD_IMM(GET_SECOND_REG(d), base, IMM_ROTL((offset) >> 12, 6)); \
+                       M_LDRD_INTERN(d, GET_SECOND_REG(d), (offset) & 0x000fff); \
+               } else { \
+                       M_SUB_IMM(GET_SECOND_REG(d), base, IMM_ROTL((-(offset)) >> 12, 6)); \
+                       M_LDRD_INTERN(d, GET_SECOND_REG(d), -(-(offset) & 0x000fff)); \
+               } \
+       } \
+} while (0)
+
+#if !defined(ENABLE_SOFTFLOAT)
+#define M_LDFS(d, base, offset) \
+do { \
+       CHECK_OFFSET(offset, 0x03ffff); \
+       if (IS_OFFSET(offset, 0x03ff)) { \
+               M_LDFS_INTERN(d, base, offset); \
+       } else { \
+               if ((offset) > 0) { \
+                       M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
+                       M_LDFS_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
+               } else { \
+                       M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
+                       M_LDFS_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
+               } \
+       } \
+} while (0)
+
+#define M_LDFD(d, base, offset) \
+do { \
+       CHECK_OFFSET(offset, 0x03ffff); \
+       if (IS_OFFSET(offset, 0x03ff)) { \
+               M_LDFD_INTERN(d, base, offset); \
+       } else { \
+               if ((offset) > 0) { \
+                       M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
+                       M_LDFD_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
+               } else { \
+                       M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
+                       M_LDFD_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
+               } \
+       } \
+} while (0)
+
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+
+#define M_STR(d, base, offset) \
+do { \
+       assert((d) != REG_ITMP3); \
+       CHECK_OFFSET(offset, 0x0fffff); \
+       if (IS_OFFSET(offset, 0x000fff)) { \
+               M_STR_INTERN(d, base, offset); \
+       } else { \
+               if ((offset) > 0) { \
+                       M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
+                       M_STR_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
+               } else { \
+                       M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 12, 6)); \
+                       M_STR_INTERN(d, REG_ITMP3, -(-(offset) & 0x000fff)); \
+               } \
+       } \
+} while (0)
+
+#define M_STRD(d, base, offset) \
+do { \
+       assert(GET_LOW_REG(d) != REG_ITMP3); \
+       assert(GET_HIGH_REG(d) != REG_ITMP3); \
+       CHECK_OFFSET(offset, 0x0fffff - 4); \
+       if (IS_OFFSET(offset, 0x000fff - 4)) { \
+               M_STRD_INTERN(d,base,offset); \
+       } else if (IS_OFFSET(offset, 0x000fff)) { \
+               dolog("M_STRD: this offset seems to be complicated (%d)", offset); \
+               assert(0); \
+       } else { \
+               if ((offset) > 0) { \
+                       M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
+                       M_STRD_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
+               } else { \
+                       M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 12, 6)); \
+                       M_STRD_INTERN(d, REG_ITMP3, -(-(offset) & 0x000fff)); \
+               } \
+       } \
+} while (0)
+
+#if !defined(ENABLE_SOFTFLOAT)
+
+#define M_STFS(d, base, offset) \
+do { \
+       CHECK_OFFSET(offset, 0x03ffff); \
+       if (IS_OFFSET(offset, 0x03ff)) { \
+               M_STFS_INTERN(d, base, offset); \
+       } else { \
+               if ((offset) > 0) { \
+                       M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
+                       M_STFS_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
+               } else { \
+                       M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
+                       M_STFS_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
+               } \
+       } \
+} while (0)
+
+#define M_STFD(d, base, offset) \
+do { \
+       CHECK_OFFSET(offset, 0x03ffff); \
+       if (IS_OFFSET(offset, 0x03ff)) { \
+               M_STFD_INTERN(d, base, offset); \
+       } else { \
+               if ((offset) > 0) { \
+                       M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 10, 5)); \
+                       M_STFD_INTERN(d, REG_ITMP3, (offset) & 0x03ff); \
+               } else { \
+                       M_SUB_IMM(REG_ITMP3, base, IMM_ROTL((-(offset)) >> 10, 5)); \
+                       M_STFD_INTERN(d, REG_ITMP3, -(-(offset) & 0x03ff)); \
+               } \
+       } \
+} while (0)
+
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+
+/* M_???_IMM_EXT_MUL4:
+   extended immediate operations, to handle immediates lager than 8bit.
+   ATTENTION: the immediate is rotatet left by 2 (multiplied by 4)!!!
+*/
+#define M_ADD_IMM_EXT_MUL4(d,n,imm) \
+       assert(d!=REG_PC); \
+       assert((imm) >= 0 && (imm) <= 0x00ffffff); \
+       M_ADD_IMM(d, n, IMM_ROTL(imm, 1)); \
+       if ((imm) > 0x000000ff) M_ADD_IMM(d, d, IMM_ROTL((imm) >>  8, 5)); \
+       if ((imm) > 0x0000ffff) M_ADD_IMM(d, d, IMM_ROTL((imm) >> 16, 9));
+#define M_SUB_IMM_EXT_MUL4(d,n,imm) \
+       assert(d!=REG_PC); \
+       assert((imm) >= 0 && (imm) <= 0x00ffffff); \
+       M_SUB_IMM(d, n, IMM_ROTL(imm, 1)); \
+       if ((imm) > 0x000000ff) M_SUB_IMM(d, d, IMM_ROTL((imm) >>  8, 5)); \
+       if ((imm) > 0x0000ffff) M_SUB_IMM(d, d, IMM_ROTL((imm) >> 16, 9));
+
+
+/* ICONST/LCONST:
+   loads the integer/long value const into register d.
+*/
+
+#define ICONST(d,c)                     emit_iconst(cd, (d), (c))
+
+#define ICONST_CONDITIONAL(cond,d,const) \
+       if (IS_IMM(const)) { \
+               /* M_MOV_IMM */ M_DAT(cond,0x0d,d,0,0,1,const); \
+       } else { \
+               disp = dseg_adds4(cd, const); \
+               /* TODO: implement this using M_DSEG_LOAD!!! */ \
+               /* M_LDR_INTERN */ CHECK_OFFSET(disp,0x0fff); M_MEM(cond,1,0,d,REG_IP,(disp<0)?-disp:disp,0,1,(disp<0)?0:1,0); \
+       }
+
+#define LCONST(d,c) \
+       if (IS_IMM((c) >> 32)) { \
+               M_MOV_IMM(GET_HIGH_REG(d), (s4) ((s8) (c) >> 32)); \
+               ICONST(GET_LOW_REG(d), (s4) ((s8) (c) & 0xffffffff)); \
+       } else if (IS_IMM((c) & 0xffffffff)) { \
+               M_MOV_IMM(GET_LOW_REG(d), (s4) ((s8) (c) & 0xffffffff)); \
+               ICONST(GET_HIGH_REG(d), (s4) ((s8) (c) >> 32)); \
+       } else { \
+               disp = dseg_add_s8(cd, (c)); \
+               M_LDRD(d, REG_IP, disp); \
+       }
+
+
+#if !defined(ENABLE_SOFTFLOAT)
+
+#define FCONST(d,c) \
+    do { \
+        disp = dseg_add_float(cd, (c)); \
+        M_LDFS(d, REG_IP, disp); \
+    } while (0)
+
+#define DCONST(d,c) \
+    do { \
+        disp = dseg_add_double(cd, (c)); \
+        M_LDFD(d, REG_IP, disp); \
+    } while (0)
+
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+
+
+/* M_RECOMPUTE_IP:
+   used to recompute our IP (something like PV) out of the current PC
+   ATTENTION: if you change this, you have to look at other functions as well!
+   Following things depend on it: asm_call_jit_compiler(); codegen_findmethod();
+*/
+#define M_RECOMPUTE_IP(disp) \
+       disp += 8; /* we use PC relative addr.  */ \
+       assert((disp & 0x03) == 0); \
+       assert(disp >= 0 && disp <= 0x03ffffff); \
+       M_SUB_IMM(REG_IP, REG_PC, IMM_ROTL(disp >> 2, 1)); \
+       if (disp > 0x000003ff) M_SUB_IMM(REG_IP, REG_IP, IMM_ROTL(disp >> 10, 5)); \
+       if (disp > 0x0003ffff) M_SUB_IMM(REG_IP, REG_IP, IMM_ROTL(disp >> 18, 9)); \
+
+/* M_INTMOVE:
+   generates an integer-move from register a to b.
+   if a and b are the same int-register, no code will be generated.
+*/
+
+#define M_INTMOVE(a,b) \
+    do { \
+        if ((a) != (b)) \
+            M_MOV(b, a); \
+    } while (0)
+
+#define M_LNGMOVE(a,b) \
+    do { \
+        if (GET_HIGH_REG(a) == GET_LOW_REG(b)) { \
+            assert((GET_LOW_REG(a) != GET_HIGH_REG(b))); \
+            M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \
+            M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \
+        } else { \
+            M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \
+            M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \
+        } \
+    } while (0)
+
+
+#if !defined(ENABLE_SOFTFLOAT)
+
+/* M_FLTMOVE:
+   generates a floating-point-move from register a to b.
+   if a and b are the same float-register, no code will be generated.
+*/
+
+#define M_FLTMOVE(a,b) \
+    do { \
+        if ((a) != (b)) \
+            M_FMOV(a, b); \
+    } while (0)
+
+#define M_DBLMOVE(a,b) \
+    do { \
+        if ((a) != (b)) \
+            M_DMOV(a, b); \
+    } while (0)
+
+#endif
+
+#if !defined(ENABLE_SOFTFLOAT)
+/* M_CAST_INT_TO_FLT_TYPED:
+   loads the value of the integer-register a (argument or result) into
+   float-register Fb. (and vice versa)
+*/
+#define M_CAST_INT_TO_FLT_TYPED(t,a,Fb) \
+       CHECK_FLT_REG(Fb); \
+       if ((t) == TYPE_FLT) { \
+               CHECK_INT_REG(a); \
+               M_STR_UPDATE(a, REG_SP, -4); \
+               M_LDFS_UPDATE(Fb, REG_SP, 4); \
+       } else { \
+               CHECK_INT_REG(GET_LOW_REG(a)); \
+               CHECK_INT_REG(GET_HIGH_REG(a)); \
+               M_STRD_UPDATE(a, REG_SP, -8); \
+               M_LDFD_UPDATE(Fb, REG_SP, 8); \
+       }
+#define M_CAST_FLT_TO_INT_TYPED(t,Fa,b) \
+       CHECK_FLT_REG(Fa); \
+       if ((t) == TYPE_FLT) { \
+               CHECK_INT_REG(b); \
+               M_STFS_UPDATE(Fa, REG_SP, -4); \
+               M_LDR_UPDATE(b, REG_SP, 4); \
+       } else { \
+               CHECK_INT_REG(GET_LOW_REG(b)); \
+               CHECK_INT_REG(GET_HIGH_REG(b)); \
+               M_STFD_UPDATE(Fa, REG_SP, -8); \
+               M_LDRD_UPDATE(b, REG_SP, 8); \
+       }
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+
+
+/* M_COMPARE:
+   generates the compare part of an if-sequece
+   uses M_CMP or M_CMP_IMM to do the compare
+   ATTENTION: uses REG_ITMP3 as intermediate register
+*/
+/* TODO: improve this and add some comments! */
+#define M_COMPARE(reg, val, cond, overjump) \
+       if (IS_IMM(val)) { \
+               if (overjump) M_BNE(1); \
+               /* M_CMP_IMM */ M_DAT(cond,0x0a,0,(reg),1,1,(val)); \
+       } else if(IS_IMM(-(val))) { \
+               if (overjump) M_BNE(1); \
+               /* M_CMN_IMM */ M_DAT(cond,0x0b,0,(reg),1,1,-(val)); \
+       } else { \
+               ICONST(REG_ITMP3, (val)); \
+               if (overjump) M_BNE(1); \
+               /* M_CMP */ M_DAT(cond,0x0a,0,(reg),1,0,REG_ITMP3); \
+       }
+
+/* M_LONGBRANCH:
+   performs a long branch to an absolute address with return address in LR
+   takes up 3 bytes of code space; address is hard-coded into code
+*/
+#define M_LONGBRANCH(adr) \
+       M_ADD_IMM(REG_LR, REG_PC, 4); \
+       M_LDR_INTERN(REG_PC, REG_PC, -4); \
+       DCD((s4) adr);
+
+/* M_DSEG_LOAD/BRANCH:
+   TODO: document me
+   ATTENTION: if you change this, you have to look at the asm_call_jit_compiler!
+   ATTENTION: we use M_LDR, so the same restrictions apply to us!
+*/
+#define M_DSEG_LOAD(reg, offset) \
+       M_LDR_NEGATIVE(reg, REG_IP, offset)
+
+#define M_DSEG_BRANCH(offset) \
+       if (IS_OFFSET(offset, 0x0fff)) { \
+               M_MOV(REG_LR, REG_PC); \
+               M_LDR_INTERN(REG_PC, REG_IP, offset); \
+       } else { \
+               /*assert((offset) <= 0);*/ \
+               CHECK_OFFSET(offset,0x0fffff); \
+               M_SUB_IMM(REG_ITMP3, REG_IP, ((-(offset) >>  12) & 0xff) | (((10) & 0x0f) << 8)); /*TODO: more to go*/ \
+               M_MOV(REG_LR, REG_PC); \
+               M_LDR_INTERN(REG_PC, REG_ITMP3, -(-(offset) & 0x0fff)); /*TODO: this looks ugly*/ \
+       }
+
+/* M_STACK_LOAD/STORE:
+   loads or stores integer values from register to stack or from stack to register
+   ATTENTION: we use M_LDR and M_STR, so the same restrictions apply to us!
+*/
+
+#define M_STACK_LOAD_LNG(reg, offset) { \
+       CHECK_INT_REG(GET_LOW_REG(reg)); \
+       CHECK_INT_REG(GET_HIGH_REG(reg)); \
+       M_LDRD(reg, REG_SP, (offset) * 4); \
+}
+
+
+#define M_ILD(a,b,c)                    M_LDR(a,b,c)
+#define M_LLD(a,b,c)                    M_LDRD(a,b,c)
+
+#define M_ILD_INTERN(a,b,c)             M_LDR_INTERN(a,b,c)
+#define M_LLD_INTERN(a,b,c)             M_LDRD_INTERN(a,b,c)
+
+#define M_ALD(a,b,c)                    M_ILD(a,b,c)
+#define M_ALD_INTERN(a,b,c)             M_ILD_INTERN(a,b,c)
+
+
+#define M_IST(a,b,c)                    M_STR(a,b,c)
+#define M_LST(a,b,c)                    M_STRD(a,b,c)
+
+#define M_IST_INTERN(a,b,c)             M_STR_INTERN(a,b,c)
+#define M_LST_INTERN(a,b,c)             M_STRD_INTERN(a,b,c)
+
+#define M_AST(a,b,c)                    M_IST(a,b,c)
+#define M_AST_INTERN(a,b,c)             M_IST_INTERN(a,b,c)
+
+
+#if !defined(ENABLE_SOFTFLOAT)
+
+#define M_STACK_LOAD_FLT_TYPED(t, reg, offset) { \
+       CHECK_FLT_REG(reg); \
+       if (IS_2_WORD_TYPE(t)) { \
+               M_LDFD(reg, REG_SP, (offset) * 4); \
+       } else { \
+               M_LDFS(reg, REG_SP, (offset) * 4); \
+       } \
+}
+
+#define M_FLD(a,b,c)                    M_LDFS(a,b,c)
+#define M_DLD(a,b,c)                    M_LDFD(a,b,c)
+
+#define M_FLD_INTERN(a,b,c)             M_LDFS_INTERN(a,b,c)
+#define M_DLD_INTERN(a,b,c)             M_LDFD_INTERN(a,b,c)
+
+
+#define M_STACK_STORE_FLT_TYPED(t, reg, offset) { \
+       CHECK_FLT_REG(reg); \
+       if (IS_2_WORD_TYPE(t)) { \
+               M_STFD(reg, REG_SP, (offset) * 4); \
+       } else { \
+               M_STFS(reg, REG_SP, (offset) * 4); \
+       } \
+}
+
+#define M_FST(a,b,c)                    M_STFS(a,b,c)
+#define M_DST(a,b,c)                    M_STFD(a,b,c)
+
+#define M_FST_INTERN(a,b,c)             M_STFS_INTERN(a,b,c)
+#define M_DST_INTERN(a,b,c)             M_STFD_INTERN(a,b,c)
+
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+
+
+/* function gen_resolvebranch **************************************************
+   ip ... pointer to instruction after branch (void*)
+   so ... offset of instruction after branch  (s4)
+   to ... offset of branch target             (s4) */
+
+#define gen_resolvebranch(ip,so,to) \
+       assert((((s4*) (ip))[-1] & 0x0e000000) == 0x0a000000); \
+       ((s4*) (ip))[-1] |= ((s4) (to) - (so) - 1) >> 2 & 0x0ffffff
+
+
+/* function gen_nullptr_check *************************************************/
+
+#define gen_nullptr_check_intern(objreg) { \
+       M_TST((objreg), (objreg)); \
+       M_BEQ(0); \
+       codegen_add_nullpointerexception_ref(cd); \
+}
+
+#define gen_nullptr_check(objreg) \
+       if (checknull) \
+               gen_nullptr_check_intern(objreg)
+
+
+/* function gen_div_check *****************************************************/
+
+#define gen_div_check(type,reg) \
+    do { \
+       if (IS_2_WORD_TYPE(type)) { \
+               M_TEQ_IMM(GET_LOW_REG(reg), 0); \
+               /* M_TEQ_EQ_IMM(GET_HIGH_REG(reg), 0) */ M_DAT(COND_EQ,0x09,0,GET_HIGH_REG(reg),1,1,0); \
+               M_BEQ(0); \
+       } else { \
+               M_TEQ_IMM((reg), 0); \
+               M_BEQ(0); \
+       } \
+       codegen_add_arithmeticexception_ref(cd); \
+    } while (0)
+
+/* function gen_bound_check ***************************************************
+   ATTENTION: uses REG_ITMP3 as intermediate register */
+/* TODO: maybe use another reg instead of REG_ITMP3! */
+
+#define gen_bound_check(arrayref,index) \
+       if (checkbounds) { \
+               M_LDR_INTERN(REG_ITMP3, (arrayref), OFFSET(java_arrayheader, size)); \
+               M_CMP((index), REG_ITMP3); \
+               M_BHS(0); \
+               codegen_add_arrayindexoutofboundsexception_ref(cd, index); \
+       }
+
+
+#endif /* _CODEGEN_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:
+ */
diff --git a/src/vm/jit/arm/disass.c b/src/vm/jit/arm/disass.c
new file mode 100644 (file)
index 0000000..d0f11db
--- /dev/null
@@ -0,0 +1,107 @@
+/* src/vm/jit/arm/disass.c - wrapper functions for GNU binutils disassembler
+
+   Copyright (C) 1996-2005, 2006 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Michael Starzinger
+
+   $Id: disass.c 6454 2006-01-23 12:19:37Z michi $
+
+*/
+
+
+#include "config.h"
+
+#include <dis-asm.h>
+
+#include "vm/types.h"
+#include "vm/global.h"
+#include "vm/jit/disass.h"
+
+
+char *regs[] = {
+       "a1",
+       "a2",
+       "a3",
+       "a4",
+       "v1",
+       "v2",
+       "v3",
+       "v4",
+       "v5",
+       "t3",
+       "t1",
+       "t2",
+       "IP",
+       "SP",
+       "LR",
+       "PC",
+       "***"
+};
+
+
+/* disassinstr *****************************************************************
+
+   Outputs a disassembler listing of one machine code instruction on
+   'stdout'.
+
+   code: pointer to instructions machine code
+
+*******************************************************************************/
+
+u1 *disassinstr(u1 *code)
+{
+       if (!disass_initialized) {
+               INIT_DISASSEMBLE_INFO(info, stdout, disass_printf);
+               info.read_memory_func = &disass_buffer_read_memory;
+               disass_initialized = true;
+       }
+
+       printf("0x%08x:   %08x    ", (u4) code, *((s4 *) code));
+
+#if defined(__ARMEL__)
+       print_insn_little_arm((bfd_vma) code, &info);
+#else
+       print_insn_big_arm((bfd_vma) code, &info);
+#endif
+
+       printf("\n");
+
+       /* 1 instruction is 4-bytes long */
+       return code + 4;
+}
+
+
+/*
+ * 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:
+ */
diff --git a/src/vm/jit/arm/emit.c b/src/vm/jit/arm/emit.c
new file mode 100644 (file)
index 0000000..ea2a185
--- /dev/null
@@ -0,0 +1,814 @@
+/* src/vm/jit/arm/emit.c - Arm code emitter functions
+
+   Copyright (C) 1996-2005, 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Christian Thalinger
+
+   $Id: emit.c 4398 2006-01-31 23:43:08Z twisti $
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+
+#include "vm/types.h"
+
+#include "md-abi.h"
+
+#include "vm/jit/arm/codegen.h"
+
+#if defined(ENABLE_THREADS)
+# include "threads/native/lock.h"
+#endif
+
+#include "vm/builtin.h"
+#include "vm/jit/asmpart.h"
+#include "vm/jit/emit-common.h"
+#include "vm/jit/jit.h"
+#include "vm/jit/replace.h"
+
+#include "toolbox/logging.h" /* XXX for debugging only */
+
+
+/* emit_load *******************************************************************
+
+   Emits a possible load of an operand.
+
+*******************************************************************************/
+
+s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
+{
+       codegendata  *cd;
+       s4            disp;
+       s4            reg;
+
+       /* get required compiler data */
+
+       cd = jd->cd;
+
+       if (src->flags & INMEMORY) {
+               COUNT_SPILLS;
+
+               disp = src->vv.regoff * 4;
+
+               if (IS_FLT_DBL_TYPE(src->type)) {
+#if !defined(ENABLE_SOFTFLOAT)
+                       if (IS_2_WORD_TYPE(src->type))
+                               M_DLD(tempreg, REG_SP, disp);
+                       else
+                               M_FLD(tempreg, REG_SP, disp);
+#else
+                       assert(0);
+#endif
+               }
+               else {
+                       if (IS_2_WORD_TYPE(src->type))
+                               M_LLD(tempreg, REG_SP, disp);
+                       else
+                               M_ILD(tempreg, REG_SP, disp);
+               }
+
+               reg = tempreg;
+       }
+       else
+               reg = src->vv.regoff;
+
+       return reg;
+}
+
+
+/* emit_load_low ***************************************************************
+
+   Emits a possible load of the low 32-bits of a long source operand.
+
+*******************************************************************************/
+
+s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
+{
+       codegendata  *cd;
+       s4            disp;
+       s4            reg;
+
+       assert(src->type == TYPE_LNG);
+
+       /* get required compiler data */
+
+       cd = jd->cd;
+
+       if (src->flags & INMEMORY) {
+               COUNT_SPILLS;
+
+               disp = src->vv.regoff * 4;
+
+#if defined(__ARMEL__)
+               M_ILD(tempreg, REG_SP, disp);
+#else
+               M_ILD(tempreg, REG_SP, disp + 4);
+#endif
+
+               reg = tempreg;
+       }
+       else
+               reg = GET_LOW_REG(src->vv.regoff);
+
+       return reg;
+}
+
+
+/* emit_load_high **************************************************************
+
+   Emits a possible load of the high 32-bits of a long source operand.
+
+*******************************************************************************/
+
+s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
+{
+       codegendata  *cd;
+       s4            disp;
+       s4            reg;
+
+       assert(src->type == TYPE_LNG);
+
+       /* get required compiler data */
+
+       cd = jd->cd;
+
+       if (src->flags & INMEMORY) {
+               COUNT_SPILLS;
+
+               disp = src->vv.regoff * 4;
+
+#if defined(__ARMEL__)
+               M_ILD(tempreg, REG_SP, disp + 4);
+#else
+               M_ILD(tempreg, REG_SP, disp);
+#endif
+
+               reg = tempreg;
+       }
+       else
+               reg = GET_HIGH_REG(src->vv.regoff);
+
+       return reg;
+}
+
+
+/* emit_store ******************************************************************
+
+   Emits a possible store to a variable.
+
+*******************************************************************************/
+
+void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
+{
+       codegendata  *cd;
+       s4            disp;
+
+       /* get required compiler data */
+
+       cd = jd->cd;
+
+       if (dst->flags & INMEMORY) {
+               COUNT_SPILLS;
+
+               disp = dst->vv.regoff * 4;
+
+#if !defined(ENABLE_SOFTFLOAT)
+               if (IS_FLT_DBL_TYPE(dst->type)) {
+                       if (IS_2_WORD_TYPE(dst->type))
+                               M_DST(d, REG_SP, disp);
+                       else
+                               M_FST(d, REG_SP, disp);
+               }
+               else {
+                       if (IS_2_WORD_TYPE(dst->type))
+                               M_LST(d, REG_SP, disp);
+                       else
+                               M_IST(d, REG_SP, disp);
+               }
+#else
+               if (IS_2_WORD_TYPE(dst->type))
+                       M_LST(d, REG_SP, disp);
+               else
+                       M_IST(d, REG_SP, disp);
+#endif
+       }
+       else if (IS_LNG_TYPE(dst->type)) {
+#if defined(__ARMEL__)
+               if (GET_HIGH_REG(dst->vv.regoff) == REG_SPLIT)
+                       M_IST_INTERN(GET_HIGH_REG(d), REG_SP, 0 * 4);
+#else
+               if (GET_LOW_REG(dst->vv.regoff) == REG_SPLIT)
+                       M_IST_INTERN(GET_LOW_REG(d), REG_SP, 0 * 4);
+#endif
+       }
+}
+
+
+/* emit_copy *******************************************************************
+
+   XXX
+
+*******************************************************************************/
+
+void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
+{
+       codegendata  *cd;
+       registerdata *rd;
+       s4            s1, d;
+
+       /* get required compiler data */
+
+       cd = jd->cd;
+       rd = jd->rd;
+
+       /* XXX dummy call, removed me!!! */
+       d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
+
+       if ((src->vv.regoff != dst->vv.regoff) ||
+               ((src->flags ^ dst->flags) & INMEMORY)) {
+
+               /* If one of the variables resides in memory, we can eliminate
+                  the register move from/to the temporary register with the
+                  order of getting the destination register and the load. */
+
+               if (IS_INMEMORY(src->flags)) {
+#if !defined(ENABLE_SOFTFLOAT)
+                       if (IS_FLT_DBL_TYPE(src->type))
+                               d = codegen_reg_of_var(iptr->opc, dst, REG_FTMP1);
+                       else
+#endif
+                       {
+                               if (IS_2_WORD_TYPE(src->type))
+                                       d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
+                               else
+                                       d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
+                       }
+
+                       s1 = emit_load(jd, iptr, src, d);
+               }
+               else {
+#if !defined(ENABLE_SOFTFLOAT)
+                       if (IS_FLT_DBL_TYPE(src->type))
+                               s1 = emit_load(jd, iptr, src, REG_FTMP1);
+                       else
+#endif
+                       {
+                               if (IS_2_WORD_TYPE(src->type))
+                                       s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
+                               else
+                                       s1 = emit_load(jd, iptr, src, REG_ITMP1);
+                       }
+
+                       d = codegen_reg_of_var(iptr->opc, dst, s1);
+               }
+
+               if (s1 != d) {
+#if !defined(ENABLE_SOFTFLOAT)
+                       if (IS_FLT_DBL_TYPE(src->type)) {
+                               if (IS_2_WORD_TYPE(src->type))
+                                       M_DMOV(s1, d);
+                               else
+                                       M_FMOV(s1, d);
+                       }
+                       else {
+                               if (IS_2_WORD_TYPE(src->type))
+                                       M_LNGMOVE(s1, d);
+                               else
+                                       /* XXX grrrr, wrong direction! */
+                                       M_MOV(d, s1);
+                       }
+#else
+                       if (IS_2_WORD_TYPE(src->type))
+                               M_LNGMOVE(s1, d);
+                       else
+                               /* XXX grrrr, wrong direction! */
+                               M_MOV(d, s1);
+#endif
+               }
+
+               emit_store(jd, iptr, dst, d);
+       }
+}
+
+
+/* emit_iconst *****************************************************************
+
+   XXX
+
+*******************************************************************************/
+
+void emit_iconst(codegendata *cd, s4 d, s4 value)
+{
+       s4 disp;
+
+       if (IS_IMM(value))
+               M_MOV_IMM(d, value);
+       else {
+               disp = dseg_add_s4(cd, value);
+               M_DSEG_LOAD(d, disp);
+       }
+}
+
+
+/* emit_nullpointer_check ******************************************************
+
+   Emit a NullPointerException check.
+
+*******************************************************************************/
+
+void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TST(reg, reg);
+               M_BEQ(0);
+               codegen_add_nullpointerexception_ref(cd);
+       }
+}
+
+
+/* emit_arrayindexoutofbounds_check ********************************************
+
+   Emit a ArrayIndexOutOfBoundsException check.
+
+*******************************************************************************/
+
+void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_ILD_INTERN(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
+               M_CMP(s2, REG_ITMP3);
+               M_BHS(0);
+               codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
+       }
+}
+
+
+/* emit_exception_stubs ********************************************************
+
+   Generates the code for the exception stubs.
+
+*******************************************************************************/
+
+void emit_exception_stubs(jitdata *jd)
+{
+       codegendata  *cd;
+       registerdata *rd;
+       exceptionref *eref;
+       s4            targetdisp;
+       s4            disp;
+
+       /* get required compiler data */
+
+       cd = jd->cd;
+       rd = jd->rd;
+
+       /* generate exception stubs */
+
+       targetdisp = 0;
+
+       for (eref = cd->exceptionrefs; eref != NULL; eref = eref->next) {
+               gen_resolvebranch(cd->mcodebase + eref->branchpos,
+                                                 eref->branchpos, cd->mcodeptr - cd->mcodebase);
+
+               MCODECHECK(100);
+
+               /* Check if the exception is an
+                  ArrayIndexOutOfBoundsException.  If so, move index register
+                  into REG_ITMP1. */
+
+               if (eref->reg != -1)
+                       M_MOV(REG_ITMP1, eref->reg);
+
+               /* calcuate exception address */
+
+               assert((eref->branchpos - 4) % 4 == 0);
+               M_ADD_IMM_EXT_MUL4(REG_ITMP2_XPC, REG_IP, (eref->branchpos - 4) / 4);
+
+               /* move function to call into REG_ITMP3 */
+
+               disp = dseg_add_functionptr(cd, eref->function);
+               M_DSEG_LOAD(REG_ITMP3, disp);
+
+               if (targetdisp == 0) {
+                       targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
+
+                       M_MOV(rd->argintregs[0], REG_IP);
+                       M_MOV(rd->argintregs[1], REG_SP);
+
+                       if (jd->isleafmethod)
+                               M_MOV(rd->argintregs[2], REG_LR);
+                       else
+                               M_LDR(rd->argintregs[2], REG_SP,
+                                         cd->stackframesize * 4 - SIZEOF_VOID_P);
+
+                       M_MOV(rd->argintregs[3], REG_ITMP2_XPC);
+
+                       /* save registers */
+                       /* TODO: we only need to save LR in leaf methods */
+
+                       M_STMFD(BITMASK_ARGS | 1<<REG_IP | 1<<REG_LR, REG_SP);
+
+                       /* move a3 to stack */
+
+                       M_STR_UPDATE(REG_ITMP1, REG_SP, -4);
+
+                       /* do the exception call */
+
+                       M_MOV(REG_LR, REG_PC);
+                       M_MOV(REG_PC, REG_ITMP3);
+
+                       M_ADD_IMM(REG_SP, REG_SP, 4);
+
+                       /* result of stacktrace is our XPTR */
+
+                       M_MOV(REG_ITMP1_XPTR, REG_RESULT);
+
+                       /* restore registers */
+
+                       M_LDMFD(BITMASK_ARGS | 1<<REG_IP | 1<<REG_LR, REG_SP);
+
+                       disp = dseg_add_functionptr(cd, asm_handle_exception);
+                       M_DSEG_LOAD(REG_ITMP3, disp);
+                       M_MOV(REG_PC, REG_ITMP3);
+               }
+               else {
+                       disp = (((u4 *) cd->mcodebase) + targetdisp) -
+                               (((u4 *) cd->mcodeptr) + 2);
+
+                       M_B(disp);
+               }
+       }
+}
+
+
+/* emit_patcher_stubs **********************************************************
+
+   Generates the code for the patcher stubs.
+
+*******************************************************************************/
+
+void emit_patcher_stubs(jitdata *jd)
+{
+       codegendata *cd;
+       patchref    *pref;
+       u4           mcode;
+       u1          *savedmcodeptr;
+       u1          *tmpmcodeptr;
+       s4           targetdisp;
+       s4           disp;
+
+       /* get required compiler data */
+
+       cd = jd->cd;
+
+       /* generate patcher stub call code */
+
+       targetdisp = 0;
+
+       for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
+               /* check code segment size */
+
+               MCODECHECK(100);
+
+               /* Get machine code which is patched back in later. The
+                  call is 1 instruction word long. */
+
+               tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
+
+               mcode = *((u4 *) tmpmcodeptr);
+
+               /* Patch in the call to call the following code (done at
+                  compile time). */
+
+               savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr              */
+               cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position     */
+
+               disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 2);
+               M_B(disp);
+
+               cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr       */
+
+               /* create stack frame */
+
+               M_SUB_IMM(REG_SP, REG_SP, 7 * 4);
+
+               /* save itmp3 onto stack */
+
+               M_STR_INTERN(REG_ITMP3, REG_SP, 6 * 4);
+
+               /* calculate return address and move it onto stack */
+               /* ATTENTION: we can not use BL to branch to patcher stub,        */
+               /* ATTENTION: because we need to preserve LR for leaf methods     */
+
+               disp = (s4) (((u4 *) cd->mcodeptr) - (((u4 *) tmpmcodeptr) + 1) + 2);
+
+               M_SUB_IMM_EXT_MUL4(REG_ITMP3, REG_PC, disp);
+               M_STR_INTERN(REG_ITMP3, REG_SP, 4 * 4);
+
+               /* move pointer to java_objectheader onto stack */
+
+#if defined(ENABLE_THREADS)
+               /* order reversed because of data segment layout */
+
+               (void) dseg_add_unique_address(cd, NULL);           /* flcword    */
+               (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
+               disp = dseg_add_unique_address(cd, NULL);           /* vftbl      */
+
+               M_SUB_IMM_EXT_MUL4(REG_ITMP3, REG_IP, -disp / 4);
+               M_STR_INTERN(REG_ITMP3, REG_SP, 3 * 4);
+#else
+               M_EOR(REG_ITMP3, REG_ITMP3, REG_ITMP3);
+               M_STR_INTERN(REG_ITMP3, REG_SP, 3 * 4);
+#endif
+
+               /* move machine code onto stack */
+
+               disp = dseg_add_unique_s4(cd, mcode);
+               M_DSEG_LOAD(REG_ITMP3, disp);
+               M_STR_INTERN(REG_ITMP3, REG_SP, 2 * 4);
+
+               /* move class/method/field reference onto stack */
+
+               disp = dseg_add_unique_address(cd, pref->ref);
+               M_DSEG_LOAD(REG_ITMP3, disp);
+               M_STR_INTERN(REG_ITMP3, REG_SP, 1 * 4);
+
+               /* move data segment displacement onto stack */
+
+               disp = dseg_add_unique_s4(cd, pref->disp);
+               M_DSEG_LOAD(REG_ITMP3, disp);
+               M_STR_INTERN(REG_ITMP3, REG_SP, 5 * 4);
+
+               /* move patcher function pointer onto stack */
+
+               disp = dseg_add_functionptr(cd, pref->patcher);
+               M_DSEG_LOAD(REG_ITMP3, disp);
+               M_STR_INTERN(REG_ITMP3, REG_SP, 0 * 4);
+
+               /* finally call the patcher via asm_patcher_wrapper */
+               /* ATTENTION: don't use REG_IP here, because some patchers need it */
+
+               if (targetdisp == 0) {
+                       targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
+
+                       disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
+                       /*M_DSEG_BRANCH_NOLINK(REG_PC, REG_IP, a);*/
+                       /* TODO: this is only a hack */
+                       M_DSEG_LOAD(REG_ITMP3, disp);
+                       M_MOV(REG_PC, REG_ITMP3);
+               }
+               else {
+                       disp = (((u4 *) cd->mcodebase) + targetdisp) -
+                               (((u4 *) cd->mcodeptr) + 2);
+
+                       M_B(disp);
+               }
+       }
+}
+
+
+/* emit_replacement_stubs ******************************************************
+
+   Generates the code for the replacement stubs.
+
+*******************************************************************************/
+
+#if defined(ENABLE_REPLACEMENT)
+void emit_replacement_stubs(jitdata *jd)
+{
+       codegendata *cd;
+       codeinfo    *code;
+       rplpoint    *rplp;
+       u1          *savedmcodeptr;
+       s4           disp;
+       s4           i;
+
+       /* get required compiler data */
+
+       cd   = jd->cd;
+       code = jd->code;
+}
+#endif /* defined(ENABLE_REPLACEMENT) */
+
+
+/* emit_verbosecall_enter ******************************************************
+
+   Generates the code for the call trace.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void emit_verbosecall_enter(jitdata *jd)
+{
+       methodinfo   *m;
+       codegendata  *cd;
+       registerdata *rd;
+       methoddesc   *md;
+       s4            stackframesize;
+       s4            disp;
+       s4            i, t, s1, s2;
+
+       /* get required compiler data */
+
+       m  = jd->m;
+       cd = jd->cd;
+       rd = jd->rd;
+
+       md = m->parseddesc;
+
+       /* stackframesize is changed below */
+
+       stackframesize = cd->stackframesize;
+
+       /* mark trace code */
+
+       M_NOP;
+
+       /* save argument registers to stack (including LR and IP) */
+       M_STMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_IP), REG_SP);
+       M_SUB_IMM(REG_SP, REG_SP, (2 + 2 + 1) * 4);     /* space for a3, a4 and m */
+
+       stackframesize += 6 + 2 + 2 + 1;
+
+       /* prepare args for tracer */
+
+       i = md->paramcount - 1;
+
+       if (i > 3)
+               i = 3;
+
+       for (; i >= 0; i--) {
+               t = md->paramtypes[i].type;
+
+               /* load argument into register (s1) and make it of TYPE_LNG */
+
+               if (!md->params[i].inmemory) {
+                       s1 = md->params[i].regoff;
+
+                       if (!IS_2_WORD_TYPE(t)) {
+                               M_MOV_IMM(REG_ITMP1, 0);
+                               s1 = PACK_REGS(s1, REG_ITMP1);
+                       }
+                       else {
+                               SPLIT_OPEN(t, s1, REG_ITMP1);
+                               SPLIT_LOAD(t, s1, stackframesize);
+                       }
+               }
+               else {
+                       s1 = md->params[i].regoff + stackframesize;
+
+                       if (IS_2_WORD_TYPE(t))
+                               M_LLD(REG_ITMP12_PACKED, REG_SP, s1 * 4);
+                       else
+                               M_ILD(REG_ITMP1, REG_SP, s1 * 4);
+               }
+
+               /* place argument for tracer */
+
+               if (i < 2) {
+#if defined(__ARMEL__)
+                       s2 = PACK_REGS(rd->argintregs[i * 2], rd->argintregs[i * 2 + 1]);
+#else /* defined(__ARMEB__) */
+                       s2 = PACK_REGS(rd->argintregs[i * 2 + 1], rd->argintregs[i * 2]);
+#endif          
+                       M_LNGMOVE(s1, s2);
+               }
+               else {
+                       s2 = (i - 2) * 2;
+                       M_LST(s1, REG_SP, s2 * 4);
+               }
+       }
+
+       /* prepare methodinfo pointer for tracer */
+
+       disp = dseg_add_address(cd, m);
+       M_DSEG_LOAD(REG_ITMP1, disp);
+       M_STR_INTERN(REG_ITMP1, REG_SP, 16);
+
+       /* call tracer here (we use a long branch) */
+
+       M_LONGBRANCH(builtin_trace_args);
+
+       /* restore argument registers from stack */
+
+       M_ADD_IMM(REG_SP, REG_SP, (2 + 2 + 1) * 4);        /* free argument stack */
+       M_LDMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_IP), REG_SP);
+
+       /* mark trace code */
+
+       M_NOP;
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* emit_verbosecall_exit *******************************************************
+
+   Generates the code for the call trace.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void emit_verbosecall_exit(jitdata *jd)
+{
+       methodinfo   *m;
+       codegendata  *cd;
+       registerdata *rd;
+       methoddesc   *md;
+       s4            disp;
+       s4            s1;
+
+       /* get required compiler data */
+
+       m  = jd->m;
+       cd = jd->cd;
+       rd = jd->rd;
+
+       md = m->parseddesc;
+
+       /* mark trace code */
+
+       M_NOP;
+
+       M_STMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_IP), REG_SP);
+       M_SUB_IMM(REG_SP, REG_SP, (1 + 1) * 4);    /* space for d[high reg] and f */
+
+#if defined(__ARMEL__)
+       s1 = PACK_REGS(rd->argintregs[1], rd->argintregs[2]);
+#else /* defined(__ARMEB__) */
+       s1 = PACK_REGS(rd->argintregs[2], rd->argintregs[1]);
+#endif
+
+       switch (md->returntype.type) {
+       case TYPE_ADR:
+       case TYPE_INT:
+               M_INTMOVE(REG_RESULT, GET_LOW_REG(s1));
+               M_MOV_IMM(GET_HIGH_REG(s1), 0);
+               break;
+
+       case TYPE_LNG:
+               M_LNGMOVE(REG_RESULT_PACKED, s1);
+               break;
+
+       case TYPE_FLT:
+               M_IST(REG_RESULT, REG_SP, 1 * 4);
+               break;
+
+       case TYPE_DBL:
+               s1 = rd->argintregs[3];
+               M_INTMOVE(REG_RESULT, s1);
+               M_IST(REG_RESULT2, REG_SP, 0 * 4);
+               break;
+       }
+
+       disp = dseg_add_address(cd, m);
+       M_DSEG_LOAD(rd->argintregs[0], disp);
+       M_LONGBRANCH(builtin_displaymethodstop);
+
+       M_ADD_IMM(REG_SP, REG_SP, (1 + 1) * 4);            /* free argument stack */
+       M_LDMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_IP), REG_SP);
+
+       /* mark trace code */
+
+       M_NOP;
+}
+#endif /* !defined(NDEBUG) */
+
+
+/*
+ * 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:
+ */
diff --git a/src/vm/jit/arm/linux/.cvsignore b/src/vm/jit/arm/linux/.cvsignore
new file mode 100644 (file)
index 0000000..8f719f9
--- /dev/null
@@ -0,0 +1,9 @@
+*.a
+*.o
+*.la
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
+TAGS
diff --git a/src/vm/jit/arm/linux/Makefile.am b/src/vm/jit/arm/linux/Makefile.am
new file mode 100644 (file)
index 0000000..a271588
--- /dev/null
@@ -0,0 +1,49 @@
+## src/vm/jit/arm/linux/Makefile.am
+##
+## Copyright (C) 1996-2005, 2006 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
+##
+## 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.
+##
+## Contact: cacao@cacaojvm.org
+##
+## Authors: Christian Thalinger
+##
+## Changes: Michael Starzinger
+##
+## $Id$
+
+## Process this file with automake to produce Makefile.in
+
+AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/vm/jit/$(ARCH_DIR)
+
+noinst_LTLIBRARIES = libmd.la
+
+libmd_la_SOURCES = \
+       md-os.c
+
+
+## Local variables:
+## mode: Makefile
+## indent-tabs-mode: t
+## c-basic-offset: 4
+## tab-width: 8
+## compile-command: "automake --add-missing"
+## End:
diff --git a/src/vm/jit/arm/linux/md-os.c b/src/vm/jit/arm/linux/md-os.c
new file mode 100644 (file)
index 0000000..1b7ef06
--- /dev/null
@@ -0,0 +1,149 @@
+/* src/vm/jit/arm/linux/md.c - machine dependent arm linux functions
+
+   Copyright (C) 1996-2005, 2006 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Michael Starzinger
+
+   Changes: Christian Thalinger
+
+   $Id: md.c 166 2006-01-22 23:38:44Z twisti $
+
+*/
+
+
+#include "config.h"
+
+#include "vm/types.h"
+
+#include "vm/jit/arm/md-abi.h"
+
+#define ucontext broken_glibc_ucontext
+#define ucontext_t broken_glibc_ucontext_t
+#include <ucontext.h>
+#undef ucontext
+#undef ucontext_t
+
+typedef struct ucontext {
+   unsigned long     uc_flags;
+   struct ucontext  *uc_link;
+   stack_t           uc_stack;
+   struct sigcontext uc_mcontext;
+   sigset_t          uc_sigmask;
+} ucontext_t;
+
+#define scontext_t struct sigcontext
+
+#include "mm/memory.h"
+#include "vm/exceptions.h"
+#include "vm/signallocal.h"
+#include "vm/stringlocal.h"
+#include "vm/jit/asmpart.h"
+#include "vm/jit/stacktrace.h"
+
+
+/* md_signal_handler_sigsegv ***************************************************
+
+   NullPointerException signal handler for hardware null pointer
+   check.
+
+*******************************************************************************/
+
+void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
+{
+       ucontext_t *_uc;
+       /*mcontext_t *_mc;*/
+       scontext_t *_sc;
+       u4          instr;
+       ptrint      addr;
+       ptrint      base;
+       u1          *pv;
+       u1          *sp;
+       u1          *ra;
+       u1          *xpc;
+
+       _uc = (ucontext_t*) _p;
+       _sc = &_uc->uc_mcontext;
+
+       /* ATTENTION: glibc included messed up kernel headers */
+       /* we needed a workaround for the ucontext structure */
+
+       addr = (ptrint) siginfo->si_addr;
+       /*xpc = (u1*) _mc->gregs[REG_PC];*/
+       xpc = (u1*) _sc->arm_pc;
+
+       instr = *((s4*) xpc);
+       base = *((s4*) _sc + OFFSET(scontext_t, arm_r0)/4 + ((instr >> 16) & 0x0f));
+
+       if (base == 0) {
+               pv  = (u1*) _sc->arm_ip;
+               sp  = (u1*) _sc->arm_sp;
+               ra  = (u1*) _sc->arm_lr; /* this is correct for leafs */
+
+               _sc->arm_r10 = (ptrint) stacktrace_hardware_nullpointerexception(pv, sp, ra, xpc);
+               _sc->arm_fp = (ptrint) xpc;
+               _sc->arm_pc = (ptrint) asm_handle_exception;
+       } else {
+               throw_cacao_exception_exit(string_java_lang_InternalError,
+                  "Segmentation fault: %p (pc=%p, instr=%x, base=%p)\n",
+                  addr, xpc, instr, base);
+       }
+}
+
+
+/* thread_restartcriticalsection ***********************************************
+
+   TODO: document me
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+void thread_restartcriticalsection(ucontext_t *_uc)
+{
+       scontext_t *_sc;
+       void       *critical;
+
+       _sc = &_uc->uc_mcontext;
+
+       critical = critical_find_restart_point((void *) _sc->arm_pc);
+
+       if (critical)
+               _sc->arm_pc = (ptrint) critical;
+}
+#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:
+ */
+
diff --git a/src/vm/jit/arm/machine-instr.h b/src/vm/jit/arm/machine-instr.h
new file mode 100644 (file)
index 0000000..05cae0e
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef _MACHINE_INSTR_H
+#define _MACHINE_INSTR_H
+
+static inline void atomic_add(int *mem, int val)
+{
+       int temp, temp2, temp3;
+       /*dolog("atomic_add(%p [%d], %d)", mem, *mem, val);*/
+
+       /* TODO: improve this one! */
+        __asm__ __volatile__ (
+               "1:\t"
+               "ldr   %0,[%3]\n\t"
+               "add   %1,%0,%4\n\t"
+               "swp   %2,%1,[%3]\n\t"
+               "cmp   %0,%2\n\t"
+               "swpne %1,%2,[%3]\n\t"
+               "bne   1b"
+               : "=&r" (temp), "=&r" (temp2), "=&r" (temp3)
+               : "r" (mem), "r"(val)
+               : "cc", "memory"
+       );
+
+       /*dolog("atomic_add() mem=%d", *mem);*/
+}
+
+static inline long compare_and_swap(long *p, long oldval, long newval)
+{
+       long ret, temp;
+       /*dolog("compare_and_swap(%p [%d], %d, %d)", p, *p, oldval, newval);*/
+
+       /* TODO: improve this one! */
+       __asm__ __volatile__ (
+               "1:\t"
+               "ldr   %0,[%2]\n\t"
+               "cmp   %0,%4\n\t"
+               "bne   2f\n\t"
+               "swp   %1,%3,[%2]\n\t"
+               "cmp   %1,%0\n\t"
+               "swpne %0,%1,[%2]\n\t"
+               "bne   1b\n\t"
+               "2:"
+               : "=&r" (ret), "=&r" (temp)
+               : "r" (p), "r" (newval), "r" (oldval)
+               : "cc", "memory"
+       );
+
+       /*dolog("compare_and_swap() return=%d mem=%d", ret, *p);*/
+       return ret;
+}
+
+#define STORE_ORDER_BARRIER() __asm__ __volatile__ ("" : : : "memory");
+#define MEMORY_BARRIER_BEFORE_ATOMIC() __asm__ __volatile__ ("" : : : "memory");
+#define MEMORY_BARRIER_AFTER_ATOMIC() __asm__ __volatile__ ("" : : : "memory");
+#define MEMORY_BARRIER() __asm__ __volatile__ ("" : : : "memory" );
+
+#endif
diff --git a/src/vm/jit/arm/md-abi.c b/src/vm/jit/arm/md-abi.c
new file mode 100644 (file)
index 0000000..eb54766
--- /dev/null
@@ -0,0 +1,253 @@
+/* src/vm/jit/arm/md-abi.c - functions for arm ABI
+
+   Copyright (C) 1996-2005, 2006 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Michael Starzinger
+
+   Changes: Christian Thalinger
+
+   $Id: md-abi.c 6548 2006-10-01 22:18:38Z edwin $
+
+*/
+
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "vm/jit/arm/md-abi.h"
+
+#include "vm/descriptor.h"
+#include "vm/global.h"
+#include "vm/jit/abi.h"
+
+
+/* register descripton array **************************************************/
+
+s4 nregdescint[] = {
+       REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
+       REG_SAV, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES,
+       REG_END
+};
+
+#if defined(ENABLE_SOFTFLOAT)
+s4 nregdescfloat[] = {
+       REG_RES, REG_RES, REG_RES, REG_RES,
+       REG_RES, REG_RES, REG_RES, REG_RES,
+       REG_END
+};
+#else
+/* TODO: FPA register usage conventions */
+s4 nregdescfloat[] = {
+       REG_TMP, REG_TMP, REG_TMP, REG_TMP,
+       REG_TMP, REG_TMP, REG_RES, REG_RES,
+       REG_END
+};
+#endif /* defined(ENABLE_SOFTFLOAT) */
+
+
+/* md_param_alloc **************************************************************
+
+   Allocate Arguments to Stackslots according the Calling Conventions
+
+   --- in:
+   md->paramcount:           Number of arguments for this method
+   md->paramtypes[].type:    Argument types
+
+   --- out:
+   md->params[].inmemory:    Argument spilled on stack
+   md->params[].regoff:      Stack offset or rd->arg[int|flt]regs index
+   md->memuse:               Stackslots needed for argument spilling
+   md->argintreguse:         max number of integer arguments used
+   md->argfltreguse:         max number of float arguments used
+
+*******************************************************************************/
+
+void md_param_alloc(methoddesc *md)
+{
+       paramdesc *pd;
+       s4         i;
+       s4         reguse;
+       s4         stacksize;
+
+       /* set default values */
+       reguse = 0;
+       stacksize = 0;
+
+       /* get params field of methoddesc */
+       pd = md->params;
+
+       for (i = 0; i < md->paramcount; i++, pd++) {
+               switch (md->paramtypes[i].type) {
+               case TYPE_INT:
+               case TYPE_ADR:
+               case TYPE_FLT:
+                       if (reguse < INT_ARG_CNT) {
+                               pd->inmemory = false;
+                               pd->regoff = reguse;
+                               reguse++;
+                       }
+                       else {
+                               pd->inmemory = true;
+                               pd->regoff = stacksize;
+                               stacksize++;
+                       }
+                       break;
+
+               case TYPE_LNG:
+               case TYPE_DBL:
+                       if (reguse+1 < INT_ARG_CNT) {
+                               pd->inmemory = false;
+#if defined(__ARMEL__)
+                               pd->regoff = PACK_REGS(reguse, reguse+1);
+#else
+                               pd->regoff = PACK_REGS(reguse+1, reguse);
+#endif
+                               reguse += 2;
+                       }
+                       else if (reguse < INT_ARG_CNT) {
+                               pd->inmemory = false;
+#if defined(__ARMEL__)
+                               pd->regoff = PACK_REGS(reguse, INT_ARG_CNT);
+#else
+                               pd->regoff = PACK_REGS(INT_ARG_CNT, reguse);
+#endif
+                               reguse++;
+                               stacksize++;
+                       }
+                       else {
+                               pd->inmemory = true;
+                               pd->regoff = stacksize;
+                               stacksize += 2;
+                       }
+                       break;
+               }
+       }
+
+       /* Since R0/R1 (==A0/A1) are used for passing return values, this
+          argument register usage has to be regarded, too. */
+
+       if (md->returntype.type != TYPE_VOID) {
+               if (!IS_2_WORD_TYPE(md->returntype.type)) {
+                       if (reguse < 1)
+                               reguse = 1;
+               }
+               else {
+                       if (reguse < 2)
+                               reguse = 2;
+               }
+       }
+
+       /* fill register and stack usage */
+
+       md->argintreguse = reguse;
+       md->argfltreguse = 0;
+       md->memuse       = stacksize;
+}
+
+
+/* md_return_alloc *************************************************************
+
+   Precolor the Java Stackelement containing the Return Value, if possible.
+
+   --- in
+   m:                       Methodinfo of current method
+   return_type:             Return Type of the Method (TYPE_INT.. TYPE_ADR)
+                            TYPE_VOID is not allowed!
+   stackslot:               Java Stackslot to contain the Return Value
+
+   --- out
+   if precoloring was possible:
+   VAR(stackslot->varnum)->flags = PREALLOC
+   VAR(stackslot->varnum)->vv.regoff = [REG_RESULT, (REG_RESULT2/REG_RESULT), REG_FRESULT]
+   rd->arg[flt|int]reguse   set to a value according the register usage
+
+*******************************************************************************/
+
+void md_return_alloc(jitdata *jd, stackptr stackslot)
+{
+       methodinfo   *m;
+       registerdata *rd;
+       methoddesc   *md;
+
+       /* get required compiler data */
+
+       m  = jd->m;
+       rd = jd->rd;
+
+       md = m->parseddesc;
+
+       /* In Leafmethods Local Vars holding parameters are precolored to
+          their argument register -> so leafmethods with paramcount > 0
+          could already use R0 == a00! */
+
+       if (!jd->isleafmethod || (md->paramcount == 0)) {
+               /* Only precolor the stackslot, if it is not a SAVEDVAR <->
+                  has not to survive method invokations. */
+
+               if (!(stackslot->flags & SAVEDVAR)) {
+#if !defined(ENABLE_SOFTFLOAT)
+                       /* Stackelements containing float or double values
+                          (TYPE_FLT | TYPE_DBL) cannot be precolored, because we
+                          use integer register to pass return values. (floats:
+                          R0, doubles: R0/R1) */
+
+                       if (!IS_FLT_DBL_TYPE(md->returntype.type)) {
+#endif
+
+                               VAR(stackslot->varnum)->flags = PREALLOC;
+
+                               if (!IS_2_WORD_TYPE(md->returntype.type)) {
+                                       if (rd->argintreguse < 1)
+                                               rd->argintreguse = 1;
+
+                                       VAR(stackslot->varnum)->vv.regoff = REG_RESULT;
+                               }
+                               else {
+                                       if (rd->argintreguse < 2)
+                                               rd->argintreguse = 2;
+
+                                       VAR(stackslot->varnum)->vv.regoff = REG_RESULT_PACKED;
+                               }
+
+#if !defined(ENABLE_SOFTFLOAT)
+                       }
+#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:
+ */
diff --git a/src/vm/jit/arm/md-abi.h b/src/vm/jit/arm/md-abi.h
new file mode 100644 (file)
index 0000000..960965c
--- /dev/null
@@ -0,0 +1,148 @@
+/* src/vm/jit/arm/md-abi.h - defines for arm ABI
+
+   Copyright (C) 1996-2005, 2006 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Michael Starzinger
+
+   $Id: md-abi.h 6545 2006-09-06 21:42:42Z twisti $
+
+*/
+
+
+#ifndef _MD_ABI_H
+#define _MD_ABI_H
+
+
+/* preallocated registers *****************************************************/
+
+/* integer registers */
+
+#define REG_RESULT      0    /* to deliver method results                     */
+#define REG_RESULT2     1    /* to deliver long method results                */
+
+#define REG_IP          12   /* intra-procedure-call scratch register         */
+#define REG_SP          13   /* stack pointer                                 */
+#define REG_LR          14   /* link register                                 */
+#define REG_PC          15   /* program counter                               */
+
+#define REG_METHODPTR   11   /* special register to fetch procedure vector    */
+
+#define REG_ITMP1       10   /* temporary register                            */
+#define REG_ITMP2       11   /* temporary register and method pointer         */
+#define REG_ITMP3       9    /* temporary register                            */
+
+#define REG_ITMP1_XPTR  10   /* exception pointer = temporary register 1      */
+#define REG_ITMP2_XPC   11   /* exception pc = temporary register 2           */
+
+#define REG_A0           0   /* define some argument registers                */
+#define REG_A1           1
+#define REG_A2           2
+#define REG_A3           3
+
+#define REG_SPLIT       16   /* dummy register to mark a split of longs and   */
+                             /* doubles across register/stack barrier         */
+                             /* set LOW_REG = ARG4 and HIGH_REG = REG_SPLIT   */
+
+#define BITMASK_ARGS    0x0f /* bitmask for LDM/STM to save method arguments  */
+#define BITMASK_RESULT  0x03 /* bitmask for LDM/STM to save method results    */
+
+#if !defined(ENABLE_SOFTFLOAT)
+/* floating point registers */
+
+#define REG_FRESULT     0    /* to deliver floating point method results      */
+#define REG_FTMP1       6    /* temporary floating point register             */
+#define REG_FTMP2       7    /* temporary floating point register             */
+
+#endif /* !defined(ENABLE_SOFTFLOAT) */
+
+
+/* register count *************************************************************/
+#define INT_REG_CNT     16   /* number of integer registers                   */
+#define INT_TMP_CNT     0    /* number of integer registers                   */
+#define INT_SAV_CNT     5    /* number of int callee saved registers          */
+#define INT_ARG_CNT     4    /* number of int argument registers              */
+#define INT_RES_CNT     7    /* number of reserved integer registers          */
+
+#define FLT_REG_CNT     8    /* number of float registers                     */
+#if defined(ENABLE_SOFTFLOAT)
+# define FLT_TMP_CNT    0    /* number of flt temp registers                  */
+# define FLT_SAV_CNT    0    /* number of flt callee saved registers          */
+# define FLT_ARG_CNT    0    /* number of flt argument registers              */
+# define FLT_RES_CNT    8    /* number of reserved float registers            */
+#else
+# define FLT_TMP_CNT    6    /* number of flt temp registers                  */
+# define FLT_SAV_CNT    0    /* number of flt callee saved registers          */
+# define FLT_ARG_CNT    0    /* number of flt argument registers              */
+# define FLT_RES_CNT    2    /* number of reserved float registers            */
+#endif /* defined(ENABLE_SOFTFLOAT) */
+
+#define TRACE_ARGS_NUM  4
+
+
+/* Register Pack/Unpack Macros ************************************************/
+
+#if defined(__ARMEL__)
+
+# define REG_ITMP12_PACKED    PACK_REGS(REG_ITMP1, REG_ITMP2)
+# define REG_ITMP23_PACKED    PACK_REGS(REG_ITMP2, REG_ITMP3)
+# define REG_RESULT_PACKED    PACK_REGS(REG_RESULT, REG_RESULT2)
+
+# define REG_A0_A1_PACKED     PACK_REGS(REG_A0, REG_A1)
+# define REG_A2_A3_PACKED     PACK_REGS(REG_A2, REG_A3)
+
+#else /* defined(__ARMEB__) */
+
+# define REG_ITMP12_PACKED    PACK_REGS(REG_ITMP2, REG_ITMP1)
+# define REG_ITMP23_PACKED    PACK_REGS(REG_ITMP3, REG_ITMP2)
+# define REG_RESULT_PACKED    PACK_REGS(REG_RESULT2, REG_RESULT)
+
+# define REG_A0_A1_PACKED     PACK_REGS(REG_A1, REG_A0)
+# define REG_A2_A3_PACKED     PACK_REGS(REG_A3, REG_A2)
+
+#endif
+
+#define REG_ITMP12_TYPED(t) ((IS_2_WORD_TYPE(t)) ? REG_ITMP12_PACKED : REG_ITMP1)
+#define REG_RESULT_TYPED(t) ((IS_2_WORD_TYPE(t)) ? REG_RESULT_PACKED : REG_RESULT)
+#define ARGUMENT_REGS(t,a)  ((IS_2_WORD_TYPE(t)) ? \
+          (PACK_REGS(rd->argintregs[GET_LOW_REG(a)],rd->argintregs[GET_HIGH_REG(a)])) : \
+          (rd->argintregs[(a)]) \
+       )
+
+
+#endif /* _MD_ABI_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:
+ */
diff --git a/src/vm/jit/arm/md-asm.h b/src/vm/jit/arm/md-asm.h
new file mode 100644 (file)
index 0000000..0956af7
--- /dev/null
@@ -0,0 +1,129 @@
+/* src/vm/jit/arm/md-asm.h - assembler defines for arm ABI
+
+   Copyright (C) 1996-2005, 2006 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Michael Starzinger
+
+   Changes: Christian Thalinger
+
+   $Id: md-asm.h 6514 2006-02-17 20:05:00Z michi $
+
+*/
+
+
+#ifndef _MD_ASM_H
+#define _MD_ASM_H
+
+#include "config.h"
+
+
+/* register defines ***********************************************************/
+
+#define res1    r0  /* result registers         */
+#define res2    r1
+
+#define a1      r0  /* argument registers       */
+#define a2      r1
+#define a3      r2
+#define a4      r3
+
+#define v1      r4  /* variable registers       */
+#define v2      r5
+#define v3      r6
+#define v4      r7
+#define v5      r8
+#define v6      r9
+#define v7      r10
+#define v8      r11
+
+#define pc      r15 /* program counter          */
+#define lr      r14 /* return address           */
+#define sp      r13 /* stack pointer            */
+#define ip      r12 /* something like pv        */
+#define fp      r11 /* frame pointer (not used) */
+
+#define itmp1   v7  /* temporary scratch regs   */
+#define itmp2   v8
+#define itmp3   v6
+
+#define mptr    v8
+
+#define xptr  itmp1 /* exception registers      */
+#define xpc   itmp2
+
+
+/* save and restore macros ****************************************************/
+
+#define SAVE_ARGUMENT_REGISTERS \
+       stmfd   sp!, {a1,a2,a3,a4,lr}
+
+#define SAVE_ARGUMENT_REGISTERS_IP \
+       stmfd   sp!, {a1,a2,a3,a4,ip,lr}
+
+#if defined(ENABLE_SOFTFLOAT)
+# define SAVE_FLOAT_REGISTERS
+#else
+# define SAVE_FLOAT_REGISTERS \
+       sfmfd   f0, 4, [sp]!; \
+       sfmfd   f4, 4, [sp]!
+#endif
+
+#define SAVE_SCRATCH_REGISTERS \
+       stmfd   sp!, {itmp3,itmp1,itmp2,lr}
+
+
+#define RESTORE_ARGUMENT_REGISTERS \
+       ldmfd   sp!, {a1,a2,a3,a4,lr}
+
+#define RESTORE_ARGUMENT_REGISTERS_IP \
+       ldmfd   sp!, {a1,a2,a3,a4,ip,lr}
+
+#if defined(ENABLE_SOFTFLOAT)
+# define RESTORE_FLOAT_REGISTERS
+#else
+# define RESTORE_FLOAT_REGISTERS \
+       lfmfd   f4, 4, [sp]!; \
+       lfmfd   f0, 4, [sp]!
+#endif
+
+#define RESTORE_SCRATCH_REGS_AND_RETURN \
+       ldmfd   sp!, {itmp3,itmp1,itmp2,pc}
+
+#endif /* _MD_ASM_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:
+ */
diff --git a/src/vm/jit/arm/md.c b/src/vm/jit/arm/md.c
new file mode 100644 (file)
index 0000000..80c6b2f
--- /dev/null
@@ -0,0 +1,285 @@
+/* src/vm/jit/arm/md.c - machine dependent Arm functions
+
+   Copyright (C) 1996-2005, 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Michael Starzinger
+            Christian Thalinger
+
+   $Id: md.c 6591 2007-01-02 19:14:25Z twisti $
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+
+#include "vm/global.h"
+#include "vm/types.h"
+
+#include "vm/jit/arm/md-abi.h"
+
+#include "vm/exceptions.h"
+#include "vm/stringlocal.h"
+#include "vm/jit/asmpart.h"
+
+
+/* md_init *********************************************************************
+
+   Do some machine dependent initialization.
+
+*******************************************************************************/
+
+void md_init(void)
+{
+       /* do nothing here */
+}
+
+
+/* md_codegen_patch_branch *****************************************************
+
+   Back-patches a branch instruction.
+
+*******************************************************************************/
+
+void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
+{
+       s4 *mcodeptr;
+       s4  disp;                           /* branch displacement                */
+
+       /* calculate the patch position */
+
+       mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
+
+       /* Calculate the branch displacement. */
+
+       disp = (targetmpc - branchmpc - 4) >> 2;
+
+       if ((disp < (s4) 0xff000000) || (disp > (s4) 0x00ffffff))
+               vm_abort("md_codegen_patch_branch: branch displacement out of range: %d > +/-%d", disp, 0x00ffffff);
+
+       /* patch the branch instruction before the mcodeptr */
+
+       mcodeptr[-1] |= (disp & 0x00ffffff);
+}
+
+
+/* md_stacktrace_get_returnaddress *********************************************
+
+   Returns the return address of the current stackframe, specified by
+   the passed stack pointer and the stack frame size.
+
+*******************************************************************************/
+
+u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
+{
+       u1 *ra;
+
+       /*printf("md_stacktrace_get_returnaddress(): called (sp=%x, framesize=%d)\n", sp, framesize);*/
+
+       /* on ARM the return address is located on the top of the stackframe */
+       /* ATTENTION: this is only true for non-leaf methods !!! */
+       ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
+
+       /*printf("md_stacktrace_get_returnaddress(): result (ra=%x)\n", ra);*/
+
+       return ra;
+}
+
+
+/* md_assembler_get_patch_address **********************************************
+
+   Gets the patch address of the currently compiled method. The offset
+   is extracted from the load instruction(s) before the jump and added
+   to the right base address (PV or REG_METHODPTR).
+
+   Machine code:
+
+   e51cc040    ldr   ip, [ip, #-64]
+   e1a0e00f    mov   lr, pc
+   e1a0f00c    mov   pc, ip
+
+   or
+
+   e590b000    ldr   fp, [r0]
+   e59bc000    ldr   ip, [fp]
+   e1a0e00f    mov   lr, pc
+   e1a0f00c    mov   pc, ip
+
+   How we find out the patching address to store new method pointer:
+    - loaded IP with LDR IP,[METHODPTR]?
+        yes=INVOKEVIRTUAL or INVOKEINTERFACE (things are easy!)
+    - loaded IP from data segment
+        yes=INVOKESTATIC or INVOKESPECIAL (things are complicated)
+        recompute pointer to data segment, maybe larger offset 
+
+*******************************************************************************/
+
+u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
+{
+       u4  mcode;
+       s4  offset;
+       u1 *pa;                             /* patch address                      */
+
+       /* sanity check: are we inside jit code? */
+
+       assert(*((u4 *) (ra - 2*4)) == 0xe1a0e00f /*MOV LR,PC*/);
+       assert(*((u4 *) (ra - 1*4)) == 0xe1a0f00c /*MOV PC,IP*/);
+
+       /* get the load instruction and offset */
+
+       mcode  = *((u4 *) (ra - 12));
+       offset = (s4) (mcode & 0x0fff);
+
+       assert ((mcode & 0xff70f000) == 0xe510c000);
+
+       if ((mcode & 0x000f0000) == 0x000b0000) {
+               /* sanity check: offset was positive */
+
+               assert((mcode & 0x00800000) == 0x00800000);
+
+               /* we loaded from REG_METHODPTR */
+
+               pa = mptr + offset;
+       }
+       else {
+               /* sanity check: we loaded from REG_IP; offset was negative or zero */
+
+               assert((mcode & 0x008f0000) == 0x000c0000 ||
+                      (mcode & 0x008f0fff) == 0x008c0000);
+
+               /* we loaded from data segment; offset can be larger */
+
+               mcode = *((u4 *) (ra - 4*4));
+
+               /* check for "SUB IP, IP, #??, ROTL 12" */
+
+               if ((mcode & 0xffffff00) == 0xe24cca00)
+                       offset += (s4) ((mcode & 0x00ff) << 12);
+
+               /* and get the final data segment address */
+
+               pa = sfi->pv - offset;        
+       }
+
+       return pa;
+}
+
+
+/* md_codegen_get_pv_from_pc ***************************************************
+
+   TODO: document me
+
+*******************************************************************************/
+
+u1 *md_codegen_get_pv_from_pc(u1 *ra)
+{
+       u1 *pv;
+       u4  mcode1, mcode2, mcode3;
+
+       pv = ra;
+
+       /* this can either be a RECOMPUTE_IP in JIT code or a fake in asm_calljavafunction */
+       mcode1 = *((u4*) ra);
+       if ((mcode1 & 0xffffff00) == 0xe24fcf00 /*sub ip,pc,#__*/)
+               pv -= (s4) ((mcode1 & 0x000000ff) <<  2);
+       else if ((mcode1 & 0xffffff00) == 0xe24fc000 /*sub ip,pc,#__*/)
+               pv -= (s4) (mcode1 & 0x000000ff);
+       else {
+               /* if this happens, we got an unexpected instruction at (*ra) */
+               throw_cacao_exception_exit(string_java_lang_InternalError,
+                  "Unable to find method: %p (instr=%x)\n",
+                  ra, mcode1);
+       }
+
+       /* if we have a RECOMPUTE_IP there can be more than one instruction */
+       mcode2 = *((u4*) (ra + 4));
+       mcode3 = *((u4*) (ra + 8));
+       if ((mcode2 & 0xffffff00) == 0xe24ccb00 /*sub ip,ip,#__*/)
+               pv -= (s4) ((mcode2 & 0x000000ff) << 10);
+       if ((mcode3 & 0xffffff00) == 0xe24cc700 /*sub ip,ip,#__*/)
+               pv -= (s4) ((mcode3 & 0x000000ff) << 18);
+
+       /* we used PC-relative adressing; but now it is LR-relative */
+       pv += 8;
+
+       /* if we found our method the data segment has to be valid */
+       /* we check this by looking up the IsLeaf field, which has to be boolean */
+       assert( *((s4*)pv-4) == (s4)true || *((s4*)pv-4) == (s4)false ); 
+
+       return pv;
+}
+
+
+/* md_cacheflush ***************************************************************
+
+   Calls the system's function to flush the instruction and data
+   cache.
+
+*******************************************************************************/
+
+void md_cacheflush(u1 *addr, s4 nbytes)
+{
+       asm_cacheflush(addr, nbytes);
+}
+
+
+/* md_icacheflush **************************************************************
+
+   Calls the system's function to flush the instruction cache.
+
+*******************************************************************************/
+
+void md_icacheflush(u1 *addr, s4 nbytes)
+{
+       asm_cacheflush(addr, nbytes);
+}
+
+
+/* md_dcacheflush **************************************************************
+
+   Calls the system's function to flush the data cache.
+
+*******************************************************************************/
+
+void md_dcacheflush(u1 *addr, s4 nbytes)
+{
+       asm_cacheflush(addr, nbytes);
+}
+
+
+/*
+ * 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:
+ */
diff --git a/src/vm/jit/arm/patcher.c b/src/vm/jit/arm/patcher.c
new file mode 100644 (file)
index 0000000..f7135b2
--- /dev/null
@@ -0,0 +1,766 @@
+/* src/vm/jit/arm/patcher.c - ARM code patching functions
+
+   Copyright (C) 1996-2005, 2006 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
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Michael Starzinger
+
+   Changes: Christian Thalinger
+
+   $Id: patcher.c 6541 2006-08-22 14:48:01Z twisti $
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+
+#include "vm/types.h"
+
+#include "mm/memory.h"
+#include "native/native.h"
+#include "vm/builtin.h"
+#include "vm/exceptions.h"
+#include "vm/field.h"
+#include "vm/initialize.h"
+#include "vm/options.h"
+#include "vm/references.h"
+#include "vm/resolve.h"
+#include "vm/jit/asmpart.h"
+#include "vm/jit/patcher.h"
+
+
+#define gen_resolveload(inst,offset) \
+       assert((offset) >= -0x0fff && (offset) <= 0x0fff); \
+       assert(!((inst) & 0x0fff)); \
+       if ((offset) <  0) { \
+               (inst) = ((inst) & 0xff7ff000) | ((-(offset)) & 0x0fff); \
+               /*(inst) &= ~(1 << 23);*/ \
+       } else { \
+               (inst) = ((inst) & 0xfffff000) | ((offset) & 0x0fff); \
+               /*(inst) |= (1 << 23);*/ \
+       }
+
+
+/* patcher_wrapper *************************************************************
+
+   Wrapper for all patchers.  It also creates the stackframe info
+   structure.
+
+   If the return value of the patcher function is false, it gets the
+   exception object, clears the exception pointer and returns the
+   exception.
+
+*******************************************************************************/
+
+java_objectheader *patcher_wrapper(u1 *sp, u1 *pv, u1 *ra)
+{
+       stackframeinfo     sfi;
+       u1                *xpc;
+       java_objectheader *o;
+       u4                 mcode;
+       functionptr        f;
+       bool               result;
+       java_objectheader *e;
+
+       /* define the patcher function */
+
+       bool (*patcher_function)(u1 *);
+
+       assert(pv != NULL);
+
+       /* get stuff from the stack */
+
+       xpc = (u1 *)                *((ptrint *) (sp + 4 * 4));
+       o   = (java_objectheader *) *((ptrint *) (sp + 3 * 4));
+       f   = (functionptr)         *((ptrint *) (sp + 0 * 4));
+
+       /* calculate and set the new return address */
+
+       xpc = xpc - 1 * 4;
+
+       *((ptrint *) (sp + 4 * 4)) = (ptrint) xpc;
+
+       /* store PV into the patcher function position */
+
+       *((ptrint *) (sp + 0 * 4)) = (ptrint) pv;
+
+       /* cast the passed function to a patcher function */
+
+       patcher_function = (bool (*)(u1 *)) (ptrint) f;
+
+       /* enter a monitor on the patching position */
+
+       PATCHER_MONITORENTER;
+
+       /* create the stackframeinfo */
+
+       stacktrace_create_extern_stackframeinfo(&sfi, pv, sp + 7 * 4, ra, xpc);
+
+       /* call the proper patcher function */
+
+       result = (patcher_function)(sp);
+
+       /* remove the stackframeinfo */
+
+       stacktrace_remove_stackframeinfo(&sfi);
+
+       /* check for an error, get the exception and return it */
+
+       if (result == false) {
+               e = exceptions_get_and_clear_exception();
+
+               PATCHER_MONITOREXIT;
+
+               return e;
+       }
+
+       /* patch back original code */
+
+       mcode = *((u4 *) (sp + 2 * 4));
+
+       *((u4 *) xpc) = mcode;
+
+       /* synchronize instruction cache */
+
+       md_icacheflush(xpc, 1 * 4);
+
+       PATCHER_MARK_PATCHED_MONITOREXIT;
+
+       return NULL;
+}
+
+
+/* patcher_get_putstatic *******************************************************
+
+   Machine code:
+
+   <patched call position>
+   e51c103c    ldr   r1, [ip, #-60]
+
+*******************************************************************************/
+
+bool patcher_get_putstatic(u1 *sp)
+{
+       s4                disp;
+       unresolved_field *uf;
+       u1               *pv;
+       fieldinfo        *fi;
+
+       /* get stuff from the stack */
+
+       disp =                      *((s4 *)     (sp + 5 * 4));
+       uf   = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
+       pv   = (u1 *)               *((ptrint *) (sp + 0 * 4));
+
+       /* get the fieldinfo */
+
+       if (!(fi = resolve_field_eager(uf)))
+               return false;
+
+       /* check if the field's class is initialized */
+
+       if (!(fi->class->state & CLASS_INITIALIZED))
+               if (!initialize_class(fi->class))
+                       return false;
+
+       /* patch the field value's address */
+
+       *((ptrint *) (pv + disp)) = (ptrint) &(fi->value);
+
+       return true;
+}
+
+
+/* patcher_get_putfield ********************************************************
+
+   Machine code:
+
+   <patched call position>
+   e58a8000    str   r8, [sl, #__]
+
+*******************************************************************************/
+
+bool patcher_get_putfield(u1 *sp)
+{
+       u1                *ra;
+       u4                 mcode;
+       unresolved_field  *uf;
+       u1                *pv;
+       fieldinfo         *fi;
+
+       /* get stuff from the stack */
+       ra    = (u1*)                 *((ptrint *) (sp + 4 * 4));
+       mcode =                       *((u4 *)     (sp + 2 * 4));
+       uf    = (unresolved_field*)   *((ptrint *) (sp + 1 * 4));
+       pv    = (u1*)                 *((ptrint *) (sp + 0 * 4));
+
+       /* get the fieldinfo */
+
+       if (!(fi = resolve_field_eager(uf)))
+               return false;
+
+       /* if we show disassembly, we have to skip the nop */
+
+       if (opt_showdisassemble) {
+               ra = ra + 1 * 4;
+
+               /* patch the field's offset into the instruction */
+
+               switch(fi->type) {
+               case TYPE_ADR:
+               case TYPE_INT:
+#if defined(ENABLE_SOFTFLOAT)
+               case TYPE_FLT:
+#endif
+                       assert(fi->offset <= 0x0fff);
+                       *((u4 *) (ra + 0 * 4)) |= (fi->offset & 0x0fff);
+                       break;
+
+               case TYPE_LNG:
+#if defined(ENABLE_SOFTFLOAT)
+               case TYPE_DBL:
+#endif
+                       assert((fi->offset + 4) <= 0x0fff);
+                       *((u4 *) (ra + 0 * 4)) |= ((fi->offset + 0) & 0x0fff);
+                       *((u4 *) (ra + 1 * 4)) |= ((fi->offset + 4) & 0x0fff);
+                       break;
+
+#if !defined(ENABLE_SOFTFLOAT)
+               case TYPE_FLT:
+               case TYPE_DBL:
+                       assert(fi->offset <= 0x03ff);
+                       *((u4 *) (ra + 0 * 4)) |= ((fi->offset >> 2) & 0x00ff);
+                       break;
+#endif
+               }
+       }
+       else {
+               /* patch the field's offset into the instruction stored on the
+                  stack and the next instruction in the code */
+
+               switch(fi->type) {
+               case TYPE_ADR:
+               case TYPE_INT:
+#if defined(ENABLE_SOFTFLOAT)
+               case TYPE_FLT:
+#endif
+                       assert(fi->offset <= 0x0fff);
+                       *((u4 *) (sp + 2 * 4)) |= (fi->offset & 0x0fff);
+                       break;
+
+               case TYPE_LNG:
+#if defined(ENABLE_SOFTFLOAT)
+               case TYPE_DBL:
+#endif
+                       assert((fi->offset + 4) <= 0x0fff);
+                       *((u4 *) (sp + 2 * 4)) |= ((fi->offset + 0) & 0x0fff);
+                       *((u4 *) (ra + 1 * 4)) |= ((fi->offset + 4) & 0x0fff);
+                       break;
+
+#if !defined(ENABLE_SOFTFLOAT)
+               case TYPE_FLT:
+               case TYPE_DBL:
+                       assert(fi->offset <= 0x03ff);
+                       *((u4 *) (sp + 2 * 4)) |= ((fi->offset >> 2) & 0x00ff);
+                       break;
+#endif
+               }
+       }
+
+       /* synchronize instruction cache */
+
+       md_icacheflush(ra, 2 * 4);
+
+       return true;
+}
+
+
+/* patcher_aconst **************************************************************
+
+   Machine code:
+
+   <patched call postition>
+   e51cc030    ldr   r0, [ip, #-48]
+
+*******************************************************************************/
+
+bool patcher_aconst(u1 *sp)
+{
+       s4                 disp;
+       constant_classref *cr;
+       u1                *pv;
+       classinfo         *c;
+
+       /* get stuff from the stack */
+
+       disp =                       *((s4 *)     (sp + 5 * 4));
+       cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
+       pv   = (u1 *)                *((ptrint *) (sp + 0 * 4));
+
+       /* get the classinfo */
+
+       if (!(c = resolve_classref_eager(cr)))
+               return false;
+
+       /* patch the classinfo pointer */
+
+       *((ptrint *) (pv + disp)) = (ptrint) c;
+
+       return true;
+}
+
+
+/* patcher_builtin_multianewarray **********************************************
+
+   Machine code:
+
+   <patched call position>
+   e3a00002    mov   r0, #2  ; 0x2
+   e51c1064    ldr   r1, [ip, #-100]
+   e1a0200d    mov   r2, sp
+   e1a0e00f    mov   lr, pc
+   e51cf068    ldr   pc, [ip, #-104]
+
+*******************************************************************************/
+
+bool patcher_builtin_multianewarray(u1 *sp)
+{
+       s4                 disp;
+       constant_classref *cr;
+       u1                *pv;
+       classinfo         *c;
+
+       /* get stuff from the stack */
+
+       disp =                       *((s4 *)     (sp + 5 * 4));
+       cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
+       pv   = (u1 *)                *((ptrint *) (sp + 0 * 4));
+
+       /* get the classinfo */
+
+       if (!(c = resolve_classref_eager(cr)))
+               return false;
+
+       /* patch the classinfo pointer */
+
+       *((ptrint *) (pv + disp)) = (ptrint) c;
+
+       return true;
+}
+
+
+/* patcher_builtin_arraycheckcast **********************************************
+
+   Machine code:
+
+   <patched call position>
+   e51c1120    ldr   r1, [ip, #-288]
+   e1a0e00f    mov   lr, pc
+   e51cf124    ldr   pc, [ip, #-292]
+
+*******************************************************************************/
+
+bool patcher_builtin_arraycheckcast(u1 *sp)
+{
+       s4                 disp;
+       constant_classref *cr;
+       u1                *pv;
+       classinfo         *c;
+
+       /* get stuff from the stack */
+
+       disp =                       *((s4 *)     (sp + 5 * 4));
+       cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
+       pv   = (u1 *)                *((ptrint *) (sp + 0 * 4));
+
+       /* get the classinfo */
+
+       if (!(c = resolve_classref_eager(cr)))
+               return false;
+
+       /* patch the classinfo pointer */
+
+       *((ptrint *) (pv + disp)) = (ptrint) c;
+
+       return true;
+}
+
+
+/* patcher_invokestatic_special ************************************************
+
+   Machine code:
+
+   <patched call position>
+   e51cc02c    ldr   ip, [ip, #-44]
+   e1a0e00f    mov   lr, pc
+   e1a0f00c    mov   pc, ip
+
+******************************************************************************/
+
+bool patcher_invokestatic_special(u1 *sp)
+{
+       s4                 disp;
+       unresolved_method *um;
+       u1                *pv;
+       methodinfo        *m;
+
+       /* get stuff from the stack */
+
+       disp  =                       *((s4 *)     (sp + 5 * 4));
+       um    = (unresolved_method*)  *((ptrint *) (sp + 1 * 4));
+       pv    = (u1*)                 *((ptrint *) (sp + 0 * 4));
+
+       /* get the methodinfo */
+
+       if (!(m = resolve_method_eager(um)))
+               return false;
+
+       /* patch stubroutine */
+
+       *((ptrint *) (pv + disp)) = (ptrint) m->stubroutine;
+
+       return true;
+}
+
+
+/* patcher_invokevirtual *******************************************************
+
+   Machine code:
+
+   <patched call position>
+   e590b000    ldr   fp, [r0]
+   e59bc000    ldr   ip, [fp, #__]
+   e1a0e00f    mov   lr, pc
+   e1a0f00c    mov   pc, ip
+
+*******************************************************************************/
+
+bool patcher_invokevirtual(u1 *sp)
+{
+       u1                *ra;
+       unresolved_method *um;
+       methodinfo        *m;
+
+       /* get stuff from the stack */
+
+       ra = (u1 *)                *((ptrint *) (sp + 4 * 4));
+       um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
+
+       /* get the methodinfo */
+
+       if (!(m = resolve_method_eager(um)))
+               return false;
+
+       /* if we show disassembly, we have to skip the nop */
+
+       if (opt_showdisassemble)
+               ra = ra + 1 * 4;
+
+       /* patch vftbl index */
+
+       gen_resolveload(*((s4 *) (ra + 1 * 4)), (s4) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex));
+
+       /* synchronize instruction cache */
+
+       md_icacheflush(ra + 1 * 4, 1 * 4);
+
+       return true;
+}
+
+
+/* patcher_invokeinterface *****************************************************
+
+   Machine code:
+
+   <patched call position>
+   e590b000    ldr   fp, [r0]
+   e59bb000    ldr   fp, [fp, #__]
+   e59bc000    ldr   ip, [fp, #__]
+   e1a0e00f    mov   lr, pc
+   e1a0f00c    mov   pc, ip
+
+
+*******************************************************************************/
+
+bool patcher_invokeinterface(u1 *sp)
+{
+       u1                *ra;
+       unresolved_method *um;
+       methodinfo        *m;
+
+       /* get stuff from the stack */
+
+       ra = (u1 *)                *((ptrint *) (sp + 4 * 4));
+       um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
+
+       /* get the methodinfo */
+
+       if (!(m = resolve_method_eager(um)))
+               return false;
+
+       /* if we show disassembly, we have to skip the nop */
+
+       if (opt_showdisassemble)
+               ra = ra + 1 * 4;
+
+       /* patch interfacetable index */
+
+       gen_resolveload(*((s4 *) (ra + 1 * 4)), (s4) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index));
+
+       /* patch method offset */
+
+       gen_resolveload(*((s4 *) (ra + 2 * 4)), (s4) (sizeof(methodptr) * (m - m->class->methods)));
+
+       /* synchronize instruction cache */
+
+       md_icacheflush(ra + 1 * 4, 2 * 4);
+
+       return true;
+}
+
+
+/* patcher_checkcast_instanceof_flags ******************************************
+
+   Machine code:
+
+   <patched call position>
+
+*******************************************************************************/
+
+bool patcher_checkcast_instanceof_flags(u1 *sp)
+{
+       s4                 disp;
+       constant_classref *cr;
+       u1                *pv;
+       classinfo         *c;
+
+       /* get stuff from the stack */
+
+       disp  =                       *((s4 *)     (sp + 5 * 4));
+       cr    = (constant_classref *) *((ptrint *) (sp + 1 * 4));
+       pv    = (u1 *)                *((ptrint *) (sp + 0 * 4));
+
+       /* get the classinfo */
+
+       if (!(c = resolve_classref_eager(cr)))
+               return false;
+
+       /* patch class flags */
+
+       *((s4 *) (pv + disp)) = (s4) c->flags;
+
+       return true;
+}
+
+
+/* patcher_checkcast_instanceof_interface **************************************
+
+   Machine code:
+
+   <patched call position>
+   e59ab000    ldr   fp, [sl]
+   e59b9010    ldr   r9, [fp, #16]
+   e3590000    cmp   r9, #0  ; 0x0
+   da000000    ble   0x000000
+   e59b9000    ldr   r9, [fp, #__]
+   e1190009    tst   r9, r9
+   0a000000    beq   0x000000
+
+*******************************************************************************/
+
+bool patcher_checkcast_instanceof_interface(u1 *sp)
+{
+       u1                *ra;
+       constant_classref *cr;
+       classinfo         *c;
+
+       /* get stuff from the stack */
+
+       ra = (u1 *)                *((ptrint *) (sp + 4 * 4));
+       cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
+
+       /* get the classinfo */
+
+       if (!(c = resolve_classref_eager(cr)))
+               return false;
+
+       /* if we show disassembly, we have to skip the nop */
+
+       if (opt_showdisassemble)
+               ra = ra + 4;
+
+       /* patch super class index */
+
+       assert(*((s4 *) (ra + 2 * 4)) == 0xe3590000);
+       assert(c->index <= 0xff);
+
+       *((s4 *) (ra + 2 * 4)) |= (s4) (c->index & 0x000000ff);
+
+       /* patch super class vftbl index */
+
+       gen_resolveload(*((s4 *) (ra + 4 * 4)), (s4) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * c->index));
+
+       /* synchronize instruction cache */
+
+       md_icacheflush(ra + 2 * 4, 3 * 4);
+
+       return true;
+}
+
+
+/* patcher_checkcast_instanceof_class ******************************************
+
+   Machine code:
+
+   <patched call position>
+
+*******************************************************************************/
+
+bool patcher_checkcast_instanceof_class(u1 *sp)
+{
+       s4                 disp;
+       constant_classref *cr;
+       u1                *pv;
+       classinfo         *c;
+
+       /* get stuff from the stack */
+
+       disp =                       *((s4 *)     (sp + 5 * 4));
+       cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
+       pv   = (u1 *)                *((ptrint *) (sp + 0 * 4));
+
+       /* get the classinfo */
+
+       if (!(c = resolve_classref_eager(cr)))
+               return false;
+
+       /* patch super class' vftbl */
+
+       *((ptrint *) (pv + disp)) = (ptrint) c->vftbl;
+
+       return true;
+}
+
+
+/* patcher_clinit **************************************************************
+
+   XXX
+
+*******************************************************************************/
+
+bool patcher_clinit(u1 *sp)
+{
+       classinfo *c;
+
+       /* get stuff from the stack */
+
+       c = (classinfo *) *((ptrint *) (sp + 1 * 4));
+
+       /* check if the class is initialized */
+
+       if (!(c->state & CLASS_INITIALIZED))
+               if (!initialize_class(c))
+                       return false;
+
+       return true;
+}
+
+
+/* patcher_athrow_areturn ******************************************************
+
+   Machine code:
+
+   <patched call position>
+
+*******************************************************************************/
+
+#ifdef ENABLE_VERIFIER
+bool patcher_athrow_areturn(u1 *sp)
+{
+       unresolved_class *uc;
+       classinfo        *c;
+
+       /* get stuff from the stack */
+
+       uc = (unresolved_class *) *((ptrint *) (sp + 1 * 4));
+
+       /* check if the class is initialized */
+
+       if (!resolve_class(uc, resolveEager, false, &c))
+               return false;
+
+       return true;
+}
+#endif /* ENABLE_VERIFIER */
+
+
+/* patcher_resolve_native ******************************************************
+
+   XXX
+
+*******************************************************************************/
+
+#if !defined(WITH_STATIC_CLASSPATH)
+bool patcher_resolve_native(u1 *sp)
+{
+       s4           disp;
+       methodinfo  *m;
+       u1          *pv;
+       functionptr  f;
+
+       /* get stuff from the stack */
+
+       disp =                *((s4 *)     (sp + 5 * 4));
+       m    = (methodinfo *) *((ptrint *) (sp + 1 * 4));
+       pv   = (u1 *)         *((ptrint *) (sp + 0 * 4));
+
+       /* resolve native function */
+
+       if (!(f = native_resolve_function(m)))
+               return false;
+
+       /* patch native function pointer */
+
+       *((ptrint *) (pv + disp)) = (ptrint) f;
+
+       return true;
+}
+#endif /* !defined(WITH_STATIC_CLASSPATH) */
+
+
+/*
+ * 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:
+ */