dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
dnl 02110-1301, USA.
dnl
-dnl $Id: configure.ac 6595 2007-01-11 14:19:48Z twisti $
+dnl $Id: configure.ac 7219 2007-01-16 22:18:57Z pm $
dnl Process this file with autoconf to produce a configure script.
USE_SCHEDULER="1"
;;
+s390 )
+ ARCH_DIR="s390"
+ ARCH_CFLAGS="-D__S390__"
+ ;;
+
+
* )
AC_MSG_ERROR($host_cpu systems are not supported at this time)
;;
dnl check for binutils headers and libraries on some architectures for the
dnl disassembler
case "${ARCH_DIR}" in
- arm | i386 | powerpc | x86_64 | sparc64 | powerpc64)
+ arm | i386 | powerpc | x86_64 | sparc64 | powerpc64 | s390)
AC_CHECK_HEADER([ansidecl.h],, [AC_MSG_ERROR(cannot find ansidecl.h)])
AC_CHECK_HEADER([symcat.h],, [AC_MSG_ERROR(cannot find symcat.h)])
AC_CHECK_HEADER([bfd.h],, [AC_MSG_ERROR(cannot find bfd.h)])
[src/vm/jit/tools/Makefile]
[src/vm/jit/verify/Makefile]
[src/vm/jit/x86_64/Makefile]
+ [src/vm/jit/s390/Makefile]
[tests/Makefile]
[tests/regression/Makefile]
[tests/regression/codepatching/Makefile]
##
## Changes: Edwin Steiner
##
-## $Id: Makefile.am 6595 2007-01-11 14:19:48Z twisti $
+## $Id: Makefile.am 7219 2007-01-16 22:18:57Z pm $
## Process this file with automake to produce Makefile.in
powerpc \
powerpc64 \
sparc64 \
- x86_64
+ x86_64 \
+ s390
SUBDIRS = \
optimizing \
Changes:
- $Id: disass-common.c 4844 2006-04-25 18:02:15Z edwin $
+ $Id: disass-common.c 7219 2007-01-16 22:18:57Z pm $
*/
/* We need this on i386 and x86_64 since we don't know the byte length
of currently printed instructions. 512 bytes should be enough. */
-#if defined(__I386__) || defined(__X86_64__)
+#if defined(__I386__) || defined(__X86_64__) || defined(__S390__)
char disass_buf[512];
s4 disass_len;
#endif
va_start(ap, fmt);
-#if defined(__I386__) || defined(__X86_64__)
+#if defined(__I386__) || defined(__X86_64__) || defined(__S390__)
disass_len += vsprintf(disass_buf + disass_len, fmt, ap);
#else
vprintf(fmt, ap);
Changes:
- $Id: disass.h 4709 2006-03-30 10:14:22Z twisti $
+ $Id: disass.h 7219 2007-01-16 22:18:57Z pm $
*/
extern char *regs[];
-#if defined(__I386__) || defined(__X86_64__)
+#if defined(__I386__) || defined(__X86_64__) || defined(__S390__)
extern char disass_buf[512];
extern s4 disass_len;
#endif
--- /dev/null
+*.a
+*.o
+*.la
+*.lo
+.deps
+.libs
+Makefile
+Makefile.in
+TAGS
+offsets.h
--- /dev/null
+## src/vm/jit/x86_64/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:
+##
+## $Id: Makefile.am 5830 2006-10-26 11:04:31Z twisti $
+
+## Process this file with automake to produce Makefile.in
+
+AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir) -I$(top_builddir)/src
+AM_CCASFLAGS = $(AM_CPPFLAGS) $(AM_LDFLAGS)
+
+LIBS =
+
+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 \
+ emit.h \
+ patcher.c \
+ \
+ md-abi.c \
+ md-abi.h \
+ md.c
+
+$(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/x86_64/arch.h - architecture defines for x86_64
+
+ 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:
+
+ $Id: arch.h 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+
+#ifndef _ARCH_H
+#define _ARCH_H
+
+/* define architecture features ***********************************************/
+
+#define U8_AVAILABLE 1
+
+/* #define USEBUILTINTABLE */
+
+#define SUPPORT_DIVISION 1
+#define SUPPORT_LONG 1
+#define SUPPORT_FLOAT 1
+#define SUPPORT_DOUBLE 1
+
+#define SUPPORT_I2F 1
+#define SUPPORT_I2D 1
+#define SUPPORT_L2F 1
+#define SUPPORT_L2D 1
+
+/* ATTENTION: x86_64 architectures support these conversions, but we
+ need the builtin functions in corner cases */
+#define SUPPORT_F2I 0
+#define SUPPORT_F2L 0
+#define SUPPORT_D2I 0
+#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 1
+#define SUPPORT_LONG_MUL 1
+#define SUPPORT_LONG_DIV 1
+
+#define SUPPORT_LONG_DIV_POW2 1
+#define SUPPORT_LONG_REM_POW2 1
+
+#define SUPPORT_CONST_LOGICAL 1 /* AND, OR, XOR with immediates */
+#define SUPPORT_CONST_MUL 1 /* mutiply with immediate */
+
+#define SUPPORT_CONST_STORE 1 /* do we support const stores */
+#define SUPPORT_CONST_STORE_ZERO_ONLY 0 /* on some risc machines we can */
+ /* only store REG_ZERO */
+
+#define CONSECUTIVE_INTEGER_ARGS
+#define CONSECUTIVE_FLOAT_ARGS
+
+#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/x86_64/asmpart.S - Java-C interface functions for x86_64
+
+ 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: Andreas Krall
+ Reinhard Grafl
+ Christian Thalinger
+
+ Changes: Edwin Steiner
+
+ $Id: asmpart.S 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+
+#include "config.h"
+
+#include "vm/jit/s390/arch.h"
+#include "vm/jit/s390/md-abi.h"
+#include "vm/jit/s390/md-asm.h"
+#include "vm/jit/s390/offsets.h"
+
+#include "vm/jit/abi-asm.h"
+#include "vm/jit/methodheader.h"
+
+/* Copy a call to a PIC function from gcc -S
+ * We setup a temporary literal pool pointer.
+ */
+
+#define PIC_CALL(fun, magic) \
+ bras itmp3, L_##magic##_lp_end ; \
+L_##magic##_lp: ; \
+L_##magic##_lp_5: ; \
+ .long fun@PLTOFF ; \
+L_##magic##_lp_4: ; \
+ .long _GLOBAL_OFFSET_TABLE_-L_##magic##_lp ; \
+L_##magic##_lp_end: ; \
+ l itmp2,L_##magic##_lp_4-L_##magic##_lp(itmp3) ; \
+ la itmp2,0(itmp2,itmp3) ; \
+ l itmp1,L_##magic##_lp_5-L_##magic##_lp(itmp3) ; \
+ bas %r14,0(itmp1,itmp2)
+
+ .text
+
+
+/* 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_replacement_out
+ .globl asm_replacement_in
+
+ .globl asm_builtin_f2i
+ .globl asm_builtin_f2l
+ .globl asm_builtin_d2i
+ .globl asm_builtin_d2l
+
+ .globl asm_criticalsections
+ .globl asm_getclassvalues_atomic
+
+
+#if 0
+asm_vm_call_method:
+asm_vm_call_method_int:
+asm_vm_call_method_long:
+asm_vm_call_method_float:
+asm_vm_call_method_double:
+#endif
+asm_vm_call_method_exception_handler:
+#if 0
+asm_call_jit_compiler:
+#endif
+asm_handle_exception:
+asm_handle_nat_exception:
+asm_abstractmethoderror:
+asm_patcher_wrapper:
+asm_replacement_out:
+asm_replacement_in:
+asm_builtin_f2i:
+asm_builtin_f2l:
+asm_builtin_d2i:
+asm_builtin_d2l:
+asm_criticalsections:
+asm_getclassvalues_atomic:
+ .long 0
+
+/********************* function asm_calljavafunction ***************************
+* *
+* 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. *
+* *
+* C-prototype: *
+* javaobject_header *asm_calljavamethod (methodinfo *m, *
+* void *arg1, void *arg2, void *arg3, void *arg4); *
+* *
+*******************************************************************************/
+ .align 8
+
+ .quad 0 /* catch type all */
+ .quad 0 /* handler pc */
+ .quad 0 /* end pc */
+ .quad 0 /* start pc */
+ .long 1 /* extable size */
+ .long 0 /* ALIGNMENT PADDING */
+ .quad 0 /* line number table start */
+ .quad 0 /* line number table size */
+ .long 0 /* ALIGNMENT PADDING */
+ .long 0 /* fltsave */
+ .long 0 /* intsave */
+ .long 0 /* isleaf */
+ .long 0 /* IsSync */
+ .long 0 /* frame size */
+ .quad 0 /* codeinfo pointer */
+
+
+asm_vm_call_method:
+asm_vm_call_method_int:
+asm_vm_call_method_long:
+asm_vm_call_method_float:
+asm_vm_call_method_double:
+
+/*
+
+a0: methodinfo *m
+a1: s4 vmargscount ---> v0: java_objectheader *
+a2: vm_arg *vmargs
+r14: return address
+
+96 ... on stack parameters (none)
+0 - 96 register save area
+-------------------------------------------------- <- SP on asm_vm_... entry
+ arguments on stack
+---------------------------------------------------- <- SP on JIT code entry
+ saved return address (callee saved)
+
+*/
+
+
+/*
+ Regiser usage:
+ itmp1: argument block pointer
+ itmp2: argument counter
+ s0: integer argument counter
+ s1: float argument counter
+ s2: integer register counter
+ s3: backup argument block pointer
+ s4: backup argument count
+*/
+
+ stm %r6, %r15, 24(sp) /* save callers regiters */
+ ahi sp, -16 /* allocate stack space for local variables */
+ stm a0, a2, 0(sp) /* save arguments */
+
+ ltr a1, a1 /* maybe we have no args... */
+ je L_no_args
+
+ lr itmp2, a1 /* load arg count */
+ lr itmp1, a2 /* load arg pointer */
+
+ ahi itmp1, -sizevmarg /* initialize arg pointer */
+ ahi itmp2, 1 /* initialize arg count */
+ lhi s0, 0 /* initialize integer arg counter */
+ lhi s2, 0 /* initialize integer register counter */
+ lhi s1, 0 /* initialize float arg counter */
+
+ lr s4, a1 /* backup arg count */
+ lr s3, a2 /* backup arg pointer */
+
+L_register_copy:
+
+ ahi itmp1, sizevmarg /* forward arg pointer */
+ ahi itmp2, -1 /* decrement arg count */
+ je L_register_copy_done /* no arguments left */
+
+ tm offvmargtype(itmp1), 0x02 /* is this a float/double type? */
+ jne L_register_handle_float
+
+L_register_handle_int:
+
+ chi s2, INT_ARG_CNT /* are we out of integer arg registers ? */
+ je L_register_copy /* yes, next loop */
+
+ tm offvmargtype(itmp1), 0x01 /* is this a 2 word type ? */
+ jne L_register_handle_long
+
+ ahi s0, 1 /* increment integer arg counter */
+ ahi s2, 1 /* increment integer register counter */
+
+ /* handle argument */
+
+ chi s2, 1
+ je L_handle_i0
+ chi s2, 2
+ je L_handle_i1
+ chi s2, 3
+ je L_handle_i2
+ chi s2, 4
+ je L_handle_i3
+ chi s2, 5
+ je L_handle_i4
+
+L_register_handle_long:
+
+ chi s2, (INT_ARG_CNT - 1) /* are there 2 integer arg registers left ? */
+ jl L_register_handle_long_continue /* yes */
+ lhi s2, INT_ARG_CNT /* no, drop last register */
+ j L_register_copy
+
+L_register_handle_long_continue:
+
+ ahi s0, 1 /* increment integer arg counter */
+ ahi s2, 2 /* consume 2 integer arg registers */
+
+ /* handle argument */
+
+ chi s2, 1
+ je L_handle_l0
+ chi s2, 2
+ je L_handle_l1
+ chi s2, 3
+ je L_handle_l2
+ chi s2, 4
+ je L_handle_l3
+
+L_register_handle_float:
+
+ chi s1, FLT_ARG_CNT /* are we out of float arg registers */
+ je L_register_copy /* no arg regisers left */
+
+ ahi s1, 1 /* increment float argument counter */
+
+ tm offvmargtype(itmp1), 0x01 /* is this a 2 word type ? */
+ jne L_register_handle_double
+
+ /* handle argument */
+
+ chi s1, 1
+ je L_handle_f0
+ chi s1, 2
+ je L_handle_f1
+
+L_register_handle_double:
+
+ /* handle argument */
+
+ chi s1, 1
+ je L_handle_d0
+ chi s1, 2
+ je L_handle_d1
+
+L_register_copy_done:
+
+/*
+ Regiser usage:
+ itmp1: argument block pointer
+ itmp2: argument counter
+ s0: integer argument counter (initialized by previous code)
+ s1: float argument counter (initialized by previous code)
+ s2: pointer to current argument on stack
+ s3: backup argument block pointer (used to initialize itmp1)
+ after used as backup of original stack pointer
+ s4: backup argument count (used to initialize itmp2)
+ after used as size of parameters on stack
+*/
+
+ lr itmp2, s4 /* restore argument counter */
+ lr itmp1, s3 /* restore argument block pointer */
+
+ /* calculate remaining arguments */
+ sr s4, s0 /* - integer arguments in registers */
+ sr s4, s1 /* - float arguments in registers */
+
+ je L_copy_done /* no arguments left for stack */
+
+ sll s4, 3 /* allocate 8 bytes per parameter on stack */
+ lr s3, sp /* backup stack pointer */
+ sr sp, s4 /* allocate stack space for arguments */
+
+ lr s2, sp /* points now to current argument on stack */
+
+ ahi itmp1, -sizevmarg /* initialize argument block pointer */
+ ahi itmp2, 1 /* initialize argument counter */
+
+L_stack_copy_loop:
+
+ ahi itmp1, sizevmarg /* forward argument block pointer */
+ ahi itmp2, -1 /* decrement argument counter */
+ je L_copy_done /* all arguments done */
+
+ tm offvmargtype(itmp1), 0x0 /* is this a float/double type? */
+ jne L_stack_handle_float
+
+L_stack_handle_int:
+
+ ahi s0, -1 /* decrement number of integer arguments in regs */
+ jhe L_stack_copy_loop /* argument is in register */
+
+ tm offvmargtype(itmp1), 0x01 /* is this a 2 word type ? */
+ jne L_stack_handle_long
+
+ mvc 0(4, s2), offvmargdata(itmp1) /* copy integer value */
+ ahi s2, 4
+ j L_stack_copy_loop
+
+L_stack_handle_long:
+
+ mvc 0(8, s2), offvmargdata(itmp1) /* copy long value */
+ ahi s2, 8
+ j L_stack_copy_loop
+
+L_stack_handle_float:
+
+ ahi s1, -1 /* decrement number of float arguments in regs */
+ jhe L_stack_copy_loop /* argument is in register */
+
+ tm offvmargtype(itmp1), 0x01 /* is this a 2 word type ? */
+ jne L_stack_handle_double
+
+ mvc 0(4, s2), offvmargdata(itmp1) /* copy float value */
+ ahi s2, 4
+ j L_stack_copy_loop
+
+L_stack_handle_double:
+
+ mvc 0(8, s2), offvmargdata(itmp1) /* copy double value */
+ ahi s2, 8
+ j L_stack_copy_loop
+
+L_copy_done:
+
+ /* Now we call the compiler in a rather questionable way i needed
+ * some days to understand:
+ *
+ * We can't simply call asm_call_jit_compiler, but we have to call an
+ * address loaded from memory like it is done in JIT code.
+ *
+ * This is because the compiler will intercept the instruction before
+ * the call instruction, extract the address where the function pointer
+ * has been loaded from and overwrite it with the code entry.
+ *
+ * Arguments are passed in temporary registers.
+ */
+
+ /* load address of L_asm_call_jit_compiler into memory */
+
+ basr mptr, 0 /* store PC */
+L_basr:
+ la mptr, L_asm_call_jit_compiler-L_basr(mptr) /* add offset to PC */
+ st mptr, 12(s3) /* store on stack */
+
+ l itmp1, 0(s3) /* load methodinfo for compiler */
+ la mptr, 12(s3) /* store **function in mptr for compiler */
+
+ /* call L_asm_call_jit_compiler like JIT code would do */
+
+ l itmp3, 12(s3) /* load address of target from memory */
+ basr %r14, itmp3 /* jump to target */
+
+ /* todo will s4 survive the call? */
+ ar sp, s4 /* remove stack space for arguments */
+
+L_asm_vm_call_method_return:
+
+ ahi sp, 16 /* remove stack space for local variables */
+ lm %r6, %r15, 24(sp) /* restore callers registers */
+ br %r14 /* return */
+
+/* .... */
+
+L_no_args:
+ lr s3, sp
+ j L_copy_done
+
+L_handle_i0:
+ l a0, offvmargdata(itmp1)
+ j L_register_copy
+L_handle_i1:
+ l a1, offvmargdata(itmp1)
+ j L_register_copy
+L_handle_i2:
+ l a2, offvmargdata(itmp1)
+ j L_register_copy
+L_handle_i3:
+ l a3, offvmargdata(itmp1)
+ j L_register_copy
+L_handle_i4:
+ l a4, offvmargdata(itmp1)
+ j L_register_copy
+
+L_handle_l0:
+ lm a0, a1, offvmargdata(itmp1)
+ j L_register_copy
+L_handle_l1:
+ lm a1, a2, offvmargdata(itmp1)
+ j L_register_copy
+L_handle_l2:
+ lm a2, a3, offvmargdata(itmp1)
+ j L_register_copy
+L_handle_l3:
+ lm a3, a4, offvmargdata(itmp1)
+ j L_register_copy
+
+L_handle_f0:
+ le fa0, offvmargdata(itmp1)
+ j L_register_copy
+L_handle_f1:
+ le fa1, offvmargdata(itmp1)
+ j L_register_copy
+
+L_handle_d0:
+ ld fa0, offvmargdata(itmp1)
+ j L_register_copy
+L_handle_d1:
+ ld fa1, offvmargdata(itmp1)
+ j L_register_copy
+
+
+/* .... */
+
+#if 0
+
+ .align 8
+
+ .quad 0 /* catch type all */
+ .quad 0 /* handler pc */
+ .quad 0 /* end pc */
+ .quad 0 /* start pc */
+ .long 1 /* extable size */
+ .long 0 /* ALIGNMENT PADDING */
+ .quad 0 /* line number table start */
+ .quad 0 /* line number table size */
+ .long 0 /* ALIGNMENT PADDING */
+ .long 0 /* fltsave */
+ .long 0 /* intsave */
+ .long 0 /* isleaf */
+ .long 0 /* IsSync */
+ .long 0 /* frame size */
+ .quad 0 /* codeinfo pointer */
+
+asm_vm_call_method:
+asm_vm_call_method_int:
+asm_vm_call_method_long:
+asm_vm_call_method_float:
+asm_vm_call_method_double:
+
+ stm %r6,%r15,24(sp) /* save callers regiters */
+
+ ahi sp, -12 /* allocate space on stack for local variables */
+
+ st a0, 0(sp) /* store method info */
+ st a1, 4(sp) /* store arg count */
+ st a2, 8(sp) /* store args */
+
+
+# define r_methodinfo itmp1
+# define r_vmargscount itmp2
+# define r_vmargs s0
+
+# define r_arg_ctr s1
+# define r_arg_ptr s2
+
+# define r_int_ctr s3
+# define r_float_ctr s4
+# define r_int_extra_ctr itmp3
+
+ /* save arguments */
+
+ lr r_methodinfo,a0 /* move method pointer for compiler */
+ lr r_vmargscount,a1
+ lr r_vmargs,a2
+
+ ltr a1,a1 /* maybe we have no args... */
+ je L_copy_done
+
+ lr r_arg_ctr,r_vmargscount /* arg count */
+ lr r_arg_ptr,r_vmargs /* pointer to arg block */
+
+ ahi r_arg_ptr,-sizevmarg /* initialize pointer (smaller code) */
+ ahi r_arg_ctr,1 /* initialize argument count */
+
+ lhi r_int_ctr,0 /* initialize integer argument counter*/
+ lhi r_float_ctr,0 /* initialize float argument counter */
+ lhi r_int_extra_ctr,0
+
+L_register_copy:
+ ahi r_arg_ptr,sizevmarg /* goto next argument block */
+ ahi r_arg_ctr,-1 /* argument count - 1 */
+ je L_register_copy_done
+
+ tm offvmargtype(r_arg_ptr),0x02 /* is this a float/double type? */
+ jne L_register_handle_float /* yes, handle it */
+
+ cli offvmargtype(r_arg_ptr),0x01
+ je L_register_handle_long
+
+L_register_handle_int:
+
+ chi r_int_ctr,INT_ARG_CNT /* are we out of integer argument */
+ je L_register_copy /* register? yes, next loop */
+
+ ahi r_int_ctr,1
+
+ chi r_int_ctr,1
+ je L_handle_a0
+ chi r_int_ctr,2
+ je L_handle_a1
+ chi r_int_ctr,3
+ je L_handle_a2
+ chi r_int_ctr,4
+ je L_handle_a3
+ chi r_int_ctr,5
+ je L_handle_a4
+
+L_register_handle_long:
+
+ chi r_int_ctr,INT_ARG_CNT-1 /* only one integer register left ? */
+ je L_register_handle_long_last_reg
+
+ chi r_int_ctr,INT_ARG_CNT /* no registers left */
+ je L_register_copy
+
+ ahi r_int_ctr,2
+ ahi r_int_extra_ctr,1
+
+ chi r_int_ctr,2
+ je L_handle_al0
+ chi r_int_ctr,3
+ je L_handle_al1
+ chi r_int_ctr,4
+ je L_handle_al2
+ chi r_int_ctr,5
+ je L_handle_al3
+
+L_register_handle_long_last_reg:
+ ahi r_int_ctr,1 /* skip the integer register */
+ ahi r_int_extra_ctr,1
+ j L_register_copy
+
+L_register_handle_float:
+ chi r_float_ctr,FLT_ARG_CNT /* are we out of float argument */
+ je L_register_copy /* register? yes, next loop */
+
+ ahi r_float_ctr,1
+
+ chi r_int_ctr,1
+ je L_handle_af0
+ chi r_int_ctr,2
+ je L_handle_af1
+
+L_register_copy_done:
+
+ lr r_arg_ctr, r_vmargscount
+ sr r_arg_ctr, r_int_ctr
+ ar r_arg_ctr, r_int_extra_ctr
+ sr r_arg_ctr, r_float_ctr
+ jle L_copy_done
+
+ /* now allocate the parameter area on the stack
+ * the register save area will be allocated later
+ */
+
+# define r_arg_stack_ptr r_arg_ptr
+
+ sll r_arg_ctr, 3 /* 8 bytes per parameter on stack */
+ sr sp,r_arg_ctr /* allocate stack space for parameters */
+ lr r_arg_stack_ptr,sp /* points now to arguments on stack */
+
+ ahi r_vmargs,-sizevmarg /* initialize pointer (smaller code) */
+ ahi r_vmargscount,1 /* initialize argument count */
+
+L_stack_copy_loop:
+ ahi r_vmargs,sizevmarg /* goto next argument block */
+ ahi r_vmargscount,-1 /* argument count - 1 */
+ jz L_copy_done /* no test needed after dec */
+
+ tm offvmargtype(r_vmargs),0x02 /* is this a float/double type? */
+ jne L_stack_handle_float /* yes, handle it */
+
+ cli offvmargtype(r_vmargs),0x01
+ je L_stack_handle_long
+
+L_stack_handle_int:
+
+ ahi r_int_ctr,-1 /* arguments assigned to registers */
+ jhe L_stack_copy_loop
+ j L_stack_copy
+
+L_stack_handle_long:
+
+ ahi r_int_ctr,-2
+ jhe L_stack_copy_loop
+ j L_stack_copy
+
+L_stack_handle_float:
+ ahi r_float_ctr,-1 /* arguments assigned to registers */
+ jhe L_stack_copy_loop
+
+L_stack_copy:
+ mvc 0(8,r_arg_stack_ptr),offvmargdata(r_vmargs) /* copy s8 argument onto stack */
+
+ ahi r_arg_stack_ptr,8 /* increase sp to next argument */
+ j L_stack_copy_loop
+
+L_copy_done:
+#if 0
+ /* itmp1 still contains method pointer*/
+ lea L_asm_call_jit_compiler(%rip),mptr
+ mov sp,itmp3 /* calculate the old stack pointer */
+ add bp,itmp3
+ mov mptr,6*8(itmp3) /* store mptr on stack */
+ lea (6*8-256)(itmp3),mptr /* We subtract 256 to force the next */
+ /* move instruction to have a 32-bit */
+ /* offset. */
+
+ mov (0*8+256)(mptr),itmp3 /* method call as in Java */
+ call *itmp3 /* call JIT compiler */
+
+ add bp,sp /* remove argument stack frame if any */
+#endif
+
+ /* itmp1 still contains method pointer*/
+
+ bras %r14, L_asm_call_jit_compiler
+ ar sp,r_arg_ctr /* r_arg_ctr in callee saved regiter */
+
+L_asm_vm_call_method_return:
+
+ ahi sp, 12 /* free stack space */
+ lm %r6,%r15,24(sp) /* restore registers */
+ br %r14 /* branch to return address */
+
+#if 0
+asm_vm_call_method_exception_handler:
+ mov xptr,a0 /* pass exception pointer */
+ call builtin_throw_exception@PLT
+ jmp L_asm_vm_call_method_return
+#endif
+
+L_handle_a0:
+ l a0,offvmargdata(r_arg_ptr)
+ j L_register_copy
+L_handle_a1:
+ l a1,offvmargdata(r_arg_ptr)
+ j L_register_copy
+L_handle_a2:
+ l a2,offvmargdata(r_arg_ptr)
+ j L_register_copy
+L_handle_a3:
+ l a3,offvmargdata(r_arg_ptr)
+ j L_register_copy
+L_handle_a4:
+ l a4,offvmargdata(r_arg_ptr)
+ j L_register_copy
+
+L_handle_al0:
+ l a0,offvmargdata(r_arg_ptr)
+ l a1,offvmargdata+4(r_arg_ptr)
+ j L_register_copy
+L_handle_al1:
+ l a1,offvmargdata(r_arg_ptr)
+ l a2,offvmargdata+4(r_arg_ptr)
+ j L_register_copy
+L_handle_al2:
+ l a2,offvmargdata(r_arg_ptr)
+ l a3,offvmargdata+4(r_arg_ptr)
+ j L_register_copy
+L_handle_al3:
+ l a3,offvmargdata(r_arg_ptr)
+ l a4,offvmargdata+4(r_arg_ptr)
+ j L_register_copy
+
+L_handle_af0:
+ ld fa0,offvmargdata(r_arg_ptr)
+ j L_register_copy
+L_handle_af1:
+ ld fa1,offvmargdata(r_arg_ptr)
+ j L_register_copy
+
+#endif
+
+/****************** function asm_call_jit_compiler *****************************
+* *
+* invokes the compiler for untranslated JavaVM methods. *
+* *
+* itmp1: methodinfo pointer *
+* itmp2: method pointer *
+* *
+*******************************************************************************/
+
+/*
+
+argument registers: arguments (like in JIT)
+
+ arguments on stack (like in JIT)
+------------------------------------------------------------- <- SP on entry
+
+ saved return address \
+ stored volatile (in terms of C ABI) floag argument registers |
+96 stored volatile (in terms of C ABI) integer argument registers | ACJC_STACKFRAME
+0 - 96 register save area (C ABI) /
+-------------------------------------------------- <- SP for jit_asm_compile
+*/
+
+/* This is called from a compiler stub.
+ * Arguments are already in registers and the stack is setup like in CACAO.
+ */
+
+asm_call_jit_compiler:
+L_asm_call_jit_compiler:
+
+# define ACJC_STACKFRAME (4 + (4 * 4) + (2 * 8) + 96)
+
+ ahi sp,-ACJC_STACKFRAME /* allocate stack space */
+
+ stm %r2,%r5,96(sp) /* store volatile int arg regs */
+ std %f0,96+16(sp) /* store volatile float arg regs */
+ std %f2,96+24(sp)
+ st %r14,96+32(sp) /* store return address */
+
+ /* load arguments */
+
+ lr a0,itmp1 /* pass methodinfo pointer */
+ lr a1,itmp2 /* pass method pointer */
+ la a2,ACJC_STACKFRAME(sp) /* pass java sp */
+ la a3,0(%r14) /* pass return address, make sure bit 32 is 0 */
+
+ /* call jit_asm_compile in a PIC way */
+
+ bras itmp3, L_bras_jac
+ .long jit_asm_compile
+L_bras_jac:
+ l itmp3, 0(itmp3)
+ basr %r14, itmp3
+
+ lm %r2,%r5,96(sp) /* restore volatile int arg regs */
+ ld %f0,96+16(sp) /* store volatile float arg regs */
+ ld %f2,96+24(sp) /* store volatile float arg regs */
+ ld %r14,96+32(sp) /* restore return address */
+
+#if 0
+ ltr v0,v0
+ je L_asm_call_jit_compiler_exception
+#endif
+
+ b 0(v0) /* call the method, it will return to the caller */
+
+
+L_asm_call_jit_compiler_exception:
+#if 0
+ call exceptions_get_and_clear_exception@PLT
+ pop xpc /* delete return address */
+ sub $3,xpc /* faulting address is ra - 3 */
+ jmp L_asm_handle_exception
+#endif
+ .long 0
+
+
+#if 0
+/* 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. *
+* *
+*******************************************************************************/
+
+asm_handle_nat_exception:
+ add $8,sp /* clear return address of native stub*/
+
+asm_handle_exception:
+L_asm_handle_exception: /* required for PIC code */
+ sub $((ARG_CNT+TMP_CNT)*8),sp /* create maybe-leaf stackframe */
+
+ SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */
+ SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */
+
+ mov $((ARG_CNT+TMP_CNT)*8),a3 /* prepare a3 for handle_exception */
+ mov $1,t0 /* set maybe-leaf flag */
+
+L_asm_handle_exception_stack_loop:
+ sub $(6*8),sp
+ mov xptr,0*8(sp) /* save exception pointer */
+ mov xpc,1*8(sp) /* save exception pc */
+ add sp,a3 /* calculate Java sp into a3... */
+ add $(6*8),a3
+ mov a3,3*8(sp) /* ...and save it */
+ mov t0,4*8(sp) /* save maybe-leaf flag */
+
+ mov xpc,a0 /* exception pc */
+ call codegen_get_pv_from_pc@PLT
+ mov v0,2*8(sp) /* save data segment pointer */
+
+ mov 0*8(sp),a0 /* pass exception pointer */
+ mov 1*8(sp),a1 /* pass exception pc */
+ mov v0,a2 /* pass data segment pointer */
+ mov 3*8(sp),a3 /* pass Java stack pointer */
+ call exceptions_handle_exception@PLT
+
+ test v0,v0
+ jz L_asm_handle_exception_not_catched
+
+ mov v0,xpc /* move handlerpc into xpc */
+ mov 0*8(sp),xptr /* restore exception pointer */
+ mov 4*8(sp),t0 /* get maybe-leaf flag */
+ add $(6*8),sp /* free stack frame */
+
+ test t0,t0 /* test for maybe-leaf flag */
+ jz L_asm_handle_exception_no_leaf
+
+ RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */
+ RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */
+
+ add $((ARG_CNT+TMP_CNT)*8),sp /* remove maybe-leaf stackframe */
+
+L_asm_handle_exception_no_leaf:
+ jmp *xpc /* jump to the handler */
+
+L_asm_handle_exception_not_catched:
+ mov 0*8(sp),xptr /* restore exception pointer */
+ mov 2*8(sp),itmp3 /* restore data segment pointer */
+ mov 4*8(sp),t0 /* get maybe-leaf flag */
+ add $(6*8),sp
+
+ test t0,t0
+ jz L_asm_handle_exception_no_leaf_stack
+
+ add $((ARG_CNT+TMP_CNT)*8),sp /* remove maybe-leaf stackframe */
+ xor t0,t0 /* clear the isleaf flags */
+
+L_asm_handle_exception_no_leaf_stack:
+ mov FrameSize(itmp3),itmp2l /* get frame size */
+ add sp,itmp2 /* pointer to save area */
+
+ mov IntSave(itmp3),a0l /* a0l = saved int register count */
+ test a0l,a0l
+ je noint
+
+ cmp $1,a0l
+ je int1
+ cmp $2,a0l
+ je int2
+ cmp $3,a0l
+ je int3
+ cmp $4,a0l
+ je int4
+
+ mov -5*8(itmp2),s0
+int4:
+ mov -4*8(itmp2),s1
+int3:
+ mov -3*8(itmp2),s2
+int2:
+ mov -2*8(itmp2),s3
+int1:
+ mov -1*8(itmp2),s4
+
+ shl $3,a0l /* multiply by 8 bytes */
+ sub a0,itmp2
+
+noint:
+#if 0
+ mov FltSave(itmp3),a0l /* a0l = saved flt register count */
+ test a0l,a0l
+ je noflt
+
+ cmpl $1,a0l
+ je flt1
+ cmpl $2,a0l
+ je flt2
+ cmpl $3,a0l
+ je flt3
+ cmpl $4,a0l
+ je flt4
+
+ movq -5*8(itmp2),%xmm11
+flt4:
+ movq -4*8(itmp2),%xmm12
+flt3:
+ movq -3*8(itmp2),%xmm13
+flt2:
+ movq -2*8(itmp2),%xmm14
+flt1:
+ movq -1*8(itmp2),%xmm15
+
+noflt:
+#endif
+ mov FrameSize(itmp3),itmp2l /* get frame size */
+ add itmp2,sp /* unwind stack */
+
+ /* exception pointer is still set */
+ pop xpc /* the new xpc is return address */
+ sub $3,xpc /* subtract 3 bytes for call */
+
+ xor a3,a3 /* prepare a3 for handle_exception */
+
+ jmp L_asm_handle_exception_stack_loop
+
+
+/* asm_abstractmethoderror *****************************************************
+
+ Creates and throws an AbstractMethodError.
+
+*******************************************************************************/
+
+asm_abstractmethoderror:
+ mov sp,a0 /* pass java sp */
+ add $1*8,a0
+ mov 0*8(sp),a1 /* pass exception address */
+ sub $3,a1
+ call exceptions_asm_new_abstractmethoderror@PLT
+ /* exception pointer is return value */
+ pop xpc /* get exception address */
+ sub $3,xpc /* exception address is ra - 3 */
+ jmp L_asm_handle_exception
+
+
+/* asm_patcher_wrapper *********************************************************
+
+ XXX
+
+ Stack layout:
+ 40 return address
+ 32 pointer to virtual java_objectheader
+ 24 machine code (which is patched back later)
+ 16 unresolved class/method/field reference
+ 8 data segment displacement from load instructions
+ 0 pointer to patcher function
+ -8 bp
+
+*******************************************************************************/
+
+asm_patcher_wrapper:
+ push bp /* save base pointer */
+ mov sp,bp /* move actual sp to bp */
+ sub $((3+ARG_CNT+TMP_CNT)*8+sizestackframeinfo),sp
+ and $0xfffffffffffffff0,sp /* align sp to 16-byte (this is for */
+ /* leaf functions) */
+
+ SAVE_ARGUMENT_REGISTERS(3)
+ SAVE_TEMPORARY_REGISTERS(3+ARG_CNT)
+
+ mov itmp1,0*8(sp) /* save itmp1 and itmp2 */
+ mov itmp2,1*8(sp) /* can be used by some instructions */
+
+ mov bp,a0 /* pass SP of patcher stub */
+ add $(1*8),a0
+ mov $0,a1 /* pass PV (if NULL, use findmethod) */
+ mov $0,a2 /* pass RA (it's on the stack) */
+ call patcher_wrapper@PLT
+ mov v0,2*8(sp) /* save return value */
+
+ RESTORE_ARGUMENT_REGISTERS(3)
+ RESTORE_TEMPORARY_REGISTERS(3+ARG_CNT)
+
+ mov 0*8(sp),itmp1 /* restore itmp1 and itmp2 */
+ mov 1*8(sp),itmp2 /* can be used by some instructions */
+ mov 2*8(sp),itmp3 /* restore return value */
+
+ mov bp,sp /* restore original sp */
+ pop bp /* restore bp */
+ add $(5*8),sp /* remove patcher stackframe, keep RA */
+
+ test itmp3,itmp3 /* exception thrown? */
+ jne L_asm_patcher_wrapper_exception
+ ret /* call new patched code */
+
+L_asm_patcher_wrapper_exception:
+ mov itmp3,xptr /* get exception */
+ pop xpc /* get and remove return address */
+ jmp L_asm_handle_exception
+
+
+/* asm_replacement_out *********************************************************
+
+ This code is jumped to from the replacement-out stubs that are executed
+ when a thread reaches an activated replacement point.
+
+ The purpose of asm_replacement_out is to read out the parts of the
+ execution state that cannot be accessed from C code, store this state,
+ and then call the C function replace_me.
+
+ Stack layout:
+ 8 start of stack inside method to replace
+ 0 rplpoint * info on the replacement point that was reached
+
+*******************************************************************************/
+
+/* some room to accomodate changes of the stack frame size during replacement */
+ /* XXX we should find a cleaner solution here */
+#define REPLACEMENT_ROOM 512
+
+asm_replacement_out:
+ /* create stack frame */
+ sub $(sizeexecutionstate + REPLACEMENT_ROOM),sp
+
+ /* save registers in execution state */
+ mov %rax,(RAX*8+offes_intregs)(sp)
+ mov %rbx,(RBX*8+offes_intregs)(sp)
+ mov %rcx,(RCX*8+offes_intregs)(sp)
+ mov %rdx,(RDX*8+offes_intregs)(sp)
+ mov %rsi,(RSI*8+offes_intregs)(sp)
+ mov %rdi,(RDI*8+offes_intregs)(sp)
+ mov %rbp,(RBP*8+offes_intregs)(sp)
+ movq $0 ,(RSP*8+offes_intregs)(sp) /* not used */
+ mov %r8 ,(R8 *8+offes_intregs)(sp)
+ mov %r9 ,(R9 *8+offes_intregs)(sp)
+ mov %r10,(R10*8+offes_intregs)(sp)
+ mov %r11,(R11*8+offes_intregs)(sp)
+ mov %r12,(R12*8+offes_intregs)(sp)
+ mov %r13,(R13*8+offes_intregs)(sp)
+ mov %r14,(R14*8+offes_intregs)(sp)
+ mov %r15,(R15*8+offes_intregs)(sp)
+
+ movq %xmm0 ,(XMM0 *8+offes_fltregs)(sp)
+ movq %xmm1 ,(XMM1 *8+offes_fltregs)(sp)
+ movq %xmm2 ,(XMM2 *8+offes_fltregs)(sp)
+ movq %xmm3 ,(XMM3 *8+offes_fltregs)(sp)
+ movq %xmm4 ,(XMM4 *8+offes_fltregs)(sp)
+ movq %xmm5 ,(XMM5 *8+offes_fltregs)(sp)
+ movq %xmm6 ,(XMM6 *8+offes_fltregs)(sp)
+ movq %xmm7 ,(XMM7 *8+offes_fltregs)(sp)
+ movq %xmm8 ,(XMM8 *8+offes_fltregs)(sp)
+ movq %xmm9 ,(XMM9 *8+offes_fltregs)(sp)
+ movq %xmm10,(XMM10*8+offes_fltregs)(sp)
+ movq %xmm11,(XMM11*8+offes_fltregs)(sp)
+ movq %xmm12,(XMM12*8+offes_fltregs)(sp)
+ movq %xmm13,(XMM13*8+offes_fltregs)(sp)
+ movq %xmm14,(XMM14*8+offes_fltregs)(sp)
+ movq %xmm15,(XMM15*8+offes_fltregs)(sp)
+
+ /* calculate sp of method */
+ mov sp,itmp1
+ add $(sizeexecutionstate + REPLACEMENT_ROOM + 8),itmp1
+ mov itmp1,(offes_sp)(sp)
+
+ /* pv must be looked up via AVL tree */
+ movq $0,(offes_pv)(sp)
+
+ /* call replace_me */
+ mov -8(itmp1),a0 /* rplpoint * */
+ mov sp,a1 /* arg1: execution state */
+ call replace_me@PLT /* call C function replace_me */
+ call abort@PLT /* NEVER REACHED */
+
+/* asm_replacement_in **********************************************************
+
+ This code writes the given execution state and jumps to the replacement
+ code.
+
+ This function never returns!
+
+ C prototype:
+ void asm_replacement_in(executionstate *es);
+
+*******************************************************************************/
+
+asm_replacement_in:
+ mov a0,%rbp /* executionstate *es */
+
+ /* set new sp */
+ mov (offes_sp)(%rbp),%rsp
+
+ /* store address of new code */
+ push (offes_pc)(%rbp)
+
+ /* copy registers from execution state */
+ movq (XMM0 *8+offes_fltregs)(%rbp),%xmm0
+ movq (XMM1 *8+offes_fltregs)(%rbp),%xmm1
+ movq (XMM2 *8+offes_fltregs)(%rbp),%xmm2
+ movq (XMM3 *8+offes_fltregs)(%rbp),%xmm3
+ movq (XMM4 *8+offes_fltregs)(%rbp),%xmm4
+ movq (XMM5 *8+offes_fltregs)(%rbp),%xmm5
+ movq (XMM6 *8+offes_fltregs)(%rbp),%xmm6
+ movq (XMM7 *8+offes_fltregs)(%rbp),%xmm7
+ movq (XMM8 *8+offes_fltregs)(%rbp),%xmm8
+ movq (XMM9 *8+offes_fltregs)(%rbp),%xmm9
+ movq (XMM10*8+offes_fltregs)(%rbp),%xmm10
+ movq (XMM11*8+offes_fltregs)(%rbp),%xmm11
+ movq (XMM12*8+offes_fltregs)(%rbp),%xmm12
+ movq (XMM13*8+offes_fltregs)(%rbp),%xmm13
+ movq (XMM14*8+offes_fltregs)(%rbp),%xmm14
+ movq (XMM15*8+offes_fltregs)(%rbp),%xmm15
+
+ mov (RAX*8+offes_intregs)(%rbp),%rax
+ mov (RBX*8+offes_intregs)(%rbp),%rbx
+ mov (RCX*8+offes_intregs)(%rbp),%rcx
+ mov (RDX*8+offes_intregs)(%rbp),%rdx
+ mov (RSI*8+offes_intregs)(%rbp),%rsi
+ mov (RDI*8+offes_intregs)(%rbp),%rdi
+ mov (R8 *8+offes_intregs)(%rbp),%r8
+ mov (R9 *8+offes_intregs)(%rbp),%r9
+ mov (R10*8+offes_intregs)(%rbp),%r10
+ mov (R11*8+offes_intregs)(%rbp),%r11
+ mov (R12*8+offes_intregs)(%rbp),%r12
+ mov (R13*8+offes_intregs)(%rbp),%r13
+ mov (R14*8+offes_intregs)(%rbp),%r14
+ mov (R15*8+offes_intregs)(%rbp),%r15
+
+ mov (RBP*8+offes_intregs)(%rbp),%rbp
+
+ /* jump to new code */
+ ret
+
+
+/* asm_builtin_x2x *************************************************************
+* *
+* Wrapper functions for float to int corner cases *
+* *
+*******************************************************************************/
+
+asm_builtin_f2i:
+ sub $(ARG_CNT*8),sp
+
+ SAVE_ARGUMENT_REGISTERS(0)
+
+ movq ftmp1,fa0
+ call builtin_f2i@PLT
+
+ RESTORE_ARGUMENT_REGISTERS(0)
+
+ add $(ARG_CNT*8),sp
+ ret
+
+
+asm_builtin_f2l:
+ sub $(ARG_CNT*8),sp
+
+ SAVE_ARGUMENT_REGISTERS(0)
+
+ movq ftmp1,fa0
+ call builtin_f2l@PLT
+
+ RESTORE_ARGUMENT_REGISTERS(0)
+
+ add $(ARG_CNT*8),sp
+ ret
+
+
+asm_builtin_d2i:
+ sub $(ARG_CNT*8),sp
+
+ SAVE_ARGUMENT_REGISTERS(0)
+
+ movq ftmp1,fa0
+ call builtin_d2i@PLT
+
+ RESTORE_ARGUMENT_REGISTERS(0)
+
+ add $(ARG_CNT*8),sp
+ ret
+
+
+asm_builtin_d2l:
+ sub $(ARG_CNT*8),sp
+
+ SAVE_ARGUMENT_REGISTERS(0)
+
+ movq ftmp1,fa0
+ call builtin_d2l@PLT
+
+ RESTORE_ARGUMENT_REGISTERS(0)
+
+ add $(ARG_CNT*8),sp
+ ret
+
+
+asm_getclassvalues_atomic:
+_crit_restart:
+_crit_begin:
+ movl offbaseval(a0),itmp1l
+ movl offdiffval(a0),itmp2l
+ movl offbaseval(a1),itmp3l
+_crit_end:
+ movl itmp1l,offcast_super_baseval(a2)
+ movl itmp2l,offcast_super_diffval(a2)
+ movl itmp3l,offcast_sub_baseval(a2)
+ ret
+
+ .data
+
+asm_criticalsections:
+#if defined(ENABLE_THREADS)
+ .quad _crit_begin
+ .quad _crit_end
+ .quad _crit_restart
+#endif
+ .quad 0
+
+
+/* Disable exec-stacks, required for Gentoo ***********************************/
+
+#if defined(__GCC__) && defined(__ELF__)
+ .section .note.GNU-stack,"",@progbits
+#endif
+
+
+#endif /* if 0 */
+
+/*
+ * 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/x86_64/codegen.c - machine code generator for x86_64
+
+ 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: Andreas Krall
+ Christian Thalinger
+ Christian Ullrich
+ Edwin Steiner
+
+ $Id: codegen.c 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "vm/types.h"
+
+#include "md-abi.h"
+
+#include "vm/jit/s390/arch.h"
+#include "vm/jit/s390/codegen.h"
+#include "vm/jit/s390/emit.h"
+
+#include "mm/memory.h"
+#include "native/jni.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/statistics.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"
+#include "vm/jit/replace.h"
+
+#if defined(ENABLE_LSRA)
+# include "vm/jit/allocator/lsra.h"
+#endif
+
+#define OOPS() assert(0);
+
+#if 0
+u1 *createcompilerstub(methodinfo *m) {
+ OOPS();
+ u1 *stub = malloc(8);
+ bzero(stub, 8);
+ return stub;
+}
+#endif
+
+#if 0
+u1 *createnativestub(functionptr f, jitdata *jd, methoddesc *nmd) {
+ OOPS();
+ return createcompilerstub(NULL);
+}
+#endif
+
+
+
+/* codegen *********************************************************************
+
+ Generates machine code.
+
+*******************************************************************************/
+
+
+bool codegen(jitdata *jd)
+{
+ methodinfo *m;
+ codeinfo *code;
+ codegendata *cd;
+ registerdata *rd;
+ s4 len, s1, s2, s3, d, disp;
+ u2 currentline;
+ ptrint a;
+ varinfo *var, *var1, *var2, *dst;
+ basicblock *bptr;
+ instruction *iptr;
+ exception_entry *ex;
+ constant_classref *cr;
+ unresolved_class *uc;
+ methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */
+ unresolved_method *um;
+ builtintable_entry *bte;
+ methoddesc *md;
+ fieldinfo *fi;
+ unresolved_field *uf;
+ s4 fieldtype;
+ rplpoint *replacementpoint;
+ s4 varindex;
+
+ /* get required compiler data */
+
+ m = jd->m;
+ code = jd->code;
+ cd = jd->cd;
+ rd = jd->rd;
+
+ /* prevent compiler warnings */
+
+ d = 0;
+ lm = NULL;
+ um = NULL;
+ bte = NULL;
+
+ {
+ s4 i, p, t, l;
+ s4 savedregs_num;
+
+ savedregs_num = 0;
+
+ /* space to save used callee saved registers */
+
+ savedregs_num += (INT_SAV_CNT - rd->savintreguse);
+ savedregs_num += (FLT_SAV_CNT - rd->savfltreguse);
+
+ cd->stackframesize = rd->memuse + savedregs_num;
+
+#if defined(ENABLE_THREADS)
+ /* space to save argument of monitor_enter */
+
+ if (checksync && (m->flags & ACC_SYNCHRONIZED))
+ cd->stackframesize++;
+#endif
+
+ /* Keep stack of non-leaf functions 16-byte aligned for calls into
+ native code e.g. libc or jni (alignment problems with
+ movaps). */
+
+ if (!jd->isleafmethod || opt_verbosecall)
+ cd->stackframesize |= 0x1;
+
+ /* create method header */
+
+ (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */
+ (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* 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) * 8); /* 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);
+ }
+
+ /* generate method profiling code */
+
+ if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) {
+ /* count frequency */
+
+ M_MOV_IMM(code, REG_ITMP3);
+ M_IINC_MEMBASE(REG_ITMP3, OFFSET(codeinfo, frequency));
+
+ PROFILE_CYCLE_START;
+ }
+
+ /* create stack frame (if necessary) */
+
+ if (cd->stackframesize)
+ M_ASUB_IMM(cd->stackframesize * 8, REG_SP);
+
+ /* save used callee saved registers */
+
+ p = cd->stackframesize;
+ for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) {
+ p--; M_LST(rd->savintregs[i], REG_SP, p * 8);
+ }
+ for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) {
+ p--; M_DST(rd->savfltregs[i], REG_SP, p * 8);
+ }
+
+ /* take arguments out of register or stack frame */
+
+ md = m->parseddesc;
+
+ for (p = 0, l = 0; p < md->paramcount; p++) {
+ t = md->paramtypes[p].type;
+
+ varindex = jd->local_map[l * 5 + t];
+
+ l++;
+ if (IS_2_WORD_TYPE(t)) /* increment local counter for 2 word types */
+ l++;
+
+ if (varindex == UNUSED)
+ continue;
+
+ var = VAR(varindex);
+
+ s1 = md->params[p].regoff;
+
+ if (IS_INT_LNG_TYPE(t)) { /* integer args */
+ s2 = rd->argintregs[s1];
+ if (!md->params[p].inmemory) { /* register arguments */
+ if (!IS_INMEMORY(var->flags)) { /* reg arg -> register */
+ M_INTMOVE(s2, var->vv.regoff);
+
+ } else { /* reg arg -> spilled */
+ M_LST(s2, REG_SP, var->vv.regoff * 8);
+ }
+
+ } else { /* stack arguments */
+ if (!IS_INMEMORY(var->flags)) { /* stack arg -> register */
+ /* + 8 for return address */
+ M_LLD(var->vv.regoff, REG_SP, (cd->stackframesize + s1) * 8 + 8);
+
+ } else { /* stack arg -> spilled */
+ var->vv.regoff = cd->stackframesize + s1 + 1;
+ }
+ }
+
+ } else { /* floating args */
+ if (!md->params[p].inmemory) { /* register arguments */
+ s2 = rd->argfltregs[s1];
+ if (!IS_INMEMORY(var->flags)) { /* reg arg -> register */
+ M_FLTMOVE(s2, var->vv.regoff);
+
+ } else { /* reg arg -> spilled */
+ M_DST(s2, REG_SP, var->vv.regoff * 8);
+ }
+
+ } else { /* stack arguments */
+ if (!IS_INMEMORY(var->flags)) { /* stack-arg -> register */
+ M_DLD(var->vv.regoff, REG_SP, (cd->stackframesize + s1) * 8 + 8);
+
+ } else {
+ var->vv.regoff = cd->stackframesize + s1 + 1;
+ }
+ }
+ }
+ } /* end for */
+
+ /* save monitorenter argument */
+
+#if defined(ENABLE_THREADS)
+ if (checksync && (m->flags & ACC_SYNCHRONIZED)) {
+ /* stack offset for monitor argument */
+
+ s1 = rd->memuse;
+
+ if (opt_verbosecall) {
+ M_LSUB_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP);
+
+ for (p = 0; p < INT_ARG_CNT; p++)
+ M_LST(rd->argintregs[p], REG_SP, p * 8);
+
+ for (p = 0; p < FLT_ARG_CNT; p++)
+ M_DST(rd->argfltregs[p], REG_SP, (INT_ARG_CNT + p) * 8);
+
+ s1 += INT_ARG_CNT + FLT_ARG_CNT;
+ }
+
+ /* decide which monitor enter function to call */
+
+ if (m->flags & ACC_STATIC) {
+ M_MOV_IMM(&m->class->object.header, REG_A0);
+ }
+ else {
+ M_TEST(REG_A0);
+ M_BEQ(0);
+ codegen_add_nullpointerexception_ref(cd);
+ }
+
+ M_AST(REG_A0, REG_SP, s1 * 8);
+ M_MOV_IMM(LOCK_monitor_enter, REG_ITMP1);
+ M_CALL(REG_ITMP1);
+
+ if (opt_verbosecall) {
+ for (p = 0; p < INT_ARG_CNT; p++)
+ M_LLD(rd->argintregs[p], REG_SP, p * 8);
+
+ for (p = 0; p < FLT_ARG_CNT; p++)
+ M_DLD(rd->argfltregs[p], REG_SP, (INT_ARG_CNT + p) * 8);
+
+ M_LADD_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP);
+ }
+ }
+#endif
+
+#if !defined(NDEBUG)
+ if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
+ emit_verbosecall_enter(jd);
+#endif /* !defined(NDEBUG) */
+
+ }
+
+ /* end of header generation */
+
+ replacementpoint = jd->code->rplpoints;
+
+ /* walk through all basic blocks */
+
+ for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
+
+ bptr->mpc = (u4) ((u1 *) cd->mcodeptr - cd->mcodebase);
+
+ if (bptr->flags >= BBREACHED) {
+
+ /* branch resolving */
+
+ codegen_resolve_branchrefs(cd, bptr);
+
+ /* handle replacement points */
+
+#if 0
+ if (bptr->bitflags & BBFLAG_REPLACEMENT) {
+ replacementpoint->pc = (u1*)(ptrint)bptr->mpc; /* will be resolved later */
+
+ replacementpoint++;
+
+ assert(cd->lastmcodeptr <= cd->mcodeptr);
+ cd->lastmcodeptr = cd->mcodeptr + 5; /* 5 byte jmp patch */
+ }
+#endif
+
+ /* copy interface registers to their destination */
+
+ len = bptr->indepth;
+ MCODECHECK(512);
+
+ /* generate basicblock profiling code */
+
+ if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) {
+ /* count frequency */
+
+ M_MOV_IMM(code->bbfrequency, REG_ITMP3);
+ M_IINC_MEMBASE(REG_ITMP3, bptr->nr * 4);
+
+ /* if this is an exception handler, start profiling again */
+
+ if (bptr->type == BBTYPE_EXH)
+ PROFILE_CYCLE_START;
+ }
+
+#if defined(ENABLE_LSRA)
+ if (opt_lsra) {
+ while (len) {
+ len--;
+ src = bptr->invars[len];
+ if ((len == bptr->indepth-1) && (bptr->type != BBTYPE_STD)) {
+ if (bptr->type == BBTYPE_EXH) {
+/* d = reg_of_var(rd, src, REG_ITMP1); */
+ if (!IS_INMEMORY(src->flags))
+ d= src->vv.regoff;
+ else
+ d=REG_ITMP1;
+ M_INTMOVE(REG_ITMP1, d);
+ emit_store(jd, NULL, src, d);
+ }
+ }
+ }
+
+ } else {
+#endif
+
+ while (len) {
+ len--;
+ var = VAR(bptr->invars[len]);
+ if ((len == bptr->indepth-1) && (bptr->type != BBTYPE_STD)) {
+ if (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
+ /* walk through all instructions */
+
+ len = bptr->icount;
+ currentline = 0;
+
+ for (iptr = bptr->iinstr; len > 0; len--, iptr++) {
+ if (iptr->line != currentline) {
+ dseg_addlinenumber(cd, iptr->line);
+ currentline = iptr->line;
+ }
+
+ MCODECHECK(1024); /* 1KB should be enough */
+
+ switch (iptr->opc) {
+ case ICMD_NOP: /* ... ==> ... */
+ case ICMD_POP: /* ..., value ==> ... */
+ case ICMD_POP2: /* ..., value, value ==> ... */
+ case ICMD_INLINE_START: /* internal ICMDs */
+ case ICMD_INLINE_END:
+ break;
+
+ case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_TEST(s1);
+ M_BEQ(0);
+ codegen_add_nullpointerexception_ref(cd);
+#endif
+ break;
+
+ /* constant operations ************************************************/
+
+ case ICMD_ICONST: /* ... ==> ..., constant */
+ OOPS();
+#if 0
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ ICONST(d, iptr->sx.val.i);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LCONST: /* ... ==> ..., constant */
+ OOPS();
+#if 0
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ LCONST(d, iptr->sx.val.l);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_FCONST: /* ... ==> ..., constant */
+ OOPS();
+#if 0
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ disp = dseg_add_float(cd, iptr->sx.val.f);
+ emit_movdl_membase_reg(cd, RIP, -((cd->mcodeptr + ((d > 7) ? 9 : 8)) - cd->mcodebase) + disp, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_DCONST: /* ... ==> ..., constant */
+ OOPS();
+#if 0
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ disp = dseg_add_double(cd, iptr->sx.val.d);
+ emit_movd_membase_reg(cd, RIP, -((cd->mcodeptr + 9) - cd->mcodebase) + disp, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_ACONST: /* ... ==> ..., constant */
+ OOPS();
+#if 0
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ cr = iptr->sx.val.c.ref;
+
+/* PROFILE_CYCLE_STOP; */
+
+ codegen_add_patch_ref(cd, PATCHER_aconst, cr, 0);
+
+/* PROFILE_CYCLE_START; */
+
+ M_MOV_IMM(NULL, d);
+
+ } else {
+ if (iptr->sx.val.anyptr == 0)
+ M_CLR(d);
+ else
+ M_MOV_IMM(iptr->sx.val.anyptr, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+
+ /* load/store/copy/move operations ************************************/
+
+ case ICMD_ILOAD: /* ... ==> ..., content of local variable */
+ case ICMD_ALOAD: /* s1 = local variable */
+ case ICMD_LLOAD:
+ case ICMD_FLOAD:
+ case ICMD_DLOAD:
+ case ICMD_ISTORE: /* ..., value ==> ... */
+ case ICMD_LSTORE:
+ case ICMD_FSTORE:
+ case ICMD_DSTORE:
+ case ICMD_COPY:
+ case ICMD_MOVE:
+ OOPS();
+#if 0
+ emit_copy(jd, iptr, VAROP(iptr->s1), VAROP(iptr->dst));
+#endif
+ break;
+
+ case ICMD_ASTORE:
+ OOPS();
+#if 0
+ if (!(iptr->flags.bits & INS_FLAG_RETADDR))
+ emit_copy(jd, iptr, VAROP(iptr->s1), VAROP(iptr->dst));
+#endif
+ break;
+
+ /* integer operations *************************************************/
+
+ case ICMD_INEG: /* ..., value ==> ..., - value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ M_INEG(d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LNEG: /* ..., value ==> ..., - value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ M_LNEG(d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_I2L: /* ..., value ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_ISEXT(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_L2I: /* ..., value ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_IMOV(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_INT2BYTE: /* ..., value ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_BSEXT(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_INT2CHAR: /* ..., value ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_CZEXT(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_INT2SHORT: /* ..., value ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_SSEXT(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+
+ case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d)
+ M_IADD(s1, d);
+ else {
+ M_INTMOVE(s1, d);
+ M_IADD(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IINC:
+ case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+
+ /* Using inc and dec is not faster than add (tested with
+ sieve). */
+
+ M_INTMOVE(s1, d);
+ M_IADD_IMM(iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d)
+ M_LADD(s1, d);
+ else {
+ M_INTMOVE(s1, d);
+ M_LADD(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */
+ /* sx.val.l = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LADD_IMM(iptr->sx.val.l, d);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_LADD(REG_ITMP2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d) {
+ M_INTMOVE(s1, REG_ITMP1);
+ M_ISUB(s2, REG_ITMP1);
+ M_INTMOVE(REG_ITMP1, d);
+ } else {
+ M_INTMOVE(s1, d);
+ M_ISUB(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ M_ISUB_IMM(iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d) {
+ M_INTMOVE(s1, REG_ITMP1);
+ M_LSUB(s2, REG_ITMP1);
+ M_INTMOVE(REG_ITMP1, d);
+ } else {
+ M_INTMOVE(s1, d);
+ M_LSUB(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */
+ /* sx.val.l = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LSUB_IMM(iptr->sx.val.l, d);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_LSUB(REG_ITMP2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d)
+ M_IMUL(s1, d);
+ else {
+ M_INTMOVE(s1, d);
+ M_IMUL(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ if (iptr->sx.val.i == 2) {
+ M_INTMOVE(s1, d);
+ M_ISLL_IMM(1, d);
+ } else
+ M_IMUL_IMM(s1, iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d)
+ M_LMUL(s1, d);
+ else {
+ M_INTMOVE(s1, d);
+ M_LMUL(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */
+ /* sx.val.l = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LMUL_IMM(s1, iptr->sx.val.l, d);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_INTMOVE(s1, d);
+ M_LMUL(REG_ITMP2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
+ OOPS();
+#if 0
+ var1 = VAROP(iptr->s1);
+ var2 = VAROP(iptr->sx.s23.s2);
+ dst = VAROP(iptr->dst);
+
+ d = codegen_reg_of_dst(jd, iptr, REG_NULL);
+ if (IS_INMEMORY(var1->flags))
+ M_ILD(RAX, REG_SP, var1->vv.regoff * 8);
+ else
+ M_INTMOVE(var1->vv.regoff, RAX);
+
+ if (IS_INMEMORY(var2->flags))
+ M_ILD(REG_ITMP3, REG_SP, var2->vv.regoff * 8);
+ else
+ M_INTMOVE(var2->vv.regoff, REG_ITMP3);
+
+ if (checknull) {
+ M_ITEST(REG_ITMP3);
+ M_BEQ(0);
+ codegen_add_arithmeticexception_ref(cd);
+ }
+
+ emit_alul_imm_reg(cd, ALU_CMP, 0x80000000, RAX); /* check as described in jvm spec */
+ emit_jcc(cd, CC_NE, 4 + 6);
+ emit_alul_imm_reg(cd, ALU_CMP, -1, REG_ITMP3); /* 4 bytes */
+ emit_jcc(cd, CC_E, 3 + 1 + 3); /* 6 bytes */
+
+ emit_mov_reg_reg(cd, RDX, REG_ITMP2); /* save %rdx, cause it's an argument register */
+ emit_cltd(cd);
+ emit_idivl_reg(cd, REG_ITMP3);
+
+ if (IS_INMEMORY(dst->flags)) {
+ emit_mov_reg_membase(cd, RAX, REG_SP, dst->vv.regoff * 8);
+ emit_mov_reg_reg(cd, REG_ITMP2, RDX); /* restore %rdx */
+
+ } else {
+ M_INTMOVE(RAX, dst->vv.regoff);
+
+ if (dst->vv.regoff != RDX) {
+ emit_mov_reg_reg(cd, REG_ITMP2, RDX); /* restore %rdx */
+ }
+ }
+#endif
+ break;
+
+ case ICMD_IREM: /* ..., val1, val2 ==> ..., val1 % val2 */
+ OOPS();
+#if 0
+ var1 = VAROP(iptr->s1);
+ var2 = VAROP(iptr->sx.s23.s2);
+ dst = VAROP(iptr->dst);
+
+ d = codegen_reg_of_dst(jd, iptr, REG_NULL);
+ if (IS_INMEMORY(var1->flags))
+ M_ILD(RAX, REG_SP, var1->vv.regoff * 8);
+ else
+ M_INTMOVE(var1->vv.regoff, RAX);
+
+ if (IS_INMEMORY(var2->flags))
+ M_ILD(REG_ITMP3, REG_SP, var2->vv.regoff * 8);
+ else
+ M_INTMOVE(var2->vv.regoff, REG_ITMP3);
+
+ if (checknull) {
+ M_ITEST(REG_ITMP3);
+ M_BEQ(0);
+ codegen_add_arithmeticexception_ref(cd);
+ }
+
+ emit_mov_reg_reg(cd, RDX, REG_ITMP2); /* save %rdx, cause it's an argument register */
+
+ emit_alul_imm_reg(cd, ALU_CMP, 0x80000000, RAX); /* check as described in jvm spec */
+ emit_jcc(cd, CC_NE, 2 + 4 + 6);
+
+
+ emit_alul_reg_reg(cd, ALU_XOR, RDX, RDX); /* 2 bytes */
+ emit_alul_imm_reg(cd, ALU_CMP, -1, REG_ITMP3); /* 4 bytes */
+ emit_jcc(cd, CC_E, 1 + 3); /* 6 bytes */
+
+ emit_cltd(cd);
+ emit_idivl_reg(cd, REG_ITMP3);
+
+ if (IS_INMEMORY(dst->flags)) {
+ emit_mov_reg_membase(cd, RDX, REG_SP, dst->vv.regoff * 8);
+ emit_mov_reg_reg(cd, REG_ITMP2, RDX); /* restore %rdx */
+
+ } else {
+ M_INTMOVE(RDX, dst->vv.regoff);
+
+ if (dst->vv.regoff != RDX) {
+ emit_mov_reg_reg(cd, REG_ITMP2, RDX); /* restore %rdx */
+ }
+ }
+#endif
+ break;
+
+ case ICMD_IDIVPOW2: /* ..., value ==> ..., value >> constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_INTMOVE(s1, REG_ITMP1);
+ emit_alul_imm_reg(cd, ALU_CMP, -1, REG_ITMP1);
+ emit_leal_membase_reg(cd, REG_ITMP1, (1 << iptr->sx.val.i) - 1, REG_ITMP2);
+ emit_cmovccl_reg_reg(cd, CC_LE, REG_ITMP2, REG_ITMP1);
+ emit_shiftl_imm_reg(cd, SHIFT_SAR, iptr->sx.val.i, REG_ITMP1);
+ emit_mov_reg_reg(cd, REG_ITMP1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_INTMOVE(s1, REG_ITMP1);
+ emit_alul_imm_reg(cd, ALU_CMP, -1, REG_ITMP1);
+ emit_leal_membase_reg(cd, REG_ITMP1, iptr->sx.val.i, REG_ITMP2);
+ emit_cmovccl_reg_reg(cd, CC_G, REG_ITMP1, REG_ITMP2);
+ emit_alul_imm_reg(cd, ALU_AND, -1 - (iptr->sx.val.i), REG_ITMP2);
+ emit_alul_reg_reg(cd, ALU_SUB, REG_ITMP2, REG_ITMP1);
+ emit_mov_reg_reg(cd, REG_ITMP1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+
+ case ICMD_LDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
+ OOPS();
+#if 0
+ var1 = VAROP(iptr->s1);
+ var2 = VAROP(iptr->sx.s23.s2);
+ dst = VAROP(iptr->dst);
+
+ d = codegen_reg_of_dst(jd, iptr, REG_NULL);
+
+ if (IS_INMEMORY(var1->flags))
+ M_LLD(RAX, REG_SP, var1->vv.regoff * 8);
+ else
+ M_INTMOVE(var1->vv.regoff, RAX);
+
+ if (IS_INMEMORY(var2->flags))
+ M_LLD(REG_ITMP3, REG_SP, var2->vv.regoff * 8);
+ else
+ M_INTMOVE(var2->vv.regoff, REG_ITMP3);
+
+ if (checknull) {
+ M_TEST(REG_ITMP3);
+ M_BEQ(0);
+ codegen_add_arithmeticexception_ref(cd);
+ }
+
+ /* check as described in jvm spec */
+ disp = dseg_add_s8(cd, 0x8000000000000000LL);
+ M_LCMP_MEMBASE(RIP, -((cd->mcodeptr + 7) - cd->mcodebase) + disp, RAX);
+ M_BNE(4 + 6);
+ M_LCMP_IMM(-1, REG_ITMP3); /* 4 bytes */
+ M_BEQ(3 + 2 + 3); /* 6 bytes */
+
+ M_MOV(RDX, REG_ITMP2); /* save %rdx, cause it's an argument register */
+ emit_cqto(cd);
+ emit_idiv_reg(cd, REG_ITMP3);
+
+ if (IS_INMEMORY(dst->flags)) {
+ M_LST(RAX, REG_SP, dst->vv.regoff * 8);
+ M_MOV(REG_ITMP2, RDX); /* restore %rdx */
+
+ } else {
+ M_INTMOVE(RAX, dst->vv.regoff);
+
+ if (dst->vv.regoff != RDX) {
+ M_MOV(REG_ITMP2, RDX); /* restore %rdx */
+ }
+ }
+#endif
+ break;
+
+ case ICMD_LREM: /* ..., val1, val2 ==> ..., val1 % val2 */
+ OOPS();
+#if 0
+ var1 = VAROP(iptr->s1);
+ var2 = VAROP(iptr->sx.s23.s2);
+ dst = VAROP(iptr->dst);
+
+ d = codegen_reg_of_dst(jd, iptr, REG_NULL);
+
+ if (IS_INMEMORY(var1->flags))
+ M_LLD(REG_ITMP1, REG_SP, var1->vv.regoff * 8);
+ else
+ M_INTMOVE(var1->vv.regoff, REG_ITMP1);
+
+ if (IS_INMEMORY(var2->flags))
+ M_LLD(REG_ITMP3, REG_SP, var2->vv.regoff * 8);
+ else
+ M_INTMOVE(var2->vv.regoff, REG_ITMP3);
+ /*
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP3);
+ M_INTMOVE(s2, REG_ITMP3);
+ */
+ if (checknull) {
+ M_ITEST(REG_ITMP3);
+ M_BEQ(0);
+ codegen_add_arithmeticexception_ref(cd);
+ }
+
+ M_MOV(RDX, REG_ITMP2); /* save %rdx, cause it's an argument register */
+
+ /* check as described in jvm spec */
+ disp = dseg_add_s8(cd, 0x8000000000000000LL);
+ M_LCMP_MEMBASE(RIP, -((cd->mcodeptr + 7) - cd->mcodebase) + disp, REG_ITMP1);
+ M_BNE(3 + 4 + 6);
+
+#if 0
+ emit_alul_reg_reg(cd, ALU_XOR, RDX, RDX); /* 2 bytes */
+#endif
+ M_LXOR(RDX, RDX); /* 3 bytes */
+ M_LCMP_IMM(-1, REG_ITMP3); /* 4 bytes */
+ M_BEQ(2 + 3); /* 6 bytes */
+
+ emit_cqto(cd);
+ emit_idiv_reg(cd, REG_ITMP3);
+
+ if (IS_INMEMORY(dst->flags)) {
+ M_LST(RDX, REG_SP, dst->vv.regoff * 8);
+ M_MOV(REG_ITMP2, RDX); /* restore %rdx */
+
+ } else {
+ M_INTMOVE(RDX, dst->vv.regoff);
+
+ if (dst->vv.regoff != RDX) {
+ M_MOV(REG_ITMP2, RDX); /* restore %rdx */
+ }
+ }
+#endif
+ break;
+
+ case ICMD_LDIVPOW2: /* ..., value ==> ..., value >> constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_INTMOVE(s1, REG_ITMP1);
+ emit_alu_imm_reg(cd, ALU_CMP, -1, REG_ITMP1);
+ emit_lea_membase_reg(cd, REG_ITMP1, (1 << iptr->sx.val.i) - 1, REG_ITMP2);
+ emit_cmovcc_reg_reg(cd, CC_LE, REG_ITMP2, REG_ITMP1);
+ emit_shift_imm_reg(cd, SHIFT_SAR, iptr->sx.val.i, REG_ITMP1);
+ emit_mov_reg_reg(cd, REG_ITMP1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */
+ /* sx.val.l = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_INTMOVE(s1, REG_ITMP1);
+ emit_alu_imm_reg(cd, ALU_CMP, -1, REG_ITMP1);
+ emit_lea_membase_reg(cd, REG_ITMP1, iptr->sx.val.i, REG_ITMP2);
+ emit_cmovcc_reg_reg(cd, CC_G, REG_ITMP1, REG_ITMP2);
+ emit_alu_imm_reg(cd, ALU_AND, -1 - (iptr->sx.val.i), REG_ITMP2);
+ emit_alu_reg_reg(cd, ALU_SUB, REG_ITMP2, REG_ITMP1);
+ emit_mov_reg_reg(cd, REG_ITMP1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */
+ OOPS();
+#if 0
+ d = codegen_reg_of_dst(jd, iptr, REG_NULL);
+ emit_ishift(jd, SHIFT_SHL, iptr);
+#endif
+ break;
+
+ case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ M_ISLL_IMM(iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
+ OOPS();
+#if 0
+ d = codegen_reg_of_dst(jd, iptr, REG_NULL);
+ emit_ishift(jd, SHIFT_SAR, iptr);
+#endif
+ break;
+
+ case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ M_INTMOVE(s1, d);
+ M_ISRA_IMM(iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
+ OOPS();
+#if 0
+ d = codegen_reg_of_dst(jd, iptr, REG_NULL);
+ emit_ishift(jd, SHIFT_SHR, iptr);
+#endif
+ break;
+
+ case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ M_INTMOVE(s1, d);
+ M_ISRL_IMM(iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */
+ OOPS();
+#if 0
+ d = codegen_reg_of_dst(jd, iptr, REG_NULL);
+ emit_lshift(jd, SHIFT_SHL, iptr);
+#endif
+ break;
+
+ case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ M_LSLL_IMM(iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
+ OOPS();
+#if 0
+ d = codegen_reg_of_dst(jd, iptr, REG_NULL);
+ emit_lshift(jd, SHIFT_SAR, iptr);
+#endif
+ break;
+
+ case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ M_INTMOVE(s1, d);
+ M_LSRA_IMM(iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
+ OOPS();
+#if 0
+ d = codegen_reg_of_dst(jd, iptr, REG_NULL);
+ emit_lshift(jd, SHIFT_SHR, iptr);
+#endif
+ break;
+
+ case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */
+ /* sx.val.l = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ M_INTMOVE(s1, d);
+ M_LSRL_IMM(iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d)
+ M_IAND(s1, d);
+ else {
+ M_INTMOVE(s1, d);
+ M_IAND(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ M_IAND_IMM(iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LAND: /* ..., val1, val2 ==> ..., val1 & val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d)
+ M_LAND(s1, d);
+ else {
+ M_INTMOVE(s1, d);
+ M_LAND(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */
+ /* sx.val.l = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LAND_IMM(iptr->sx.val.l, d);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_LAND(REG_ITMP2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d)
+ M_IOR(s1, d);
+ else {
+ M_INTMOVE(s1, d);
+ M_IOR(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IORCONST: /* ..., value ==> ..., value | constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ M_IOR_IMM(iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LOR: /* ..., val1, val2 ==> ..., val1 | val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d)
+ M_LOR(s1, d);
+ else {
+ M_INTMOVE(s1, d);
+ M_LOR(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LORCONST: /* ..., value ==> ..., value | constant */
+ /* sx.val.l = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LOR_IMM(iptr->sx.val.l, d);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_LOR(REG_ITMP2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d)
+ M_IXOR(s1, d);
+ else {
+ M_INTMOVE(s1, d);
+ M_IXOR(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */
+ /* sx.val.i = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ M_IXOR_IMM(iptr->sx.val.i, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ if (s2 == d)
+ M_LXOR(s1, d);
+ else {
+ M_INTMOVE(s1, d);
+ M_LXOR(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */
+ /* sx.val.l = constant */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, d);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LXOR_IMM(iptr->sx.val.l, d);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_LXOR(REG_ITMP2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+
+ /* floating operations ************************************************/
+
+ case ICMD_FNEG: /* ..., value ==> ..., - value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ disp = dseg_add_s4(cd, 0x80000000);
+ M_FLTMOVE(s1, d);
+ emit_movss_membase_reg(cd, RIP, -((cd->mcodeptr + 9) - cd->mcodebase) + disp, REG_FTMP2);
+ emit_xorps_reg_reg(cd, REG_FTMP2, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_DNEG: /* ..., value ==> ..., - value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ disp = dseg_add_s8(cd, 0x8000000000000000);
+ M_FLTMOVE(s1, d);
+ emit_movd_membase_reg(cd, RIP, -((cd->mcodeptr + 9) - cd->mcodebase) + disp, REG_FTMP2);
+ emit_xorpd_reg_reg(cd, REG_FTMP2, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ if (s2 == d)
+ M_FADD(s1, d);
+ else {
+ M_FLTMOVE(s1, d);
+ M_FADD(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ if (s2 == d)
+ M_DADD(s1, d);
+ else {
+ M_FLTMOVE(s1, d);
+ M_DADD(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ if (s2 == d) {
+ M_FLTMOVE(s2, REG_FTMP2);
+ s2 = REG_FTMP2;
+ }
+ M_FLTMOVE(s1, d);
+ M_FSUB(s2, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ if (s2 == d) {
+ M_FLTMOVE(s2, REG_FTMP2);
+ s2 = REG_FTMP2;
+ }
+ M_FLTMOVE(s1, d);
+ M_DSUB(s2, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ if (s2 == d)
+ M_FMUL(s1, d);
+ else {
+ M_FLTMOVE(s1, d);
+ M_FMUL(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ if (s2 == d)
+ M_DMUL(s1, d);
+ else {
+ M_FLTMOVE(s1, d);
+ M_DMUL(s2, d);
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ if (s2 == d) {
+ M_FLTMOVE(s2, REG_FTMP2);
+ s2 = REG_FTMP2;
+ }
+ M_FLTMOVE(s1, d);
+ M_FDIV(s2, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ if (s2 == d) {
+ M_FLTMOVE(s2, REG_FTMP2);
+ s2 = REG_FTMP2;
+ }
+ M_FLTMOVE(s1, d);
+ M_DDIV(s2, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_I2F: /* ..., value ==> ..., (float) value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ M_CVTIF(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_I2D: /* ..., value ==> ..., (double) value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ M_CVTID(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_L2F: /* ..., value ==> ..., (float) value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ M_CVTLF(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_L2D: /* ..., value ==> ..., (double) value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ M_CVTLD(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_F2I: /* ..., value ==> ..., (int) value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_CVTFI(s1, d);
+ M_ICMP_IMM(0x80000000, d); /* corner cases */
+ disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 +
+ ((REG_RESULT == d) ? 0 : 3);
+ M_BNE(disp);
+ M_FLTMOVE(s1, REG_FTMP1);
+ M_MOV_IMM(asm_builtin_f2i, REG_ITMP2);
+ M_CALL(REG_ITMP2);
+ M_INTMOVE(REG_RESULT, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_D2I: /* ..., value ==> ..., (int) value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_CVTDI(s1, d);
+ M_ICMP_IMM(0x80000000, d); /* corner cases */
+ disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 +
+ ((REG_RESULT == d) ? 0 : 3);
+ M_BNE(disp);
+ M_FLTMOVE(s1, REG_FTMP1);
+ M_MOV_IMM(asm_builtin_d2i, REG_ITMP2);
+ M_CALL(REG_ITMP2);
+ M_INTMOVE(REG_RESULT, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_F2L: /* ..., value ==> ..., (long) value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_CVTFL(s1, d);
+ M_MOV_IMM(0x8000000000000000, REG_ITMP2);
+ M_LCMP(REG_ITMP2, d); /* corner cases */
+ disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 +
+ ((REG_RESULT == d) ? 0 : 3);
+ M_BNE(disp);
+ M_FLTMOVE(s1, REG_FTMP1);
+ M_MOV_IMM(asm_builtin_f2l, REG_ITMP2);
+ M_CALL(REG_ITMP2);
+ M_INTMOVE(REG_RESULT, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_D2L: /* ..., value ==> ..., (long) value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_CVTDL(s1, d);
+ M_MOV_IMM(0x8000000000000000, REG_ITMP2);
+ M_LCMP(REG_ITMP2, d); /* corner cases */
+ disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 +
+ ((REG_RESULT == d) ? 0 : 3);
+ M_BNE(disp);
+ M_FLTMOVE(s1, REG_FTMP1);
+ M_MOV_IMM(asm_builtin_d2l, REG_ITMP2);
+ M_CALL(REG_ITMP2);
+ M_INTMOVE(REG_RESULT, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_F2D: /* ..., value ==> ..., (double) value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ M_CVTFD(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_D2F: /* ..., value ==> ..., (float) value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ M_CVTDF(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_FCMPL: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */
+ /* == => 0, < => 1, > => -1 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_CLR(d);
+ M_MOV_IMM(1, REG_ITMP1);
+ M_MOV_IMM(-1, REG_ITMP2);
+ emit_ucomiss_reg_reg(cd, s1, s2);
+ M_CMOVB(REG_ITMP1, d);
+ M_CMOVA(REG_ITMP2, d);
+ M_CMOVP(REG_ITMP2, d); /* treat unordered as GT */
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_FCMPG: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */
+ /* == => 0, < => 1, > => -1 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_CLR(d);
+ M_MOV_IMM(1, REG_ITMP1);
+ M_MOV_IMM(-1, REG_ITMP2);
+ emit_ucomiss_reg_reg(cd, s1, s2);
+ M_CMOVB(REG_ITMP1, d);
+ M_CMOVA(REG_ITMP2, d);
+ M_CMOVP(REG_ITMP1, d); /* treat unordered as LT */
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_DCMPL: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */
+ /* == => 0, < => 1, > => -1 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_CLR(d);
+ M_MOV_IMM(1, REG_ITMP1);
+ M_MOV_IMM(-1, REG_ITMP2);
+ emit_ucomisd_reg_reg(cd, s1, s2);
+ M_CMOVB(REG_ITMP1, d);
+ M_CMOVA(REG_ITMP2, d);
+ M_CMOVP(REG_ITMP2, d); /* treat unordered as GT */
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_DCMPG: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */
+ /* == => 0, < => 1, > => -1 */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ s2 = emit_load_s2(jd, iptr, REG_FTMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ M_CLR(d);
+ M_MOV_IMM(1, REG_ITMP1);
+ M_MOV_IMM(-1, REG_ITMP2);
+ emit_ucomisd_reg_reg(cd, s1, s2);
+ M_CMOVB(REG_ITMP1, d);
+ M_CMOVA(REG_ITMP2, d);
+ M_CMOVP(REG_ITMP1, d); /* treat unordered as LT */
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+
+ /* memory operations **************************************************/
+
+ case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., (int) length */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ gen_nullptr_check(s1);
+ M_ILD(d, s1, OFFSET(java_arrayheader, size));
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ gen_nullptr_check(s1);
+ gen_bound_check;
+ }
+ emit_movsbq_memindex_reg(cd, OFFSET(java_bytearray, data[0]), s1, s2, 0, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ gen_nullptr_check(s1);
+ gen_bound_check;
+ }
+ emit_movzwq_memindex_reg(cd, OFFSET(java_chararray, data[0]), s1, s2, 1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ gen_nullptr_check(s1);
+ gen_bound_check;
+ }
+ emit_movswq_memindex_reg(cd, OFFSET(java_shortarray, data[0]), s1, s2, 1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ gen_nullptr_check(s1);
+ gen_bound_check;
+ }
+ emit_movl_memindex_reg(cd, OFFSET(java_intarray, data[0]), s1, s2, 2, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ gen_nullptr_check(s1);
+ gen_bound_check;
+ }
+ emit_mov_memindex_reg(cd, OFFSET(java_longarray, data[0]), s1, s2, 3, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ gen_nullptr_check(s1);
+ gen_bound_check;
+ }
+ emit_movss_memindex_reg(cd, OFFSET(java_floatarray, data[0]), s1, s2, 2, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP3);
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ gen_nullptr_check(s1);
+ gen_bound_check;
+ }
+ emit_movsd_memindex_reg(cd, OFFSET(java_doublearray, data[0]), s1, s2, 3, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ 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_ITMP2);
+ emit_array_checks(cd, iptr, s1, s2);
+ M_SAADDQ(s2, s1, REG_ITMP1);
+ M_ALD(d, REG_ITMP1, OFFSET(java_objectarray, data[0]));
+ emit_store_dst(jd, iptr, d);
+ break;
+
+ case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+ emit_movb_reg_memindex(cd, s3, OFFSET(java_bytearray, data[0]), s1, s2, 0);
+#endif
+ break;
+
+ case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+ emit_movw_reg_memindex(cd, s3, OFFSET(java_chararray, data[0]), s1, s2, 1);
+#endif
+ break;
+
+ case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+ emit_movw_reg_memindex(cd, s3, OFFSET(java_shortarray, data[0]), s1, s2, 1);
+#endif
+ break;
+
+ case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+ emit_movl_reg_memindex(cd, s3, OFFSET(java_intarray, data[0]), s1, s2, 2);
+#endif
+ break;
+
+ case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+ emit_mov_reg_memindex(cd, s3, OFFSET(java_longarray, data[0]), s1, s2, 3);
+#endif
+ break;
+
+ case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ s3 = emit_load_s3(jd, iptr, REG_FTMP3);
+ emit_movss_reg_memindex(cd, s3, OFFSET(java_floatarray, data[0]), s1, s2, 2);
+#endif
+ break;
+
+ case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ s3 = emit_load_s3(jd, iptr, REG_FTMP3);
+ emit_movsd_reg_memindex(cd, s3, OFFSET(java_doublearray, data[0]), s1, s2, 3);
+#endif
+ break;
+
+ case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+
+ M_MOV(s1, REG_A0);
+ M_MOV(s3, REG_A1);
+ M_MOV_IMM(BUILTIN_canstore, REG_ITMP1);
+ M_CALL(REG_ITMP1);
+ M_TEST(REG_RESULT);
+ M_BEQ(0);
+ codegen_add_arraystoreexception_ref(cd);
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ s3 = emit_load_s3(jd, iptr, REG_ITMP3);
+ emit_mov_reg_memindex(cd, s3, OFFSET(java_objectarray, data[0]), s1, s2, 3);
+#endif
+ break;
+
+
+ case ICMD_BASTORECONST: /* ..., arrayref, index ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ emit_movb_imm_memindex(cd, iptr->sx.s23.s3.constval, OFFSET(java_bytearray, data[0]), s1, s2, 0);
+#endif
+ break;
+
+ case ICMD_CASTORECONST: /* ..., arrayref, index ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ emit_movw_imm_memindex(cd, iptr->sx.s23.s3.constval, OFFSET(java_chararray, data[0]), s1, s2, 1);
+#endif
+ break;
+
+ case ICMD_SASTORECONST: /* ..., arrayref, index ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ emit_movw_imm_memindex(cd, iptr->sx.s23.s3.constval, OFFSET(java_shortarray, data[0]), s1, s2, 1);
+#endif
+ break;
+
+ case ICMD_IASTORECONST: /* ..., arrayref, index ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ emit_movl_imm_memindex(cd, iptr->sx.s23.s3.constval, OFFSET(java_intarray, data[0]), s1, s2, 2);
+#endif
+ break;
+
+ case ICMD_LASTORECONST: /* ..., arrayref, index ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+
+ if (IS_IMM32(iptr->sx.s23.s3.constval)) {
+ emit_mov_imm_memindex(cd, (u4) (iptr->sx.s23.s3.constval & 0x00000000ffffffff), OFFSET(java_longarray, data[0]), s1, s2, 3);
+ } else {
+ emit_movl_imm_memindex(cd, (u4) (iptr->sx.s23.s3.constval & 0x00000000ffffffff), OFFSET(java_longarray, data[0]), s1, s2, 3);
+ emit_movl_imm_memindex(cd, (u4) (iptr->sx.s23.s3.constval >> 32), OFFSET(java_longarray, data[0]) + 4, s1, s2, 3);
+ }
+#endif
+ break;
+
+ case ICMD_AASTORECONST: /* ..., arrayref, index ==> ... */
+ OOPS();
+#if 0
+ 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;
+ }
+ emit_mov_imm_memindex(cd, 0, OFFSET(java_objectarray, data[0]), s1, s2, 3);
+#endif
+ break;
+
+
+ case ICMD_GETSTATIC: /* ... ==> ..., value */
+
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ uf = iptr->sx.s23.s3.uf;
+ fieldtype = uf->fieldref->parseddesc.fd->type;
+ disp = dseg_add_unique_address(cd, NULL);
+
+ /* must be calculated before codegen_add_patch_ref */
+
+ if (opt_shownops)
+ disp -= PATCHER_CALL_SIZE;
+
+/* PROFILE_CYCLE_STOP; */
+
+ codegen_add_patch_ref(cd, PATCHER_get_putstatic, uf, disp);
+
+/* PROFILE_CYCLE_START; */
+ }
+ else {
+ fi = iptr->sx.s23.s3.fmiref->p.field;
+ fieldtype = fi->type;
+ disp = dseg_add_address(cd, &(fi->value));
+
+ if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
+ PROFILE_CYCLE_STOP;
+
+ codegen_add_patch_ref(cd, PATCHER_clinit, fi->class, 0);
+
+ if (opt_shownops)
+ disp -= PATCHER_CALL_SIZE;
+
+ PROFILE_CYCLE_START;
+ }
+ }
+
+ M_ALD(REG_ITMP1, REG_PV, disp);
+
+ switch (fieldtype) {
+ case TYPE_INT:
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ M_ILD(d, REG_ITMP1, 0);
+ break;
+ case TYPE_LNG:
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
+ M_LLD(d, REG_ITMP1, 0);
+ break;
+ case TYPE_ADR:
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ M_ALD(d, REG_ITMP1, 0);
+ break;
+ case TYPE_FLT:
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ M_FLD(d, REG_ITMP1, 0);
+ break;
+ case TYPE_DBL:
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ M_DLD(d, REG_ITMP1, 0);
+ break;
+ }
+
+ emit_store_dst(jd, iptr, d);
+
+ break;
+
+ case ICMD_PUTSTATIC: /* ..., value ==> ... */
+ OOPS();
+#if 0
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ uf = iptr->sx.s23.s3.uf;
+ fieldtype = uf->fieldref->parseddesc.fd->type;
+ disp = dseg_add_unique_address(cd, NULL);
+ disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp;
+
+ /* must be calculated before codegen_add_patch_ref */
+
+ if (opt_shownops)
+ disp -= PATCHER_CALL_SIZE;
+
+/* PROFILE_CYCLE_STOP; */
+
+ codegen_add_patch_ref(cd, PATCHER_get_putstatic, uf, disp);
+
+/* PROFILE_CYCLE_START; */
+ }
+ else {
+ fi = iptr->sx.s23.s3.fmiref->p.field;
+ fieldtype = fi->type;
+ disp = dseg_add_address(cd, &(fi->value));
+ disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp;
+
+ if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
+ PROFILE_CYCLE_STOP;
+
+ codegen_add_patch_ref(cd, PATCHER_clinit, fi->class, 0);
+
+ if (opt_shownops)
+ disp -= PATCHER_CALL_SIZE;
+
+ PROFILE_CYCLE_START;
+ }
+ }
+
+ /* This approach is much faster than moving the field
+ address inline into a register. */
+
+ M_ALD(REG_ITMP1, RIP, disp);
+
+ switch (fieldtype) {
+ case TYPE_INT:
+ s1 = emit_load_s1(jd, iptr, REG_ITMP2);
+ M_IST(s1, REG_ITMP1, 0);
+ break;
+ case TYPE_LNG:
+ case TYPE_ADR:
+ s1 = emit_load_s1(jd, iptr, REG_ITMP2);
+ M_LST(s1, REG_ITMP1, 0);
+ break;
+ case TYPE_FLT:
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ M_FST(s1, REG_ITMP1, 0);
+ break;
+ case TYPE_DBL:
+ s1 = emit_load_s1(jd, iptr, REG_FTMP1);
+ M_DST(s1, REG_ITMP1, 0);
+ break;
+ }
+#endif
+ break;
+
+ case ICMD_PUTSTATICCONST: /* ... ==> ... */
+ /* val = value (in current instruction) */
+ /* following NOP) */
+ OOPS();
+#if 0
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ uf = iptr->sx.s23.s3.uf;
+ fieldtype = uf->fieldref->parseddesc.fd->type;
+ disp = dseg_add_unique_address(cd, NULL);
+ disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp;
+
+ /* must be calculated before codegen_add_patch_ref */
+
+ if (opt_shownops)
+ disp -= PATCHER_CALL_SIZE;
+
+
+/* PROFILE_CYCLE_STOP; */
+
+ codegen_add_patch_ref(cd, PATCHER_get_putstatic, uf, disp);
+
+/* PROFILE_CYCLE_START; */
+ }
+ else {
+ fi = iptr->sx.s23.s3.fmiref->p.field;
+ fieldtype = fi->type;
+ disp = dseg_add_address(cd, &(fi->value));
+ disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp;
+
+ if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
+ PROFILE_CYCLE_STOP;
+
+ codegen_add_patch_ref(cd, PATCHER_clinit, fi->class, 0);
+
+ if (opt_shownops)
+ disp -= PATCHER_CALL_SIZE;
+
+ PROFILE_CYCLE_START;
+ }
+ }
+
+ /* This approach is much faster than moving the field
+ address inline into a register. */
+
+ M_ALD(REG_ITMP1, RIP, disp);
+
+ switch (fieldtype) {
+ case TYPE_INT:
+ case TYPE_FLT:
+ M_IST_IMM(iptr->sx.s23.s2.constval, REG_ITMP1, 0);
+ break;
+ case TYPE_LNG:
+ case TYPE_ADR:
+ case TYPE_DBL:
+ if (IS_IMM32(iptr->sx.s23.s2.constval))
+ M_LST_IMM32(iptr->sx.s23.s2.constval, REG_ITMP1, 0);
+ else {
+ M_IST_IMM(iptr->sx.s23.s2.constval, REG_ITMP1, 0);
+ M_IST_IMM(iptr->sx.s23.s2.constval >> 32, REG_ITMP1, 4);
+ }
+ break;
+ }
+#endif
+ break;
+
+ case ICMD_GETFIELD: /* ... ==> ..., value */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ gen_nullptr_check(s1);
+
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ uf = iptr->sx.s23.s3.uf;
+ fieldtype = uf->fieldref->parseddesc.fd->type;
+ disp = 0;
+
+/* PROFILE_CYCLE_STOP; */
+
+ codegen_add_patch_ref(cd, PATCHER_get_putfield, uf, 0);
+
+/* PROFILE_CYCLE_START; */
+ }
+ else {
+ fi = iptr->sx.s23.s3.fmiref->p.field;
+ fieldtype = fi->type;
+ disp = fi->offset;
+ }
+
+ switch (fieldtype) {
+ case TYPE_INT:
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_ILD32(d, s1, disp);
+ break;
+ case TYPE_LNG:
+ case TYPE_ADR:
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+ M_LLD32(d, s1, disp);
+ break;
+ case TYPE_FLT:
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ M_FLD32(d, s1, disp);
+ break;
+ case TYPE_DBL:
+ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ M_DLD32(d, s1, disp);
+ break;
+ }
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_PUTFIELD: /* ..., objectref, value ==> ... */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ gen_nullptr_check(s1);
+
+ s2 = emit_load_s2(jd, iptr, REG_IFTMP);
+
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ uf = iptr->sx.s23.s3.uf;
+ fieldtype = uf->fieldref->parseddesc.fd->type;
+ disp = 0;
+
+/* PROFILE_CYCLE_STOP; */
+
+ codegen_add_patch_ref(cd, PATCHER_get_putfield, uf, 0);
+
+/* PROFILE_CYCLE_START; */
+ }
+ else {
+ fi = iptr->sx.s23.s3.fmiref->p.field;
+ fieldtype = fi->type;
+ disp = fi->offset;
+ }
+
+ switch (fieldtype) {
+ case TYPE_INT:
+ M_IST32(s2, s1, disp);
+ break;
+ case TYPE_LNG:
+ case TYPE_ADR:
+ M_LST32(s2, s1, disp);
+ break;
+ case TYPE_FLT:
+ M_FST32(s2, s1, disp);
+ break;
+ case TYPE_DBL:
+ M_DST32(s2, s1, disp);
+ break;
+ }
+#endif
+ break;
+
+ case ICMD_PUTFIELDCONST: /* ..., objectref, value ==> ... */
+ /* val = value (in current instruction) */
+ /* following NOP) */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ gen_nullptr_check(s1);
+
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ uf = iptr->sx.s23.s3.uf;
+ fieldtype = uf->fieldref->parseddesc.fd->type;
+ disp = 0;
+
+/* PROFILE_CYCLE_STOP; */
+
+ codegen_add_patch_ref(cd, PATCHER_putfieldconst, uf, 0);
+
+/* PROFILE_CYCLE_START; */
+ }
+ else {
+ fi = iptr->sx.s23.s3.fmiref->p.field;
+ fieldtype = fi->type;
+ disp = fi->offset;
+ }
+
+ switch (fieldtype) {
+ case TYPE_INT:
+ case TYPE_FLT:
+ M_IST32_IMM(iptr->sx.s23.s2.constval, s1, disp);
+ break;
+ case TYPE_LNG:
+ case TYPE_ADR:
+ case TYPE_DBL:
+ /* XXX why no check for IS_IMM32? */
+ M_IST32_IMM(iptr->sx.s23.s2.constval, s1, disp);
+ M_IST32_IMM(iptr->sx.s23.s2.constval >> 32, s1, disp + 4);
+ break;
+ }
+#endif
+ break;
+
+
+ /* branch operations **************************************************/
+
+ case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, REG_ITMP1_XPTR);
+
+ PROFILE_CYCLE_STOP;
+
+#ifdef ENABLE_VERIFIER
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ uc = iptr->sx.s23.s2.uc;
+
+ codegen_add_patch_ref(cd, PATCHER_athrow_areturn, uc, 0);
+ }
+#endif /* ENABLE_VERIFIER */
+
+ M_CALL_IMM(0); /* passing exception pc */
+ M_POP(REG_ITMP2_XPC);
+
+ M_MOV_IMM(asm_handle_exception, REG_ITMP3);
+ M_JMP(REG_ITMP3);
+#endif
+ break;
+
+ case ICMD_GOTO: /* ... ==> ... */
+ case ICMD_RET: /* ... ==> ... */
+ OOPS();
+#if 0
+ M_JMP_IMM(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_JSR: /* ... ==> ... */
+ OOPS();
+#if 0
+ M_JMP_IMM(0);
+ codegen_add_branch_ref(cd, iptr->sx.s23.s3.jsrtarget.block);
+#endif
+ break;
+
+ case ICMD_IFNULL: /* ..., value ==> ... */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_TEST(s1);
+ M_BEQ(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IFNONNULL: /* ..., value ==> ... */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_TEST(s1);
+ M_BNE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IFEQ: /* ..., value ==> ... */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_ICMP_IMM(iptr->sx.val.i, s1);
+ M_BEQ(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IFLT: /* ..., value ==> ... */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_ICMP_IMM(iptr->sx.val.i, s1);
+ M_BLT(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IFLE: /* ..., value ==> ... */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_ICMP_IMM(iptr->sx.val.i, s1);
+ M_BLE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IFNE: /* ..., value ==> ... */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_ICMP_IMM(iptr->sx.val.i, s1);
+ M_BNE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IFGT: /* ..., value ==> ... */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_ICMP_IMM(iptr->sx.val.i, s1);
+ M_BGT(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IFGE: /* ..., value ==> ... */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_ICMP_IMM(iptr->sx.val.i, s1);
+ M_BGE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LEQ: /* ..., value ==> ... */
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LCMP_IMM(iptr->sx.val.l, s1);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_LCMP(REG_ITMP2, s1);
+ }
+ M_BEQ(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LLT: /* ..., value ==> ... */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LCMP_IMM(iptr->sx.val.l, s1);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_LCMP(REG_ITMP2, s1);
+ }
+ M_BLT(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LLE: /* ..., value ==> ... */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LCMP_IMM(iptr->sx.val.l, s1);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_LCMP(REG_ITMP2, s1);
+ }
+ M_BLE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LNE: /* ..., value ==> ... */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LCMP_IMM(iptr->sx.val.l, s1);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_LCMP(REG_ITMP2, s1);
+ }
+ M_BNE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LGT: /* ..., value ==> ... */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LCMP_IMM(iptr->sx.val.l, s1);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_LCMP(REG_ITMP2, s1);
+ }
+ M_BGT(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LGE: /* ..., value ==> ... */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ if (IS_IMM32(iptr->sx.val.l))
+ M_LCMP_IMM(iptr->sx.val.l, s1);
+ else {
+ M_MOV_IMM(iptr->sx.val.l, REG_ITMP2);
+ M_LCMP(REG_ITMP2, s1);
+ }
+ M_BGE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_ICMP(s2, s1);
+ M_BEQ(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LCMPEQ: /* ..., value, value ==> ... */
+ case ICMD_IF_ACMPEQ: /* op1 = target JavaVM pc */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_LCMP(s2, s1);
+ M_BEQ(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_ICMPNE: /* ..., value, value ==> ... */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_ICMP(s2, s1);
+ M_BNE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LCMPNE: /* ..., value, value ==> ... */
+ case ICMD_IF_ACMPNE: /* op1 = target JavaVM pc */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_LCMP(s2, s1);
+ M_BNE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_ICMP(s2, s1);
+ M_BLT(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LCMPLT: /* ..., value, value ==> ... */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_LCMP(s2, s1);
+ M_BLT(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */
+ OOPS();
+#if 0
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_ICMP(s2, s1);
+ M_BGT(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LCMPGT: /* ..., value, value ==> ... */
+
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_LCMP(s2, s1);
+ M_BGT(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */
+
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_ICMP(s2, s1);
+ M_BLE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LCMPLE: /* ..., value, value ==> ... */
+
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_LCMP(s2, s1);
+ M_BLE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */
+
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_ICMP(s2, s1);
+ M_BGE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IF_LCMPGE: /* ..., value, value ==> ... */
+
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2(jd, iptr, REG_ITMP2);
+ M_LCMP(s2, s1);
+ M_BGE(0);
+ codegen_add_branch_ref(cd, iptr->dst.block);
+#endif
+ break;
+
+ case ICMD_IRETURN: /* ..., retvalue ==> ... */
+ case ICMD_LRETURN:
+
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_RESULT);
+ M_INTMOVE(s1, REG_RESULT);
+#endif
+ goto nowperformreturn;
+
+ case ICMD_ARETURN: /* ..., retvalue ==> ... */
+
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_RESULT);
+ M_INTMOVE(s1, REG_RESULT);
+
+#ifdef ENABLE_VERIFIER
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ uc = iptr->sx.s23.s2.uc;
+
+ PROFILE_CYCLE_STOP;
+
+ codegen_add_patch_ref(cd, PATCHER_athrow_areturn, uc, 0);
+
+ PROFILE_CYCLE_START;
+ }
+#endif /* ENABLE_VERIFIER */
+#endif
+ goto nowperformreturn;
+
+ case ICMD_FRETURN: /* ..., retvalue ==> ... */
+ case ICMD_DRETURN:
+
+ OOPS();
+#if 0
+ s1 = emit_load_s1(jd, iptr, REG_FRESULT);
+ M_FLTMOVE(s1, REG_FRESULT);
+#endif
+ goto nowperformreturn;
+
+ case ICMD_RETURN: /* ... ==> ... */
+
+nowperformreturn:
+ OOPS();
+#if 0
+ {
+ s4 i, p;
+
+ p = cd->stackframesize;
+
+#if !defined(NDEBUG)
+ if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
+ emit_verbosecall_exit(jd);
+#endif /* !defined(NDEBUG) */
+
+#if defined(ENABLE_THREADS)
+ if (checksync && (m->flags & ACC_SYNCHRONIZED)) {
+ M_ALD(REG_A0, REG_SP, rd->memuse * 8);
+
+ /* we need to save the proper return value */
+ switch (iptr->opc) {
+ case ICMD_IRETURN:
+ case ICMD_ARETURN:
+ case ICMD_LRETURN:
+ M_LST(REG_RESULT, REG_SP, rd->memuse * 8);
+ break;
+ case ICMD_FRETURN:
+ case ICMD_DRETURN:
+ M_DST(REG_FRESULT, REG_SP, rd->memuse * 8);
+ break;
+ }
+
+ M_MOV_IMM(LOCK_monitor_exit, REG_ITMP1);
+ M_CALL(REG_ITMP1);
+
+ /* and now restore the proper return value */
+ switch (iptr->opc) {
+ case ICMD_IRETURN:
+ case ICMD_ARETURN:
+ case ICMD_LRETURN:
+ M_LLD(REG_RESULT, REG_SP, rd->memuse * 8);
+ break;
+ case ICMD_FRETURN:
+ case ICMD_DRETURN:
+ M_DLD(REG_FRESULT, REG_SP, rd->memuse * 8);
+ break;
+ }
+ }
+#endif
+
+ /* restore saved registers */
+
+ for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) {
+ p--; M_LLD(rd->savintregs[i], REG_SP, p * 8);
+ }
+ for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) {
+ p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8);
+ }
+
+ /* deallocate stack */
+
+ if (cd->stackframesize)
+ M_AADD_IMM(cd->stackframesize * 8, REG_SP);
+
+ /* generate method profiling code */
+
+ PROFILE_CYCLE_STOP;
+
+ M_RET;
+ }
+#endif
+ break;
+
+
+ case ICMD_TABLESWITCH: /* ..., index ==> ... */
+ OOPS();
+#if 0
+ {
+ s4 i, l;
+ branch_target_t *table;
+
+ table = iptr->dst.table;
+
+ l = iptr->sx.s23.s2.tablelow;
+ i = iptr->sx.s23.s3.tablehigh;
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+ M_INTMOVE(s1, REG_ITMP1);
+
+ if (l != 0)
+ M_ISUB_IMM(l, REG_ITMP1);
+
+ /* number of targets */
+ i = i - l + 1;
+
+ /* range check */
+ M_ICMP_IMM(i - 1, REG_ITMP1);
+ M_BA(0);
+
+ codegen_add_branch_ref(cd, table[0].block); /* default target */
+
+ /* 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 */
+
+ M_MOV_IMM(0, REG_ITMP2);
+ dseg_adddata(cd);
+ emit_mov_memindex_reg(cd, -(cd->dseglen), REG_ITMP2, REG_ITMP1, 3, REG_ITMP1);
+ M_JMP(REG_ITMP1);
+ }
+#endif
+ break;
+
+
+ case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */
+ OOPS();
+#if 0
+ {
+ s4 i;
+ lookup_target_t *lookup;
+
+ lookup = iptr->dst.lookup;
+
+ i = iptr->sx.s23.s2.lookupcount;
+
+ MCODECHECK(8 + ((7 + 6) * i) + 5);
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+
+ while (--i >= 0) {
+ M_ICMP_IMM(lookup->value, s1);
+ M_BEQ(0);
+ codegen_add_branch_ref(cd, lookup->target.block);
+ lookup++;
+ }
+
+ M_JMP_IMM(0);
+
+ codegen_add_branch_ref(cd, iptr->sx.s23.s3.lookupdefault.block);
+ }
+#endif
+ break;
+
+
+ case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */
+ OOPS();
+#if 0
+
+ bte = iptr->sx.s23.s3.bte;
+ md = bte->md;
+#endif
+ goto gen_method;
+
+ case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */
+ case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */
+ case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */
+ case ICMD_INVOKEINTERFACE:
+ OOPS();
+#if 0
+
+ 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;
+ }
+#endif
+gen_method:
+#if 0
+ s3 = md->paramcount;
+
+ MCODECHECK((20 * s3) + 128);
+
+ /* copy arguments to registers or stack location */
+
+ for (s3 = s3 - 1; s3 >= 0; s3--) {
+ var = VAR(iptr->sx.s23.s2.args[s3]);
+
+ /* Already Preallocated (ARGVAR) ? */
+ if (var->flags & PREALLOC)
+ continue;
+
+ if (IS_INT_LNG_TYPE(var->type)) {
+ if (!md->params[s3].inmemory) {
+ s1 = rd->argintregs[md->params[s3].regoff];
+ d = emit_load(jd, iptr, var, s1);
+ M_INTMOVE(d, s1);
+ }
+ else {
+ d = emit_load(jd, iptr, var, REG_ITMP1);
+ M_LST(d, REG_SP, md->params[s3].regoff * 8);
+ }
+ }
+ else {
+ if (!md->params[s3].inmemory) {
+ s1 = rd->argfltregs[md->params[s3].regoff];
+ d = emit_load(jd, iptr, var, s1);
+ M_FLTMOVE(d, s1);
+ }
+ else {
+ d = emit_load(jd, iptr, var, REG_FTMP1);
+
+ if (IS_2_WORD_TYPE(var->type))
+ M_DST(d, REG_SP, md->params[s3].regoff * 8);
+ else
+ M_FST(d, REG_SP, md->params[s3].regoff * 8);
+ }
+ }
+ }
+
+ /* generate method profiling code */
+
+ PROFILE_CYCLE_STOP;
+
+ switch (iptr->opc) {
+ case ICMD_BUILTIN:
+ M_MOV_IMM(bte->fp, REG_ITMP1);
+ M_CALL(REG_ITMP1);
+
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ M_TEST(REG_RESULT);
+ M_BEQ(0);
+ codegen_add_fillinstacktrace_ref(cd);
+ }
+ break;
+
+ case ICMD_INVOKESPECIAL:
+ M_TEST(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);
+ disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp;
+
+ /* must be calculated before codegen_add_patch_ref */
+
+ if (opt_shownops)
+ disp -= PATCHER_CALL_SIZE;
+
+ codegen_add_patch_ref(cd, PATCHER_invokestatic_special,
+ um, disp);
+
+/* a = 0; */
+ }
+ else {
+ disp = dseg_add_functionptr(cd, lm->stubroutine);
+ disp = -((cd->mcodeptr + 7) - cd->mcodebase) + disp;
+
+/* a = (ptrint) lm->stubroutine; */
+ }
+
+/* M_MOV_IMM(a, REG_ITMP2); */
+ M_ALD(REG_ITMP2, RIP, disp);
+ M_CALL(REG_ITMP2);
+ break;
+
+ case ICMD_INVOKEVIRTUAL:
+ gen_nullptr_check(REG_A0);
+
+ if (lm == NULL) {
+ codegen_add_patch_ref(cd, PATCHER_invokevirtual, um, 0);
+
+ s1 = 0;
+ }
+ else
+ s1 = OFFSET(vftbl_t, table[0]) +
+ sizeof(methodptr) * lm->vftblindex;
+
+ M_ALD(REG_METHODPTR, REG_A0,
+ OFFSET(java_objectheader, vftbl));
+ M_ALD32(REG_ITMP3, REG_METHODPTR, s1);
+ M_CALL(REG_ITMP3);
+ break;
+
+ case ICMD_INVOKEINTERFACE:
+ gen_nullptr_check(REG_A0);
+
+ if (lm == NULL) {
+ codegen_add_patch_ref(cd, PATCHER_invokeinterface, um, 0);
+
+ s1 = 0;
+ s2 = 0;
+ }
+ else {
+ s1 = OFFSET(vftbl_t, interfacetable[0]) -
+ sizeof(methodptr) * lm->class->index;
+
+ s2 = sizeof(methodptr) * (lm - lm->class->methods);
+ }
+
+ M_ALD(REG_METHODPTR, REG_A0,
+ OFFSET(java_objectheader, vftbl));
+ M_ALD32(REG_METHODPTR, REG_METHODPTR, s1);
+ M_ALD32(REG_ITMP3, REG_METHODPTR, s2);
+ M_CALL(REG_ITMP3);
+ break;
+ }
+
+ /* generate method profiling code */
+
+ PROFILE_CYCLE_START;
+
+ /* store return value */
+
+ d = md->returntype.type;
+
+ if (d != TYPE_VOID) {
+ if (IS_INT_LNG_TYPE(d)) {
+ s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT);
+ M_INTMOVE(REG_RESULT, s1);
+ }
+ else {
+ s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT);
+ M_FLTMOVE(REG_FRESULT, s1);
+ }
+ emit_store_dst(jd, iptr, s1);
+ }
+#endif
+ break;
+
+
+ case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */
+ OOPS();
+#if 0
+
+ /* val.a: (classinfo *) superclass */
+
+ /* superclass is an interface:
+ *
+ * OK if ((sub == NULL) ||
+ * (sub->vftbl->interfacetablelength > super->index) &&
+ * (sub->vftbl->interfacetable[-super->index] != NULL));
+ *
+ * superclass is a class:
+ *
+ * OK if ((sub == NULL) || (0
+ * <= (sub->vftbl->baseval - super->vftbl->baseval) <=
+ * super->vftbl->diffval));
+ */
+
+ if (!(iptr->flags.bits & INS_FLAG_ARRAY)) {
+ /* object type cast-check */
+
+ classinfo *super;
+ vftbl_t *supervftbl;
+ s4 superindex;
+
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ super = NULL;
+ superindex = 0;
+ supervftbl = NULL;
+ }
+ else {
+ super = iptr->sx.s23.s3.c.cls;
+ superindex = super->index;
+ supervftbl = super->vftbl;
+ }
+
+#if defined(ENABLE_THREADS)
+ codegen_threadcritrestart(cd, cd->mcodeptr - cd->mcodebase);
+#endif
+ s1 = emit_load_s1(jd, iptr, REG_ITMP1);
+
+ /* calculate interface checkcast code size */
+
+ s2 = 3; /* mov_membase_reg */
+ CALCOFFSETBYTES(s2, s1, OFFSET(java_objectheader, vftbl));
+
+ s2 += 3 + 4 /* movl_membase32_reg */ + 3 + 4 /* sub imm32 */ +
+ 3 /* test */ + 6 /* jcc */ + 3 + 4 /* mov_membase32_reg */ +
+ 3 /* test */ + 6 /* jcc */;
+
+ if (super == NULL)
+ s2 += (opt_shownops ? 5 : 0);
+
+ /* calculate class checkcast code size */
+
+ s3 = 3; /* mov_membase_reg */
+ CALCOFFSETBYTES(s3, s1, OFFSET(java_objectheader, vftbl));
+ s3 += 10 /* mov_imm_reg */ + 3 + 4 /* movl_membase32_reg */;
+
+#if 0
+ if (s1 != REG_ITMP1) {
+ a += 3; /* movl_membase_reg - only if REG_ITMP3 == R11 */
+ CALCOFFSETBYTES(a, REG_ITMP3, OFFSET(vftbl_t, baseval));
+ a += 3; /* movl_membase_reg - only if REG_ITMP3 == R11 */
+ CALCOFFSETBYTES(a, REG_ITMP3, OFFSET(vftbl_t, diffval));
+ a += 3; /* sub */
+
+ } else
+#endif
+ {
+ s3 += 3 + 4 /* movl_membase32_reg */ + 3 /* sub */ +
+ 10 /* mov_imm_reg */ + 3 /* movl_membase_reg */;
+ CALCOFFSETBYTES(s3, REG_ITMP3, OFFSET(vftbl_t, diffval));
+ }
+
+ s3 += 3 /* cmp */ + 6 /* jcc */;
+
+ if (super == NULL)
+ s3 += (opt_shownops ? 5 : 0);
+
+ /* if class is not resolved, check which code to call */
+
+ if (super == NULL) {
+ M_TEST(s1);
+ M_BEQ(6 + (opt_shownops ? 5 : 0) + 7 + 6 + s2 + 5 + s3);
+
+ codegen_add_patch_ref(cd, PATCHER_checkcast_instanceof_flags,
+ iptr->sx.s23.s3.c.ref, 0);
+
+ M_IMOV_IMM(0, REG_ITMP2); /* super->flags */
+ M_IAND_IMM(ACC_INTERFACE, REG_ITMP2);
+ M_BEQ(s2 + 5);
+ }
+
+ /* interface checkcast code */
+
+ if ((super == NULL) || (super->flags & ACC_INTERFACE)) {
+ if (super != NULL) {
+ M_TEST(s1);
+ M_BEQ(s2);
+ }
+
+ M_ALD(REG_ITMP2, s1, OFFSET(java_objectheader, vftbl));
+
+ if (super == NULL) {
+ codegen_add_patch_ref(cd,
+ PATCHER_checkcast_instanceof_interface,
+ iptr->sx.s23.s3.c.ref,
+ 0);
+ }
+
+ emit_movl_membase32_reg(cd, REG_ITMP2,
+ OFFSET(vftbl_t, interfacetablelength),
+ REG_ITMP3);
+ /* XXX TWISTI: should this be int arithmetic? */
+ M_LSUB_IMM32(superindex, REG_ITMP3);
+ M_TEST(REG_ITMP3);
+ M_BLE(0);
+ codegen_add_classcastexception_ref(cd, s1);
+ emit_mov_membase32_reg(cd, REG_ITMP2,
+ OFFSET(vftbl_t, interfacetable[0]) -
+ superindex * sizeof(methodptr*),
+ REG_ITMP3);
+ M_TEST(REG_ITMP3);
+ M_BEQ(0);
+ codegen_add_classcastexception_ref(cd, s1);
+
+ if (super == NULL)
+ M_JMP_IMM(s3);
+ }
+
+ /* class checkcast code */
+
+ if ((super == NULL) || !(super->flags & ACC_INTERFACE)) {
+ if (super != NULL) {
+ M_TEST(s1);
+ M_BEQ(s3);
+ }
+
+ M_ALD(REG_ITMP2, s1, OFFSET(java_objectheader, vftbl));
+
+ if (super == NULL) {
+ codegen_add_patch_ref(cd, PATCHER_checkcast_class,
+ iptr->sx.s23.s3.c.ref,
+ 0);
+ }
+
+ M_MOV_IMM(supervftbl, REG_ITMP3);
+#if defined(ENABLE_THREADS)
+ codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase);
+#endif
+ emit_movl_membase32_reg(cd, REG_ITMP2,
+ OFFSET(vftbl_t, baseval),
+ REG_ITMP2);
+ /* if (s1 != REG_ITMP1) { */
+ /* emit_movl_membase_reg(cd, REG_ITMP3, */
+ /* OFFSET(vftbl_t, baseval), */
+ /* REG_ITMP1); */
+ /* emit_movl_membase_reg(cd, REG_ITMP3, */
+ /* OFFSET(vftbl_t, diffval), */
+ /* REG_ITMP3); */
+ /* #if defined(ENABLE_THREADS) */
+ /* codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); */
+ /* #endif */
+ /* emit_alu_reg_reg(cd, ALU_SUB, REG_ITMP1, REG_ITMP2); */
+
+ /* } else { */
+ emit_movl_membase32_reg(cd, REG_ITMP3,
+ OFFSET(vftbl_t, baseval),
+ REG_ITMP3);
+ M_LSUB(REG_ITMP3, REG_ITMP2);
+ M_MOV_IMM(supervftbl, REG_ITMP3);
+ M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval));
+ /* } */
+#if defined(ENABLE_THREADS)
+ codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase);
+#endif
+ M_LCMP(REG_ITMP3, REG_ITMP2);
+ M_BA(0); /* (u) REG_ITMP1 > (u) REG_ITMP2 -> jump */
+ codegen_add_classcastexception_ref(cd, s1);
+ }
+
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
+ }
+ else {
+ /* array type cast-check */
+
+ s1 = emit_load_s1(jd, iptr, REG_ITMP2);
+ M_INTMOVE(s1, REG_A0);
+
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ codegen_add_patch_ref(cd, PATCHER_builtin_arraycheckcast,
+ iptr->sx.s23.s3.c.ref, 0);
+ }
+
+ M_MOV_IMM(iptr->sx.s23.s3.c.cls, REG_A1);
+ M_MOV_IMM(BUILTIN_arraycheckcast, REG_ITMP1);
+ M_CALL(REG_ITMP1);
+
+ /* s1 may have been destroyed over the function call */
+ s1 = emit_load_s1(jd, iptr, REG_ITMP2);
+ M_TEST(REG_RESULT);
+ M_BEQ(0);
+ codegen_add_classcastexception_ref(cd, s1);
+
+ d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
+ }
+
+ M_INTMOVE(s1, d);
+ emit_store_dst(jd, iptr, d);
+#endif
+ break;
+
+ case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */
+ OOPS();
+#if 0
+
+ /* val.a: (classinfo *) superclass */
+
+ /* superclass is an interface:
+ *
+ * return (sub != NULL) &&
+ * (sub->vftbl->interfacetablelength > super->index) &&
+ * (sub->vftbl->interfacetable[-super->index] != NULL);
+ *
+ * superclass is a class:
+ *
+ * return ((sub != NULL) && (0
+ * <= (sub->vftbl->baseval - super->vftbl->baseval) <=
+ * super->vftbl->diffvall));
+ */
+
+ {
+ classinfo *super;
+ vftbl_t *supervftbl;
+ s4 superindex;
+
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ super = NULL;
+ superindex = 0;
+ supervftbl = NULL;
+
+ } else {
+ super = iptr->sx.s23.s3.c.cls;
+ superindex = super->index;
+ supervftbl = super->vftbl;
+ }
+
+#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_INTMOVE(s1, REG_ITMP1);
+ s1 = REG_ITMP1;
+ }
+
+ /* calculate interface instanceof code size */
+
+ s2 = 3; /* mov_membase_reg */
+ CALCOFFSETBYTES(s2, s1, OFFSET(java_objectheader, vftbl));
+ s2 += 3 + 4 /* movl_membase32_reg */ + 3 + 4 /* sub_imm32 */ +
+ 3 /* test */ + 6 /* jcc */ + 3 + 4 /* mov_membase32_reg */ +
+ 3 /* test */ + 4 /* setcc */;
+
+ if (!super)
+ s2 += (opt_shownops ? 5 : 0);
+
+ /* calculate class instanceof code size */
+
+ s3 = 3; /* mov_membase_reg */
+ CALCOFFSETBYTES(s3, s1, OFFSET(java_objectheader, vftbl));
+ s3 += 10; /* mov_imm_reg */
+ s3 += 2; /* movl_membase_reg - only if REG_ITMP1 == RAX */
+ CALCOFFSETBYTES(s3, REG_ITMP1, OFFSET(vftbl_t, baseval));
+ s3 += 3; /* movl_membase_reg - only if REG_ITMP2 == R10 */
+ CALCOFFSETBYTES(s3, REG_ITMP2, OFFSET(vftbl_t, baseval));
+ s3 += 3; /* movl_membase_reg - only if REG_ITMP2 == R10 */
+ CALCOFFSETBYTES(s3, REG_ITMP2, OFFSET(vftbl_t, diffval));
+ s3 += 3 /* sub */ + 3 /* xor */ + 3 /* cmp */ + 4 /* setcc */;
+
+ if (super == NULL)
+ s3 += (opt_shownops ? 5 : 0);
+
+ emit_alu_reg_reg(cd, ALU_XOR, d, d);
+
+ /* if class is not resolved, check which code to call */
+
+ if (super == NULL) {
+ emit_test_reg_reg(cd, s1, s1);
+ emit_jcc(cd, CC_Z, (6 + (opt_shownops ? 5 : 0) +
+ 7 + 6 + s2 + 5 + s3));
+
+ codegen_add_patch_ref(cd, PATCHER_checkcast_instanceof_flags,
+ iptr->sx.s23.s3.c.ref, 0);
+
+ emit_movl_imm_reg(cd, 0, REG_ITMP3); /* super->flags */
+ emit_alul_imm_reg(cd, ALU_AND, ACC_INTERFACE, REG_ITMP3);
+ emit_jcc(cd, CC_Z, s2 + 5);
+ }
+
+ /* interface instanceof code */
+
+ if ((super == NULL) || (super->flags & ACC_INTERFACE)) {
+ if (super != NULL) {
+ emit_test_reg_reg(cd, s1, s1);
+ emit_jcc(cd, CC_Z, s2);
+ }
+
+ emit_mov_membase_reg(cd, s1,
+ OFFSET(java_objectheader, vftbl),
+ REG_ITMP1);
+
+ if (super == NULL) {
+ codegen_add_patch_ref(cd,
+ PATCHER_checkcast_instanceof_interface,
+ iptr->sx.s23.s3.c.ref, 0);
+ }
+
+ emit_movl_membase32_reg(cd, REG_ITMP1,
+ OFFSET(vftbl_t, interfacetablelength),
+ REG_ITMP3);
+ emit_alu_imm32_reg(cd, ALU_SUB, superindex, REG_ITMP3);
+ emit_test_reg_reg(cd, REG_ITMP3, REG_ITMP3);
+
+ a = 3 + 4 /* mov_membase32_reg */ + 3 /* test */ + 4 /* setcc */;
+
+ emit_jcc(cd, CC_LE, a);
+ emit_mov_membase32_reg(cd, REG_ITMP1,
+ OFFSET(vftbl_t, interfacetable[0]) -
+ superindex * sizeof(methodptr*),
+ REG_ITMP1);
+ emit_test_reg_reg(cd, REG_ITMP1, REG_ITMP1);
+ emit_setcc_reg(cd, CC_NE, d);
+
+ if (!super)
+ emit_jmp_imm(cd, s3);
+ }
+
+ /* class instanceof code */
+
+ if ((super == NULL) || !(super->flags & ACC_INTERFACE)) {
+ if (super != NULL) {
+ emit_test_reg_reg(cd, s1, s1);
+ emit_jcc(cd, CC_E, s3);
+ }
+
+ emit_mov_membase_reg(cd, s1,
+ OFFSET(java_objectheader, vftbl),
+ REG_ITMP1);
+
+ if (super == NULL) {
+ codegen_add_patch_ref(cd, PATCHER_instanceof_class,
+ iptr->sx.s23.s3.c.ref, 0);
+ }
+
+ emit_mov_imm_reg(cd, (ptrint) supervftbl, REG_ITMP2);
+#if defined(ENABLE_THREADS)
+ codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase);
+#endif
+ emit_movl_membase_reg(cd, REG_ITMP1,
+ OFFSET(vftbl_t, baseval),
+ REG_ITMP1);
+ emit_movl_membase_reg(cd, REG_ITMP2,
+ OFFSET(vftbl_t, diffval),
+ REG_ITMP3);
+ emit_movl_membase_reg(cd, REG_ITMP2,
+ OFFSET(vftbl_t, baseval),
+ REG_ITMP2);
+#if defined(ENABLE_THREADS)
+ codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase);
+#endif
+ emit_alu_reg_reg(cd, ALU_SUB, REG_ITMP2, REG_ITMP1);
+ emit_alu_reg_reg(cd, ALU_XOR, d, d); /* may be REG_ITMP2 */
+ emit_alu_reg_reg(cd, ALU_CMP, REG_ITMP3, REG_ITMP1);
+ emit_setcc_reg(cd, CC_BE, d);
+ }
+ emit_store_dst(jd, iptr, d);
+ }
+#endif
+ break;
+
+ case ICMD_MULTIANEWARRAY:/* ..., cnt1, [cnt2, ...] ==> ..., arrayref */
+ OOPS();
+#if 0
+
+ /* check for negative sizes and copy sizes to stack if necessary */
+
+ MCODECHECK((10 * 4 * iptr->s1.argcount) + 5 + 10 * 8);
+
+ for (s1 = iptr->s1.argcount; --s1 >= 0; ) {
+
+ /* copy SAVEDVAR sizes to stack */
+ var = VAR(iptr->sx.s23.s2.args[s1]);
+
+ /* Already Preallocated? */
+ if (!(var->flags & PREALLOC)) {
+ s2 = emit_load(jd, iptr, var, REG_ITMP1);
+ M_LST(s2, REG_SP, s1 * 8);
+ }
+ }
+
+ /* is a patcher function set? */
+
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ codegen_add_patch_ref(cd, PATCHER_builtin_multianewarray,
+ iptr->sx.s23.s3.c.ref, 0);
+ }
+
+ /* a0 = dimension count */
+
+ M_MOV_IMM(iptr->s1.argcount, REG_A0);
+
+ /* a1 = classinfo */
+
+ M_MOV_IMM(iptr->sx.s23.s3.c.cls, REG_A1);
+
+ /* a2 = pointer to dimensions = stack pointer */
+
+ M_MOV(REG_SP, REG_A2);
+
+ M_MOV_IMM(BUILTIN_multianewarray, REG_ITMP1);
+ M_CALL(REG_ITMP1);
+
+ /* check for exception before result assignment */
+
+ M_TEST(REG_RESULT);
+ M_BEQ(0);
+ codegen_add_fillinstacktrace_ref(cd);
+
+ s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT);
+ M_INTMOVE(REG_RESULT, s1);
+ emit_store_dst(jd, iptr, s1);
+#endif
+ break;
+
+ default:
+ *exceptionptr = new_internalerror("Unknown ICMD %d", iptr->opc);
+ return false;
+ } /* switch */
+
+ } /* for instruction */
+
+ MCODECHECK(512); /* XXX require a lower number? */
+
+ /* At the end of a basic block we may have to append some nops,
+ because the patcher stub calling code might be longer than the
+ actual instruction. So codepatching does not change the
+ following block unintentionally. */
+
+ if (cd->mcodeptr < cd->lastmcodeptr) {
+ while (cd->mcodeptr < cd->lastmcodeptr) {
+ M_NOP;
+ }
+ }
+
+ } /* if (bptr -> flags >= BBREACHED) */
+ } /* for basic block */
+
+ dseg_createlinenumbertable(cd);
+
+ /* generate stubs */
+
+ emit_exception_stubs(jd);
+ emit_patcher_stubs(jd);
+#if 0
+ emit_replacement_stubs(jd);
+#endif
+
+ 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 (SZ_BRAS + SZ_AHI + (2 * SZ_L) + SZ_BR)
+
+#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;
+
+ 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 */
+
+ /* don't touch ITMP3 as it cointains the return address */
+
+ N_L2(REG_ITMP1, -2 * 4, REG_PV); /* methodinfo */
+ /* TODO where is methodpointer loaded into itmp2? is it already inside? */
+ N_L2(REG_PV, -3 * 4, REG_PV); /* compiler pointer */
+ N_BR(REG_PV);
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ count_cstub_len += COMPILERSTUB_SIZE;
+#endif
+
+ /* release dump area */
+
+ dump_release(dumpsize);
+
+ return s;
+}
+
+
+/* createnativestub ************************************************************
+
+ Creates a stub routine which calls a native method.
+
+*******************************************************************************/
+
+/*
+ arguments on stack \
+-------------------------------------------------| <- SP on nativestub entry
+ return address |
+ callee saved int regs (none) |
+ callee saved float regs (none) | stack frame like in cacao
+ local variable slots (none) |
+ arguments for calling methods (none) /
+------------------------------------------------------------------ <- datasp
+ stackframe info
+ locaref table
+ integer arguments
+ float arguments
+96 - ... on stack parameters (nmd->memuse slots) \ stack frame like in ABI
+0 - 96 register save area for callee /
+-------------------------------------------------------- <- SP native method
+ ==
+ SP after method entry
+*/
+
+u1 *createnativestub(functionptr f, jitdata *jd, methoddesc *nmd)
+{
+ methodinfo *m;
+ codeinfo *code;
+ codegendata *cd;
+ registerdata *rd;
+ methoddesc *md;
+ s4 nativeparams;
+ s4 i, j; /* count variables */
+ s4 t;
+ s4 s1, s2;
+ s4 disp;
+
+ /* 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 stack frame size */
+#if 0
+ cd->stackframesize =
+ sizeof(stackframeinfo) / SIZEOF_VOID_P +
+ sizeof(localref_table) / SIZEOF_VOID_P +
+ INT_ARG_CNT + FLT_ARG_CNT +
+ 1 + /* functionptr, TODO: store in data segment */
+ nmd->memuse;
+
+ cd->stackframesize |= 0x1; /* keep stack 16-byte aligned */
+#endif
+
+ cd->stackframesize =
+ 1 + /* r14 - return address */ +
+ sizeof(stackframeinfo) / SIZEOF_VOID_P +
+ sizeof(localref_table) / SIZEOF_VOID_P +
+ 1 + /* itmp3 */
+ (INT_ARG_CNT + FLT_ARG_CNT) * 2 +
+ nmd->memuse + /* parameter passing */
+ 96 / SIZEOF_VOID_P /* required by ABI */;
+
+
+ /* create method header */
+
+ (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */
+ (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* 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 native method profiling code */
+#if 0
+ if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) {
+ /* count frequency */
+
+ M_MOV_IMM(code, REG_ITMP3);
+ M_IINC_MEMBASE(REG_ITMP3, OFFSET(codeinfo, frequency));
+ }
+#endif
+
+ /* generate stub code */
+
+ N_AHI(REG_SP, -(cd->stackframesize * SIZEOF_VOID_P));
+
+ /* save return address */
+
+ N_ST(R14, (cd->stackframesize - 1) * SIZEOF_VOID_P, 0, REG_SP)
+
+#if 0
+#if !defined(NDEBUG)
+ if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
+ emit_verbosecall_enter(jd);
+#endif
+#endif
+
+ /* get function address (this must happen before the stackframeinfo) */
+
+#if !defined(WITH_STATIC_CLASSPATH)
+ if (f == NULL)
+ codegen_add_patch_ref(cd, PATCHER_resolve_native, m, 0);
+#endif
+
+ disp = dseg_add_functionptr(cd, f);
+ N_L2(REG_ITMP3, disp, REG_PV);
+
+ j = 96 + (nmd->memuse * 4);
+
+ /* todo some arg registers are not volatile in C-abi terms */
+
+ /* save integer and float argument registers */
+
+ for (i = 0; i < md->paramcount; i++) {
+ if (! md->params[i].inmemory) {
+ s1 = md->params[i].regoff;
+
+ if (IS_INT_LNG_TYPE(md->paramtypes[i].type)) {
+ if (IS_2_WORD_TYPE(t)) {
+ /* todo store multiple */
+ N_ST(rd->argintregs[GET_HIGH_REG(s1)], j, 0, REG_SP);
+ N_ST(rd->argintregs[GET_LOW_REG(s1)], j + 4, 0, REG_SP);
+ } else {
+ N_ST(rd->argintregs[s1], j, 0, REG_SP);
+ }
+ } else {
+ if (IS_2_WORD_TYPE(t)) {
+ N_STD(rd->argfltregs[s1], j, 0, REG_SP);
+ } else {
+ N_STE(rd->argfltregs[s1], j, 0, REG_SP);
+ }
+ }
+
+ j += 8;
+ }
+ }
+
+ N_ST(REG_ITMP3, j, 0, REG_SP);
+
+ /* create dynamic stack info */
+
+ N_LAE(REG_A0, (cd->stackframesize - 1) * 4, 0, REG_SP); /* datasp */
+ N_LR(REG_A1, REG_PV) /* pv */
+ N_LAE(REG_A2, cd->stackframesize * 4, 0, REG_SP); /* old SP */
+ N_L(REG_A3, (cd->stackframesize - 1) * 4, 0, REG_SP); /* return address */
+
+ disp = dseg_add_functionptr(cd, codegen_start_native_call);
+ N_L2(REG_ITMP1, disp, REG_PV);
+
+ M_CALL(REG_ITMP1); /* call */
+
+ /* restore integer and float argument registers */
+
+ j = 96 + (nmd->memuse * 4);
+
+ for (i = 0; i < md->paramcount; i++) {
+ if (! md->params[i].inmemory) {
+ s1 = md->params[i].regoff;
+
+ if (IS_INT_LNG_TYPE(md->paramtypes[i].type)) {
+ if (IS_2_WORD_TYPE(t)) {
+ /* todo load multiple ! */
+ N_L(rd->argintregs[GET_HIGH_REG(s1)], j, 0, REG_SP);
+ N_L(rd->argintregs[GET_LOW_REG(s1)], j + 4, 0, REG_SP);
+ } else {
+ N_L(rd->argintregs[s1], j, 0, REG_SP);
+ }
+ } else {
+ if (IS_2_WORD_TYPE(t)) {
+ N_LD(rd->argfltregs[s1], j, 0, REG_SP);
+ } else {
+ N_LE(rd->argfltregs[s1], j, 0, REG_SP);
+ }
+ }
+
+ j += 8;
+ }
+ }
+
+ N_L(REG_ITMP3, j, 0, REG_SP);
+
+ /* copy or spill arguments to new locations */
+
+ for (i = md->paramcount - 1, j = i + nativeparams; i >= 0; i--, j--) {
+ t = md->paramtypes[i].type;
+
+ if (IS_INT_LNG_TYPE(t)) {
+
+ if (!md->params[i].inmemory) {
+
+ s1 = rd->argintregs[md->params[i].regoff];
+
+ if (!nmd->params[j].inmemory) {
+ s2 = rd->argintregs[nmd->params[j].regoff];
+ if (IS_2_WORD_TYPE(t)) {
+ N_LR(GET_HIGH_REG(s2), GET_HIGH_REG(s1));
+ N_LR(GET_LOW_REG(s2), GET_LOW_REG(s1));
+ } else {
+ N_LR(s2, s1);
+ }
+ } else {
+ s2 = nmd->params[j].regoff;
+ if (IS_2_WORD_TYPE(t)) {
+ N_LM(GET_LOW_REG(s1), GET_HIGH_REG(s1), 96 + (s2 * 4), REG_SP);
+ } else {
+ N_L(s1, 96 + (s2 * 4), 0, REG_SP);
+ }
+ }
+
+ } else {
+ s1 = md->params[i].regoff + cd->stackframesize + 1; /* + 1 (RA) */
+ s2 = nmd->params[j].regoff;
+
+ if (IS_2_WORD_TYPE(t)) {
+ N_MVC(96 + (s2 * 4), 8, REG_SP, s1, REG_SP);
+ } else {
+ N_MVC(96 + (s2 * 4), 4, REG_SP, s1, REG_SP);
+ }
+ }
+
+ } else {
+ /* We only copy spilled float arguments, as the float argument */
+ /* registers keep unchanged. */
+
+ if (md->params[i].inmemory) {
+ s1 = md->params[i].regoff + cd->stackframesize + 1; /* + 1 (RA) */
+ s2 = nmd->params[j].regoff;
+
+ if (IS_2_WORD_TYPE(t)) {
+ N_MVC(96 + (s2 * 4), 8, REG_SP, s1, REG_SP);
+ } else {
+ N_MVC(96 + (s2 * 4), 4, REG_SP, s1, REG_SP);
+ }
+ }
+ }
+ }
+
+ /* put class into second argument register */
+
+ if (m->flags & ACC_STATIC) {
+ disp = dseg_add_address(cd, m->class);
+ N_L2(REG_A1, disp, REG_PV);
+ }
+
+ /* put env into first argument register */
+
+ disp = dseg_add_address(cd, _Jv_env);
+ N_L2(REG_A0, disp, REG_PV);
+
+ /* do the native function call */
+
+ M_CALL(REG_ITMP3); /* call */
+
+ /* save return value */
+
+ t = md->returntype.type;
+
+ if (t != TYPE_VOID) {
+ if (IS_INT_LNG_TYPE(t)) {
+ if (IS_2_WORD_TYPE(t)) {
+ N_STM(REG_RESULT, REG_RESULT2, 96, REG_SP);
+ } else {
+ N_ST(REG_RESULT, 96, 0, REG_SP);
+ }
+ } else {
+ if (IS_2_WORD_TYPE(t)) {
+ N_STD(REG_FRESULT, 96, 0, REG_SP);
+ } else {
+ N_STE(REG_FRESULT, 96, 0, REG_SP);
+ }
+ }
+ }
+
+#if 0
+#if !defined(NDEBUG)
+ if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
+ emit_verbosecall_exit(jd);
+#endif
+#endif
+
+ /* remove native stackframe info */
+
+ N_LAE(REG_A0, cd->stackframesize * 4, 0, REG_SP);
+ disp = dseg_add_functionptr(cd, codegen_finish_native_call);
+ N_L2(REG_ITMP1, disp, REG_PV);
+ M_CALL(REG_ITMP1);
+ N_LR(REG_ITMP3, REG_RESULT);
+
+ /* restore return value */
+
+ if (t != TYPE_VOID) {
+ if (IS_INT_LNG_TYPE(t)) {
+ if (IS_2_WORD_TYPE(t)) {
+ N_LM(REG_RESULT, REG_RESULT2, 96, REG_SP);
+ } else {
+ N_L(REG_RESULT, 96, 0, REG_SP);
+ }
+ } else {
+ if (IS_2_WORD_TYPE(t)) {
+ N_LD(REG_FRESULT, 96, 0, REG_SP);
+ } else {
+ N_LE(REG_FRESULT, 96, 0, REG_SP);
+ }
+ }
+ }
+
+ /* remove stackframe */
+
+ N_AHI(REG_SP, cd->stackframesize * 4);
+
+ /* test for exception */
+
+ N_LTR(REG_ITMP3, REG_ITMP3);
+ N_BRC(DD_NE, SZ_BRC + SZ_BC);
+ N_BC(DD_ANY, 0, 0, REG_SP); /* return */
+
+ /* handle exception */
+
+ N_LONG_0();
+
+#if 0
+ M_MOV(REG_ITMP3, REG_ITMP1_XPTR);
+ M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8); /* get return address from stack */
+ M_ASUB_IMM(3, REG_ITMP2_XPC); /* callq */
+
+ M_MOV_IMM(asm_handle_nat_exception, REG_ITMP3);
+ M_JMP(REG_ITMP3);
+
+ /* generate patcher stubs */
+
+ emit_patcher_stubs(jd);
+
+#endif
+ codegen_finish(jd);
+
+ return code->entrypoint;
+ return NULL;
+}
+
+
+
+/*
+ * 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/x86_64/codegen.h - code generation macros for x86_64
+
+ 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: Andreas Krall
+ Christian Thalinger
+
+ $Id: codegen.h 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+
+#ifndef _CODEGEN_H
+#define _CODEGEN_H
+
+#include "config.h"
+
+#include <ucontext.h>
+
+#include "vm/types.h"
+
+#include "vm/jit/jit.h"
+
+
+/* additional functions and macros to generate code ***************************/
+
+#define CALCOFFSETBYTES(var, reg, val) \
+ if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
+ else if ((s4) (val) != 0) (var) += 1; \
+ else if ((reg) == RBP || (reg) == RSP || (reg) == R12 || (reg) == R13) (var) += 1;
+
+
+#define CALCIMMEDIATEBYTES(var, val) \
+ if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
+ else (var) += 1;
+
+
+/* gen_nullptr_check(objreg) */
+
+#define gen_nullptr_check(objreg) \
+ if (checknull) { \
+ M_TEST(objreg); \
+ M_BEQ(0); \
+ codegen_add_nullpointerexception_ref(cd); \
+ }
+
+
+#define gen_bound_check \
+ if (checkbounds) { \
+ M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));\
+ M_ICMP(REG_ITMP3, s2); \
+ M_BAE(0); \
+ codegen_add_arrayindexoutofboundsexception_ref(cd, s2); \
+ }
+
+
+/* MCODECHECK(icnt) */
+
+#define MCODECHECK(icnt) \
+ do { \
+ if ((cd->mcodeptr + (icnt)) > cd->mcodeend) \
+ codegen_increase(cd); \
+ } while (0)
+
+
+#define ALIGNCODENOP \
+ if ((s4) (((ptrint) cd->mcodeptr) & 7)) { \
+ M_NOP; \
+ }
+
+
+/* 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(reg,dreg) \
+ do { \
+ if ((reg) != (dreg)) { \
+ M_MOV(reg, dreg); \
+ } \
+ } while (0)
+
+
+/* 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(reg,dreg) \
+ do { \
+ if ((reg) != (dreg)) { \
+ M_FMOV(reg, dreg); \
+ } \
+ } while (0)
+
+
+#define ICONST(r,c) \
+ do { \
+ if ((c) == 0) \
+ M_CLR((d)); \
+ else \
+ M_IMOV_IMM((c), (d)); \
+ } while (0)
+/* do { \ */
+/* M_IMOV_IMM((c), (d)); \ */
+/* } while (0) */
+
+
+#define LCONST(r,c) \
+ do { \
+ if ((c) == 0) \
+ M_CLR((d)); \
+ else \
+ M_MOV_IMM((c), (d)); \
+ } while (0)
+
+
+/* some patcher defines *******************************************************/
+
+#define PATCHER_CALL_SIZE 5 /* size in bytes of a patcher call */
+
+#define PATCHER_NOPS \
+ do { \
+ M_NOP; \
+ M_NOP; \
+ M_NOP; \
+ M_NOP; \
+ M_NOP; \
+ } while (0)
+
+
+/* macros to create code ******************************************************/
+
+/* Conventions:
+ * N_foo: defines the instrucition foo as in `ESA/390 Principles of operations'
+ * SZ_foo: defines the size of the instruction N_foo
+ * DD_foo: defines a condition code as used by s390 GCC
+ * M_foo: defines the alpha like instruction used in cacao
+ * the instruction is defined by an equivalent N_ instruction
+ * CC_foo: defines a condition code as used
+ * the instruction is defined as an equivalent DD_ condition code
+ */
+
+/* S390 specific code */
+
+/* Instruction formats */
+
+#define _CODE(t, code) \
+ do { \
+ *((t *) cd->mcodeptr) = (code); \
+ cd->mcodeptr += sizeof(t); \
+ } while (0);
+
+#define _CODE2(code) _CODE(u2, code)
+#define _CODE4(code) _CODE(u4, code)
+
+#define _IFNEG(val, neg, pos) \
+ do { if ((val) < 0) { neg ; } else { pos ; } } while (0)
+
+#define N_RR(op, r1, r2) \
+ _CODE2( (op << 8) | (r1 << 4) | (r2) )
+
+#define SZ_RR 2
+
+#define N_RR2(op, i) \
+ _CODE2( (op << 8) | (i) )
+
+#define N_RX(op, r1, d2, x2, b2) \
+ _CODE4( ((op) << 24) | ((r1) << 20) | ((x2) << 16) | ((b2) << 12) | ((d2) << 0) )
+
+#define SZ_RX 4
+
+#define N_RI(op1, op2, r1, i2) \
+ _CODE4( ((op1) << 24) | ((r1) << 20) | ((op2) << 16) | ((u2) i2) )
+
+#define SZ_RI 4
+
+#define N_SI(op, d1, b1, i2) \
+ _CODE4( ((op) << 24) | ((i2) << 16) | ((b1) << 12) | (d1) )
+
+#define SZ_SI 4
+
+#define N_SS(op, d1, l, b1, d2, b2) \
+ _CODE4( ((op) << 24) | ((l) << 16) | ((b1) << 12) | (d1) ) \
+ _CODE2( ((b2) << 12) | (d2) )
+
+#define SZ_SS 6
+
+#define N_SS2(op, d1, l1, b1, d2, l2, b2) \
+ N_SS(op, d1, ((l1) << 4) | (l2), b1, d2, l2)
+
+#define N_RS(op, r1, r3, d2, b2) \
+ _CODE4( ((op) << 24) | ((r1) << 20) | ((r3) << 16) | ((b2) << 12) | (d2) )
+
+#define SZ_RS 4
+
+#define N_RSI(op, r1, r2, i2) \
+ _CODE4( ((op) << 24) | ((r1) << 20) | ((r3) << 16) | ((u2)i2) )
+
+#define SZ_RSI 4
+
+#define N_RRE(op, r1, r2) \
+ _CODE4( ((op) << 16) | ((r1) << 4) | (r2) )
+
+#define SZ_RRE 4
+
+#define N_S2(d2, b2) \
+ _CODE4( ((op) << 16) | ((b2) << 12) | (d2) )
+
+#define SZ_S2 4
+
+#define N_E(op) \
+ _CODE2( (op) )
+
+#define SZ_E 2
+
+/* Condition codes */
+
+#define DD_O 1
+#define DD_H 2
+#define DD_NLE 3
+#define DD_L 4
+#define DD_NHE 5
+#define DD_LH 6
+#define DD_NE 7
+#define DD_E 8
+#define DD_NLH 9
+#define DD_HE 10
+#define DD_NL 11
+#define DD_LE 12
+#define DD_NH 13
+#define DD_NO 14
+#define DD_ANY 15
+
+/* Misc */
+
+#define N_LONG_0() _CODE4(0)
+
+/* Chapter 7. General instructions */
+
+#define N_AR(r1, r2) N_RR(0x1A, r1, r2)
+#define N_A(r1, d2, x2, b2) N_RX(0x5A, r1, d2, x2, b2)
+#define N_AH(r1, d2, x2, b2) N_RX(0x4A, r1, d2, x2, b2)
+#define N_AHI(r1, i2) N_RI(0xA7, 0xA, r1, i2)
+# define SZ_AHI SZ_RI
+#define N_ALR(r1, r2) N_RR(0x1E, r1, r2)
+#define N_AL(r1, d2, x2, b2) N_RX(0x5E, r1, d2, x2, b2)
+#define N_NR(r1, r2) N_RR(r1, r2)
+#define N_N(r1, d2, x2, b2) N_RX(0x54, r1, d2, x2, b2)
+#define N_NI(d1, b1, i2) N_SI(0x94, d1, b1, i2)
+#define N_NC(d1, l, b1, d2, b2) N_NC(0xD4, l, b1, d1, b2, d2)
+#define N_BALR(r1, r2) N_RR(0x05, r1, r2)
+#define N_BAL(r1, d2, x2, b2) N_RX(0x45, r1, d2, x2, b2)
+#define N_BASR(r1, r2) N_RR(0x0D, r1, r2)
+#define N_BAS(r1, d2, x2, b2) N_RX(0x4D, r1, d2, x2, b2)
+#define N_BASSM(r1, r2) N_RR(0x0C, r1, r2)
+#define N_BSM(r1, r2) N_RR(0x0B, r1, r2)
+#define N_BCR(m1, r2) N_RR(0x07, m1, r2)
+# define SZ_BCR SZ_RR
+# define N_BR(r2) N_BCR(DD_ANY, r2)
+# define SZ_BR SZ_BCR
+#define N_BC(m1, d2, x2, b2) N_RS(0x47, m1, d2, x2, b2)
+# define SZ_BC SZ_RS
+#define N_BCTR(r1, r2) N_RR(0x06, r1, r2)
+#define N_BCT(r1, d2, x2, b2) N_RX(0x46, r1, d2, x2, b2)
+#define N_BHX(r1, r2, d2, b2) N_RS(0xB6, r1, r3, d2, b2)
+#define N_BXLE(r1, r3, d2, b2) N_RS(0xB7, r1, r3, d2, b2)
+#define N_BRAS(r1, i2) N_RI(0xA7, 0x5, r1, (i2) / 2)
+# define SZ_BRAS SZ_RI
+#define N_BRC(m1, i2) N_RI(0xA7, 0x4, m1, (i2) / 2)
+# define N_J(i2) N_BRC(DD_ANY, i2)
+# define SZ_BRC SZ_RI
+# define SZ_J SZ_RI
+#define N_BRCT(r1, i2) N_RI(0xA7, 0x6, r1, (i2) / 2)
+#define N_BRXH(r1, r3, i2) N_RSI(0x84, r1, r3, (i2) / 2)
+#define N_BRXLE(r1, r3, i2) N_RSI(0x85, r1, r2, (i2) / 2)
+#define N_CKSM(r1, r2) N_RRE(0xB241, r1, r2)
+#define N_CR(r1, r2), N_RR(0x19, r1, r2)
+#define N_C(r1, d2, x2, b2) N_RX(0x59, r1, d2, x2, b2)
+#define N_CFC(d2, b2) N_S2(0xB21A, d2, b2)
+#define N_CS(r1, r3, d2, b2) N_RS(0xBA, r1, r3, d2, b2)
+#define N_CDS(r1, r3, d2, b2) N_RS(0xBB, r1, r3, d2, b2)
+#define N_CH(r1, d2, x2, b2) N_CH(0x49, r1, d2, x2, b2)
+#define N_CHI(r1, i2) N_RI(0xA7, 0xE, r1, i2)
+#define N_CLR(r1, r2) N_RR(0x15, r1, r2)
+#define N_CL(r1, d2, x2, b2) N_RX(0x55, r1, d2, x2, b2)
+#define N_CLI(d1, b1, i2) N_SI(0x95, d1, b1, i2)
+#define N_CLC(d1, l, b1, d2, b2) N_SS(0xD5, d1, l, b1, d2, b2)
+#define N_CLM(r1, m3, d2, b2) N_RS(0xBD, r1, m3, d2, b2)
+#define N_CLCL(r1, r2) N_RR(0x0F, r1, r2)
+#define N_CLCLE(r1, r3, d2, b2) N_RS(0xA9, r1, r3, d2, b2)
+#define N_CLST(r1, r2) N_RRE(0xB25D, r1, r2)
+#define N_CUSE(r1, r2) N_RRE(0xB257, r1, r2)
+#define N_CVB(r1, d2, x2, b2) N_RX(0x4F, r1, r2, x2, b2)
+#define N_CVD(r1, d2, x2, b2) N_RX(0x4E, r1, d2, x2, b2)
+#define N_CUUTF(r1, r2) N_RRE(0xB2A6, r1, r2)
+#define N_CUTFU(r1, r2) N_RRE(0xB2A7, r1, r2)
+#define N_CPYA(r1, r2) N_RRE(0xB240, r1, r2)
+#define N_DR(r1, r2) N_RR(0x1D, r1, r2)
+#define N_D(r1, d2, x2, b2) N_RX(0x5D, r1, d2, x2, b2)
+#define N_XR(r1, r2) N_RR(0x17, r1, r2)
+#define N_X(r1, d2, x2, b2) N_RX(0x57, r1, d2, x2, b2)
+#define N_XI(d1, b1, i2) N_SI(0x97, d1, b1, i2)
+#define N_XC(d1, l, b1, d2, b2) N_SS(0xD7, d1, l, b1, d2, b2)
+#define N_EX(r1, d2, x2, b2) N_RX(0x44, r1, d2, x2, b2)
+#define N_EAR(r1, r2) N_RRE(0xB24F, r1, r2)
+#define N_IC(r1, d2, x2, b2) N_RX(0x43, r1, d2, x2, b2)
+#define N_ICM(r1, m3, d2, b2) N_RS(0xBF, r1, m3, d2, b2)
+#define N_IPM(r1) N_RRE(0xB222, r1, 0)
+#define N_LR(r1, r2) N_RR(0x18, r1, r2)
+#define N_L(r1, d2, x2, b2) N_RX(0x58, r1, d2, x2, b2)
+# define SZ_L SZ_RX
+# define N_L2(r1, d2, b2) \
+ do { N_LHI(r1, d2); N_L(r1, 0, r1, b2); } while (0)
+#define N_LAM(r1, r3, d2, b2) N_RS(0x9A, r1, r3, d2, b2)
+#define N_LA(r1, d2, x2, b2) N_RX(0x41, r1, d2, x2, b2)
+# define N_LA2(r1, d2, b2) \
+ do { N_LHI(r1, d2); N_LA(r1, 0, r1, b2); } while (0)
+#define N_LAE(r1, d2, x2, b2) N_RX(0x51, r1, d2, x2, b2)
+#define N_LTR(r1, r2) N_RR(0x12, r1, r2)
+#define N_LCR(r1, r2) N_RR(0x13, r1, r2)
+#define N_LH(r1, d2, x2, b2) N_RX(0x48, r1, d2, x2, b2)
+#define N_LHI(r1, i2) N_RI(0xA7, 0x8, r1, i2)
+#define N_LM(r1, r3, d2, b2) N_RS(0x98, r1, r3, d2, b2)
+#define N_LNR(r1, r2) N_RR(0x11, r1, r2)
+#define N_LPR(r1, r2) N_RR(0x10, r1, r2)
+#define N_MC(d1, b1, i2) N_SI(0xAF, d1, b1, i2)
+#define N_MVI(d1, b1, i2) N_SI(0x92, d1, b1, i2)
+#define N_MVC(d1, l, b1, d2, b2) N_SS(0xD2, d1, l, b1, d2, b2)
+#define N_MVCIN(d1, l, b1, d2, b2) N_SS(0xEB, d1, l, b1, d2, b2)
+#define N_MVCL(r1, r2) N_RR(0x0E, r1, r2)
+#define N_MVCLE(r1, r3, d2, b2) N_RS(0xAB, r1, r3, d2, b2)
+#define N_MVN(d1, l, b1, d2, b2) N_SS(0xD1, d1, l, b1, d2, b2)
+#define N_MVPG(r1, r2) N_RRE(0xB254, r1, r2)
+#define N_MVST(r1, r2) N_RRE(0xB255, r1, r2)
+#define N_MVO(d1, l1, b1, d2, l2, b2) N_SS2(0xF1, d1, l1, b1, d2, l2, b2)
+#define N_MVZ(d1, l, b1, d2, b2) N_SS(0xD3, d1, l, b1, d2, b2)
+#define N_MR(r1, r2) N_RR(0x1C, r1, r2)
+#define N_M(r1, d2, x2, b2) N_RX(0x5C, r1, d2, x2, b2)
+#define N_MH(r1, d2, x2, b2) N_RX(0x4C, r1, d2, x2, b2)
+#define N_MHI(r1, i2) N_RI(0xA7, 0xC, r1, i2)
+#define N_MSR(r1, r2) N_RRE(0xB252, r1, r2)
+#define N_MS(r1, d2, x2, b2) N_RX(0x71, r1, d2, x2, b2)
+#define N_OR(r1, r2) N_RR(0x16, r1, r2)
+#define N_O(r1, d2, x2, b2) N_RX(0x56, r1, d2, x2, b2)
+#define N_OI(d1, b1, i2) N_SI(0x96, d1, b1, i2)
+#define N_OC(d1, l, b1, d2, b2) N_SS(0xD6, d1, l, b1, d2, b2)
+#define N_PACK(d1, l1, b1, d2, l2, b2) N_SS2(0xF2, d1, l1, b1, d2, l2, b2)
+#define N_PLO(r1, d2, b2, r3, d4, b4) N_SS2(0xEE, d2, r1, b2, d4, r3, b4)
+#define N_SRST(r1, r2) N_RRE(0xB25E, r1, r2)
+#define N_SAR(r1, r2) N_RRE(0xB24E, r1, r2)
+#define N_SPM(r1) N_RR(0x04, r1, 0x00)
+#define N_SLDA(r1, d2, b2) N_RS(0x8F, r1, 0x00, d2, b2)
+#define N_SLDL(r1, d2, b2) N_RS(0x8D, r1, 0x00, d2, b2)
+#define N_SLA(r1, d2, b2) N_RS(0x8B, r1, 0x00, d2, b2)
+#define N_SLL(r1, d2, b2) N_RS(0x89, r1, 0x00, d2, b2)
+#define N_SRDA(r1, d2, b2) N_RS(0x8E, r1, 0x00, d2, b2)
+#define N_SRDL(r1, d2, b2) N_RS(0x8C, r1, 0x00, d2, b2)
+#define N_SRA(r1, d2, b2) N_RS(0x8A, r1, 0x00, d2, b2)
+#define N_SRL(r1, d2, b2) N_RS(0x88, r1, 0x00, d2, b2)
+#define N_ST(r1, d2, x2, b2) N_RX(0x50, r1, d2, x2, b2)
+#define N_STAM(r1, r3, d2, b2) N_RS(0x9B, r1, r3, d2, b2)
+#define N_STC(r1, d2, x2, b2) N_RX(0x42, r1, d2, x2, b2)
+#define N_STCM(r1, m3, d2, b2) N_RS(0xBE, r1, m3, d2, b2)
+#define N_STCK(d2, b2) N_S2(0xB205, d2, b2)
+#define N_STCKE(d2, b2) N_S2(0xB278, d2, b2)
+#define N_STH(r1, d2, x2, b2) N_RX(0x40, r1, d2, x2, b2)
+#define N_STM(r1, r3, d2, b2) N_RS(0x90, r1, r3, d2, b2)
+#define N_SR(r1, r2) N_RR(0x1B, r1, r2)
+#define N_S(r1, d2, x2, b2) N_RX(0x5B, r1, d2, x2, b2)
+#define N_SH(r1, d2, x2, b2) N_RX(0x4B, r1, d2, x2, b2)
+#define N_SLR(r1, r2) N_RR(0x1F, r1, r2)
+#define N_SL(r1, d2, x2, b2) N_RX(0x5F, r1, d2, x2, b2)
+#define N_SVC(i) N_RR2(0x0A, i)
+#define N_TS(d2, b2) N_S2(0x93, d2, b2)
+#define N_TM(d1, b1, i2) N_SI(0x91, d1, b1, i2)
+#define N_TMH(r1, i2) N_RI(0xA7, 0x00, r1, i2)
+#define N_TML(r1, i2) N_RI(0xA7, 0x01, r1, i2)
+#define N_TR(d1, l, b1, d2, b2) N_SS(0xDC, d1, l, b1, d2, b2)
+#define N_TRT(d1, l, b1, d2, b2) N_SS(0xDD, d1, l, b1, d2, b2)
+#define N_TRE(r1, r2) N_RRE(0xB2A5, r1, r2)
+#define N_UNPK(d1, l1, b1, d2, l2, b2) N_SS2(0xF3, d1, l1, b1, d2, l2, b2)
+#define N_UPT() N_E(0x0102)
+
+/* Chapter 9. Floating point instructions */
+
+#define N_LER(r1, r2) N_RR(0x38, r1, r2)
+#define N_LDR(r1, r2) N_RR(0x28, r1, r2)
+#define N_LXR(r1, r2) N_RRE(0xB365, r1, r2)
+#define N_LE(r1, d2, x2, b2) N_RX(0x78, r1, d2, x2, b2)
+#define N_LD(r1, d2, x2, b2) N_RX(0x68, r1, d2, x2, b2)
+#define N_LZER(r1) N_RRE(0xB374, r1, 0x0)
+#define N_LZDR(r1) N_RRE(0xB375, r1, 0x0)
+#define N_LZXR(r1) N_RRE(0xB376, r1, 0x0)
+#define N_STE(r1, d2, x2, b2) N_RX(0x70, r1, d2, x2, b2)
+#define N_STD(r1, d2, x2, b2) N_RX(0x60, r1, d2, x2, b2)
+
+/* chapter 19. Binary floating point instructions */
+
+/* Alpha like instructions */
+
+#define M_CALL(r2) N_BASR(R14, r2)
+
+#define M_ALD(r, b, d) _IFNEG(d, N_L2(r, d, b), N_L(r, d, 0, b))
+#define M_ILD(r, b, d) _IFNEG(d, N_LA2(r, d, b), N_LA(r, d, 0, b))
+#define M_FLD(r, b, d) _IFNEG(d, assert(0), N_LE(r, d, 0, b))
+#define M_DLD(r, b, d) _IFNEG(d, assert(0), N_LD(r, d, 0, b))
+/* TODO 3 instead of 4 instrs for d < 0 ! */
+#define M_LLD(r, b, d) \
+ do { M_ILD(GET_HIGH_REG(r), b, d); M_ILD(GET_LOW_REG(r), b, d + 4); } while(0)
+
+/* ----------------------------------------------- */
+
+#define M_MOV(a,b) emit_mov_reg_reg(cd, (a), (b))
+#define M_MOV_IMM(a,b) emit_mov_imm_reg(cd, (u8) (a), (b))
+
+#define M_IMOV(a,b) emit_movl_reg_reg(cd, (a), (b))
+#define M_IMOV_IMM(a,b) emit_movl_imm_reg(cd, (u4) (a), (b))
+
+#define M_FMOV(a,b) emit_movq_reg_reg(cd, (a), (b))
+
+#define M__ILD(a,b,disp) emit_movl_membase_reg(cd, (b), (disp), (a))
+#define M__LLD(a,b,disp) emit_mov_membase_reg(cd, (b), (disp), (a))
+
+#define M_ILD32(a,b,disp) emit_movl_membase32_reg(cd, (b), (disp), (a))
+#define M_LLD32(a,b,disp) emit_mov_membase32_reg(cd, (b), (disp), (a))
+
+#define M_IST(a,b,disp) emit_movl_reg_membase(cd, (a), (b), (disp))
+#define M_LST(a,b,disp) emit_mov_reg_membase(cd, (a), (b), (disp))
+
+#define M_IST_IMM(a,b,disp) emit_movl_imm_membase(cd, (a), (b), (disp))
+#define M_LST_IMM32(a,b,disp) emit_mov_imm_membase(cd, (a), (b), (disp))
+
+#define M_IST32(a,b,disp) emit_movl_reg_membase32(cd, (a), (b), (disp))
+#define M_LST32(a,b,disp) emit_mov_reg_membase32(cd, (a), (b), (disp))
+
+#define M_IST32_IMM(a,b,disp) emit_movl_imm_membase32(cd, (a), (b), (disp))
+#define M_LST32_IMM32(a,b,disp) emit_mov_imm_membase32(cd, (a), (b), (disp))
+
+#define M_IADD(a,b) emit_alul_reg_reg(cd, ALU_ADD, (a), (b))
+#define M_ISUB(a,b) emit_alul_reg_reg(cd, ALU_SUB, (a), (b))
+#define M_IMUL(a,b) emit_imull_reg_reg(cd, (a), (b))
+
+#define M_IADD_IMM(a,b) emit_alul_imm_reg(cd, ALU_ADD, (a), (b))
+#define M_ISUB_IMM(a,b) emit_alul_imm_reg(cd, ALU_SUB, (a), (b))
+#define M_IMUL_IMM(a,b,c) emit_imull_imm_reg_reg(cd, (b), (a), (c))
+
+#define M_LADD(a,b) emit_alu_reg_reg(cd, ALU_ADD, (a), (b))
+#define M_LSUB(a,b) emit_alu_reg_reg(cd, ALU_SUB, (a), (b))
+#define M_LMUL(a,b) emit_imul_reg_reg(cd, (a), (b))
+
+#define M_LADD_IMM(a,b) emit_alu_imm_reg(cd, ALU_ADD, (a), (b))
+#define M_LSUB_IMM(a,b) emit_alu_imm_reg(cd, ALU_SUB, (a), (b))
+#define M_LMUL_IMM(a,b,c) emit_imul_imm_reg_reg(cd, (b), (a), (c))
+
+#define M_IINC(a) emit_incl_reg(cd, (a))
+#define M_IDEC(a) emit_decl_reg(cd, (a))
+
+#define M__ALD(a,b,disp) M_LLD(a,b,disp)
+#define M_ALD32(a,b,disp) M_LLD32(a,b,disp)
+
+#define M_AST(a,b,c) M_LST(a,b,c)
+#define M_AST_IMM32(a,b,c) M_LST_IMM32(a,b,c)
+
+#define M_AADD(a,b) M_LADD(a,b)
+#define M_AADD_IMM(a,b) M_LADD_IMM(a,b)
+#define M_ASUB_IMM(a,b) M_LSUB_IMM(a,b)
+
+#define M_LADD_IMM32(a,b) emit_alu_imm32_reg(cd, ALU_ADD, (a), (b))
+#define M_AADD_IMM32(a,b) M_LADD_IMM32(a,b)
+#define M_LSUB_IMM32(a,b) emit_alu_imm32_reg(cd, ALU_SUB, (a), (b))
+
+#define M_ILEA(a,b,c) emit_leal_membase_reg(cd, (a), (b), (c))
+#define M_LLEA(a,b,c) emit_lea_membase_reg(cd, (a), (b), (c))
+#define M_ALEA(a,b,c) M_LLEA(a,b,c)
+
+#define M_INEG(a) emit_negl_reg(cd, (a))
+#define M_LNEG(a) emit_neg_reg(cd, (a))
+
+#define M_IAND(a,b) emit_alul_reg_reg(cd, ALU_AND, (a), (b))
+#define M_IOR(a,b) emit_alul_reg_reg(cd, ALU_OR, (a), (b))
+#define M_IXOR(a,b) emit_alul_reg_reg(cd, ALU_XOR, (a), (b))
+
+#define M_IAND_IMM(a,b) emit_alul_imm_reg(cd, ALU_AND, (a), (b))
+#define M_IOR_IMM(a,b) emit_alul_imm_reg(cd, ALU_OR, (a), (b))
+#define M_IXOR_IMM(a,b) emit_alul_imm_reg(cd, ALU_XOR, (a), (b))
+
+#define M_LAND(a,b) emit_alu_reg_reg(cd, ALU_AND, (a), (b))
+#define M_LOR(a,b) emit_alu_reg_reg(cd, ALU_OR, (a), (b))
+#define M_LXOR(a,b) emit_alu_reg_reg(cd, ALU_XOR, (a), (b))
+
+#define M_LAND_IMM(a,b) emit_alu_imm_reg(cd, ALU_AND, (a), (b))
+#define M_LOR_IMM(a,b) emit_alu_imm_reg(cd, ALU_OR, (a), (b))
+#define M_LXOR_IMM(a,b) emit_alu_imm_reg(cd, ALU_XOR, (a), (b))
+
+#define M_BSEXT(a,b) emit_movsbq_reg_reg(cd, (a), (b))
+#define M_SSEXT(a,b) emit_movswq_reg_reg(cd, (a), (b))
+#define M_ISEXT(a,b) emit_movslq_reg_reg(cd, (a), (b))
+
+#define M_CZEXT(a,b) emit_movzwq_reg_reg(cd, (a), (b))
+
+#define M_ISLL_IMM(a,b) emit_shiftl_imm_reg(cd, SHIFT_SHL, (a), (b))
+#define M_ISRA_IMM(a,b) emit_shiftl_imm_reg(cd, SHIFT_SAR, (a), (b))
+#define M_ISRL_IMM(a,b) emit_shiftl_imm_reg(cd, SHIFT_SHR, (a), (b))
+
+#define M_LSLL_IMM(a,b) emit_shift_imm_reg(cd, SHIFT_SHL, (a), (b))
+#define M_LSRA_IMM(a,b) emit_shift_imm_reg(cd, SHIFT_SAR, (a), (b))
+#define M_LSRL_IMM(a,b) emit_shift_imm_reg(cd, SHIFT_SHR, (a), (b))
+
+#define M_TEST(a) emit_test_reg_reg(cd, (a), (a))
+#define M_ITEST(a) emit_testl_reg_reg(cd, (a), (a))
+
+#define M_LCMP(a,b) emit_alu_reg_reg(cd, ALU_CMP, (a), (b))
+#define M_LCMP_IMM(a,b) emit_alu_imm_reg(cd, ALU_CMP, (a), (b))
+#define M_LCMP_IMM_MEMBASE(a,b,c) emit_alu_imm_membase(cd, ALU_CMP, (a), (b), (c))
+#define M_LCMP_MEMBASE(a,b,c) emit_alu_membase_reg(cd, ALU_CMP, (a), (b), (c))
+
+#define M_ICMP(a,b) emit_alul_reg_reg(cd, ALU_CMP, (a), (b))
+#define M_ICMP_IMM(a,b) emit_alul_imm_reg(cd, ALU_CMP, (a), (b))
+#define M_ICMP_IMM_MEMBASE(a,b,c) emit_alul_imm_membase(cd, ALU_CMP, (a), (b), (c))
+#define M_ICMP_MEMBASE(a,b,c) emit_alul_membase_reg(cd, ALU_CMP, (a), (b), (c))
+
+#define M_BEQ(disp) emit_jcc(cd, CC_E, (disp))
+#define M_BNE(disp) emit_jcc(cd, CC_NE, (disp))
+#define M_BLT(disp) emit_jcc(cd, CC_L, (disp))
+#define M_BLE(disp) emit_jcc(cd, CC_LE, (disp))
+#define M_BGE(disp) emit_jcc(cd, CC_GE, (disp))
+#define M_BGT(disp) emit_jcc(cd, CC_G, (disp))
+#define M_BAE(disp) emit_jcc(cd, CC_AE, (disp))
+#define M_BA(disp) emit_jcc(cd, CC_A, (disp))
+
+#define M_CMOVEQ(a,b) emit_cmovcc_reg_reg(cd, CC_E, (a), (b))
+#define M_CMOVNE(a,b) emit_cmovcc_reg_reg(cd, CC_NE, (a), (b))
+#define M_CMOVLT(a,b) emit_cmovcc_reg_reg(cd, CC_L, (a), (b))
+#define M_CMOVLE(a,b) emit_cmovcc_reg_reg(cd, CC_LE, (a), (b))
+#define M_CMOVGE(a,b) emit_cmovcc_reg_reg(cd, CC_GE, (a), (b))
+#define M_CMOVGT(a,b) emit_cmovcc_reg_reg(cd, CC_G, (a), (b))
+
+#define M_CMOVEQ_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_E, (a), (b))
+#define M_CMOVNE_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_NE, (a), (b))
+#define M_CMOVLT_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_L, (a), (b))
+#define M_CMOVLE_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_LE, (a), (b))
+#define M_CMOVGE_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_GE, (a), (b))
+#define M_CMOVGT_MEMBASE(a,b,c) emit_cmovcc_reg_membase(cd, CC_G, (a), (b))
+
+#define M_CMOVB(a,b) emit_cmovcc_reg_reg(cd, CC_B, (a), (b))
+#define M_CMOVA(a,b) emit_cmovcc_reg_reg(cd, CC_A, (a), (b))
+#define M_CMOVP(a,b) emit_cmovcc_reg_reg(cd, CC_P, (a), (b))
+
+#define M_PUSH(a) emit_push_reg(cd, (a))
+#define M_PUSH_IMM(a) emit_push_imm(cd, (a))
+#define M_POP(a) emit_pop_reg(cd, (a))
+
+#define M_JMP(a) emit_jmp_reg(cd, (a))
+#define M_JMP_IMM(a) emit_jmp_imm(cd, (a))
+#define M__CALL(a) emit_call_reg(cd, (a))
+#define M_CALL_IMM(a) emit_call_imm(cd, (a))
+#define M_RET emit_ret(cd)
+
+#define M_NOP emit_nop(cd)
+
+#define M_CLR(a) M_LXOR(a,a)
+
+
+#define M__FLD(a,b,disp) emit_movss_membase_reg(cd, (b), (disp), (a))
+#define M__DLD(a,b,disp) emit_movsd_membase_reg(cd, (b), (disp), (a))
+
+#define M_FLD32(a,b,disp) emit_movss_membase32_reg(cd, (b), (disp), (a))
+#define M_DLD32(a,b,disp) emit_movsd_membase32_reg(cd, (b), (disp), (a))
+
+#define M_FST(a,b,disp) emit_movss_reg_membase(cd, (a), (b), (disp))
+#define M_DST(a,b,disp) emit_movsd_reg_membase(cd, (a), (b), (disp))
+
+#define M_FST32(a,b,disp) emit_movss_reg_membase32(cd, (a), (b), (disp))
+#define M_DST32(a,b,disp) emit_movsd_reg_membase32(cd, (a), (b), (disp))
+
+#define M_FADD(a,b) emit_addss_reg_reg(cd, (a), (b))
+#define M_DADD(a,b) emit_addsd_reg_reg(cd, (a), (b))
+#define M_FSUB(a,b) emit_subss_reg_reg(cd, (a), (b))
+#define M_DSUB(a,b) emit_subsd_reg_reg(cd, (a), (b))
+#define M_FMUL(a,b) emit_mulss_reg_reg(cd, (a), (b))
+#define M_DMUL(a,b) emit_mulsd_reg_reg(cd, (a), (b))
+#define M_FDIV(a,b) emit_divss_reg_reg(cd, (a), (b))
+#define M_DDIV(a,b) emit_divsd_reg_reg(cd, (a), (b))
+
+#define M_CVTIF(a,b) emit_cvtsi2ss_reg_reg(cd, (a), (b))
+#define M_CVTID(a,b) emit_cvtsi2sd_reg_reg(cd, (a), (b))
+#define M_CVTLF(a,b) emit_cvtsi2ssq_reg_reg(cd, (a), (b))
+#define M_CVTLD(a,b) emit_cvtsi2sdq_reg_reg(cd, (a), (b))
+#define M_CVTFI(a,b) emit_cvttss2si_reg_reg(cd, (a), (b))
+#define M_CVTDI(a,b) emit_cvttsd2si_reg_reg(cd, (a), (b))
+#define M_CVTFL(a,b) emit_cvttss2siq_reg_reg(cd, (a), (b))
+#define M_CVTDL(a,b) emit_cvttsd2siq_reg_reg(cd, (a), (b))
+
+#define M_CVTFD(a,b) emit_cvtss2sd_reg_reg(cd, (a), (b))
+#define M_CVTDF(a,b) emit_cvtsd2ss_reg_reg(cd, (a), (b))
+
+
+/* system instructions ********************************************************/
+
+#define M_RDTSC emit_rdtsc(cd)
+
+#define M_IINC_MEMBASE(a,b) emit_incl_membase(cd, (a), (b))
+
+#define M_IADD_MEMBASE(a,b,c) emit_alul_reg_membase(cd, ALU_ADD, (a), (b), (c))
+#define M_IADC_MEMBASE(a,b,c) emit_alul_reg_membase(cd, ALU_ADC, (a), (b), (c))
+#define M_ISUB_MEMBASE(a,b,c) emit_alul_reg_membase(cd, ALU_SUB, (a), (b), (c))
+#define M_ISBB_MEMBASE(a,b,c) emit_alul_reg_membase(cd, ALU_SBB, (a), (b), (c))
+
+#define PROFILE_CYCLE_START
+#define __PROFILE_CYCLE_START \
+ do { \
+ if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { \
+ M_PUSH(RAX); \
+ M_PUSH(RDX); \
+ \
+ M_MOV_IMM(code, REG_ITMP3); \
+ M_RDTSC; \
+ M_ISUB_MEMBASE(RAX, REG_ITMP3, OFFSET(codeinfo, cycles)); \
+ M_ISBB_MEMBASE(RDX, REG_ITMP3, OFFSET(codeinfo, cycles) + 4); \
+ \
+ M_POP(RDX); \
+ M_POP(RAX); \
+ } \
+ } while (0)
+
+#define PROFILE_CYCLE_STOP
+#define __PROFILE_CYCLE_STOP \
+ do { \
+ if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { \
+ M_PUSH(RAX); \
+ M_PUSH(RDX); \
+ \
+ M_MOV_IMM(code, REG_ITMP3); \
+ M_RDTSC; \
+ M_IADD_MEMBASE(RAX, REG_ITMP3, OFFSET(codeinfo, cycles)); \
+ M_IADC_MEMBASE(RDX, REG_ITMP3, OFFSET(codeinfo, cycles) + 4); \
+ \
+ M_POP(RDX); \
+ M_POP(RAX); \
+ } \
+ } while (0)
+
+
+/* function gen_resolvebranch **************************************************
+
+ backpatches a branch instruction
+
+ parameters: ip ... pointer to instruction after branch (void*)
+ so ... offset of instruction after branch (s8)
+ to ... offset of branch target (s8)
+
+*******************************************************************************/
+
+#define gen_resolvebranch(ip,so,to) \
+ *((s4*) ((ip) - 4)) = (s4) ((to) - (so));
+
+#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:
+ */
--- /dev/null
+/* src/vm/jit/x86_64/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: Andreas Krall
+ Reinhard Grafl
+
+ Changes: Christian Thalinger
+
+ $Id: disass.c 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+
+#include "config.h"
+
+#include <dis-asm.h>
+#include <stdio.h>
+
+#include "vm/types.h"
+
+#include "vm/global.h"
+#include "vm/jit/disass.h"
+
+
+/* global variables ***********************************************************/
+
+/* name table for 16 integer registers */
+
+char *regs[] = {
+ "r0",
+ "r1",
+ "r2",
+ "r3",
+ "r4",
+ "r5",
+ "r6",
+ "r7",
+ "r8",
+ "r9",
+ "r10",
+ "r11",
+ "r12",
+ "r13",
+ "r14",
+ "r15"
+};
+
+
+/* disassinstr *****************************************************************
+
+ Outputs a disassembler listing of one machine code instruction on
+ `stdout'.
+
+ code: pointer to machine code
+
+*******************************************************************************/
+
+u1 *disassinstr(u1 *code)
+{
+ s4 seqlen;
+ s4 i;
+
+ if (!disass_initialized) {
+ INIT_DISASSEMBLE_INFO(info, NULL, disass_printf);
+
+ /* setting the struct members must be done after
+ INIT_DISASSEMBLE_INFO */
+
+ info.mach = bfd_mach_s390_31;
+ info.read_memory_func = &disass_buffer_read_memory;
+
+ disass_initialized = true;
+ }
+
+ printf("0x%08x: ", (s4) code);
+
+ disass_len = 0;
+
+ seqlen = print_insn_s390((bfd_vma) code, &info);
+
+ for (i = 0; i < seqlen; i++, code++) {
+ printf("%02x ", *code);
+ }
+
+ for (; i < 10; i++) {
+ printf(" ");
+ }
+
+ printf(" %s\n", disass_buf);
+
+ return code;
+}
+
+
+/*
+ * 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/x86_64/emit.c - x86_64 code emitter 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: Christian Thalinger
+
+ $Id: emit.c 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+#include "config.h"
+
+#include "vm/types.h"
+
+#include "md-abi.h"
+
+#include "vm/jit/s390/codegen.h"
+#include "vm/jit/s390/emit.h"
+
+#if defined(ENABLE_THREADS)
+# include "threads/native/lock.h"
+#endif
+
+#include "vm/builtin.h"
+#include "vm/jit/abi-asm.h"
+#include "vm/jit/asmpart.h"
+#include "vm/jit/codegen-common.h"
+#include "vm/jit/emit-common.h"
+#include "vm/jit/jit.h"
+#include "vm/jit/replace.h"
+
+#define __PORTED__
+
+/* emit_load *******************************************************************
+
+ Emits a possible load of an operand.
+
+*******************************************************************************/
+
+__PORTED__ 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 (IS_INMEMORY(src->flags)) {
+ COUNT_SPILLS;
+
+ disp = src->vv.regoff * 4;
+
+ if (IS_FLT_DBL_TYPE(src->type)) {
+ if (IS_2_WORD_TYPE(src->type))
+ M_DLD(tempreg, REG_SP, disp);
+ else
+ M_FLD(tempreg, REG_SP, disp);
+ }
+ 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_store ******************************************************************
+
+ 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.
+
+*******************************************************************************/
+
+inline void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
+{
+ codegendata *cd;
+ s4 disp;
+#if 0
+ s4 s;
+ u2 opcode;
+#endif
+
+ /* get required compiler data */
+
+ cd = jd->cd;
+
+#if 0
+ /* do we have to generate a conditional move? */
+
+ if ((iptr != NULL) && (iptr->opc & ICMD_CONDITION_MASK)) {
+ /* the passed register d is actually the source register */
+
+ s = d;
+
+ /* Only pass the opcode to codegen_reg_of_var to get the real
+ destination register. */
+
+ opcode = iptr->opc & ICMD_OPCODE_MASK;
+
+ /* get the real destination register */
+
+ d = codegen_reg_of_var(rd, opcode, dst, REG_ITMP1);
+
+ /* and emit the conditional move */
+
+ emit_cmovxx(cd, iptr, s, d);
+ }
+#endif
+
+ if (IS_INMEMORY(dst->flags)) {
+ COUNT_SPILLS;
+
+ disp = dst->vv.regoff * 8;
+
+ 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
+ M_LST(d, REG_SP, disp);
+ }
+}
+
+
+/* emit_copy *******************************************************************
+
+ Generates a register/memory to register/memory copy.
+
+*******************************************************************************/
+
+void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
+{
+ codegendata *cd;
+ s4 s1, d;
+
+ /* get required compiler data */
+
+ cd = jd->cd;
+
+ 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)) {
+ d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
+ s1 = emit_load(jd, iptr, src, d);
+ }
+ else {
+ s1 = emit_load(jd, iptr, src, REG_IFTMP);
+ d = codegen_reg_of_var(iptr->opc, dst, s1);
+ }
+
+ if (s1 != d) {
+ if (IS_FLT_DBL_TYPE(src->type))
+ M_FMOV(s1, d);
+ else
+ M_MOV(s1, d);
+ }
+
+ emit_store(jd, iptr, dst, d);
+ }
+}
+
+
+void emit_cmovxx(codegendata *cd, instruction *iptr, s4 s, s4 d)
+{
+#if 0
+ switch (iptr->flags.fields.condition) {
+ case ICMD_IFEQ:
+ M_CMOVEQ(s, d);
+ break;
+ case ICMD_IFNE:
+ M_CMOVNE(s, d);
+ break;
+ case ICMD_IFLT:
+ M_CMOVLT(s, d);
+ break;
+ case ICMD_IFGE:
+ M_CMOVGE(s, d);
+ break;
+ case ICMD_IFGT:
+ M_CMOVGT(s, d);
+ break;
+ case ICMD_IFLE:
+ M_CMOVLE(s, d);
+ break;
+ }
+#endif
+}
+
+
+/* emit_exception_stubs ********************************************************
+
+ Generates the code for the exception stubs.
+
+*******************************************************************************/
+
+void emit_exception_stubs(jitdata *jd)
+{
+ codegendata *cd;
+ registerdata *rd;
+ exceptionref *er;
+ s4 branchmpc;
+ s4 targetmpc;
+ s4 targetdisp;
+
+ /* get required compiler data */
+
+ cd = jd->cd;
+ rd = jd->rd;
+
+ /* generate exception stubs */
+
+ targetdisp = 0;
+
+ for (er = cd->exceptionrefs; er != NULL; er = er->next) {
+ /* back-patch the branch to this exception code */
+
+ branchmpc = er->branchpos;
+ targetmpc = cd->mcodeptr - cd->mcodebase;
+
+ md_codegen_patch_branch(cd, branchmpc, targetmpc);
+
+ MCODECHECK(512);
+
+ /* Check if the exception is an
+ ArrayIndexOutOfBoundsException. If so, move index register
+ into a4. */
+
+ if (er->reg != -1)
+ M_MOV(er->reg, rd->argintregs[4]);
+
+ /* calcuate exception address */
+
+ M_MOV_IMM(0, rd->argintregs[3]);
+ dseg_adddata(cd);
+ M_AADD_IMM32(er->branchpos - 6, rd->argintregs[3]);
+
+ /* move function to call into REG_ITMP3 */
+
+ M_MOV_IMM(er->function, REG_ITMP3);
+
+ if (targetdisp == 0) {
+ targetdisp = cd->mcodeptr - cd->mcodebase;
+
+ emit_lea_membase_reg(cd, RIP, -((cd->mcodeptr + 7) - cd->mcodebase), rd->argintregs[0]);
+ M_MOV(REG_SP, rd->argintregs[1]);
+ M_ALD(rd->argintregs[2], REG_SP, cd->stackframesize * 8);
+
+ M_ASUB_IMM(2 * 8, REG_SP);
+ M_AST(rd->argintregs[3], REG_SP, 0 * 8); /* store XPC */
+
+ M_CALL(REG_ITMP3);
+
+ M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8);
+ M_AADD_IMM(2 * 8, REG_SP);
+
+ M_MOV_IMM(asm_handle_exception, REG_ITMP3);
+ M_JMP(REG_ITMP3);
+ }
+ else {
+ M_JMP_IMM((cd->mcodebase + targetdisp) -
+ (cd->mcodeptr + PATCHER_CALL_SIZE));
+ }
+ }
+}
+
+
+/* emit_patcher_stubs **********************************************************
+
+ Generates the code for the patcher stubs.
+
+*******************************************************************************/
+
+void emit_patcher_stubs(jitdata *jd)
+{
+ codegendata *cd;
+ patchref *pref;
+ u8 mcode;
+ u1 *savedmcodeptr;
+ u1 *tmpmcodeptr;
+ s4 targetdisp;
+ s4 disp;
+
+ /* get required compiler data */
+
+ cd = jd->cd;
+
+ /* generate code patching stub call code */
+
+ targetdisp = 0;
+
+ for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
+ /* check size of code segment */
+
+ MCODECHECK(512);
+
+ /* Get machine code which is patched back in later. A
+ `call rel32' is 5 bytes long (but read 8 bytes). */
+
+ savedmcodeptr = cd->mcodebase + pref->branchpos;
+ mcode = *((u8 *) savedmcodeptr);
+
+ /* patch in `call rel32' to call the following code */
+
+ tmpmcodeptr = cd->mcodeptr; /* save current mcodeptr */
+ cd->mcodeptr = savedmcodeptr; /* set mcodeptr to patch position */
+
+ M_CALL_IMM(tmpmcodeptr - (savedmcodeptr + PATCHER_CALL_SIZE));
+
+ cd->mcodeptr = tmpmcodeptr; /* restore the current mcodeptr */
+
+ /* move pointer to java_objectheader onto stack */
+
+#if defined(ENABLE_THREADS)
+ /* create a virtual java_objectheader */
+
+ (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 */
+
+ emit_lea_membase_reg(cd, RIP, -((cd->mcodeptr + 7) - cd->mcodebase) + disp, REG_ITMP3);
+ M_PUSH(REG_ITMP3);
+#else
+ M_PUSH_IMM(0);
+#endif
+
+ /* move machine code bytes and classinfo pointer into registers */
+
+ M_MOV_IMM(mcode, REG_ITMP3);
+ M_PUSH(REG_ITMP3);
+
+ M_MOV_IMM(pref->ref, REG_ITMP3);
+ M_PUSH(REG_ITMP3);
+
+ M_MOV_IMM(pref->disp, REG_ITMP3);
+ M_PUSH(REG_ITMP3);
+
+ M_MOV_IMM(pref->patcher, REG_ITMP3);
+ M_PUSH(REG_ITMP3);
+
+ if (targetdisp == 0) {
+ targetdisp = cd->mcodeptr - cd->mcodebase;
+
+ M_MOV_IMM(asm_patcher_wrapper, REG_ITMP3);
+ M_JMP(REG_ITMP3);
+ }
+ else {
+ M_JMP_IMM((cd->mcodebase + targetdisp) -
+ (cd->mcodeptr + PATCHER_CALL_SIZE));
+ }
+ }
+}
+
+
+/* emit_replacement_stubs ******************************************************
+
+ Generates the code for the replacement stubs.
+
+*******************************************************************************/
+
+void emit_replacement_stubs(jitdata *jd)
+{
+ codegendata *cd;
+ codeinfo *code;
+ rplpoint *rplp;
+ s4 disp;
+ s4 i;
+
+ /* get required compiler data */
+
+ cd = jd->cd;
+ code = jd->code;
+
+ rplp = code->rplpoints;
+
+ for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
+ /* check code segment size */
+
+ MCODECHECK(512);
+
+ /* note start of stub code */
+
+ rplp->outcode = (u1 *) (ptrint) (cd->mcodeptr - cd->mcodebase);
+
+ /* make machine code for patching */
+
+ disp = (ptrint) (rplp->outcode - rplp->pc) - 5;
+
+ rplp->mcode = 0xe9 | ((u8) disp << 8);
+
+ /* push address of `rplpoint` struct */
+
+ M_MOV_IMM(rplp, REG_ITMP3);
+ M_PUSH(REG_ITMP3);
+
+ /* jump to replacement function */
+
+ M_MOV_IMM(asm_replacement_out, REG_ITMP3);
+ M_JMP(REG_ITMP3);
+ }
+}
+
+
+/* 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 i, j, k;
+
+ /* get required compiler data */
+
+ m = jd->m;
+ cd = jd->cd;
+ rd = jd->rd;
+
+ md = m->parseddesc;
+
+ /* mark trace code */
+
+ M_NOP;
+
+ /* additional +1 is for 16-byte stack alignment */
+
+ M_LSUB_IMM((ARG_CNT + TMP_CNT + 1 + 1) * 8, REG_SP);
+
+ /* save argument registers */
+
+ for (i = 0; i < INT_ARG_CNT; i++)
+ M_LST(rd->argintregs[i], REG_SP, (1 + i) * 8);
+
+ for (i = 0; i < FLT_ARG_CNT; i++)
+ M_DST(rd->argfltregs[i], REG_SP, (1 + INT_ARG_CNT + i) * 8);
+
+ /* save temporary registers for leaf methods */
+
+ if (jd->isleafmethod) {
+ for (i = 0; i < INT_TMP_CNT; i++)
+ M_LST(rd->tmpintregs[i], REG_SP, (1 + ARG_CNT + i) * 8);
+
+ for (i = 0; i < FLT_TMP_CNT; i++)
+ M_DST(rd->tmpfltregs[i], REG_SP, (1 + ARG_CNT + INT_TMP_CNT + i) * 8);
+ }
+
+ /* show integer hex code for float arguments */
+
+ for (i = 0, j = 0; i < md->paramcount && i < INT_ARG_CNT; i++) {
+ /* If the paramtype is a float, we have to right shift all
+ following integer registers. */
+
+ if (IS_FLT_DBL_TYPE(md->paramtypes[i].type)) {
+ for (k = INT_ARG_CNT - 2; k >= i; k--)
+ M_MOV(rd->argintregs[k], rd->argintregs[k + 1]);
+
+ emit_movd_freg_reg(cd, rd->argfltregs[j], rd->argintregs[i]);
+ j++;
+ }
+ }
+
+ M_MOV_IMM(m, REG_ITMP2);
+ M_AST(REG_ITMP2, REG_SP, 0 * 8);
+ M_MOV_IMM(builtin_trace_args, REG_ITMP1);
+ M_CALL(REG_ITMP1);
+
+ /* restore argument registers */
+
+ for (i = 0; i < INT_ARG_CNT; i++)
+ M_LLD(rd->argintregs[i], REG_SP, (1 + i) * 8);
+
+ for (i = 0; i < FLT_ARG_CNT; i++)
+ M_DLD(rd->argfltregs[i], REG_SP, (1 + INT_ARG_CNT + i) * 8);
+
+ /* restore temporary registers for leaf methods */
+
+ if (jd->isleafmethod) {
+ for (i = 0; i < INT_TMP_CNT; i++)
+ M_LLD(rd->tmpintregs[i], REG_SP, (1 + ARG_CNT + i) * 8);
+
+ for (i = 0; i < FLT_TMP_CNT; i++)
+ M_DLD(rd->tmpfltregs[i], REG_SP, (1 + ARG_CNT + INT_TMP_CNT + i) * 8);
+ }
+
+ M_LADD_IMM((ARG_CNT + TMP_CNT + 1 + 1) * 8, 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;
+
+ /* get required compiler data */
+
+ m = jd->m;
+ cd = jd->cd;
+ rd = jd->rd;
+
+ /* mark trace code */
+
+ M_NOP;
+
+ M_ASUB_IMM(2 * 8, REG_SP);
+
+ M_LST(REG_RESULT, REG_SP, 0 * 8);
+ M_DST(REG_FRESULT, REG_SP, 1 * 8);
+
+ M_MOV_IMM(m, rd->argintregs[0]);
+ M_MOV(REG_RESULT, rd->argintregs[1]);
+ M_FLTMOVE(REG_FRESULT, rd->argfltregs[0]);
+ M_FLTMOVE(REG_FRESULT, rd->argfltregs[1]);
+
+ M_MOV_IMM(builtin_displaymethodstop, REG_ITMP1);
+ M_CALL(REG_ITMP1);
+
+ M_LLD(REG_RESULT, REG_SP, 0 * 8);
+ M_DLD(REG_FRESULT, REG_SP, 1 * 8);
+
+ M_AADD_IMM(2 * 8, REG_SP);
+
+ /* mark trace code */
+
+ M_NOP;
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* code generation functions **************************************************/
+
+static void emit_membase(codegendata *cd, s4 basereg, s4 disp, s4 dreg)
+{
+ if ((basereg == REG_SP) || (basereg == R12)) {
+ if (disp == 0) {
+ emit_address_byte(0, dreg, REG_SP);
+ emit_address_byte(0, REG_SP, REG_SP);
+
+ } else if (IS_IMM8(disp)) {
+ emit_address_byte(1, dreg, REG_SP);
+ emit_address_byte(0, REG_SP, REG_SP);
+ emit_imm8(disp);
+
+ } else {
+ emit_address_byte(2, dreg, REG_SP);
+ emit_address_byte(0, REG_SP, REG_SP);
+ emit_imm32(disp);
+ }
+
+ } else if ((disp) == 0 && (basereg) != RBP && (basereg) != R13) {
+ emit_address_byte(0,(dreg),(basereg));
+
+ } else if ((basereg) == RIP) {
+ emit_address_byte(0, dreg, RBP);
+ emit_imm32(disp);
+
+ } else {
+ if (IS_IMM8(disp)) {
+ emit_address_byte(1, dreg, basereg);
+ emit_imm8(disp);
+
+ } else {
+ emit_address_byte(2, dreg, basereg);
+ emit_imm32(disp);
+ }
+ }
+}
+
+
+static void emit_membase32(codegendata *cd, s4 basereg, s4 disp, s4 dreg)
+{
+ if ((basereg == REG_SP) || (basereg == R12)) {
+ emit_address_byte(2, dreg, REG_SP);
+ emit_address_byte(0, REG_SP, REG_SP);
+ emit_imm32(disp);
+ }
+ else {
+ emit_address_byte(2, dreg, basereg);
+ emit_imm32(disp);
+ }
+}
+
+
+static void emit_memindex(codegendata *cd, s4 reg, s4 disp, s4 basereg, s4 indexreg, s4 scale)
+{
+ if (basereg == -1) {
+ emit_address_byte(0, reg, 4);
+ emit_address_byte(scale, indexreg, 5);
+ emit_imm32(disp);
+ }
+ else if ((disp == 0) && (basereg != RBP) && (basereg != R13)) {
+ emit_address_byte(0, reg, 4);
+ emit_address_byte(scale, indexreg, basereg);
+ }
+ else if (IS_IMM8(disp)) {
+ emit_address_byte(1, reg, 4);
+ emit_address_byte(scale, indexreg, basereg);
+ emit_imm8(disp);
+ }
+ else {
+ emit_address_byte(2, reg, 4);
+ emit_address_byte(scale, indexreg, basereg);
+ emit_imm32(disp);
+ }
+}
+
+
+void emit_ishift(jitdata *jd, s4 shift_op, instruction *iptr)
+{
+ s4 s1, s2, d, d_old;
+ varinfo *v_s1,*v_s2,*v_dst;
+ codegendata *cd;
+
+ /* get required compiler data */
+
+ cd = jd->cd;
+
+ v_s1 = VAROP(iptr->s1);
+ v_s2 = VAROP(iptr->sx.s23.s2);
+ v_dst = VAROP(iptr->dst);
+
+ s1 = v_s1->vv.regoff;
+ s2 = v_s2->vv.regoff;
+ d = v_dst->vv.regoff;
+
+ M_INTMOVE(RCX, REG_ITMP1); /* save RCX */
+
+ if (IS_INMEMORY(v_dst->flags)) {
+ if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
+ if (s1 == d) {
+ M_ILD(RCX, REG_SP, s2 * 8);
+ emit_shiftl_membase(cd, shift_op, REG_SP, d * 8);
+
+ } else {
+ M_ILD(RCX, REG_SP, s2 * 8);
+ M_ILD(REG_ITMP2, REG_SP, s1 * 8);
+ emit_shiftl_reg(cd, shift_op, REG_ITMP2);
+ M_IST(REG_ITMP2, REG_SP, d * 8);
+ }
+
+ } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) {
+ /* s1 may be equal to RCX */
+ if (s1 == RCX) {
+ if (s2 == d) {
+ M_ILD(REG_ITMP1, REG_SP, s2 * 8);
+ M_IST(s1, REG_SP, d * 8);
+ M_INTMOVE(REG_ITMP1, RCX);
+
+ } else {
+ M_IST(s1, REG_SP, d * 8);
+ M_ILD(RCX, REG_SP, s2 * 8);
+ }
+
+ } else {
+ M_ILD(RCX, REG_SP, s2 * 8);
+ M_IST(s1, REG_SP, d * 8);
+ }
+
+ emit_shiftl_membase(cd, shift_op, REG_SP, d * 8);
+
+ } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
+ if (s1 == d) {
+ M_INTMOVE(s2, RCX);
+ emit_shiftl_membase(cd, shift_op, REG_SP, d * 8);
+
+ } else {
+ M_INTMOVE(s2, RCX);
+ M_ILD(REG_ITMP2, REG_SP, s1 * 8);
+ emit_shiftl_reg(cd, shift_op, REG_ITMP2);
+ M_IST(REG_ITMP2, REG_SP, d * 8);
+ }
+
+ } else {
+ /* s1 may be equal to RCX */
+ M_IST(s1, REG_SP, d * 8);
+ M_INTMOVE(s2, RCX);
+ emit_shiftl_membase(cd, shift_op, REG_SP, d * 8);
+ }
+
+ M_INTMOVE(REG_ITMP1, RCX); /* restore RCX */
+
+ } else {
+ d_old = d;
+ if (d == RCX) {
+ d = REG_ITMP3;
+ }
+
+ if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
+ M_ILD(RCX, REG_SP, s2 * 8);
+ M_ILD(d, REG_SP, s1 * 8);
+ emit_shiftl_reg(cd, shift_op, d);
+
+ } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) {
+ /* s1 may be equal to RCX */
+ M_INTMOVE(s1, d);
+ M_ILD(RCX, REG_SP, s2 * 8);
+ emit_shiftl_reg(cd, shift_op, d);
+
+ } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
+ M_INTMOVE(s2, RCX);
+ M_ILD(d, REG_SP, s1 * 8);
+ emit_shiftl_reg(cd, shift_op, d);
+
+ } else {
+ /* s1 may be equal to RCX */
+ if (s1 == RCX) {
+ if (s2 == d) {
+ /* d cannot be used to backup s1 since this would
+ overwrite s2. */
+ M_INTMOVE(s1, REG_ITMP3);
+ M_INTMOVE(s2, RCX);
+ M_INTMOVE(REG_ITMP3, d);
+
+ } else {
+ M_INTMOVE(s1, d);
+ M_INTMOVE(s2, RCX);
+ }
+
+ } else {
+ /* d may be equal to s2 */
+ M_INTMOVE(s2, RCX);
+ M_INTMOVE(s1, d);
+ }
+ emit_shiftl_reg(cd, shift_op, d);
+ }
+
+ if (d_old == RCX)
+ M_INTMOVE(REG_ITMP3, RCX);
+ else
+ M_INTMOVE(REG_ITMP1, RCX); /* restore RCX */
+ }
+}
+
+
+void emit_lshift(jitdata *jd, s4 shift_op, instruction *iptr)
+{
+ s4 s1, s2, d, d_old;
+ varinfo *v_s1,*v_s2,*v_dst;
+ codegendata *cd;
+
+ /* get required compiler data */
+
+ cd = jd->cd;
+
+ v_s1 = VAROP(iptr->s1);
+ v_s2 = VAROP(iptr->sx.s23.s2);
+ v_dst = VAROP(iptr->dst);
+
+ s1 = v_s1->vv.regoff;
+ s2 = v_s2->vv.regoff;
+ d = v_dst->vv.regoff;
+
+ M_INTMOVE(RCX, REG_ITMP1); /* save RCX */
+
+ if (IS_INMEMORY(v_dst->flags)) {
+ if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
+ if (s1 == d) {
+ M_ILD(RCX, REG_SP, s2 * 8);
+ emit_shift_membase(cd, shift_op, REG_SP, d * 8);
+
+ } else {
+ M_ILD(RCX, REG_SP, s2 * 8);
+ M_LLD(REG_ITMP2, REG_SP, s1 * 8);
+ emit_shift_reg(cd, shift_op, REG_ITMP2);
+ M_LST(REG_ITMP2, REG_SP, d * 8);
+ }
+
+ } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) {
+ /* s1 may be equal to RCX */
+ if (s1 == RCX) {
+ if (s2 == d) {
+ M_ILD(REG_ITMP1, REG_SP, s2 * 8);
+ M_LST(s1, REG_SP, d * 8);
+ M_INTMOVE(REG_ITMP1, RCX);
+
+ } else {
+ M_LST(s1, REG_SP, d * 8);
+ M_ILD(RCX, REG_SP, s2 * 8);
+ }
+
+ } else {
+ M_ILD(RCX, REG_SP, s2 * 8);
+ M_LST(s1, REG_SP, d * 8);
+ }
+
+ emit_shift_membase(cd, shift_op, REG_SP, d * 8);
+
+ } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
+ if (s1 == d) {
+ M_INTMOVE(s2, RCX);
+ emit_shift_membase(cd, shift_op, REG_SP, d * 8);
+
+ } else {
+ M_INTMOVE(s2, RCX);
+ M_LLD(REG_ITMP2, REG_SP, s1 * 8);
+ emit_shift_reg(cd, shift_op, REG_ITMP2);
+ M_LST(REG_ITMP2, REG_SP, d * 8);
+ }
+
+ } else {
+ /* s1 may be equal to RCX */
+ M_LST(s1, REG_SP, d * 8);
+ M_INTMOVE(s2, RCX);
+ emit_shift_membase(cd, shift_op, REG_SP, d * 8);
+ }
+
+ M_INTMOVE(REG_ITMP1, RCX); /* restore RCX */
+
+ } else {
+ d_old = d;
+ if (d == RCX) {
+ d = REG_ITMP3;
+ }
+
+ if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
+ M_ILD(RCX, REG_SP, s2 * 8);
+ M_LLD(d, REG_SP, s1 * 8);
+ emit_shift_reg(cd, shift_op, d);
+
+ } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) {
+ /* s1 may be equal to RCX */
+ M_INTMOVE(s1, d);
+ M_ILD(RCX, REG_SP, s2 * 8);
+ emit_shift_reg(cd, shift_op, d);
+
+ } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
+ M_INTMOVE(s2, RCX);
+ M_LLD(d, REG_SP, s1 * 8);
+ emit_shift_reg(cd, shift_op, d);
+
+ } else {
+ /* s1 may be equal to RCX */
+ if (s1 == RCX) {
+ if (s2 == d) {
+ /* d cannot be used to backup s1 since this would
+ overwrite s2. */
+ M_INTMOVE(s1, REG_ITMP3);
+ M_INTMOVE(s2, RCX);
+ M_INTMOVE(REG_ITMP3, d);
+
+ } else {
+ M_INTMOVE(s1, d);
+ M_INTMOVE(s2, RCX);
+ }
+
+ } else {
+ /* d may be equal to s2 */
+ M_INTMOVE(s2, RCX);
+ M_INTMOVE(s1, d);
+ }
+ emit_shift_reg(cd, shift_op, d);
+ }
+
+ if (d_old == RCX)
+ M_INTMOVE(REG_ITMP3, RCX);
+ else
+ M_INTMOVE(REG_ITMP1, RCX); /* restore RCX */
+ }
+}
+
+
+/* low-level code emitter functions *******************************************/
+
+void emit_mov_reg_reg(codegendata *cd, s8 reg, s8 dreg)
+{
+ emit_rex(1,(reg),0,(dreg));
+ *(cd->mcodeptr++) = 0x89;
+ emit_reg((reg),(dreg));
+}
+
+
+void emit_mov_imm_reg(codegendata *cd, s8 imm, s8 reg)
+{
+ emit_rex(1,0,0,(reg));
+ *(cd->mcodeptr++) = 0xb8 + ((reg) & 0x07);
+ emit_imm64((imm));
+}
+
+
+void emit_movl_reg_reg(codegendata *cd, s8 reg, s8 dreg)
+{
+ emit_rex(0,(reg),0,(dreg));
+ *(cd->mcodeptr++) = 0x89;
+ emit_reg((reg),(dreg));
+}
+
+
+void emit_movl_imm_reg(codegendata *cd, s8 imm, s8 reg) {
+ emit_rex(0,0,0,(reg));
+ *(cd->mcodeptr++) = 0xb8 + ((reg) & 0x07);
+ emit_imm32((imm));
+}
+
+
+void emit_mov_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) {
+ emit_rex(1,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x8b;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+/*
+ * this one is for INVOKEVIRTUAL/INVOKEINTERFACE to have a
+ * constant membase immediate length of 32bit
+ */
+void emit_mov_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) {
+ emit_rex(1,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x8b;
+ emit_membase32(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_movl_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg)
+{
+ emit_rex(0,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x8b;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+/* ATTENTION: Always emit a REX byte, because the instruction size can
+ be smaller when all register indexes are smaller than 7. */
+void emit_movl_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg)
+{
+ emit_byte_rex((reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x8b;
+ emit_membase32(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_mov_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) {
+ emit_rex(1,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x89;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_mov_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp) {
+ emit_rex(1,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x89;
+ emit_membase32(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_movl_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) {
+ emit_rex(0,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x89;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+/* Always emit a REX byte, because the instruction size can be smaller when */
+/* all register indexes are smaller than 7. */
+void emit_movl_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp) {
+ emit_byte_rex((reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x89;
+ emit_membase32(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_mov_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) {
+ emit_rex(1,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x8b;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_movl_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) {
+ emit_rex(0,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x8b;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_mov_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) {
+ emit_rex(1,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x89;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_movl_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) {
+ emit_rex(0,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x89;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_movw_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x89;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_movb_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) {
+ emit_byte_rex((reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x88;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_mov_imm_membase(codegendata *cd, s8 imm, s8 basereg, s8 disp) {
+ emit_rex(1,0,0,(basereg));
+ *(cd->mcodeptr++) = 0xc7;
+ emit_membase(cd, (basereg),(disp),0);
+ emit_imm32((imm));
+}
+
+
+void emit_mov_imm_membase32(codegendata *cd, s8 imm, s8 basereg, s8 disp) {
+ emit_rex(1,0,0,(basereg));
+ *(cd->mcodeptr++) = 0xc7;
+ emit_membase32(cd, (basereg),(disp),0);
+ emit_imm32((imm));
+}
+
+
+void emit_movl_imm_membase(codegendata *cd, s8 imm, s8 basereg, s8 disp) {
+ emit_rex(0,0,0,(basereg));
+ *(cd->mcodeptr++) = 0xc7;
+ emit_membase(cd, (basereg),(disp),0);
+ emit_imm32((imm));
+}
+
+
+/* Always emit a REX byte, because the instruction size can be smaller when */
+/* all register indexes are smaller than 7. */
+void emit_movl_imm_membase32(codegendata *cd, s8 imm, s8 basereg, s8 disp) {
+ emit_byte_rex(0,0,(basereg));
+ *(cd->mcodeptr++) = 0xc7;
+ emit_membase32(cd, (basereg),(disp),0);
+ emit_imm32((imm));
+}
+
+
+void emit_movsbq_reg_reg(codegendata *cd, s8 reg, s8 dreg)
+{
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xbe;
+ /* XXX: why do reg and dreg have to be exchanged */
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_movswq_reg_reg(codegendata *cd, s8 reg, s8 dreg)
+{
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xbf;
+ /* XXX: why do reg and dreg have to be exchanged */
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_movslq_reg_reg(codegendata *cd, s8 reg, s8 dreg)
+{
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x63;
+ /* XXX: why do reg and dreg have to be exchanged */
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_movzwq_reg_reg(codegendata *cd, s8 reg, s8 dreg)
+{
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xb7;
+ /* XXX: why do reg and dreg have to be exchanged */
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_movswq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) {
+ emit_rex(1,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xbf;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_movsbq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) {
+ emit_rex(1,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xbe;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_movzwq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) {
+ emit_rex(1,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xb7;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_mov_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale)
+{
+ emit_rex(1,0,(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0xc7;
+ emit_memindex(cd, 0,(disp),(basereg),(indexreg),(scale));
+ emit_imm32((imm));
+}
+
+
+void emit_movl_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale)
+{
+ emit_rex(0,0,(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0xc7;
+ emit_memindex(cd, 0,(disp),(basereg),(indexreg),(scale));
+ emit_imm32((imm));
+}
+
+
+void emit_movw_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale)
+{
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,0,(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0xc7;
+ emit_memindex(cd, 0,(disp),(basereg),(indexreg),(scale));
+ emit_imm16((imm));
+}
+
+
+void emit_movb_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale)
+{
+ emit_rex(0,0,(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0xc6;
+ emit_memindex(cd, 0,(disp),(basereg),(indexreg),(scale));
+ emit_imm8((imm));
+}
+
+
+/*
+ * alu operations
+ */
+void emit_alu_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg)
+{
+ emit_rex(1,(reg),0,(dreg));
+ *(cd->mcodeptr++) = (((opc)) << 3) + 1;
+ emit_reg((reg),(dreg));
+}
+
+
+void emit_alul_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg)
+{
+ emit_rex(0,(reg),0,(dreg));
+ *(cd->mcodeptr++) = (((opc)) << 3) + 1;
+ emit_reg((reg),(dreg));
+}
+
+
+void emit_alu_reg_membase(codegendata *cd, s8 opc, s8 reg, s8 basereg, s8 disp)
+{
+ emit_rex(1,(reg),0,(basereg));
+ *(cd->mcodeptr++) = (((opc)) << 3) + 1;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_alul_reg_membase(codegendata *cd, s8 opc, s8 reg, s8 basereg, s8 disp)
+{
+ emit_rex(0,(reg),0,(basereg));
+ *(cd->mcodeptr++) = (((opc)) << 3) + 1;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_alu_membase_reg(codegendata *cd, s8 opc, s8 basereg, s8 disp, s8 reg)
+{
+ emit_rex(1,(reg),0,(basereg));
+ *(cd->mcodeptr++) = (((opc)) << 3) + 3;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_alul_membase_reg(codegendata *cd, s8 opc, s8 basereg, s8 disp, s8 reg)
+{
+ emit_rex(0,(reg),0,(basereg));
+ *(cd->mcodeptr++) = (((opc)) << 3) + 3;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_alu_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) {
+ if (IS_IMM8(imm)) {
+ emit_rex(1,0,0,(dreg));
+ *(cd->mcodeptr++) = 0x83;
+ emit_reg((opc),(dreg));
+ emit_imm8((imm));
+ } else {
+ emit_rex(1,0,0,(dreg));
+ *(cd->mcodeptr++) = 0x81;
+ emit_reg((opc),(dreg));
+ emit_imm32((imm));
+ }
+}
+
+
+void emit_alu_imm32_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) {
+ emit_rex(1,0,0,(dreg));
+ *(cd->mcodeptr++) = 0x81;
+ emit_reg((opc),(dreg));
+ emit_imm32((imm));
+}
+
+
+void emit_alul_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) {
+ if (IS_IMM8(imm)) {
+ emit_rex(0,0,0,(dreg));
+ *(cd->mcodeptr++) = 0x83;
+ emit_reg((opc),(dreg));
+ emit_imm8((imm));
+ } else {
+ emit_rex(0,0,0,(dreg));
+ *(cd->mcodeptr++) = 0x81;
+ emit_reg((opc),(dreg));
+ emit_imm32((imm));
+ }
+}
+
+
+void emit_alu_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) {
+ if (IS_IMM8(imm)) {
+ emit_rex(1,(basereg),0,0);
+ *(cd->mcodeptr++) = 0x83;
+ emit_membase(cd, (basereg),(disp),(opc));
+ emit_imm8((imm));
+ } else {
+ emit_rex(1,(basereg),0,0);
+ *(cd->mcodeptr++) = 0x81;
+ emit_membase(cd, (basereg),(disp),(opc));
+ emit_imm32((imm));
+ }
+}
+
+
+void emit_alul_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) {
+ if (IS_IMM8(imm)) {
+ emit_rex(0,(basereg),0,0);
+ *(cd->mcodeptr++) = 0x83;
+ emit_membase(cd, (basereg),(disp),(opc));
+ emit_imm8((imm));
+ } else {
+ emit_rex(0,(basereg),0,0);
+ *(cd->mcodeptr++) = 0x81;
+ emit_membase(cd, (basereg),(disp),(opc));
+ emit_imm32((imm));
+ }
+}
+
+
+void emit_test_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ emit_rex(1,(reg),0,(dreg));
+ *(cd->mcodeptr++) = 0x85;
+ emit_reg((reg),(dreg));
+}
+
+
+void emit_testl_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ emit_rex(0,(reg),0,(dreg));
+ *(cd->mcodeptr++) = 0x85;
+ emit_reg((reg),(dreg));
+}
+
+
+void emit_test_imm_reg(codegendata *cd, s8 imm, s8 reg) {
+ *(cd->mcodeptr++) = 0xf7;
+ emit_reg(0,(reg));
+ emit_imm32((imm));
+}
+
+
+void emit_testw_imm_reg(codegendata *cd, s8 imm, s8 reg) {
+ *(cd->mcodeptr++) = 0x66;
+ *(cd->mcodeptr++) = 0xf7;
+ emit_reg(0,(reg));
+ emit_imm16((imm));
+}
+
+
+void emit_testb_imm_reg(codegendata *cd, s8 imm, s8 reg) {
+ *(cd->mcodeptr++) = 0xf6;
+ emit_reg(0,(reg));
+ emit_imm8((imm));
+}
+
+
+void emit_lea_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) {
+ emit_rex(1,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x8d;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_leal_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) {
+ emit_rex(0,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x8d;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+
+void emit_incl_membase(codegendata *cd, s8 basereg, s8 disp)
+{
+ emit_rex(0,0,0,(basereg));
+ *(cd->mcodeptr++) = 0xff;
+ emit_membase(cd, (basereg),(disp),0);
+}
+
+
+
+void emit_cltd(codegendata *cd) {
+ *(cd->mcodeptr++) = 0x99;
+}
+
+
+void emit_cqto(codegendata *cd) {
+ emit_rex(1,0,0,0);
+ *(cd->mcodeptr++) = 0x99;
+}
+
+
+
+void emit_imul_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xaf;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_imull_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xaf;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_imul_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) {
+ emit_rex(1,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xaf;
+ emit_membase(cd, (basereg),(disp),(dreg));
+}
+
+
+void emit_imull_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) {
+ emit_rex(0,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xaf;
+ emit_membase(cd, (basereg),(disp),(dreg));
+}
+
+
+void emit_imul_imm_reg(codegendata *cd, s8 imm, s8 dreg) {
+ if (IS_IMM8((imm))) {
+ emit_rex(1,0,0,(dreg));
+ *(cd->mcodeptr++) = 0x6b;
+ emit_reg(0,(dreg));
+ emit_imm8((imm));
+ } else {
+ emit_rex(1,0,0,(dreg));
+ *(cd->mcodeptr++) = 0x69;
+ emit_reg(0,(dreg));
+ emit_imm32((imm));
+ }
+}
+
+
+void emit_imul_imm_reg_reg(codegendata *cd, s8 imm, s8 reg, s8 dreg) {
+ if (IS_IMM8((imm))) {
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x6b;
+ emit_reg((dreg),(reg));
+ emit_imm8((imm));
+ } else {
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x69;
+ emit_reg((dreg),(reg));
+ emit_imm32((imm));
+ }
+}
+
+
+void emit_imull_imm_reg_reg(codegendata *cd, s8 imm, s8 reg, s8 dreg) {
+ if (IS_IMM8((imm))) {
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x6b;
+ emit_reg((dreg),(reg));
+ emit_imm8((imm));
+ } else {
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x69;
+ emit_reg((dreg),(reg));
+ emit_imm32((imm));
+ }
+}
+
+
+void emit_imul_imm_membase_reg(codegendata *cd, s8 imm, s8 basereg, s8 disp, s8 dreg) {
+ if (IS_IMM8((imm))) {
+ emit_rex(1,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x6b;
+ emit_membase(cd, (basereg),(disp),(dreg));
+ emit_imm8((imm));
+ } else {
+ emit_rex(1,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x69;
+ emit_membase(cd, (basereg),(disp),(dreg));
+ emit_imm32((imm));
+ }
+}
+
+
+void emit_imull_imm_membase_reg(codegendata *cd, s8 imm, s8 basereg, s8 disp, s8 dreg) {
+ if (IS_IMM8((imm))) {
+ emit_rex(0,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x6b;
+ emit_membase(cd, (basereg),(disp),(dreg));
+ emit_imm8((imm));
+ } else {
+ emit_rex(0,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x69;
+ emit_membase(cd, (basereg),(disp),(dreg));
+ emit_imm32((imm));
+ }
+}
+
+
+void emit_idiv_reg(codegendata *cd, s8 reg) {
+ emit_rex(1,0,0,(reg));
+ *(cd->mcodeptr++) = 0xf7;
+ emit_reg(7,(reg));
+}
+
+
+void emit_idivl_reg(codegendata *cd, s8 reg) {
+ emit_rex(0,0,0,(reg));
+ *(cd->mcodeptr++) = 0xf7;
+ emit_reg(7,(reg));
+}
+
+
+
+void emit_ret(codegendata *cd) {
+ *(cd->mcodeptr++) = 0xc3;
+}
+
+
+
+/*
+ * shift ops
+ */
+void emit_shift_reg(codegendata *cd, s8 opc, s8 reg) {
+ emit_rex(1,0,0,(reg));
+ *(cd->mcodeptr++) = 0xd3;
+ emit_reg((opc),(reg));
+}
+
+
+void emit_shiftl_reg(codegendata *cd, s8 opc, s8 reg) {
+ emit_rex(0,0,0,(reg));
+ *(cd->mcodeptr++) = 0xd3;
+ emit_reg((opc),(reg));
+}
+
+
+void emit_shift_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp) {
+ emit_rex(1,0,0,(basereg));
+ *(cd->mcodeptr++) = 0xd3;
+ emit_membase(cd, (basereg),(disp),(opc));
+}
+
+
+void emit_shiftl_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp) {
+ emit_rex(0,0,0,(basereg));
+ *(cd->mcodeptr++) = 0xd3;
+ emit_membase(cd, (basereg),(disp),(opc));
+}
+
+
+void emit_shift_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) {
+ if ((imm) == 1) {
+ emit_rex(1,0,0,(dreg));
+ *(cd->mcodeptr++) = 0xd1;
+ emit_reg((opc),(dreg));
+ } else {
+ emit_rex(1,0,0,(dreg));
+ *(cd->mcodeptr++) = 0xc1;
+ emit_reg((opc),(dreg));
+ emit_imm8((imm));
+ }
+}
+
+
+void emit_shiftl_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) {
+ if ((imm) == 1) {
+ emit_rex(0,0,0,(dreg));
+ *(cd->mcodeptr++) = 0xd1;
+ emit_reg((opc),(dreg));
+ } else {
+ emit_rex(0,0,0,(dreg));
+ *(cd->mcodeptr++) = 0xc1;
+ emit_reg((opc),(dreg));
+ emit_imm8((imm));
+ }
+}
+
+
+void emit_shift_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) {
+ if ((imm) == 1) {
+ emit_rex(1,0,0,(basereg));
+ *(cd->mcodeptr++) = 0xd1;
+ emit_membase(cd, (basereg),(disp),(opc));
+ } else {
+ emit_rex(1,0,0,(basereg));
+ *(cd->mcodeptr++) = 0xc1;
+ emit_membase(cd, (basereg),(disp),(opc));
+ emit_imm8((imm));
+ }
+}
+
+
+void emit_shiftl_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) {
+ if ((imm) == 1) {
+ emit_rex(0,0,0,(basereg));
+ *(cd->mcodeptr++) = 0xd1;
+ emit_membase(cd, (basereg),(disp),(opc));
+ } else {
+ emit_rex(0,0,0,(basereg));
+ *(cd->mcodeptr++) = 0xc1;
+ emit_membase(cd, (basereg),(disp),(opc));
+ emit_imm8((imm));
+ }
+}
+
+
+
+/*
+ * jump operations
+ */
+void emit_jmp_imm(codegendata *cd, s8 imm) {
+ *(cd->mcodeptr++) = 0xe9;
+ emit_imm32((imm));
+}
+
+
+void emit_jmp_reg(codegendata *cd, s8 reg) {
+ emit_rex(0,0,0,(reg));
+ *(cd->mcodeptr++) = 0xff;
+ emit_reg(4,(reg));
+}
+
+
+void emit_jcc(codegendata *cd, s8 opc, s8 imm) {
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = (0x80 + (opc));
+ emit_imm32((imm));
+}
+
+
+
+/*
+ * conditional set and move operations
+ */
+
+/* we need the rex byte to get all low bytes */
+void emit_setcc_reg(codegendata *cd, s8 opc, s8 reg) {
+ *(cd->mcodeptr++) = (0x40 | (((reg) >> 3) & 0x01));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = (0x90 + (opc));
+ emit_reg(0,(reg));
+}
+
+
+/* we need the rex byte to get all low bytes */
+void emit_setcc_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp) {
+ *(cd->mcodeptr++) = (0x40 | (((basereg) >> 3) & 0x01));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = (0x90 + (opc));
+ emit_membase(cd, (basereg),(disp),0);
+}
+
+
+void emit_cmovcc_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg)
+{
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = (0x40 + (opc));
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_cmovccl_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg)
+{
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = (0x40 + (opc));
+ emit_reg((dreg),(reg));
+}
+
+
+
+void emit_neg_reg(codegendata *cd, s8 reg)
+{
+ emit_rex(1,0,0,(reg));
+ *(cd->mcodeptr++) = 0xf7;
+ emit_reg(3,(reg));
+}
+
+
+void emit_negl_reg(codegendata *cd, s8 reg)
+{
+ emit_rex(0,0,0,(reg));
+ *(cd->mcodeptr++) = 0xf7;
+ emit_reg(3,(reg));
+}
+
+
+void emit_push_reg(codegendata *cd, s8 reg) {
+ emit_rex(0,0,0,(reg));
+ *(cd->mcodeptr++) = 0x50 + (0x07 & (reg));
+}
+
+
+void emit_push_imm(codegendata *cd, s8 imm) {
+ *(cd->mcodeptr++) = 0x68;
+ emit_imm32((imm));
+}
+
+
+void emit_pop_reg(codegendata *cd, s8 reg) {
+ emit_rex(0,0,0,(reg));
+ *(cd->mcodeptr++) = 0x58 + (0x07 & (reg));
+}
+
+
+void emit_xchg_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ emit_rex(1,(reg),0,(dreg));
+ *(cd->mcodeptr++) = 0x87;
+ emit_reg((reg),(dreg));
+}
+
+
+void emit_nop(codegendata *cd) {
+ *(cd->mcodeptr++) = 0x90;
+}
+
+
+
+/*
+ * call instructions
+ */
+void emit_call_reg(codegendata *cd, s8 reg) {
+ emit_rex(1,0,0,(reg));
+ *(cd->mcodeptr++) = 0xff;
+ emit_reg(2,(reg));
+}
+
+
+void emit_call_imm(codegendata *cd, s8 imm) {
+ *(cd->mcodeptr++) = 0xe8;
+ emit_imm32((imm));
+}
+
+
+void emit_call_mem(codegendata *cd, ptrint mem)
+{
+ *(cd->mcodeptr++) = 0xff;
+ emit_mem(2,(mem));
+}
+
+
+
+/*
+ * floating point instructions (SSE2)
+ */
+void emit_addsd_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x58;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_addss_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x58;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_cvtsi2ssq_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x2a;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_cvtsi2ss_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x2a;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_cvtsi2sdq_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x2a;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_cvtsi2sd_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x2a;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_cvtss2sd_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x5a;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_cvtsd2ss_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x5a;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_cvttss2siq_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x2c;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_cvttss2si_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x2c;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_cvttsd2siq_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(1,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x2c;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_cvttsd2si_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x2c;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_divss_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x5e;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_divsd_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x5e;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_movd_reg_freg(codegendata *cd, s8 reg, s8 freg) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(1,(freg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x6e;
+ emit_reg((freg),(reg));
+}
+
+
+void emit_movd_freg_reg(codegendata *cd, s8 freg, s8 reg) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(1,(freg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x7e;
+ emit_reg((freg),(reg));
+}
+
+
+void emit_movd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x7e;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_movd_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x7e;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_movd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(1,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x6e;
+ emit_membase(cd, (basereg),(disp),(dreg));
+}
+
+
+void emit_movdl_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x6e;
+ emit_membase(cd, (basereg),(disp),(dreg));
+}
+
+
+void emit_movd_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,(dreg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x6e;
+ emit_memindex(cd, (dreg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_movq_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x7e;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_movq_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xd6;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_movq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x7e;
+ emit_membase(cd, (basereg),(disp),(dreg));
+}
+
+
+void emit_movss_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(reg),0,(dreg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x10;
+ emit_reg((reg),(dreg));
+}
+
+
+void emit_movsd_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(reg),0,(dreg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x10;
+ emit_reg((reg),(dreg));
+}
+
+
+void emit_movss_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x11;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+/* Always emit a REX byte, because the instruction size can be smaller when */
+/* all register indexes are smaller than 7. */
+void emit_movss_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_byte_rex((reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x11;
+ emit_membase32(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_movsd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x11;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+/* Always emit a REX byte, because the instruction size can be smaller when */
+/* all register indexes are smaller than 7. */
+void emit_movsd_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_byte_rex((reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x11;
+ emit_membase32(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_movss_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x10;
+ emit_membase(cd, (basereg),(disp),(dreg));
+}
+
+
+/* Always emit a REX byte, because the instruction size can be smaller when */
+/* all register indexes are smaller than 7. */
+void emit_movss_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_byte_rex((dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x10;
+ emit_membase32(cd, (basereg),(disp),(dreg));
+}
+
+
+void emit_movlps_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg)
+{
+ emit_rex(0,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x12;
+ emit_membase(cd, (basereg),(disp),(dreg));
+}
+
+
+void emit_movlps_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp)
+{
+ emit_rex(0,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x13;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_movsd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x10;
+ emit_membase(cd, (basereg),(disp),(dreg));
+}
+
+
+/* Always emit a REX byte, because the instruction size can be smaller when */
+/* all register indexes are smaller than 7. */
+void emit_movsd_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_byte_rex((dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x10;
+ emit_membase32(cd, (basereg),(disp),(dreg));
+}
+
+
+void emit_movlpd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg)
+{
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x12;
+ emit_membase(cd, (basereg),(disp),(dreg));
+}
+
+
+void emit_movlpd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp)
+{
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,(reg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x13;
+ emit_membase(cd, (basereg),(disp),(reg));
+}
+
+
+void emit_movss_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x11;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_movsd_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x11;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_movss_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(dreg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x10;
+ emit_memindex(cd, (dreg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_movsd_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(dreg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x10;
+ emit_memindex(cd, (dreg),(disp),(basereg),(indexreg),(scale));
+}
+
+
+void emit_mulss_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x59;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_mulsd_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x59;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_subss_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf3;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x5c;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_subsd_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0xf2;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x5c;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_ucomiss_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x2e;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_ucomisd_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x2e;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_xorps_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x57;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_xorps_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) {
+ emit_rex(0,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x57;
+ emit_membase(cd, (basereg),(disp),(dreg));
+}
+
+
+void emit_xorpd_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,(dreg),0,(reg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x57;
+ emit_reg((dreg),(reg));
+}
+
+
+void emit_xorpd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg) {
+ *(cd->mcodeptr++) = 0x66;
+ emit_rex(0,(dreg),0,(basereg));
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x57;
+ emit_membase(cd, (basereg),(disp),(dreg));
+}
+
+
+/* system instructions ********************************************************/
+
+void emit_rdtsc(codegendata *cd)
+{
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x31;
+}
+
+
+/*
+ * 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/x86_64/md-emit.h - machine dependent emit function prototypes
+
+ 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:
+
+ $Id: emit.h 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+
+#ifndef _MD_EMIT_H
+#define _MD_EMIT_H
+
+#include "vm/types.h"
+
+
+/* macros to create code ******************************************************/
+
+/* immediate data union */
+
+typedef union {
+ s4 i;
+ s8 l;
+ float f;
+ double d;
+ void *a;
+ u1 b[8];
+} imm_buf;
+
+
+/* opcodes for alu instructions */
+
+#define ALU_ADD 0
+#define ALU_OR 1
+#define ALU_ADC 2
+#define ALU_SBB 3
+#define ALU_AND 4
+#define ALU_SUB 5
+#define ALU_XOR 6
+#define ALU_CMP 7
+
+
+#define SHIFT_ROL 0
+#define SHIFT_ROR 1
+#define SHIFT_RCL 2
+#define SHIFT_RCR 3
+#define SHIFT_SHL 4
+#define SHIFT_SHR 5
+#define SHIFT_SAR 7
+
+#if 0
+#define CC_O 0
+#define CC_NO 1
+#define CC_B 2
+#define CC_C 2
+#define CC_NAE 2
+#define CC_AE 3
+#define CC_NB 3
+#define CC_NC 3
+#define CC_E 4
+#define CC_Z 4
+#define CC_NE 5
+#define CC_NZ 5
+#define CC_BE 6
+#define CC_NA 6
+#define CC_A 7
+#define CC_NBE 7
+#define CC_S 8
+#define CC_LZ 8
+#define CC_NS 9
+#define CC_GEZ 9
+#define CC_P 0x0a
+#define CC_PE 0x0a
+#define CC_NP 0x0b
+#define CC_PO 0x0b
+#define CC_L 0x0c
+#define CC_NGE 0x0c
+#define CC_GE 0x0d
+#define CC_NL 0x0d
+#define CC_LE 0x0e
+#define CC_NG 0x0e
+#define CC_G 0x0f
+#define CC_NLE 0x0f
+#endif
+
+
+/* modrm and stuff */
+
+#define emit_address_byte(mod,reg,rm) \
+ do { \
+ *(cd->mcodeptr++) = ((((mod) & 0x03) << 6) | (((reg) & 0x07) << 3) | ((rm) & 0x07)); \
+ } while (0);
+
+
+#define emit_rex(size,reg,index,rm) \
+ do { \
+ if (((size) == 1) || ((reg) > 7) || ((index) > 7) || ((rm) > 7)) \
+ *(cd->mcodeptr++) = (0x40 | (((size) & 0x01) << 3) | ((((reg) >> 3) & 0x01) << 2) | ((((index) >> 3) & 0x01) << 1) | (((rm) >> 3) & 0x01)); \
+ } while (0)
+
+
+#define emit_byte_rex(reg,index,rm) \
+ do { \
+ *(cd->mcodeptr++) = (0x40 | ((((reg) >> 3) & 0x01) << 2) | ((((index) >> 3) & 0x01) << 1) | (((rm) >> 3) & 0x01)); \
+ } while (0)
+
+
+#define emit_mem(r,disp) \
+ do { \
+ emit_address_byte(0,(r),5); \
+ emit_imm32((disp)); \
+ } while (0)
+
+
+#define emit_imm8(imm) \
+ do { \
+ *(cd->mcodeptr++) = (u1) ((imm) & 0xff); \
+ } while (0)
+
+
+#define emit_imm16(imm) \
+ do { \
+ imm_buf imb; \
+ imb.i = (s4) (imm); \
+ *(cd->mcodeptr++) = imb.b[0]; \
+ *(cd->mcodeptr++) = imb.b[1]; \
+ } while (0)
+
+
+#define emit_imm32(imm) \
+ do { \
+ imm_buf imb; \
+ imb.i = (s4) (imm); \
+ *(cd->mcodeptr++) = imb.b[0]; \
+ *(cd->mcodeptr++) = imb.b[1]; \
+ *(cd->mcodeptr++) = imb.b[2]; \
+ *(cd->mcodeptr++) = imb.b[3]; \
+ } while (0)
+
+
+#define emit_imm64(imm) \
+ do { \
+ imm_buf imb; \
+ imb.l = (s8) (imm); \
+ *(cd->mcodeptr++) = imb.b[0]; \
+ *(cd->mcodeptr++) = imb.b[1]; \
+ *(cd->mcodeptr++) = imb.b[2]; \
+ *(cd->mcodeptr++) = imb.b[3]; \
+ *(cd->mcodeptr++) = imb.b[4]; \
+ *(cd->mcodeptr++) = imb.b[5]; \
+ *(cd->mcodeptr++) = imb.b[6]; \
+ *(cd->mcodeptr++) = imb.b[7]; \
+ } while (0)
+
+
+/* convenience macros *********************************************************/
+
+#define emit_reg(reg,rm) emit_address_byte(3,(reg),(rm))
+
+
+/* function prototypes ********************************************************/
+
+void emit_cmovxx(codegendata *cd, instruction *iptr, s4 s, s4 d);
+
+
+/* code generation prototypes */
+
+void emit_ishift(jitdata *jd, s4 shift_op, instruction *iptr);
+void emit_lshift(jitdata *jd, s4 shift_op, instruction *iptr);
+
+
+/* integer instructions */
+
+void emit_mov_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_mov_imm_reg(codegendata *cd, s8 imm, s8 reg);
+void emit_movl_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_movl_imm_reg(codegendata *cd, s8 imm, s8 reg);
+void emit_mov_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg);
+void emit_mov_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg);
+void emit_movl_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg);
+void emit_movl_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg);
+void emit_mov_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_mov_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_movl_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_movl_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_mov_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg);
+void emit_movl_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg);
+void emit_mov_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale);
+void emit_movl_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale);
+void emit_movw_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale);
+void emit_movb_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale);
+void emit_mov_imm_membase(codegendata *cd, s8 imm, s8 basereg, s8 disp);
+void emit_mov_imm_membase32(codegendata *cd, s8 imm, s8 basereg, s8 disp);
+void emit_movl_imm_membase(codegendata *cd, s8 imm, s8 basereg, s8 disp);
+void emit_movl_imm_membase32(codegendata *cd, s8 imm, s8 basereg, s8 disp);
+void emit_movsbq_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_movsbq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movswq_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_movswq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movslq_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_movslq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movzwq_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_movzwq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movswq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg);
+void emit_movsbq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg);
+void emit_movzwq_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg);
+void emit_mov_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale);
+void emit_movl_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale);
+void emit_movw_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale);
+void emit_movb_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 indexreg, s4 scale);
+void emit_alu_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg);
+void emit_alul_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg);
+void emit_alu_reg_membase(codegendata *cd, s8 opc, s8 reg, s8 basereg, s8 disp);
+void emit_alul_reg_membase(codegendata *cd, s8 opc, s8 reg, s8 basereg, s8 disp);
+void emit_alu_membase_reg(codegendata *cd, s8 opc, s8 basereg, s8 disp, s8 reg);
+void emit_alul_membase_reg(codegendata *cd, s8 opc, s8 basereg, s8 disp, s8 reg);
+void emit_alu_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg);
+void emit_alu_imm32_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg);
+void emit_alul_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg);
+void emit_alu_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp);
+void emit_alul_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp);
+void emit_test_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_testl_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_test_imm_reg(codegendata *cd, s8 imm, s8 reg);
+void emit_testw_imm_reg(codegendata *cd, s8 imm, s8 reg);
+void emit_testb_imm_reg(codegendata *cd, s8 imm, s8 reg);
+void emit_lea_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg);
+void emit_leal_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg);
+
+void emit_incl_membase(codegendata *cd, s8 basereg, s8 disp);
+
+void emit_cltd(codegendata *cd);
+void emit_cqto(codegendata *cd);
+void emit_imul_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_imull_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_imul_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_imull_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_imul_imm_reg(codegendata *cd, s8 imm, s8 dreg);
+void emit_imul_imm_reg_reg(codegendata *cd, s8 imm,s8 reg, s8 dreg);
+void emit_imull_imm_reg_reg(codegendata *cd, s8 imm, s8 reg, s8 dreg);
+void emit_imul_imm_membase_reg(codegendata *cd, s8 imm, s8 basereg, s8 disp, s8 dreg);
+void emit_imull_imm_membase_reg(codegendata *cd, s8 imm, s8 basereg, s8 disp, s8 dreg);
+void emit_idiv_reg(codegendata *cd, s8 reg);
+void emit_idivl_reg(codegendata *cd, s8 reg);
+void emit_ret(codegendata *cd);
+void emit_shift_reg(codegendata *cd, s8 opc, s8 reg);
+void emit_shiftl_reg(codegendata *cd, s8 opc, s8 reg);
+void emit_shift_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp);
+void emit_shiftl_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp);
+void emit_shift_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg);
+void emit_shiftl_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg);
+void emit_shift_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp);
+void emit_shiftl_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp);
+void emit_jmp_imm(codegendata *cd, s8 imm);
+void emit_jmp_reg(codegendata *cd, s8 reg);
+void emit_jcc(codegendata *cd, s8 opc, s8 imm);
+void emit_setcc_reg(codegendata *cd, s8 opc, s8 reg);
+void emit_setcc_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp);
+void emit_cmovcc_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg);
+void emit_cmovccl_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg);
+void emit_neg_reg(codegendata *cd, s8 reg);
+void emit_negl_reg(codegendata *cd, s8 reg);
+void emit_neg_membase(codegendata *cd, s8 basereg, s8 disp);
+void emit_negl_membase(codegendata *cd, s8 basereg, s8 disp);
+void emit_push_reg(codegendata *cd, s8 reg);
+void emit_push_imm(codegendata *cd, s8 imm);
+void emit_pop_reg(codegendata *cd, s8 reg);
+void emit_xchg_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_nop(codegendata *cd);
+void emit_call_reg(codegendata *cd, s8 reg);
+void emit_call_imm(codegendata *cd, s8 imm);
+void emit_call_mem(codegendata *cd, ptrint mem);
+
+
+/* floating point instructions (SSE2) */
+
+void emit_addsd_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_addss_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_cvtsi2ssq_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_cvtsi2ss_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_cvtsi2sdq_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_cvtsi2sd_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_cvtss2sd_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_cvtsd2ss_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_cvttss2siq_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_cvttss2si_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_cvttsd2siq_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_cvttsd2si_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_divss_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_divsd_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_movd_reg_freg(codegendata *cd, s8 reg, s8 freg);
+void emit_movd_freg_reg(codegendata *cd, s8 freg, s8 reg);
+void emit_movd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_movd_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale);
+void emit_movd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movdl_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movd_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg);
+void emit_movq_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_movq_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_movq_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movss_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_movsd_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_movss_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_movss_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_movsd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_movsd_reg_membase32(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_movss_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movss_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movlps_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movlps_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_movsd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movsd_membase32_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movlpd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_movlpd_reg_membase(codegendata *cd, s8 reg, s8 basereg, s8 disp);
+void emit_movss_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale);
+void emit_movsd_reg_memindex(codegendata *cd, s8 reg, s8 disp, s8 basereg, s8 indexreg, s8 scale);
+void emit_movss_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg);
+void emit_movsd_memindex_reg(codegendata *cd, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 dreg);
+void emit_mulss_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_mulsd_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_subss_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_subsd_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_ucomiss_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_ucomisd_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_xorps_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_xorps_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+void emit_xorpd_reg_reg(codegendata *cd, s8 reg, s8 dreg);
+void emit_xorpd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg);
+
+
+/* system instructions ********************************************************/
+
+void emit_rdtsc(codegendata *cd);
+
+#endif /* _MD_EMIT_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
+#ifndef _MACHINE_INSTR_H
+#define _MACHINE_INSTR_H
+
+static inline void
+__attribute__ ((unused))
+atomic_add (volatile int *mem, int val)
+{
+#if 0
+ __asm__ __volatile__ ("lock; addl %1,%0"
+ : "=m" (*mem)
+ : "ir" (val), "m" (*mem));
+#endif
+}
+
+static inline long
+__attribute__ ((unused))
+compare_and_swap (volatile long *p, long oldval, long newval)
+{
+#if 0
+ long ret;
+
+ __asm__ __volatile__ ("lock; cmpxchgq %2, %1"
+ : "=a" (ret), "=m" (*p)
+ : "r" (newval), "m" (*p), "0" (oldval));
+ return ret;
+#endif
+}
+
+#if 0
+#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__ ( \
+ "mfence" : : : "memory" )
+#endif
+
+#define STORE_ORDER_BARRIER()
+#define MEMORY_BARRIER_BEFORE_ATOMIC()
+#define MEMORY_BARRIER_AFTER_ATOMIC()
+#define MEMORY_BARRIER()
+
+#endif
--- /dev/null
+/* src/vm/jit/x86_64/md-abi.c - functions for x86_64 Linux 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: Christian Thalinger
+
+ Changes:
+
+ $Id: md-abi.c 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "vm/jit/s390/md-abi.h"
+
+#include "vm/descriptor.h"
+#include "vm/global.h"
+
+
+/* register descripton array **************************************************/
+
+s4 nregdescint[] = {
+#if 0
+ REG_RET, REG_ARG, REG_ARG, REG_TMP, REG_RES, REG_SAV, REG_ARG, REG_ARG,
+ REG_ARG, REG_ARG, REG_RES, REG_RES, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
+#endif
+ REG_TMP, REG_TMP, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_SAV,
+ REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_RES, REG_TMP, REG_RES,
+ REG_END
+};
+
+
+s4 nregdescfloat[] = {
+#if 0
+ REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG,
+ REG_RES, REG_RES, REG_RES, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
+#endif
+ REG_ARG, REG_TMP, REG_ARG, REG_TMP, REG_SAV, REG_TMP, REG_SAV, REG_TMP,
+ REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
+ REG_END
+};
+
+
+/* md_param_alloc **************************************************************
+
+ XXX
+
+*******************************************************************************/
+
+void md_param_alloc(methoddesc *md)
+{
+ paramdesc *pd;
+ s4 i;
+ s4 iarg;
+ s4 farg;
+ s4 stacksize;
+
+ /* set default values */
+
+ iarg = 0;
+ farg = 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_LNG:
+ if (iarg < INT_ARG_CNT) {
+ pd->inmemory = false;
+ pd->regoff = iarg;
+ }
+ else {
+ pd->inmemory = true;
+ pd->regoff = stacksize;
+ }
+ if (iarg < INT_ARG_CNT)
+ iarg++;
+ else
+ stacksize++;
+ break;
+
+ case TYPE_FLT:
+ case TYPE_DBL:
+ if (farg < FLT_ARG_CNT) {
+ pd->inmemory = false;
+ pd->regoff = farg;
+ }
+ else {
+ pd->inmemory = true;
+ pd->regoff = stacksize;
+ }
+ if (farg < FLT_ARG_CNT)
+ farg++;
+ else
+ stacksize++;
+ break;
+ }
+ }
+
+ /* Since XMM0 (==A0) is used for passing return values, this
+ argument register usage has to be regarded, too. */
+
+ if (IS_FLT_DBL_TYPE(md->returntype.type))
+ if (farg < 1)
+ farg = 1;
+
+ /* fill register and stack usage */
+
+ md->argintreguse = iarg;
+ md->argfltreguse = farg;
+ md->memuse = stacksize;
+}
+
+
+/* md_return_alloc *************************************************************
+
+ Precolor the Java Stackelement containing the Return Value. Only
+ for float/ double types straight forward possible, since INT_LNG
+ types use "reserved" registers Float/Double values use a00 as
+ return register.
+
+ --- in
+ jd: jitdata of the current method
+ stackslot: Java Stackslot to contain the Return Value
+
+ --- out
+ if precoloring was possible:
+ VAR(stackslot->varnum)->flags = PREALLOC
+ ->vv.regoff = [REG_RESULT|REG_FRESULT]
+ rd->arg[flt|int]reguse set to a value according the register usage
+
+ NOTE: Do not pass a LOCALVAR in stackslot->varnum.
+
+*******************************************************************************/
+
+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;
+
+ /* precoloring only straightforward possible with flt/dbl types
+ For Address/Integer/Long REG_RESULT == rax == REG_ITMP1 and so
+ could be destroyed if the return value Stack Slot "lives too
+ long" */
+
+ if (IS_FLT_DBL_TYPE(md->returntype.type)) {
+ /* In Leafmethods Local Vars holding parameters are precolored
+ to their argument register -> so leafmethods with
+ paramcount > 0 could already use 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)) {
+
+ VAR(stackslot->varnum)->flags = PREALLOC;
+
+ /* float/double */
+ if (rd->argfltreguse < 1)
+ rd->argfltreguse = 1;
+
+ VAR(stackslot->varnum)->vv.regoff = REG_FRESULT;
+ }
+ }
+ }
+}
+
+
+/*
+ * 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/x86_64/md-abi.h - defines for x86_64 Linux 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: Christian Thalinger
+
+ Changes:
+
+ $Id: md-abi.h 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+
+#ifndef _MD_ABI_H
+#define _MD_ABI_H
+
+/* keep old code happy */
+
+#define RIP -1
+#define RAX 0
+#define RCX 1
+#define RDX 2
+#define RBX 3
+#define RSP 4
+#define RBP 5
+#define RSI 6
+#define RDI 7
+#define R8 8
+#define R9 9
+#define R10 10
+#define R11 11
+#define R12 12
+#define R13 13
+#define R14 14
+#define R15 15
+
+
+#define XMM0 0
+#define XMM1 1
+#define XMM2 2
+#define XMM3 3
+#define XMM4 4
+#define XMM5 5
+#define XMM6 6
+#define XMM7 7
+#define XMM8 8
+#define XMM9 9
+#define XMM10 10
+#define XMM11 11
+#define XMM12 12
+#define XMM13 13
+#define XMM14 14
+#define XMM15 15
+
+
+#define REG_IFTMP 10 /* temporary integer and floating point register */
+
+
+/* define registers ***********************************************************/
+
+#define R0 0
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define R5 5
+#define R6 6
+#define R7 7
+#define R8 8
+#define R9 9
+#define R10 10
+#define R11 11
+#define R12 12
+#define R13 13
+#define R14 14
+#define R15 15
+
+#define F0 0
+#define F1 1
+#define F2 2
+#define F3 3
+#define F4 4
+#define F5 5
+#define F6 6
+#define F7 7
+#define F8 8
+#define F9 9
+#define F10 10
+#define F11 11
+#define F12 12
+#define F13 13
+#define F14 14
+#define F15 15
+
+/* preallocated registers *****************************************************/
+
+/* integer registers */
+
+#define REG_RESULT R2 /* to deliver method results */
+#define REG_RESULT2 R3
+
+#define REG_ITMP1 R0 /* temporary register */
+#define REG_ITMP2 R1 /* temporary register and method pointer */
+#define REG_ITMP3 R14 /* temporary register */
+
+#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_METHODPTR REG_ITMP2/* pointer to the place from where the */
+ /* procedure vector has been fetched */
+
+#define REG_NULL -1 /* used for reg_of_var where d is not needed */
+
+#define REG_ITMP1_XPTR REG_ITMP1/* exception pointer = temporary register 1 */
+#define REG_ITMP2_XPC REG_ITMP2/* exception pc = temporary register 2 */
+
+#define REG_SP R15 /* stack pointer */
+
+#define REG_PV R13
+
+#define REG_A0 R2 /* define some argument registers */
+#define REG_A1 R3
+#define REG_A2 R4
+#define REG_A3 R5
+#define REG_A4 R6
+
+/* floating point registers */
+
+#define REG_FRESULT F0 /* to deliver floating point method results */
+
+#define REG_FTMP1 F1 /* temporary floating point register */
+#define REG_FTMP2 F3 /* temporary floating point register */
+#define REG_FTMP3 F5 /* temporary floating point register */
+
+#define __REG_IFTMP 10 /* temporary integer and floating point register */
+
+
+#define INT_REG_CNT 16 /* number of integer registers */
+#define INT_SAV_CNT 6 /* number of integer callee saved registers */
+#define INT_ARG_CNT 5 /* number of integer argument registers */
+#define INT_TMP_CNT 3 /* number of integer temporary registers */
+#define INT_RES_CNT 2 /* number of integer reserved registers */
+
+#define FLT_REG_CNT 16 /* number of float registers */
+#define FLT_SAV_CNT 2 /* number of float callee saved registers */
+#define FLT_ARG_CNT 2 /* number of float argument registers */
+#define FLT_TMP_CNT 12 /* number of float temporary registers */
+#define FLT_RES_CNT 0 /* number of float reserved registers */
+
+#define TRACE_ARGS_NUM 6
+
+
+
+
+
+
+
+
+
+
+
+
+#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/x86_64/md-asm.h - assembler defines for x86_64 Linux 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: Christian Thalinger
+
+ Changes:
+
+ $Id: md-asm.h 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+
+#ifndef _MD_ASM_H
+#define _MD_ASM_H
+
+/* register defines ***********************************************************/
+
+#if 0
+
+#define v0 %rax
+#define v0l %eax
+#define itmp1 v0
+
+#define a3 %rcx
+#define a2 %rdx
+
+#define t0 %rbx
+#define t0l %ebx
+
+#define sp %rsp
+#define s0 %rbp
+
+#define a1 %rsi
+#define a0 %rdi
+#define a0l %edi
+
+#define a4 %r8
+#define a5 %r9
+
+#define itmp2 %r10
+#define itmp3 %r14
+
+#define s1 %r12
+#define s2 %r13
+#define s3 %r14
+#define s4 %r15
+
+
+#define bp s0
+
+#define itmp1l %eax
+#define itmp2l %r10d
+#define itmp3l %r11d
+
+#define xptr itmp1
+#define xpc itmp2
+#define mptr itmp2
+
+
+#define fa0 %xmm0
+#define fa1 %xmm1
+#define fa2 %xmm2
+#define fa3 %xmm3
+#define fa4 %xmm4
+#define fa5 %xmm5
+#define fa6 %xmm6
+#define fa7 %xmm7
+
+#define ftmp1 %xmm8
+#define ftmp2 %xmm9
+#define ftmp3 %xmm10
+
+#define ft0 %xmm11
+#define ft1 %xmm12
+#define ft2 %xmm13
+#define ft3 %xmm14
+#define ft4 %xmm15
+
+#endif
+
+#define a0 %r2
+#define a1 %r3
+#define a2 %r4
+#define a3 %r5
+#define a4 %r6
+
+#define sp %r15
+#define itmp1 %r0
+#define itmp2 %r1
+#define itmp3 %r14
+#define v0 %r2
+#define pv %r13
+
+#define mptr itmp2
+
+#define s0 %r7
+#define s1 %r8
+#define s2 %r9
+#define s3 %r10
+#define s4 %r11
+#define s5 %r12
+
+#define fa0 %f0
+#define fa1 %f2
+
+/* save and restore macros ****************************************************/
+
+#define SAVE_ARGUMENT_REGISTERS(off) \
+ mov a0,(0+(off))*8(sp) ; \
+ mov a1,(1+(off))*8(sp) ; \
+ mov a2,(2+(off))*8(sp) ; \
+ mov a3,(3+(off))*8(sp) ; \
+ mov a4,(4+(off))*8(sp) ; \
+ mov a5,(5+(off))*8(sp) ; \
+ \
+ movq fa0,(6+(off))*8(sp) ; \
+ movq fa1,(7+(off))*8(sp) ; \
+ movq fa2,(8+(off))*8(sp) ; \
+ movq fa3,(9+(off))*8(sp) ; \
+ movq fa4,(10+(off))*8(sp) ; \
+ movq fa5,(11+(off))*8(sp) ; \
+ movq fa6,(12+(off))*8(sp) ; \
+ movq fa7,(13+(off))*8(sp) ;
+
+
+#define RESTORE_ARGUMENT_REGISTERS(off) \
+ mov (0+(off))*8(sp),a0 ; \
+ mov (1+(off))*8(sp),a1 ; \
+ mov (2+(off))*8(sp),a2 ; \
+ mov (3+(off))*8(sp),a3 ; \
+ mov (4+(off))*8(sp),a4 ; \
+ mov (5+(off))*8(sp),a5 ; \
+ \
+ movq (6+(off))*8(sp),fa0 ; \
+ movq (7+(off))*8(sp),fa1 ; \
+ movq (8+(off))*8(sp),fa2 ; \
+ movq (9+(off))*8(sp),fa3 ; \
+ movq (10+(off))*8(sp),fa4 ; \
+ movq (11+(off))*8(sp),fa5 ; \
+ movq (12+(off))*8(sp),fa6 ; \
+ movq (13+(off))*8(sp),fa7 ;
+
+
+#define SAVE_TEMPORARY_REGISTERS(off) \
+ mov t0,(0+(off))*8(sp) ; \
+ movq ft0,(1+(off))*8(sp) ; \
+ movq ft1,(2+(off))*8(sp) ; \
+ movq ft2,(3+(off))*8(sp) ; \
+ movq ft3,(4+(off))*8(sp) ;
+
+
+#define RESTORE_TEMPORARY_REGISTERS(off) \
+ mov (0+(off))*8(sp),t0 ; \
+ movq (1+(off))*8(sp),ft0 ; \
+ movq (2+(off))*8(sp),ft1 ; \
+ movq (3+(off))*8(sp),ft2 ; \
+ movq (4+(off))*8(sp),ft3 ;
+
+#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:
+ */
--- /dev/null
+/* src/vm/jit/x86_64/md.c - machine dependent x86_64 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: Christian Thalinger
+
+ Changes: Edwin Steiner
+
+ $Id: md.c 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+#define REG_RSP 0
+#define REG_RIP 0
+#define REG_RAX 0
+#define REG_R10 0
+#define REG_ITMP2 0
+#define REG_RIP 0
+#define REG_RSP 0
+#define REG_RIP 0
+#define REG_RAX 0
+#define REG_R10 0
+#define REG_ITMP2 0
+#define REG_RIP 0
+#define REG_METHODPTR 0
+
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <ucontext.h>
+
+#include "vm/jit/s390/md-abi.h"
+
+#if defined(ENABLE_THREADS)
+# include "threads/native/threads.h"
+#endif
+
+#include "vm/exceptions.h"
+#include "vm/signallocal.h"
+#include "vm/jit/asmpart.h"
+#include "vm/jit/stacktrace.h"
+
+#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
+#include "vm/options.h" /* XXX debug */
+#include "vm/jit/disass.h" /* XXX debug */
+#endif
+
+
+/* md_init *********************************************************************
+
+ Do some machine dependent initialization.
+
+*******************************************************************************/
+
+void md_init(void)
+{
+ /* nothing to do */
+}
+
+
+/* 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;
+ u1 *sp;
+ u1 *ra;
+ u1 *xpc;
+
+ _uc = (ucontext_t *) _p;
+ _mc = &_uc->uc_mcontext;
+
+ /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
+ different to the ones in <ucontext.h>. */
+
+ sp = (u1 *) _mc->gregs[REG_RSP];
+ xpc = (u1 *) _mc->gregs[REG_RIP];
+ ra = xpc; /* return address is equal to xpc */
+
+#if 0
+ /* check for StackOverflowException */
+
+ threads_check_stackoverflow(sp);
+#endif
+
+ _mc->gregs[REG_RAX] =
+ (ptrint) stacktrace_hardware_nullpointerexception(NULL, sp, ra, xpc);
+
+ _mc->gregs[REG_R10] = (ptrint) xpc; /* REG_ITMP2_XPC */
+ _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
+}
+
+
+/* md_signal_handler_sigfpe ****************************************************
+
+ ArithmeticException signal handler for hardware divide by zero
+ check.
+
+*******************************************************************************/
+
+void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
+{
+ ucontext_t *_uc;
+ mcontext_t *_mc;
+ u1 *sp;
+ u1 *ra;
+ u1 *xpc;
+
+ _uc = (ucontext_t *) _p;
+ _mc = &_uc->uc_mcontext;
+
+ /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
+ different to the ones in <ucontext.h>. */
+
+ sp = (u1 *) _mc->gregs[REG_RSP];
+ xpc = (u1 *) _mc->gregs[REG_RIP];
+ ra = xpc; /* return address is equal to xpc */
+
+ _mc->gregs[REG_RAX] =
+ (ptrint) stacktrace_hardware_arithmeticexception(NULL, sp, ra, xpc);
+
+ _mc->gregs[REG_R10] = (ptrint) xpc; /* REG_ITMP2_XPC */
+ _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
+}
+
+
+/* md_signal_handler_sigusr2 ***************************************************
+
+ Signal handler for profiling sampling.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
+{
+ threadobject *t;
+ ucontext_t *_uc;
+ mcontext_t *_mc;
+ u1 *pc;
+
+ t = THREADOBJECT;
+
+ _uc = (ucontext_t *) _p;
+ _mc = &_uc->uc_mcontext;
+
+ /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
+ different to the ones in <ucontext.h>. */
+
+ pc = (u1 *) _mc->gregs[REG_RIP];
+
+ t->pc = pc;
+}
+#endif
+
+
+#if defined(ENABLE_THREADS)
+void thread_restartcriticalsection(ucontext_t *_uc)
+{
+ mcontext_t *_mc;
+ void *pc;
+
+ _mc = &_uc->uc_mcontext;
+
+ pc = critical_find_restart_point((void *) _mc->gregs[REG_RIP]);
+
+ if (pc != NULL)
+ _mc->gregs[REG_RIP] = (ptrint) pc;
+}
+#endif
+
+
+/* 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;
+
+ /* I don't think we have to check for branch-displacement
+ overflow. +/-2GB should be enough. */
+
+ /* patch the branch instruction before the mcodeptr */
+
+ mcodeptr[-1] = disp;
+}
+
+
+/* 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;
+
+ /* on x86_64 the return address is above the current stack frame */
+
+ ra = *((u1 **) (sp + framesize));
+
+ return ra;
+}
+
+
+/* md_get_method_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).
+
+ INVOKESTATIC/SPECIAL:
+
+ 4d 8b 15 e2 fe ff ff mov -286(%rip),%r10
+ 49 ff d2 rex64Z callq *%r10
+
+ INVOKEVIRTUAL:
+
+ 4c 8b 17 mov (%rdi),%r10
+ 49 8b 82 00 00 00 00 mov 0x0(%r10),%rax
+ 48 ff d3 rex64 callq *%rax
+
+ INVOKEINTERFACE:
+
+ 4c 8b 17 mov (%rdi),%r10
+ 4d 8b 92 00 00 00 00 mov 0x0(%r10),%r10
+ 49 8b 82 00 00 00 00 mov 0x0(%r10),%rax
+ 48 ff d3 rex64 callq *%r11
+
+*******************************************************************************/
+
+u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
+{
+ u1 mcode;
+ s4 offset;
+ u1 *pa; /* patch address */
+
+ /* go back to the actual call instruction (3-bytes) */
+
+ ra = ra - 3;
+
+ /* get the last byte of the call */
+
+ mcode = ra[2];
+
+ /* check for the different calls */
+
+ if (mcode == 0xd2) {
+ /* INVOKESTATIC/SPECIAL */
+
+ /* Get the offset from the instruction (the offset address is
+ 4-bytes before the call instruction). */
+
+ offset = *((s4 *) (ra - 4));
+
+ /* add the offset to the return address (IP-relative addressing) */
+
+ pa = ra + offset;
+ }
+ else if (mcode == 0xd3) {
+ /* INVOKEVIRTUAL/INTERFACE */
+
+ /* Get the offset from the instruction (the offset address is
+ 4-bytes before the call instruction). */
+
+ offset = *((s4 *) (ra - 4));
+
+ /* add the offset to the method pointer */
+
+ pa = mptr + offset;
+ }
+ else {
+ /* catch any problems */
+
+ assert(0);
+ }
+
+ return pa;
+}
+
+
+/* md_codegen_get_pv_from_pc ***************************************************
+
+ On this architecture just a wrapper function to
+ codegen_get_pv_from_pc.
+
+*******************************************************************************/
+
+u1 *md_codegen_get_pv_from_pc(u1 *ra)
+{
+ u1 *pv;
+
+ /* Get the start address of the function which contains this
+ address from the method table. */
+
+ pv = codegen_get_pv_from_pc(ra);
+
+ return pv;
+}
+
+
+/* md_cacheflush ***************************************************************
+
+ Calls the system's function to flush the instruction and data
+ cache.
+
+*******************************************************************************/
+
+void md_cacheflush(u1 *addr, s4 nbytes)
+{
+ /* do nothing */
+}
+
+
+/* md_icacheflush **************************************************************
+
+ Calls the system's function to flush the instruction cache.
+
+*******************************************************************************/
+
+void md_icacheflush(u1 *addr, s4 nbytes)
+{
+ /* do nothing */
+}
+
+
+/* md_dcacheflush **************************************************************
+
+ Calls the system's function to flush the data cache.
+
+*******************************************************************************/
+
+void md_dcacheflush(u1 *addr, s4 nbytes)
+{
+ /* do nothing */
+}
+
+
+/* md_patch_replacement_point **************************************************
+
+ Patch the given replacement point.
+
+*******************************************************************************/
+
+void md_patch_replacement_point(rplpoint *rp)
+{
+ u8 mcode;
+
+ /* XXX this is probably unsafe! */
+
+ /* save the current machine code */
+ mcode = *(u8*)rp->pc;
+
+ /* write spinning instruction */
+ *(u2*)(rp->pc) = 0xebfe;
+
+ /* write 5th byte */
+ rp->pc[4] = (rp->mcode >> 32);
+
+ /* write first word */
+ *(u4*)(rp->pc) = (u4) rp->mcode;
+
+ /* store saved mcode */
+ rp->mcode = mcode;
+
+#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
+ {
+ u1* u1ptr = rp->pc;
+ DISASSINSTR(u1ptr);
+ fflush(stdout);
+ }
+#endif
+
+ /* XXX if required asm_cacheflush(rp->pc,8); */
+}
+
+/*
+ * 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/x86_64/patcher.c - x86_64 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: Christian Thalinger
+
+ Changes:
+
+ $Id: patcher.c 7219 2007-01-16 22:18:57Z pm $
+
+*/
+
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "vm/jit/s390/codegen.h"
+
+#include "mm/memory.h"
+#include "native/native.h"
+#include "vm/builtin.h"
+#include "vm/class.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/patcher.h"
+
+
+/* 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;
+ functionptr f;
+ bool result;
+ java_objectheader *e;
+
+ /* define the patcher function */
+
+ bool (*patcher_function)(u1 *);
+
+ /* get stuff from the stack */
+
+ xpc = (u1 *) *((ptrint *) (sp + 5 * 8));
+ o = (java_objectheader *) *((ptrint *) (sp + 4 * 8));
+ f = (functionptr) *((ptrint *) (sp + 0 * 8));
+
+ /* calculate and set the new return address */
+
+ xpc = xpc - PATCHER_CALL_SIZE;
+
+ *((ptrint *) (sp + 5 * 8)) = (ptrint) xpc;
+
+ /* 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 */
+
+ /* RA is passed as NULL, but the XPC is correct and can be used in
+ stacktrace_create_extern_stackframeinfo for
+ md_codegen_get_pv_from_pc. */
+
+ stacktrace_create_extern_stackframeinfo(&sfi, pv, sp + 6 * 8, xpc, xpc);
+
+ /* call the proper patcher function */
+
+ result = (patcher_function)(sp);
+
+ /* remove the stackframeinfo */
+
+ stacktrace_remove_stackframeinfo(&sfi);
+
+ /* check for return value and exit accordingly */
+
+ if (result == false) {
+ e = exceptions_get_and_clear_exception();
+
+ PATCHER_MONITOREXIT;
+
+ return e;
+ }
+
+ PATCHER_MARK_PATCHED_MONITOREXIT;
+
+ return NULL;
+}
+
+
+/* patcher_get_putstatic *******************************************************
+
+ Machine code:
+
+ <patched call position>
+ 4d 8b 15 86 fe ff ff mov -378(%rip),%r10
+ 49 8b 32 mov (%r10),%rsi
+
+*******************************************************************************/
+
+bool patcher_get_putstatic(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ unresolved_field *uf;
+ s4 disp;
+ fieldinfo *fi;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ uf = (unresolved_field *) *((ptrint *) (sp + 2 * 8));
+ disp = *((s4 *) (sp + 1 * 8));
+
+ /* 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 back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch the field value's address */
+
+ *((ptrint *) (ra + 7 + disp)) = (ptrint) &(fi->value);
+
+ return true;
+}
+
+
+/* patcher_get_putfield ********************************************************
+
+ Machine code:
+
+ <patched call position>
+ 45 8b 8f 00 00 00 00 mov 0x0(%r15),%r9d
+
+*******************************************************************************/
+
+bool patcher_get_putfield(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ unresolved_field *uf;
+ fieldinfo *fi;
+ u1 byte;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ uf = (unresolved_field *) *((ptrint *) (sp + 2 * 8));
+
+ /* get the fieldinfo */
+
+ if (!(fi = resolve_field_eager(uf)))
+ return false;
+
+ /* patch back original code (instruction code is smaller than 8 bytes) */
+
+ *((u4 *) (ra + 0)) = (u4) mcode;
+ *((u1 *) (ra + 4)) = (u1) (mcode >> 32);
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch the field's offset: we check for the field type, because the */
+ /* instructions have different lengths */
+
+ if (IS_INT_LNG_TYPE(fi->type)) {
+ /* check for special case: %rsp or %r12 as base register */
+
+ byte = *(ra + 3);
+
+ if (byte == 0x24)
+ *((u4 *) (ra + 4)) = (u4) (fi->offset);
+ else
+ *((u4 *) (ra + 3)) = (u4) (fi->offset);
+ }
+ else {
+ /* check for special case: %rsp or %r12 as base register */
+
+ byte = *(ra + 5);
+
+ if (byte == 0x24)
+ *((u4 *) (ra + 6)) = (u4) (fi->offset);
+ else
+ *((u4 *) (ra + 5)) = (u4) (fi->offset);
+ }
+
+ return true;
+}
+
+
+/* patcher_putfieldconst *******************************************************
+
+ Machine code:
+
+ <patched call position>
+ 41 c7 85 00 00 00 00 7b 00 00 00 movl $0x7b,0x0(%r13)
+
+*******************************************************************************/
+
+bool patcher_putfieldconst(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ unresolved_field *uf;
+ fieldinfo *fi;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ uf = (unresolved_field *) *((ptrint *) (sp + 2 * 8));
+
+ /* get the fieldinfo */
+
+ if (!(fi = resolve_field_eager(uf)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch the field's offset */
+
+ if (IS_2_WORD_TYPE(fi->type) || IS_ADR_TYPE(fi->type)) {
+ /* handle special case when the base register is %r12 */
+
+ if (*(ra + 2) == 0x84) {
+ *((u4 *) (ra + 4)) = (u4) (fi->offset);
+ *((u4 *) (ra + 12 + 4)) = (u4) (fi->offset + 4);
+ }
+ else {
+ *((u4 *) (ra + 3)) = (u4) (fi->offset);
+ *((u4 *) (ra + 11 + 3)) = (u4) (fi->offset + 4);
+ }
+ }
+ else {
+ /* handle special case when the base register is %r12 */
+
+ if (*(ra + 2) == 0x84)
+ *((u4 *) (ra + 4)) = (u4) (fi->offset);
+ else
+ *((u4 *) (ra + 3)) = (u4) (fi->offset);
+ }
+
+ return true;
+}
+
+
+/* patcher_aconst **************************************************************
+
+ Machine code:
+
+ <patched call position>
+ 48 bf a0 f0 92 00 00 00 00 00 mov $0x92f0a0,%rdi
+
+*******************************************************************************/
+
+bool patcher_aconst(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ constant_classref *cr;
+ classinfo *c;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ cr = (constant_classref *) *((ptrint *) (sp + 2 * 8));
+
+ /* get the classinfo */
+
+ if (!(c = resolve_classref_eager(cr)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch the classinfo pointer */
+
+ *((ptrint *) (ra + 2)) = (ptrint) c;
+
+ return true;
+}
+
+
+/* patcher_builtin_multianewarray **********************************************
+
+ Machine code:
+
+ <patched call position>
+ 48 bf 02 00 00 00 00 00 00 00 mov $0x2,%rdi
+ 48 be 30 40 b2 00 00 00 00 00 mov $0xb24030,%rsi
+ 48 89 e2 mov %rsp,%rdx
+ 48 b8 7c 96 4b 00 00 00 00 00 mov $0x4b967c,%rax
+ 48 ff d0 callq *%rax
+
+*******************************************************************************/
+
+bool patcher_builtin_multianewarray(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ constant_classref *cr;
+ classinfo *c;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ cr = (constant_classref *) *((ptrint *) (sp + 2 * 8));
+
+ /* get the classinfo */
+
+ if (!(c = resolve_classref_eager(cr)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch the classinfo pointer */
+
+ *((ptrint *) (ra + 10 + 2)) = (ptrint) c;
+
+ return true;
+}
+
+
+/* patcher_builtin_arraycheckcast **********************************************
+
+ Machine code:
+
+ <patched call position>
+ 48 be b8 3f b2 00 00 00 00 00 mov $0xb23fb8,%rsi
+ 48 b8 00 00 00 00 00 00 00 00 mov $0x0,%rax
+ 48 ff d0 callq *%rax
+
+*******************************************************************************/
+
+bool patcher_builtin_arraycheckcast(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ constant_classref *cr;
+ classinfo *c;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ cr = (constant_classref *) *((ptrint *) (sp + 2 * 8));
+
+ /* get the classinfo */
+
+ if (!(c = resolve_classref_eager(cr)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch the classinfo pointer */
+
+ *((ptrint *) (ra + 2)) = (ptrint) c;
+
+ return true;
+}
+
+
+/* patcher_invokestatic_special ************************************************
+
+ Machine code:
+
+ <patched call position>
+ 49 ba 00 00 00 00 00 00 00 00 mov $0x0,%r10
+ 49 ff d2 callq *%r10
+
+*******************************************************************************/
+
+bool patcher_invokestatic_special(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ unresolved_method *um;
+ s4 disp;
+ methodinfo *m;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ um = (unresolved_method *) *((ptrint *) (sp + 2 * 8));
+ disp = *((s4 *) (sp + 1 * 8));
+
+ /* get the fieldinfo */
+
+ if (!(m = resolve_method_eager(um)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch stubroutine */
+
+/* *((ptrint *) (ra + 2)) = (ptrint) m->stubroutine; */
+ *((ptrint *) (ra + 7 + disp)) = (ptrint) m->stubroutine;
+
+ return true;
+}
+
+
+/* patcher_invokevirtual *******************************************************
+
+ Machine code:
+
+ <patched call position>
+ 4c 8b 17 mov (%rdi),%r10
+ 49 8b 82 00 00 00 00 mov 0x0(%r10),%rax
+ 48 ff d0 callq *%rax
+
+*******************************************************************************/
+
+bool patcher_invokevirtual(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ unresolved_method *um;
+ methodinfo *m;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ um = (unresolved_method *) *((ptrint *) (sp + 2 * 8));
+
+ /* get the fieldinfo */
+
+ if (!(m = resolve_method_eager(um)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch vftbl index */
+
+ *((s4 *) (ra + 3 + 3)) = (s4) (OFFSET(vftbl_t, table[0]) +
+ sizeof(methodptr) * m->vftblindex);
+
+ return true;
+}
+
+
+/* patcher_invokeinterface *****************************************************
+
+ Machine code:
+
+ <patched call position>
+ 4c 8b 17 mov (%rdi),%r10
+ 4d 8b 92 00 00 00 00 mov 0x0(%r10),%r10
+ 49 8b 82 00 00 00 00 mov 0x0(%r10),%rax
+ 48 ff d0 callq *%rax
+
+*******************************************************************************/
+
+bool patcher_invokeinterface(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ unresolved_method *um;
+ methodinfo *m;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ um = (unresolved_method *) *((ptrint *) (sp + 2 * 8));
+
+ /* get the fieldinfo */
+
+ if (!(m = resolve_method_eager(um)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch interfacetable index */
+
+ *((s4 *) (ra + 3 + 3)) = (s4) (OFFSET(vftbl_t, interfacetable[0]) -
+ sizeof(methodptr) * m->class->index);
+
+ /* patch method offset */
+
+ *((s4 *) (ra + 3 + 7 + 3)) =
+ (s4) (sizeof(methodptr) * (m - m->class->methods));
+
+ return true;
+}
+
+
+/* patcher_checkcast_instanceof_flags ******************************************
+
+ Machine code:
+
+ <patched call position>
+ 41 ba 00 00 00 00 mov $0x0,%r10d
+ 41 81 e2 00 02 00 00 and $0x200,%r10d
+ 0f 84 35 00 00 00 je 0x00002aaaaab01479
+
+*******************************************************************************/
+
+bool patcher_checkcast_instanceof_flags(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ constant_classref *cr;
+ classinfo *c;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ cr = (constant_classref *) *((ptrint *) (sp + 2 * 8));
+
+ /* get the fieldinfo */
+
+ if (!(c = resolve_classref_eager(cr)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch class flags */
+
+ *((s4 *) (ra + 2)) = (s4) c->flags;
+
+ return true;
+}
+
+
+/* patcher_checkcast_instanceof_interface **************************************
+
+ Machine code:
+
+ <patched call position>
+ 45 8b 9a 1c 00 00 00 mov 0x1c(%r10),%r11d
+ 49 81 eb 00 00 00 00 sub $0x0,%r11
+ 4d 85 db test %r11,%r11
+ 0f 8e 94 04 00 00 jle 0x00002aaaaab018f8
+ 4d 8b 9a 00 00 00 00 mov 0x0(%r10),%r11
+
+*******************************************************************************/
+
+bool patcher_checkcast_instanceof_interface(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ constant_classref *cr;
+ classinfo *c;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ cr = (constant_classref *) *((ptrint *) (sp + 2 * 8));
+
+ /* get the fieldinfo */
+
+ if (!(c = resolve_classref_eager(cr)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch super class index */
+
+ *((s4 *) (ra + 7 + 3)) = (s4) c->index;
+
+ *((s4 *) (ra + 7 + 7 + 3 + 6 + 3)) =
+ (s4) (OFFSET(vftbl_t, interfacetable[0]) -
+ c->index * sizeof(methodptr*));
+
+ return true;
+}
+
+
+/* patcher_checkcast_class *****************************************************
+
+ Machine code:
+
+ <patched call position>
+ 49 bb 00 00 00 00 00 00 00 00 mov $0x0,%r11
+ 45 8b 92 20 00 00 00 mov 0x20(%r10),%r10d
+ 45 8b 9b 20 00 00 00 mov 0x20(%r11),%r11d
+ 4d 29 da sub %r11,%r10
+ 49 bb 00 00 00 00 00 00 00 00 mov $0x0,%r11
+
+*******************************************************************************/
+
+bool patcher_checkcast_class(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ constant_classref *cr;
+ classinfo *c;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ cr = (constant_classref *) *((ptrint *) (sp + 2 * 8));
+
+ /* get the fieldinfo */
+
+ if (!(c = resolve_classref_eager(cr)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch super class' vftbl */
+
+ *((ptrint *) (ra + 2)) = (ptrint) c->vftbl;
+ *((ptrint *) (ra + 10 + 7 + 7 + 3 + 2)) = (ptrint) c->vftbl;
+
+ return true;
+}
+
+
+/* patcher_instanceof_class ****************************************************
+
+ Machine code:
+
+ <patched call position>
+ 49 ba 00 00 00 00 00 00 00 00 mov $0x0,%r10
+
+*******************************************************************************/
+
+bool patcher_instanceof_class(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ constant_classref *cr;
+ classinfo *c;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ cr = (constant_classref *) *((ptrint *) (sp + 2 * 8));
+
+ /* get the fieldinfo */
+
+ if (!(c = resolve_classref_eager(cr)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch super class' vftbl */
+
+ *((ptrint *) (ra + 2)) = (ptrint) c->vftbl;
+
+ return true;
+}
+
+
+/* patcher_clinit **************************************************************
+
+ May be used for GET/PUTSTATIC and in native stub.
+
+ Machine code:
+
+ <patched call position>
+ 4d 8b 15 92 ff ff ff mov -110(%rip),%r10
+ 49 89 1a mov %rbx,(%r10)
+
+*******************************************************************************/
+
+bool patcher_clinit(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ classinfo *c;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ c = (classinfo *) *((ptrint *) (sp + 2 * 8));
+
+ /* check if the class is initialized */
+
+ if (!(c->state & CLASS_INITIALIZED))
+ if (!initialize_class(c))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ return true;
+}
+
+
+/* patcher_athrow_areturn ******************************************************
+
+ Machine code:
+
+ <patched call position>
+
+*******************************************************************************/
+
+#ifdef ENABLE_VERIFIER
+bool patcher_athrow_areturn(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ unresolved_class *uc;
+ classinfo *c;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ uc = (unresolved_class *) *((ptrint *) (sp + 2 * 8));
+
+ /* resolve the class */
+
+ if (!resolve_class(uc, resolveEager, false, &c))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ return true;
+}
+#endif /* ENABLE_VERIFIER */
+
+
+/* patcher_resolve_native ******************************************************
+
+ Machine code:
+
+ <patched call position>
+ 48 b8 00 00 00 00 00 00 00 00 mov $0x0,%rax
+ 48 ff d0 callq *%rax
+
+*******************************************************************************/
+
+#if !defined(WITH_STATIC_CLASSPATH)
+bool patcher_resolve_native(u1 *sp)
+{
+ u1 *ra;
+ u8 mcode;
+ methodinfo *m;
+ functionptr f;
+
+ /* get stuff from the stack */
+
+ ra = (u1 *) *((ptrint *) (sp + 5 * 8));
+ mcode = *((u8 *) (sp + 3 * 8));
+ m = (methodinfo *) *((ptrint *) (sp + 2 * 8));
+
+ /* resolve native function */
+
+ if (!(f = native_resolve_function(m)))
+ return false;
+
+ /* patch back original code */
+
+ *((u8 *) ra) = mcode;
+
+ /* if we show disassembly, we have to skip the nop's */
+
+ if (opt_shownops)
+ ra = ra + 5;
+
+ /* patch native function pointer */
+
+ *((ptrint *) (ra + 2)) = (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:
+ */