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.
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.
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)])
[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]
##
## 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
\
intrp \
alpha \
+ arm \
i386 \
mips \
parisc \
--- /dev/null
+*.a
+*.o
+*.la
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
+TAGS
+offsets.h
--- /dev/null
+## 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:
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */
--- /dev/null
+*.a
+*.o
+*.la
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
+TAGS
--- /dev/null
+## 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:
--- /dev/null
+/* 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:
+ */
+
--- /dev/null
+#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
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */