From: tbfg Date: Thu, 6 Jul 2006 13:59:01 +0000 (+0000) Subject: powerpc64 compiles X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=f9ad61ac6c0b0a9d0552898672124e593e84574e;p=cacao.git powerpc64 compiles arch.h and md-abi.h: modified PV register assignment --HG-- rename : src/vm/jit/powerpc/Makefile.am => src/vm/jit/powerpc64/Makefile.am rename : src/vm/jit/powerpc/asmpart.S => src/vm/jit/powerpc64/asmpart.S rename : src/vm/jit/powerpc/codegen.c => src/vm/jit/powerpc64/codegen.c rename : src/vm/jit/powerpc/codegen.h => src/vm/jit/powerpc64/codegen.h rename : src/vm/jit/powerpc/disass.c => src/vm/jit/powerpc64/disass.c rename : src/vm/jit/powerpc/emit.c => src/vm/jit/powerpc64/emit.c rename : src/vm/jit/powerpc/linux/Makefile.am => src/vm/jit/powerpc64/linux/Makefile.am rename : src/vm/jit/powerpc/linux/md-abi.c => src/vm/jit/powerpc64/linux/md-abi.c rename : src/vm/jit/powerpc/linux/md-asm.h => src/vm/jit/powerpc64/linux/md-asm.h rename : src/vm/jit/powerpc/linux/md-os.c => src/vm/jit/powerpc64/linux/md-os.c rename : src/vm/jit/powerpc/machine-instr.h => src/vm/jit/powerpc64/machine-instr.h rename : src/vm/jit/powerpc/md.c => src/vm/jit/powerpc64/md.c rename : src/vm/jit/powerpc/patcher.c => src/vm/jit/powerpc64/patcher.c --- diff --git a/configure.ac b/configure.ac index 5a4896757..77be62674 100644 --- a/configure.ac +++ b/configure.ac @@ -340,7 +340,7 @@ if test x"${ENABLE_DISASSEMBLER}" = "xyes"; then dnl check for binutils headers and libraries on some architectures for the dnl disassembler case "${ARCH_DIR}" in - arm | i386 | powerpc | x86_64 | sparc64 ) + arm | i386 | powerpc | x86_64 | sparc64 | powerpc64) 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)]) @@ -818,6 +818,8 @@ AC_CONFIG_FILES([Makefile] [src/vm/jit/powerpc/darwin/Makefile] [src/vm/jit/powerpc/linux/Makefile] [src/vm/jit/powerpc/netbsd/Makefile] + [src/vm/jit/powerpc64/Makefile] + [src/vm/jit/powerpc64/linux/Makefile] [src/vm/jit/profile/Makefile] [src/vm/jit/schedule/Makefile] [src/vm/jit/sparc64/Makefile] diff --git a/src/vm/jit/patcher.h b/src/vm/jit/patcher.h index 03919780c..6aba53588 100644 --- a/src/vm/jit/patcher.h +++ b/src/vm/jit/patcher.h @@ -28,7 +28,7 @@ Changes: Edwin Steiner - $Id: patcher.h 5077 2006-07-04 19:06:56Z twisti $ + $Id: patcher.h 5081 2006-07-06 13:59:01Z tbfg $ */ @@ -150,7 +150,7 @@ bool patcher_checkcast_instanceof_flags(u1 *sp); bool patcher_checkcast_instanceof_interface(u1 *sp); #define PATCHER_checkcast_instanceof_interface (functionptr) patcher_checkcast_instanceof_interface -#if defined(__I386__) || defined(__X86_64__) || defined(__POWERPC__) +#if defined(__I386__) || defined(__X86_64__) || defined(__POWERPC__) || defined(__POWERPC64__) bool patcher_checkcast_class(u1 *sp); #define PATCHER_checkcast_class (functionptr) patcher_checkcast_class @@ -158,12 +158,12 @@ bool patcher_checkcast_class(u1 *sp); bool patcher_instanceof_class(u1 *sp); #define PATCHER_instanceof_class (functionptr) patcher_instanceof_class -#else /* defined(__I386__) || defined(__X86_64__) || defined(__POWERPC__) */ +#else /* defined(__I386__) || defined(__X86_64__) || defined(__POWERPC__) || defined(__POWERPC64__)*/ bool patcher_checkcast_instanceof_class(u1 *sp); #define PATCHER_checkcast_instanceof_class (functionptr) patcher_checkcast_instanceof_class -#endif /* defined(__I386__) || defined(__X86_64__) || defined(__POWERPC__) */ +#endif /* defined(__I386__) || defined(__X86_64__) || defined(__POWERPC__) || defined(__POWERPC64__)*/ bool patcher_clinit(u1 *sp); #define PATCHER_clinit (functionptr) patcher_clinit diff --git a/src/vm/jit/powerpc64/Makefile.am b/src/vm/jit/powerpc64/Makefile.am new file mode 100644 index 000000000..84504b822 --- /dev/null +++ b/src/vm/jit/powerpc64/Makefile.am @@ -0,0 +1,84 @@ +## src/vm/jit/powerpc/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 5081 2006-07-06 13:59:01Z tbfg $ + +## Process this file with automake to produce Makefile.in + +DIST_SUBDIRS = \ + linux + +SUBDIRS = $(OS_DIR) + +AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir) -I$(top_builddir)/src -I$(top_srcdir)/src/vm/jit/$(ARCH_DIR)/$(OS_DIR) +AM_CCASFLAGS = $(AM_CPPFLAGS) + +LIBS = + +BUILT_SOURCES = offsets.h + +CLEANFILES = offsets.h + +noinst_HEADERS = \ + arch.h \ + machine-instr.h + +noinst_LTLIBRARIES = libarch.la + +if ENABLE_DISASSEMBLER +DISASS_SOURCES = \ + disass.c +endif + +libarch_la_SOURCES = \ + asmpart.S \ + codegen.c \ + codegen.h \ + $(DISASS_SOURCES) \ + emit.c \ + md.c \ + patcher.c + +libarch_la_LIBADD = \ + $(OS_DIR)/libmd.la + +$(srcdir)/asmpart.S: $(top_builddir)/config.h offsets.h + +offsets.h: $(top_builddir)/src/vm/jit/tools/genoffsets $(top_builddir)/config.h + $(top_builddir)/src/vm/jit/tools/genoffsets > offsets.h + + +## Local variables: +## mode: Makefile +## indent-tabs-mode: t +## c-basic-offset: 4 +## tab-width: 8 +## compile-command: "automake --add-missing" +## End: diff --git a/src/vm/jit/powerpc64/arch.h b/src/vm/jit/powerpc64/arch.h index 5f0853409..bc5bea25e 100644 --- a/src/vm/jit/powerpc64/arch.h +++ b/src/vm/jit/powerpc64/arch.h @@ -28,7 +28,7 @@ Changes: - $Id: arch.h 4912 2006-05-14 12:22:25Z edwin $ + $Id: arch.h 5081 2006-07-06 13:59:01Z tbfg $ */ @@ -51,17 +51,17 @@ #define SUPPORT_FMOD 0 #define SUPPORT_FICVT 1 -#define SUPPORT_IFCVT 0 +#define SUPPORT_IFCVT 1 #define SUPPORT_LONG_ADD 1 #define SUPPORT_LONG_CMP 1 #define SUPPORT_LONG_CMP_CONST 1 #define SUPPORT_LONG_LOGICAL 1 -#define SUPPORT_LONG_SHIFT 0 -#define SUPPORT_LONG_MUL 0 -#define SUPPORT_LONG_DIV 0 -#define SUPPORT_LONG_ICVT 0 -#define SUPPORT_LONG_FCVT 0 +#define SUPPORT_LONG_SHIFT 1 +#define SUPPORT_LONG_MUL 1 +#define SUPPORT_LONG_DIV 1 +#define SUPPORT_LONG_ICVT 1 +#define SUPPORT_LONG_FCVT 1 #define SUPPORT_CONST_LOGICAL 1 /* AND, OR, XOR with immediates */ #define SUPPORT_CONST_MUL 1 /* mutiply with immediate */ diff --git a/src/vm/jit/powerpc64/asmpart.S b/src/vm/jit/powerpc64/asmpart.S new file mode 100644 index 000000000..ae9a00fa2 --- /dev/null +++ b/src/vm/jit/powerpc64/asmpart.S @@ -0,0 +1,1581 @@ +/* src/vm/jit/powerpc/asmpart.S - Java-C interface functions for PowerPC + + 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.text; 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 + Stefan Ring + + Changes: Christian Thalinger + Edwin Steiner + + $Id: asmpart.S 5081 2006-07-06 13:59:01Z tbfg $ + +*/ + + +#include "config.h" + +#include "md-abi.h" +#include "md-asm.h" + +#include "vm/jit/abi-asm.h" +#include "vm/jit/methodheader.h" +#include "vm/jit/powerpc64/offsets.h" + + + .text + + .align 2 + + +/* export functions ***********************************************************/ + + .globl asm_vm_call_method + .globl asm_vm_call_method_int + .globl asm_vm_call_method_long + .globl asm_vm_call_method_float + .globl asm_vm_call_method_double + + .globl asm_vm_call_method_exception_handler + + .globl asm_call_jit_compiler + + .globl asm_handle_nat_exception + .globl asm_handle_exception + + .globl asm_abstractmethoderror + + .globl asm_wrapper_patcher + + .globl asm_replacement_out + .globl asm_replacement_in + + .globl asm_cacheflush + .globl asm_criticalsections + .globl asm_getclassvalues_atomic + + +/* asm_vm_call_method ********************************************************** +* * +* This function calls a Java-method (which possibly needs compilation) * +* with up to 4 address parameters. * +* * +* This functions calls the JIT-compiler which eventually translates the * +* method into machine code. * +* * +* C-prototype: * +* javaobject_header *asm_calljavamethod (methodinfo *m, * +* void *arg1, void *arg2, void *arg3, void *arg4); * +* * +*******************************************************************************/ + + .align 2 + + .long 0 /* catch type all */ + .long 0 /* exception handler pc */ + .long 0 /* end pc */ + .long 0 /* start pc */ + .long 1 /* extable size */ + .long 0 /* line number table start */ + .long 0 /* line number table size */ + .long 0 /* fltsave */ + .long 0 /* intsave */ + .long 0 /* isleaf */ + .long 0 /* IsSync */ + .long 0 /* frame size */ + .long 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: + mflr r0 + stw r0,LA_LR_OFFSET(r1) + stwu r1,-40*4(r1) + + stw s0,8*4(sp) /* save used callee saved registers */ + stw a0,9*4(sp) /* save method pointer for compiler */ + +#if defined(__DARWIN__) + stw itmp1,10*4(sp) /* register r11 is callee saved */ +#endif + stw pv,11*4(sp) /* save PV register */ + + stw itmp3,12*4(sp) /* registers r14-r31 are callee saved */ + stfd ftmp1,14*4(sp) /* registers f14-f31 are callee saved */ + stfd ftmp2,16*4(sp) + +#if defined(__DARWIN__) + stw t1,18*4(r1) + stw t2,19*4(r1) + stw t3,20*4(r1) + stw t4,21*4(r1) + stw t5,22*4(r1) + stw t6,23*4(r1) + stw t7,24*4(r1) + + stfd ft0,26*4(r1) + stfd ft1,28*4(r1) + stfd ft2,30*4(r1) + stfd ft3,32*4(r1) + stfd ft4,34*4(r1) + stfd ft5,36*4(r1) +#else + SAVE_TEMPORARY_REGISTERS(18) /* the offset has to be even */ +#endif + + mr itmp2,a1 /* arg count */ + mr itmp1,a2 /* pointer to arg block */ + + mr t4,itmp2 /* save argument count */ + mr t5,itmp1 /* save argument block pointer */ + + mr s0,sp /* save current sp to s0 */ + + addi itmp1,itmp1,-sizevmarg /* initialize pointer (smaller code) */ + addi itmp2,itmp2,1 /* initialize argument count */ + li t0,0 /* initialize integer argument counter */ + li t1,0 /* initialize float argument counter */ + li t6,0 /* initialize integer register counter */ +#if defined(__DARWIN__) + li t7,0 /* initialize stack slot counter */ +#endif + + mflr r0 /* save link register (PIC code) */ + bl L_asm_vm_call_method_get_pc +L_asm_vm_call_method_get_pc: + mflr t3 /* t3 contains the current pc */ + mtlr r0 + +L_register_copy: + addi itmp1,itmp1,sizevmarg /* goto next argument block */ + addi itmp2,itmp2,-1 /* argument count - 1 */ + mr. itmp2,itmp2 + beq L_register_copy_done + + lwz itmp3,offvmargtype+4(itmp1) + andi. r0,itmp3,0x0002 /* is this a float/double type? */ + bne L_register_handle_float + +L_register_handle_int: + cmpwi t6,INT_ARG_CNT /* are we out of integer argument */ + beq L_register_copy /* registers? yes, next loop */ + + andi. r0,itmp3,0x0001 /* is this a 2-word type? */ + bne L_register_handle_long + +#if defined(__DARWIN__) + addis itmp3,t3,ha16(L_jumptable_int - L_asm_vm_call_method_get_pc) + la itmp3,lo16(L_jumptable_int - L_asm_vm_call_method_get_pc)(itmp3) +#else + lis itmp3,L_jumptable_int@ha + addi itmp3,itmp3,L_jumptable_int@l +#endif + + slwi t2,t6,2 /* multiple of 4-bytes */ + add itmp3,itmp3,t2 /* calculate address of jumptable */ + lwz itmp3,0(itmp3) /* load function address */ + mtctr itmp3 + addi t0,t0,1 /* integer argument counter */ + addi t6,t6,1 /* integer argument register counter */ +#if defined(__DARWIN__) + addi t7,t7,1 /* stack slot counter */ +#endif + bctr + +L_register_handle_long: +#if defined(__DARWIN__) + addis itmp3,t3,ha16(L_jumptable_long - L_asm_vm_call_method_get_pc) + la itmp3,lo16(L_jumptable_long - L_asm_vm_call_method_get_pc)(itmp3) +#else + lis itmp3,L_jumptable_long@ha + addi itmp3,itmp3,L_jumptable_long@l +#endif +#if !defined(__DARWIN__) + addi t6,t6,1 /* align to even numbers */ + andi. t6,t6,0xfffe +#endif + + cmpwi t6,(INT_ARG_CNT - 1) /* are we out of integer argument */ + blt L_register_handle_long_continue /* registers? */ + + li t6,INT_ARG_CNT /* yes, set integer argument register */ + b L_register_copy /* count to max and next loop */ + +L_register_handle_long_continue: + slwi t2,t6,2 /* multiple of 4-bytes */ + add itmp3,itmp3,t2 /* calculate address of jumptable */ + lwz itmp3,0(itmp3) /* load function address */ + mtctr itmp3 + addi t0,t0,1 /* integer argument counter */ + addi t6,t6,2 /* integer argument register counter */ +#if defined(__DARWIN__) + addi t7,t7,2 /* stack slot counter */ +#endif + bctr + +L_register_handle_float: + cmpwi t1,FLT_ARG_CNT /* are we out of float argument */ + beq L_register_copy /* registers? yes, next loop */ + + andi. r0,itmp3,0x0001 /* is this a 2-word type? */ + bne L_register_handle_double + +#if defined(__DARWIN__) + addis itmp3,t3,ha16(L_jumptable_float - L_asm_vm_call_method_get_pc) + la itmp3,lo16(L_jumptable_float - L_asm_vm_call_method_get_pc)(itmp3) +#else + lis itmp3,L_jumptable_float@ha + addi itmp3,itmp3,L_jumptable_float@l +#endif + + slwi t2,t1,2 /* multiple of 4-bytes */ + add itmp3,itmp3,t2 /* calculate address of jumptable */ + lwz itmp3,0(itmp3) /* load function address */ + mtctr itmp3 + addi t1,t1,1 /* float argument counter */ +#if defined(__DARWIN__) + addi t7,t7,1 /* stack slot counter */ + addi t6,t6,1 /* skip 1 integer argument register */ +#endif + bctr + +L_register_handle_double: +#if defined(__DARWIN__) + addis itmp3,t3,ha16(L_jumptable_double - L_asm_vm_call_method_get_pc) + la itmp3,lo16(L_jumptable_double - L_asm_vm_call_method_get_pc)(itmp3) +#else + lis itmp3,L_jumptable_double@ha + addi itmp3,itmp3,L_jumptable_double@l +#endif + + slwi t2,t1,2 /* multiple of 4-bytes */ + add itmp3,itmp3,t2 /* calculate address of jumptable */ + lwz itmp3,0(itmp3) /* load function address */ + mtctr itmp3 + addi t1,t1,1 /* float argument counter */ +#if defined(__DARWIN__) + addi t7,t7,2 /* stack slot counter */ + addi t6,t6,2 /* skip 2 integer argument registers */ +#endif + bctr + +L_register_copy_done: + /* calculate remaining arguments */ + sub itmp3,t4,t0 /* - integer arguments in registers */ + sub itmp3,itmp3,t1 /* - float arguments in registers */ + mr. itmp3,itmp3 + beq L_stack_copy_done + + mr itmp2,t4 /* restore argument count */ + mr itmp1,t5 /* restore argument block pointer */ + + slwi t4,itmp3,3 /* XXX use 8-bytes slots for now */ + addi t4,t4,LA_SIZE /* add size of linkage area */ + +#if defined(__DARWIN__) + slwi t5,t7,2 /* add stack space for arguments */ + add t4,t4,t5 +#endif + + sub sp,sp,t4 + + mr t6,sp /* use t6 as temporary sp */ + addi t6,t6,LA_SIZE /* skip linkage area */ +#if defined(__DARWIN__) + add t6,t6,t5 /* skip stack space for arguments */ +#endif + + addi itmp1,itmp1,-sizevmarg /* initialize pointer (smaller code) */ + addi itmp2,itmp2,1 /* initialize argument count */ + +L_stack_copy_loop: + addi itmp1,itmp1,sizevmarg /* goto next argument block */ + addi itmp2,itmp2,-1 /* argument count - 1 */ + mr. itmp2,itmp2 + beq L_stack_copy_done + + lwz itmp3,offvmargtype+4(itmp1) + andi. r0,itmp3,0x0002 /* is this a float/double type? */ + bne L_stack_handle_float + +L_stack_handle_int: + addi t0,t0,-1 /* arguments assigned to registers */ + mr. t0,t0 + bge L_stack_copy_loop + + andi. r0,itmp3,0x0001 /* is this a 2-word type? */ + bne L_stack_handle_long + + lwz itmp3,offvmargdata+4(itmp1) /* get integer argument */ + stw itmp3,0(t6) /* and store it on the stack */ + addi t6,t6,4 /* increase temporary sp by 1 slot */ + b L_stack_copy_loop + +L_stack_handle_long: +#if !defined(__DARWIN__) + addi t6,t6,4 /* align stack to 8-bytes */ + rlwinm t6,t6,0,30,28 /* clear lower 4-bits */ +#endif + + lwz itmp3,offvmargdata+0(itmp1) /* get long argument */ + stw itmp3,0(t6) /* and store it on the stack */ + lwz itmp3,offvmargdata+4(itmp1) + stw itmp3,4(t6) + addi t6,t6,8 /* increase temporary sp by 2 slots */ + b L_stack_copy_loop + +L_stack_handle_float: + addi t1,t1,-1 /* arguments assigned to registers */ + mr. t1,t1 + bge L_stack_copy_loop + + andi. r0,itmp3,0x0001 /* is this a 2-word type? */ + bne L_stack_handle_double + + lfs ftmp3,offvmargdata(itmp1) /* get float argument */ + stfs ftmp3,0(t6) /* and store it on the stack */ + addi t6,t6,4 /* increase temporary sp by 1 slot */ + b L_stack_copy_loop + +L_stack_handle_double: +#if !defined(__DARWIN__) + addi t6,t6,4 /* align stack to 8-bytes */ + rlwinm t6,t6,0,30,28 /* clear lower 4-bits */ +#endif + + lfd ftmp3,offvmargdata(itmp1) /* get double argument */ + stfd ftmp3,0(t6) /* and store it on the stack */ + addi t6,t6,8 /* increase temporary sp by 2 slots */ + b L_stack_copy_loop + +L_stack_copy_done: + lwz itmp1,9*4(s0) /* pass method pointer via tmp1 */ + +#if defined(__DARWIN__) + addis mptr,t3,ha16(L_asm_call_jit_compiler - L_asm_vm_call_method_get_pc) + la mptr,lo16(L_asm_call_jit_compiler - L_asm_vm_call_method_get_pc)(mptr) +#else + lis mptr,L_asm_call_jit_compiler@ha + addi mptr,mptr,L_asm_call_jit_compiler@l +#endif + stw mptr,7*4(s0) + addi mptr,s0,7*4 + + lwz pv,0*4(mptr) + mtctr pv + bctrl +1: + mflr itmp1 +#if defined(__DARWIN__) + addi pv,itmp1,lo16(asm_vm_call_method - 1b) +#else + addi pv,itmp1,(asm_vm_call_method - 1b)@l +#endif + +L_asm_vm_call_method_return: + mr sp,s0 /* restore the function's sp */ + + lwz s0,8*4(sp) /* restore used callee saved registers */ + +#if defined(__DARWIN__) + lwz itmp1,10*4(sp) /* register r11 is callee saved */ +#endif + lwz pv,11*4(sp) /* save PV register */ + + lwz itmp3,12*4(sp) + lfd ftmp1,14*4(sp) /* registers f14-f31 are callee saved */ + lfd ftmp2,16*4(sp) + +#if defined(__DARWIN__) + lwz t1,18*4(r1) + lwz t2,19*4(r1) + lwz t3,20*4(r1) + lwz t4,21*4(r1) + lwz t5,22*4(r1) + lwz t6,23*4(r1) + lwz t7,24*4(r1) + + lfd ft0,26*4(r1) + lfd ft1,28*4(r1) + lfd ft2,30*4(r1) + lfd ft3,32*4(r1) + lfd ft4,34*4(r1) + lfd ft5,36*4(r1) +#else + RESTORE_TEMPORARY_REGISTERS(18) /* the offset has to be even */ +#endif + + lwz r0,40*4+LA_LR_OFFSET(r1) + mtlr r0 + addi r1,r1,40*4 + blr + +asm_vm_call_method_exception_handler: + mr r3,itmp1 + bl builtin_throw_exception + b L_asm_vm_call_method_return + + + .data + .align 2 + +L_jumptable_int: + .long L_handle_a0 + .long L_handle_a1 + .long L_handle_a2 + .long L_handle_a3 + .long L_handle_a4 + .long L_handle_a5 + .long L_handle_a6 + .long L_handle_a7 + + .text + .align 2 + +L_handle_a0: + lwz a0,offvmargdata+4(itmp1) + b L_register_copy +L_handle_a1: + lwz a1,offvmargdata+4(itmp1) + b L_register_copy +L_handle_a2: + lwz a2,offvmargdata+4(itmp1) + b L_register_copy +L_handle_a3: + lwz a3,offvmargdata+4(itmp1) + b L_register_copy +L_handle_a4: + lwz a4,offvmargdata+4(itmp1) + b L_register_copy +L_handle_a5: + lwz a5,offvmargdata+4(itmp1) + b L_register_copy +L_handle_a6: + lwz a6,offvmargdata+4(itmp1) + b L_register_copy +L_handle_a7: + lwz a7,offvmargdata+4(itmp1) + b L_register_copy + + + .data + .align 2 + +L_jumptable_long: +#if defined(__DARWIN__) + .long L_handle_a0_a1 + .long L_handle_a1_a2 + .long L_handle_a2_a3 + .long L_handle_a3_a4 + .long L_handle_a4_a5 + .long L_handle_a5_a6 + .long L_handle_a6_a7 +#else + /* we have two entries here, so we get the even argument register + alignment for linux */ + + .long L_handle_a0_a1 + .long 0 + .long L_handle_a2_a3 + .long 0 + .long L_handle_a4_a5 + .long 0 + .long L_handle_a6_a7 +#endif + + .text + .align 2 + +L_handle_a0_a1: + lwz a0,offvmargdata+0(itmp1) + lwz a1,offvmargdata+4(itmp1) + b L_register_copy +#if defined(__DARWIN__) +L_handle_a1_a2: + lwz a1,offvmargdata+0(itmp1) + lwz a2,offvmargdata+4(itmp1) + b L_register_copy +#endif +L_handle_a2_a3: + lwz a2,offvmargdata+0(itmp1) + lwz a3,offvmargdata+4(itmp1) + b L_register_copy +#if defined(__DARWIN__) +L_handle_a3_a4: + lwz a3,offvmargdata+0(itmp1) + lwz a4,offvmargdata+4(itmp1) + b L_register_copy +#endif +L_handle_a4_a5: + lwz a4,offvmargdata+0(itmp1) + lwz a5,offvmargdata+4(itmp1) + b L_register_copy +#if defined(__DARWIN__) +L_handle_a5_a6: + lwz a5,offvmargdata+0(itmp1) + lwz a6,offvmargdata+4(itmp1) + b L_register_copy +#endif +L_handle_a6_a7: + lwz a6,offvmargdata+0(itmp1) + lwz a7,offvmargdata+4(itmp1) + b L_register_copy + + + .data + .align 2 + +L_jumptable_float: + .long L_handle_fa0 + .long L_handle_fa1 + .long L_handle_fa2 + .long L_handle_fa3 + .long L_handle_fa4 + .long L_handle_fa5 + .long L_handle_fa6 + .long L_handle_fa7 + +#if defined(__DARWIN__) + .long L_handle_fa8 + .long L_handle_fa9 + .long L_handle_fa10 + .long L_handle_fa11 + .long L_handle_fa12 +#endif + + .text + .align 2 + +L_handle_fa0: + lfs fa0,offvmargdata(itmp1) + b L_register_copy +L_handle_fa1: + lfs fa1,offvmargdata(itmp1) + b L_register_copy +L_handle_fa2: + lfs fa2,offvmargdata(itmp1) + b L_register_copy +L_handle_fa3: + lfs fa3,offvmargdata(itmp1) + b L_register_copy +L_handle_fa4: + lfs fa4,offvmargdata(itmp1) + b L_register_copy +L_handle_fa5: + lfs fa5,offvmargdata(itmp1) + b L_register_copy +L_handle_fa6: + lfs fa6,offvmargdata(itmp1) + b L_register_copy +L_handle_fa7: + lfs fa7,offvmargdata(itmp1) + b L_register_copy + +#if defined(__DARWIN__) +L_handle_fa8: + lfs fa8,offvmargdata(itmp1) + b L_register_copy +L_handle_fa9: + lfs fa9,offvmargdata(itmp1) + b L_register_copy +L_handle_fa10: + lfs fa10,offvmargdata(itmp1) + b L_register_copy +L_handle_fa11: + lfs fa11,offvmargdata(itmp1) + b L_register_copy +L_handle_fa12: + lfs fa12,offvmargdata(itmp1) + b L_register_copy +#endif + + + .data + .align 2 + +L_jumptable_double: + .long L_handle_fda0 + .long L_handle_fda1 + .long L_handle_fda2 + .long L_handle_fda3 + .long L_handle_fda4 + .long L_handle_fda5 + .long L_handle_fda6 + .long L_handle_fda7 + +#if defined(__DARWIN__) + .long L_handle_fda8 + .long L_handle_fda9 + .long L_handle_fda10 + .long L_handle_fda11 + .long L_handle_fda12 +#endif + + .text + .align 2 + +L_handle_fda0: + lfd fa0,offvmargdata(itmp1) + b L_register_copy +L_handle_fda1: + lfd fa1,offvmargdata(itmp1) + b L_register_copy +L_handle_fda2: + lfd fa2,offvmargdata(itmp1) + b L_register_copy +L_handle_fda3: + lfd fa3,offvmargdata(itmp1) + b L_register_copy +L_handle_fda4: + lfd fa4,offvmargdata(itmp1) + b L_register_copy +L_handle_fda5: + lfd fa5,offvmargdata(itmp1) + b L_register_copy +L_handle_fda6: + lfd fa6,offvmargdata(itmp1) + b L_register_copy +L_handle_fda7: + lfd fa7,offvmargdata(itmp1) + b L_register_copy + +#if defined(__DARWIN__) +L_handle_fda8: + lfd fa8,offvmargdata(itmp1) + b L_register_copy +L_handle_fda9: + lfd fa9,offvmargdata(itmp1) + b L_register_copy +L_handle_fda10: + lfd fa10,offvmargdata(itmp1) + b L_register_copy +L_handle_fda11: + lfd fa11,offvmargdata(itmp1) + b L_register_copy +L_handle_fda12: + lfd fa12,offvmargdata(itmp1) + b L_register_copy +#endif + + +/* asm_call_jit_compiler ******************************************************* + + Invokes the compiler for untranslated JavaVM methods. + +*******************************************************************************/ + +asm_call_jit_compiler: +L_asm_call_jit_compiler: /* required for PIC code */ + mflr r0 + stw r0,LA_LR_OFFSET(r1) /* save return address */ + stwu r1,-(LA_SIZE + 5*4 + INT_ARG_CNT*4 + FLT_ARG_CNT*8)(r1) + +#if defined(__DARWIN__) + stw a0,(LA_WORD_SIZE+5+0)*4(r1) + stw a1,(LA_WORD_SIZE+5+1)*4(r1) + stw a2,(LA_WORD_SIZE+5+2)*4(r1) + stw a3,(LA_WORD_SIZE+5+3)*4(r1) + stw a4,(LA_WORD_SIZE+5+4)*4(r1) + stw a5,(LA_WORD_SIZE+5+5)*4(r1) + stw a6,(LA_WORD_SIZE+5+6)*4(r1) + stw a7,(LA_WORD_SIZE+5+7)*4(r1) + + stfd fa0,(LA_WORD_SIZE+5+8)*4(r1) + stfd fa1,(LA_WORD_SIZE+5+10)*4(r1) + stfd fa2,(LA_WORD_SIZE+5+12)*4(r1) + stfd fa3,(LA_WORD_SIZE+5+14)*4(r1) + stfd fa4,(LA_WORD_SIZE+5+16)*4(r1) + stfd fa5,(LA_WORD_SIZE+5+18)*4(r1) + stfd fa6,(LA_WORD_SIZE+5+20)*4(r1) + stfd fa7,(LA_WORD_SIZE+5+22)*4(r1) + stfd fa8,(LA_WORD_SIZE+5+24)*4(r1) + stfd fa9,(LA_WORD_SIZE+5+26)*4(r1) + stfd fa10,(LA_WORD_SIZE+5+28)*4(r1) + stfd fa11,(LA_WORD_SIZE+5+30)*4(r1) + stfd fa12,(LA_WORD_SIZE+5+32)*4(r1) +#else + SAVE_ARGUMENT_REGISTERS(LA_WORD_SIZE+1) +#endif + + mr a0,itmp1 + mr a1,mptr + addi a2,sp,(LA_SIZE + 5*4 + INT_ARG_CNT*4 + FLT_ARG_CNT*8) + lwz a3,(LA_SIZE + 5*4 + INT_ARG_CNT*4 + FLT_ARG_CNT*8)+LA_LR_OFFSET(sp) + bl jit_asm_compile + mr pv,v0 /* move address to pv register */ + +#if defined(__DARWIN__) + lwz a0,(LA_WORD_SIZE+5+0)*4(r1) + lwz a1,(LA_WORD_SIZE+5+1)*4(r1) + lwz a2,(LA_WORD_SIZE+5+2)*4(r1) + lwz a3,(LA_WORD_SIZE+5+3)*4(r1) + lwz a4,(LA_WORD_SIZE+5+4)*4(r1) + lwz a5,(LA_WORD_SIZE+5+5)*4(r1) + lwz a6,(LA_WORD_SIZE+5+6)*4(r1) + lwz a7,(LA_WORD_SIZE+5+7)*4(r1) + + lfd fa0,(LA_WORD_SIZE+5+8)*4(r1) + lfd fa1,(LA_WORD_SIZE+5+10)*4(r1) + lfd fa2,(LA_WORD_SIZE+5+12)*4(r1) + lfd fa3,(LA_WORD_SIZE+5+14)*4(r1) + lfd fa4,(LA_WORD_SIZE+5+16)*4(r1) + lfd fa5,(LA_WORD_SIZE+5+18)*4(r1) + lfd fa6,(LA_WORD_SIZE+5+20)*4(r1) + lfd fa7,(LA_WORD_SIZE+5+22)*4(r1) + lfd fa8,(LA_WORD_SIZE+5+24)*4(r1) + lfd fa9,(LA_WORD_SIZE+5+26)*4(r1) + lfd fa10,(LA_WORD_SIZE+5+28)*4(r1) + lfd fa11,(LA_WORD_SIZE+5+30)*4(r1) + lfd fa12,(LA_WORD_SIZE+5+32)*4(r1) +#else + RESTORE_ARGUMENT_REGISTERS(LA_WORD_SIZE+1) +#endif + + lwz itmp1,(LA_SIZE + 5*4 + INT_ARG_CNT*4 + FLT_ARG_CNT*8)+LA_LR_OFFSET(r1) + mtlr itmp1 + + addi sp,sp,(LA_SIZE + 5*4 + INT_ARG_CNT*4 + FLT_ARG_CNT*8) + + mr. pv,pv /* test for exception */ + beq L_asm_call_jit_compiler_exception + + mtctr pv /* move method address to control reg */ + bctr /* and call the Java method */ + +L_asm_call_jit_compiler_exception: + mflr r0 + stw r0,LA_LR_OFFSET(sp) + stwu sp,-LA_SIZE_ALIGNED(sp) /* preserve linkage area */ + bl exceptions_get_and_clear_exception + lwz xpc,LA_SIZE_ALIGNED+LA_LR_OFFSET(sp) + mtlr xpc + addi sp,sp,LA_SIZE_ALIGNED + + mr xptr,v0 /* get exception */ + addi xpc,xpc,-4 /* exception address is ra - 4 */ + b L_asm_handle_nat_exception + + +/********************* function asm_handle_exception *************************** +* * +* This function handles an exception. It does not use the usual calling * +* conventions. The exception pointer is passed in REG_ITMP1 and the * +* pc from the exception raising position is passed in REG_ITMP2. It searches * +* the local exception table for a handler. If no one is found, it unwinds * +* stacks and continues searching the callers. * +* * +* void asm_handle_exception (exceptionptr, exceptionpc); * +* * +*******************************************************************************/ + +asm_handle_nat_exception: +L_asm_handle_nat_exception: /* required for PIC code */ + mflr r9 + lwz itmp3,4(r9) + extsh itmp3,itmp3 + add pv,itmp3,r9 + lwz itmp3,8(r9) + srwi itmp3,itmp3,16 + cmpwi itmp3,0x3dad + bne L_asm_handle_exception + lwz itmp3,8(r9) + slwi itmp3,itmp3,16 + add pv,pv,itmp3 + +asm_handle_exception: +L_asm_handle_exception: /* required for PIC code */ + addi sp,sp,-(ARG_CNT+TMP_CNT)*8 /* create maybe-leaf stackframe */ + +#if defined(__DARWIN__) +#else + SAVE_ARGUMENT_REGISTERS(0) /* we save arg and temp registers in */ + SAVE_TEMPORARY_REGISTERS(ARG_CNT) /* case this is a leaf method */ +#endif + + li a3,(ARG_CNT+TMP_CNT)*8 /* prepare a3 for handle_exception */ + li a4,1 /* set maybe-leaf flag */ + +L_asm_handle_exception_stack_loop: + addi sp,sp,-(LA_WORD_SIZE+4+5)*4 /* allocate stack */ + stw xptr,LA_SIZE+4*4(sp) /* save exception pointer */ + stw xpc,LA_SIZE+5*4(sp) /* save exception pc */ + stw pv,LA_SIZE+6*4(sp) /* save data segment pointer */ + mflr r0 /* save return address */ + stw r0,LA_SIZE+5*4(sp) + add a3,a3,sp /* calculate Java sp into a3... */ + addi a3,a3,(LA_WORD_SIZE+4+5)*4 + stw a4,LA_SIZE+8*4(sp) /* save maybe-leaf flag */ + + mr a0,xptr /* pass exception pointer */ + mr a1,xpc /* pass exception pc */ + mr a2,pv /* pass data segment pointer */ + /* a3 is still set */ + bl exceptions_handle_exception + + mr. v0,v0 + beq L_asm_handle_exception_not_catched + + mr xpc,v0 /* move handlerpc into xpc */ + lwz xptr,LA_SIZE+4*4(sp) /* restore exception pointer */ + lwz pv,LA_SIZE+6*4(sp) /* restore data segment pointer */ + lwz r0,LA_SIZE+5*4(sp) /* restore return address */ + mtlr r0 + lwz a4,LA_SIZE+8*4(sp) /* get maybe-leaf flag */ + addi sp,sp,(LA_WORD_SIZE+4+5)*4 /* free stack frame */ + + mr. a4,a4 + beq L_asm_handle_exception_no_leaf + +#if defined(__DARWIN__) +#else + RESTORE_ARGUMENT_REGISTERS(0) /* if this is a leaf method, we have */ + RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers */ +#endif + + addi sp,sp,(ARG_CNT+TMP_CNT)*8 /* remove maybe-leaf stackframe */ + +L_asm_handle_exception_no_leaf: + mtctr xpc /* jump to the handler */ + bctr + +L_asm_handle_exception_not_catched: + lwz xptr,LA_SIZE+4*4(sp) /* restore exception pointer */ + lwz pv,LA_SIZE+6*4(sp) /* restore data segment pointer */ + lwz r0,LA_SIZE+5*4(sp) /* restore return address */ + mtlr r0 + lwz a4,LA_SIZE+8*4(sp) /* get maybe-leaf flag */ + addi sp,sp,(LA_WORD_SIZE+4+5)*4 /* free stack frame */ + + mr. a4,a4 + beq L_asm_handle_exception_no_leaf_stack + + addi sp,sp,(ARG_CNT+TMP_CNT)*8 /* remove maybe-leaf stackframe */ + li a4,0 /* clear the maybe-leaf flag */ + +L_asm_handle_exception_no_leaf_stack: + lwz t0,FrameSize(pv) /* get frame size */ + add t0,sp,t0 /* pointer to save area */ + + lwz t1,IsLeaf(pv) /* is leaf procedure */ + mr. t1,t1 + bne L_asm_handle_exception_no_ra_restore + + lwz r0,LA_LR_OFFSET(t0) /* restore ra */ + mtlr r0 + +L_asm_handle_exception_no_ra_restore: + mflr xpc /* the new xpc is ra */ + lwz t1,IntSave(pv) /* t1 = saved int register count */ + bl ex_int1 +ex_int1: + mflr t2 /* t2 = current pc */ +#if defined(__DARWIN__) + addi t2,t2,lo16(ex_int2-ex_int1) +#else + addi t2,t2,(ex_int2-ex_int1)@l +#endif + slwi t1,t1,2 /* t1 = register count * 4 */ + subf t2,t1,t2 /* t2 = IntSave - t1 */ + mtctr t2 + bctr + + lwz s0,-10*4(t0) + lwz s1,-9*4(t0) + lwz s2,-8*4(t0) + lwz s3,-7*4(t0) + lwz s4,-6*4(t0) + lwz s5,-5*4(t0) + lwz s6,-4*4(t0) + lwz s7,-3*4(t0) + lwz s8,-2*4(t0) + lwz s9,-1*4(t0) + +ex_int2: + subf t0,t1,t0 /* t0 = t0 - register count * 4 */ + + lwz t1,FltSave(pv) + bl ex_flt1 +ex_flt1: + mflr t2 +#if defined(__DARWIN__) + addi t2,t2,lo16(ex_flt2-ex_flt1) +#else + addi t2,t2,(ex_flt2-ex_flt1)@l +#endif + slwi t1,t1,2 /* t1 = register count * 4 */ + subf t2,t1,t2 /* t2 = FltSave - t1 */ + mtctr t2 + bctr + + lfd fs0,-10*8(t0) + lfd fs1,-9*8(t0) + lfd fs2,-8*8(t0) + lfd fs3,-7*8(t0) + lfd fs4,-6*8(t0) + lfd fs5,-5*8(t0) + lfd fs6,-4*8(t0) + lfd fs7,-3*8(t0) + lfd fs8,-2*8(t0) + lfd fs9,-1*8(t0) + +ex_flt2: + lwz t0,FrameSize(pv) /* get frame size */ + add sp,sp,t0 /* unwind stack */ + li a3,0 /* prepare a3 for handle_exception */ + + mtlr xpc + lwz itmp3,4(xpc) + extsh itmp3,itmp3 + add pv,itmp3,xpc + lwz itmp3,8(xpc) + srwi itmp3,itmp3,16 + cmpwi itmp3,0x3dad + bne L_asm_handle_exception_stack_loop + lwz itmp3,8(xpc) + slwi itmp3,itmp3,16 + add pv,pv,itmp3 + + b L_asm_handle_exception_stack_loop + + +/* asm_abstractmethoderror ***************************************************** + + Creates and throws an AbstractMethodError. + +*******************************************************************************/ + +asm_abstractmethoderror: + mflr r0 + stw r0,LA_LR_OFFSET(sp) + stwu sp,-LA_SIZE_ALIGNED(sp) /* preserve linkage area */ + addi a0,sp,LA_SIZE_ALIGNED /* pass java sp */ + mr a1,r0 /* pass exception address */ + bl exceptions_asm_new_abstractmethoderror + lwz r0,LA_SIZE_ALIGNED+LA_LR_OFFSET(sp) + mtlr r0 /* restore return address */ + addi sp,sp,LA_SIZE_ALIGNED + + mr xptr,v0 /* get exception pointer */ + mr xpc,r0 /* we can't use r0 directly in addi */ + addi xpc,xpc,-4 /* exception address is ra - 4 */ + b L_asm_handle_nat_exception + + +/* asm_wrapper_patcher ********************************************************* + + XXX + + Stack layout: + 20 return address into JIT code (patch position) + 16 pointer to virtual java_objectheader + 12 machine code (which is patched back later) + 8 unresolved class/method/field reference + 4 data segment displacement from load instructions + 0 patcher function pointer to call (pv is saved here afterwards) + +*******************************************************************************/ + +asm_wrapper_patcher: + mflr r0 /* get Java return address (leaf) */ + stw r0,6*4(sp) /* store it in the stub stackframe */ + /* keep stack 16-bytes aligned: 6+1+37 = 44 */ + stwu sp,-(LA_SIZE+(5+58)*4)(sp) + +#if defined(__DARWIN__) + stw a0,LA_SIZE+(5+0)*4(r1) /* save argument registers */ + stw a1,LA_SIZE+(5+1)*4(r1) /* preserve linkage area (24 bytes) */ + stw a2,LA_SIZE+(5+2)*4(r1) /* and 4 bytes for 4 argument */ + stw a3,LA_SIZE+(5+3)*4(r1) + stw a4,LA_SIZE+(5+4)*4(r1) + stw a5,LA_SIZE+(5+5)*4(r1) + stw a6,LA_SIZE+(5+6)*4(r1) + stw a7,LA_SIZE+(5+7)*4(r1) + + stfd fa0,LA_SIZE+(5+8)*4(sp) + stfd fa1,LA_SIZE+(5+10)*4(sp) + stfd fa2,LA_SIZE+(5+12)*4(sp) + stfd fa3,LA_SIZE+(5+14)*4(sp) + stfd fa4,LA_SIZE+(5+16)*4(sp) + stfd fa5,LA_SIZE+(5+18)*4(sp) + stfd fa6,LA_SIZE+(5+20)*4(sp) + stfd fa7,LA_SIZE+(5+22)*4(sp) + stfd fa8,LA_SIZE+(5+24)*4(sp) + stfd fa9,LA_SIZE+(5+26)*4(sp) + stfd fa10,LA_SIZE+(5+28)*4(sp) + stfd fa11,LA_SIZE+(5+30)*4(sp) + stfd fa12,LA_SIZE+(5+32)*4(sp) + + stw t0,(LA_WORD_SIZE+5+33)*4(r1) + stw t1,(LA_WORD_SIZE+5+34)*4(r1) + stw t2,(LA_WORD_SIZE+5+35)*4(r1) + stw t3,(LA_WORD_SIZE+5+36)*4(r1) + stw t4,(LA_WORD_SIZE+5+37)*4(r1) + stw t5,(LA_WORD_SIZE+5+38)*4(r1) + stw t6,(LA_WORD_SIZE+5+39)*4(r1) + stw t7,(LA_WORD_SIZE+5+40)*4(r1) + + stfd ft0,(LA_WORD_SIZE+5+42)*4(r1) + stfd ft1,(LA_WORD_SIZE+5+44)*4(r1) + stfd ft2,(LA_WORD_SIZE+5+46)*4(r1) + stfd ft3,(LA_WORD_SIZE+5+48)*4(r1) + stfd ft4,(LA_WORD_SIZE+5+50)*4(r1) + stfd ft5,(LA_WORD_SIZE+5+52)*4(r1) +#else + SAVE_ARGUMENT_REGISTERS(LA_WORD_SIZE+1) /* save 8 int/8 float arguments */ + SAVE_TEMPORARY_REGISTERS(LA_WORD_SIZE+1+24) +#endif + + stw itmp1,LA_SIZE+(5+54)*4(sp) + stw itmp2,LA_SIZE+(5+55)*4(sp) + stw pv,LA_SIZE+(5+56)*4(sp) + + addi a0,sp,LA_SIZE+(5+58)*4 /* pass SP of patcher stub */ + mr a1,pv /* pass PV */ + mr a2,r0 /* pass RA (correct for leafs) */ + bl patcher_wrapper + stw v0,LA_SIZE+(5+57)*4(sp) /* save return value */ + +#if defined(__DARWIN__) + lwz a0,LA_SIZE+(5+0)*4(r1) + lwz a1,LA_SIZE+(5+1)*4(r1) + lwz a2,LA_SIZE+(5+2)*4(r1) + lwz a3,LA_SIZE+(5+3)*4(r1) + lwz a4,LA_SIZE+(5+4)*4(r1) + lwz a5,LA_SIZE+(5+5)*4(r1) + lwz a6,LA_SIZE+(5+6)*4(r1) + lwz a7,LA_SIZE+(5+7)*4(r1) + + lfd fa0,LA_SIZE+(5+8)*4(sp) + lfd fa1,LA_SIZE+(5+10)*4(sp) + lfd fa2,LA_SIZE+(5+12)*4(sp) + lfd fa3,LA_SIZE+(5+14)*4(sp) + lfd fa4,LA_SIZE+(5+16)*4(sp) + lfd fa5,LA_SIZE+(5+18)*4(sp) + lfd fa6,LA_SIZE+(5+20)*4(sp) + lfd fa7,LA_SIZE+(5+22)*4(sp) + lfd fa8,LA_SIZE+(5+24)*4(sp) + lfd fa9,LA_SIZE+(5+26)*4(sp) + lfd fa10,LA_SIZE+(5+28)*4(sp) + lfd fa11,LA_SIZE+(5+30)*4(sp) + lfd fa12,LA_SIZE+(5+32)*4(sp) + + lwz t0,(LA_WORD_SIZE+5+33)*4(r1) + lwz t1,(LA_WORD_SIZE+5+34)*4(r1) + lwz t2,(LA_WORD_SIZE+5+35)*4(r1) + lwz t3,(LA_WORD_SIZE+5+36)*4(r1) + lwz t4,(LA_WORD_SIZE+5+37)*4(r1) + lwz t5,(LA_WORD_SIZE+5+38)*4(r1) + lwz t6,(LA_WORD_SIZE+5+39)*4(r1) + lwz t7,(LA_WORD_SIZE+5+40)*4(r1) + + lfd ft0,(LA_WORD_SIZE+5+42)*4(r1) + lfd ft1,(LA_WORD_SIZE+5+44)*4(r1) + lfd ft2,(LA_WORD_SIZE+5+46)*4(r1) + lfd ft3,(LA_WORD_SIZE+5+48)*4(r1) + lfd ft4,(LA_WORD_SIZE+5+50)*4(r1) + lfd ft5,(LA_WORD_SIZE+5+52)*4(r1) +#else + RESTORE_ARGUMENT_REGISTERS(LA_WORD_SIZE+1) /* restore 8 int/8 float args */ + RESTORE_TEMPORARY_REGISTERS(LA_WORD_SIZE+1+24) +#endif + + lwz itmp1,LA_SIZE+(5+54)*4(sp) + lwz itmp2,LA_SIZE+(5+55)*4(sp) + lwz pv,LA_SIZE+(5+56)*4(sp) + lwz itmp3,LA_SIZE+(5+57)*4(sp) /* restore return value into temp reg.*/ + + lwz r0,(6+LA_WORD_SIZE+5+58)*4(sp) /* restore RA */ + mtlr r0 + + mr. itmp3,itmp3 /* check for an exception */ + bne L_asm_wrapper_patcher_exception + + /* get return address (into JIT code) */ + lwz itmp3,(5+LA_WORD_SIZE+5+58)*4(sp) + + /* remove stack frame + patcher stub stack */ + addi sp,sp,(8+LA_WORD_SIZE+5+58)*4 + + mtctr itmp3 + bctr /* jump to new patched code */ + +L_asm_wrapper_patcher_exception: + mr xptr,itmp3 /* get exception */ + lwz xpc,(5+LA_WORD_SIZE+5+58)*4(sp) + addi sp,sp,(8+LA_WORD_SIZE+5+58)*4 + b 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: + 16 start of stack inside method to replace + 0 rplpoint * info on the replacement point that was reached + + NOTE: itmp3 has been clobbered by the replacement-out stub! + +*******************************************************************************/ + +/* 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 */ + addi sp,sp,-(sizeexecutionstate + REPLACEMENT_ROOM) /* XXX align */ + + /* save link register */ + mflr r16 + + /* save registers in execution state */ + stw r0 ,( 0*8+offes_intregs)(sp) + stw r1 ,( 1*8+offes_intregs)(sp) + stw r2 ,( 2*8+offes_intregs)(sp) + stw r3 ,( 3*8+offes_intregs)(sp) + stw r4 ,( 4*8+offes_intregs)(sp) + stw r5 ,( 5*8+offes_intregs)(sp) + stw r6 ,( 6*8+offes_intregs)(sp) + stw r7 ,( 7*8+offes_intregs)(sp) + stw r8 ,( 8*8+offes_intregs)(sp) + stw r9 ,( 9*8+offes_intregs)(sp) + stw r10,(10*8+offes_intregs)(sp) + stw r11,(11*8+offes_intregs)(sp) + stw r12,(12*8+offes_intregs)(sp) + stw r13,(13*8+offes_intregs)(sp) + stw r14,(14*8+offes_intregs)(sp) + stw r15,(15*8+offes_intregs)(sp) + stw r16,(16*8+offes_intregs)(sp) /* link register */ + stw r17,(17*8+offes_intregs)(sp) + stw r18,(18*8+offes_intregs)(sp) + stw r19,(19*8+offes_intregs)(sp) + stw r20,(20*8+offes_intregs)(sp) + stw r21,(21*8+offes_intregs)(sp) + stw r22,(22*8+offes_intregs)(sp) + stw r23,(23*8+offes_intregs)(sp) + stw r24,(24*8+offes_intregs)(sp) + stw r25,(25*8+offes_intregs)(sp) + stw r26,(26*8+offes_intregs)(sp) + stw r27,(27*8+offes_intregs)(sp) + stw r28,(28*8+offes_intregs)(sp) + stw r29,(29*8+offes_intregs)(sp) + stw r30,(30*8+offes_intregs)(sp) + stw r31,(31*8+offes_intregs)(sp) + + stfd fr0 ,( 0*8+offes_fltregs)(sp) + stfd fr1 ,( 1*8+offes_fltregs)(sp) + stfd fr2 ,( 2*8+offes_fltregs)(sp) + stfd fr3 ,( 3*8+offes_fltregs)(sp) + stfd fr4 ,( 4*8+offes_fltregs)(sp) + stfd fr5 ,( 5*8+offes_fltregs)(sp) + stfd fr6 ,( 6*8+offes_fltregs)(sp) + stfd fr7 ,( 7*8+offes_fltregs)(sp) + stfd fr8 ,( 8*8+offes_fltregs)(sp) + stfd fr9 ,( 9*8+offes_fltregs)(sp) + stfd fr10,(10*8+offes_fltregs)(sp) + stfd fr11,(11*8+offes_fltregs)(sp) + stfd fr12,(12*8+offes_fltregs)(sp) + stfd fr13,(13*8+offes_fltregs)(sp) + stfd fr14,(14*8+offes_fltregs)(sp) + stfd fr15,(15*8+offes_fltregs)(sp) + stfd fr16,(16*8+offes_fltregs)(sp) + stfd fr17,(17*8+offes_fltregs)(sp) + stfd fr18,(18*8+offes_fltregs)(sp) + stfd fr19,(19*8+offes_fltregs)(sp) + stfd fr20,(20*8+offes_fltregs)(sp) + stfd fr21,(21*8+offes_fltregs)(sp) + stfd fr22,(22*8+offes_fltregs)(sp) + stfd fr23,(23*8+offes_fltregs)(sp) + stfd fr24,(24*8+offes_fltregs)(sp) + stfd fr25,(25*8+offes_fltregs)(sp) + stfd fr26,(26*8+offes_fltregs)(sp) + stfd fr27,(27*8+offes_fltregs)(sp) + stfd fr28,(28*8+offes_fltregs)(sp) + stfd fr29,(29*8+offes_fltregs)(sp) + stfd fr30,(30*8+offes_fltregs)(sp) + stfd fr31,(31*8+offes_fltregs)(sp) + + /* calculate sp of method */ + addi itmp1,sp,(sizeexecutionstate + REPLACEMENT_ROOM + 4*4) + stw itmp1,(offes_sp)(sp) + + /* store pv */ + stw pv,(offes_pv)(sp) + + /* call replace_me */ + lwz a0,-(4*4)(itmp1) /* arg0: rplpoint * */ + mr a1,sp /* arg1: execution state */ + addi sp,sp,-(LA_SIZE_ALIGNED) + b replace_me /* call C function replace_me */ + +/* asm_replacement_in ********************************************************** + + This code writes the given execution state and jumps to the replacement + code. + + This function never returns! + + NOTE: itmp3 is not restored! + + C prototype: + void asm_replacement_in(executionstate *es); + +*******************************************************************************/ + +asm_replacement_in: + /* a0 == executionstate *es */ + + /* set new sp and pv */ + lwz sp,(offes_sp)(a0) + lwz pv,(offes_pv)(a0) + + /* copy registers from execution state */ + lwz r0 ,( 0*8+offes_intregs)(a0) + /* r1 is sp */ + /* r2 is reserved */ + /* a0 is loaded below */ + lwz r4 ,( 4*8+offes_intregs)(a0) + lwz r5 ,( 5*8+offes_intregs)(a0) + lwz r6 ,( 6*8+offes_intregs)(a0) + lwz r7 ,( 7*8+offes_intregs)(a0) + lwz r8 ,( 8*8+offes_intregs)(a0) + lwz r9 ,( 9*8+offes_intregs)(a0) + lwz r10,(10*8+offes_intregs)(a0) + lwz r11,(11*8+offes_intregs)(a0) + lwz r12,(12*8+offes_intregs)(a0) + /* r13 is pv */ + lwz r14,(14*8+offes_intregs)(a0) + lwz r15,(15*8+offes_intregs)(a0) + lwz r16,(16*8+offes_intregs)(a0) /* link register */ + lwz r17,(17*8+offes_intregs)(a0) + lwz r18,(18*8+offes_intregs)(a0) + lwz r19,(19*8+offes_intregs)(a0) + lwz r20,(20*8+offes_intregs)(a0) + lwz r21,(21*8+offes_intregs)(a0) + lwz r22,(22*8+offes_intregs)(a0) + lwz r23,(23*8+offes_intregs)(a0) + lwz r24,(24*8+offes_intregs)(a0) + lwz r25,(25*8+offes_intregs)(a0) + lwz r26,(26*8+offes_intregs)(a0) + lwz r27,(27*8+offes_intregs)(a0) + lwz r28,(28*8+offes_intregs)(a0) + lwz r29,(29*8+offes_intregs)(a0) + lwz r30,(30*8+offes_intregs)(a0) + lwz r31,(31*8+offes_intregs)(a0) + + lfd fr0 ,( 0*8+offes_fltregs)(a0) + lfd fr1 ,( 1*8+offes_fltregs)(a0) + lfd fr2 ,( 2*8+offes_fltregs)(a0) + lfd fr3 ,( 3*8+offes_fltregs)(a0) + lfd fr4 ,( 4*8+offes_fltregs)(a0) + lfd fr5 ,( 5*8+offes_fltregs)(a0) + lfd fr6 ,( 6*8+offes_fltregs)(a0) + lfd fr7 ,( 7*8+offes_fltregs)(a0) + lfd fr8 ,( 8*8+offes_fltregs)(a0) + lfd fr9 ,( 9*8+offes_fltregs)(a0) + lfd fr10,(10*8+offes_fltregs)(a0) + lfd fr11,(11*8+offes_fltregs)(a0) + lfd fr12,(12*8+offes_fltregs)(a0) + lfd fr13,(13*8+offes_fltregs)(a0) + lfd fr14,(14*8+offes_fltregs)(a0) + lfd fr15,(15*8+offes_fltregs)(a0) + lfd fr16,(16*8+offes_fltregs)(a0) + lfd fr17,(17*8+offes_fltregs)(a0) + lfd fr18,(18*8+offes_fltregs)(a0) + lfd fr19,(19*8+offes_fltregs)(a0) + lfd fr20,(20*8+offes_fltregs)(a0) + lfd fr21,(21*8+offes_fltregs)(a0) + lfd fr22,(22*8+offes_fltregs)(a0) + lfd fr23,(23*8+offes_fltregs)(a0) + lfd fr24,(24*8+offes_fltregs)(a0) + lfd fr25,(25*8+offes_fltregs)(a0) + lfd fr26,(26*8+offes_fltregs)(a0) + lfd fr27,(27*8+offes_fltregs)(a0) + lfd fr28,(28*8+offes_fltregs)(a0) + lfd fr29,(29*8+offes_fltregs)(a0) + lfd fr30,(30*8+offes_fltregs)(a0) + lfd fr31,(31*8+offes_fltregs)(a0) + + /* restore link register */ + + mtlr r16 + + /* load new pc */ + + lwz itmp3,offes_pc(a0) + + /* load a0 */ + + lwz a0,(3*8+offes_intregs)(a0) + + /* jump to new code */ + + mtctr itmp3 + bctr + +/*********************************************************************/ + +asm_cacheflush: + add r4,r3,r4 + rlwinm r3,r3,0,0,26 + addi r4,r4,31 + rlwinm r4,r4,0,0,26 + mr r5,r3 +1: + cmplw r3,r4 + bge 0f + dcbst 0,r3 + addi r3,r3,32 + b 1b +0: + sync +1: + cmplw r5,r4 + bge 0f + icbi 0,r5 + addi r5,r5,32 + b 1b +0: + sync + isync + blr + + +asm_getclassvalues_atomic: +_crit_restart: +_crit_begin: + lwz r6,offbaseval(r3) + lwz r7,offdiffval(r3) + lwz r8,offbaseval(r4) +_crit_end: + stw r6,offcast_super_baseval(r5) + stw r7,offcast_super_diffval(r5) + stw r8,offcast_sub_baseval(r5) + blr + + .data + +asm_criticalsections: +#if defined(ENABLE_THREADS) + .long _crit_begin + .long _crit_end + .long _crit_restart +#endif + .long 0 + + +#if defined(__DARWIN__) + +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 2 +L_builtin_throw_exception$stub: + .indirect_symbol _builtin_throw_exception + mflr r0 + bcl 20,31,L00$_builtin_throw_exception +L00$_builtin_throw_exception: + mflr r11 + addis r11,r11,ha16(L_builtin_throw_exception$lazy_ptr - L00$_builtin_throw_exception) + mtlr r0 + lwzu r12,lo16(L_builtin_throw_exception$lazy_ptr - L00$_builtin_throw_exception)(r11) + mtctr r12 + bctr +.data +.lazy_symbol_pointer +L_builtin_throw_exception$lazy_ptr: + .indirect_symbol _builtin_throw_exception + .long dyld_stub_binding_helper + + +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 2 +L_exceptions_handle_exception$stub: + .indirect_symbol _exceptions_handle_exception + mflr r0 + bcl 20,31,L00$_exceptions_handle_exception +L00$_exceptions_handle_exception: + mflr r11 + addis r11,r11,ha16(L_exceptions_handle_exception$lazy_ptr - L00$_exceptions_handle_exception) + mtlr r0 + lwzu r12,lo16(L_exceptions_handle_exception$lazy_ptr - L00$_exceptions_handle_exception)(r11) + mtctr r12 + bctr +.data +.lazy_symbol_pointer +L_exceptions_handle_exception$lazy_ptr: + .indirect_symbol _exceptions_handle_exception + .long dyld_stub_binding_helper + + +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 2 +L_stacktrace_create_extern_stackframeinfo$stub: + .indirect_symbol _stacktrace_create_extern_stackframeinfo + mflr r0 + bcl 20,31,L00$_stacktrace_create_extern_stackframeinfo +L00$_stacktrace_create_extern_stackframeinfo: + mflr r11 + addis r11,r11,ha16(L_stacktrace_create_extern_stackframeinfo$lazy_ptr - L00$_stacktrace_create_extern_stackframeinfo) + mtlr r0 + lwzu r12,lo16(L_stacktrace_create_extern_stackframeinfo$lazy_ptr - L00$_stacktrace_create_extern_stackframeinfo)(r11) + mtctr r12 + bctr +.data +.lazy_symbol_pointer +L_stacktrace_create_extern_stackframeinfo$lazy_ptr: + .indirect_symbol _stacktrace_create_extern_stackframeinfo + .long dyld_stub_binding_helper + + +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 2 +L_jit_asm_compile$stub: + .indirect_symbol _jit_asm_compile + mflr r0 + bcl 20,31,L00$_jit_asm_compile +L00$_jit_asm_compile: + mflr r11 + addis r11,r11,ha16(L_jit_asm_compile$lazy_ptr - L00$_jit_asm_compile) + mtlr r0 + lwzu r12,lo16(L_jit_asm_compile$lazy_ptr - L00$_jit_asm_compile)(r11) + mtctr r12 + bctr +.data +.lazy_symbol_pointer +L_jit_asm_compile$lazy_ptr: + .indirect_symbol _jit_asm_compile + .long dyld_stub_binding_helper + + +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 2 +L_stacktrace_remove_stackframeinfo$stub: + .indirect_symbol _stacktrace_remove_stackframeinfo + mflr r0 + bcl 20,31,L00$_stacktrace_remove_stackframeinfo +L00$_stacktrace_remove_stackframeinfo: + mflr r11 + addis r11,r11,ha16(L_stacktrace_remove_stackframeinfo$lazy_ptr - L00$_stacktrace_remove_stackframeinfo) + mtlr r0 + lwzu r12,lo16(L_stacktrace_remove_stackframeinfo$lazy_ptr - L00$_stacktrace_remove_stackframeinfo)(r11) + mtctr r12 + bctr +.data +.lazy_symbol_pointer +L_stacktrace_remove_stackframeinfo$lazy_ptr: + .indirect_symbol _stacktrace_remove_stackframeinfo + .long dyld_stub_binding_helper + + +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 2 +L_exceptions_get_and_clear_exception$stub: + .indirect_symbol _exceptions_get_and_clear_exception + mflr r0 + bcl 20,31,L00$_exceptions_get_and_clear_exception +L00$_exceptions_get_and_clear_exception: + mflr r11 + addis r11,r11,ha16(L_exceptions_get_and_clear_exception$lazy_ptr - L00$_exceptions_get_and_clear_exception) + mtlr r0 + lwzu r12,lo16(L_exceptions_get_and_clear_exception$lazy_ptr - L00$_exceptions_get_and_clear_exception)(r11) + mtctr r12 + bctr +.data +.lazy_symbol_pointer +L_exceptions_get_and_clear_exception$lazy_ptr: + .indirect_symbol _exceptions_get_and_clear_exception + .long dyld_stub_binding_helper + + +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 2 +L_exceptions_asm_new_abstractmethoderror$stub: + .indirect_symbol _exceptions_asm_new_abstractmethoderror + mflr r0 + bcl 20,31,L00$_exceptions_asm_new_abstractmethoderror +L00$_exceptions_asm_new_abstractmethoderror: + mflr r11 + addis r11,r11,ha16(L_exceptions_asm_new_abstractmethoderror$lazy_ptr - L00$_exceptions_asm_new_abstractmethoderror) + mtlr r0 + lwzu r12,lo16(L_exceptions_asm_new_abstractmethoderror$lazy_ptr - L00$_exceptions_asm_new_abstractmethoderror)(r11) + mtctr r12 + bctr +.data +.lazy_symbol_pointer +L_exceptions_asm_new_abstractmethoderror$lazy_ptr: + .indirect_symbol _exceptions_asm_new_abstractmethoderror + .long dyld_stub_binding_helper + + +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 2 +L_replace_me$stub: + .indirect_symbol _replace_me + mflr r0 + bcl 20,31,L00$_replace_me +L00$_replace_me: + mflr r11 + addis r11,r11,ha16(L_replace_me$lazy_ptr - L00$_replace_me) + mtlr r0 + lwzu r12,lo16(L_replace_me$lazy_ptr - L00$_replace_me)(r11) + mtctr r12 + bctr +.data +.lazy_symbol_pointer +L_replace_me$lazy_ptr: + .indirect_symbol _replace_me + .long dyld_stub_binding_helper + +#endif /* defined(__DARWIN__) */ + + +/* Disable exec-stacks, required for Gentoo ***********************************/ + +#if defined(__GCC__) && defined(__ELF__) + .section .note.GNU-stack,"",@progbits +#endif + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: asm + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/powerpc64/codegen.c b/src/vm/jit/powerpc64/codegen.c new file mode 100644 index 000000000..ce3f32448 --- /dev/null +++ b/src/vm/jit/powerpc64/codegen.c @@ -0,0 +1,4371 @@ +/* src/vm/jit/powerpc/codegen.c - machine code generator for 32-bit PowerPC + + 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 + Stefan Ring + + Changes: Christian Thalinger + Christian Ullrich + Edwin Steiner + + $Id: codegen.c 5081 2006-07-06 13:59:01Z tbfg $ + +*/ + + +#include "config.h" + +#include +#include +#include + +#include "vm/types.h" + +#include "md-abi.h" + +#include "vm/jit/powerpc64/arch.h" +#include "vm/jit/powerpc64/codegen.h" + +#include "mm/memory.h" +#include "native/native.h" +#include "vm/builtin.h" +#include "vm/exceptions.h" +#include "vm/global.h" +#include "vm/loader.h" +#include "vm/options.h" +#include "vm/stringlocal.h" +#include "vm/vm.h" +#include "vm/jit/asmpart.h" +#include "vm/jit/codegen-common.h" +#include "vm/jit/dseg.h" +#include "vm/jit/emit.h" +#include "vm/jit/jit.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 + + +void codegen_trace_args(jitdata *jd, s4 stackframesize, bool nativestub); + +/* codegen ********************************************************************* + + Generates machine code. + +*******************************************************************************/ + +bool codegen(jitdata *jd) +{ + methodinfo *m; + codeinfo *code; + codegendata *cd; + registerdata *rd; + s4 len, s1, s2, s3, d, disp; + ptrint a; + s4 stackframesize; + stackptr src; + varinfo *var; + basicblock *bptr; + instruction *iptr; + exceptiontable *ex; + u2 currentline; + methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ + builtintable_entry *bte; + methoddesc *md; + rplpoint *replacementpoint; + + /* get required compiler data */ + + m = jd->m; + code = jd->code; + cd = jd->cd; + rd = jd->rd; + + /* prevent compiler warnings */ + + d = 0; + lm = 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) * 2; + + stackframesize = rd->memuse + savedregs_num; + +#if defined(ENABLE_THREADS) + /* space to save argument of monitor_enter and Return Values to survive */ + /* monitor_exit. The stack position for the argument can not be shared */ + /* with place to save the return register on PPC, since both values */ + /* reside in R3 */ + if (checksync && (m->flags & ACC_SYNCHRONIZED)) { + /* reserve 2 slots for long/double return values for monitorexit */ + + if (IS_2_WORD_TYPE(m->parseddesc->returntype.type)) + stackframesize += 3; + else + stackframesize += 2; + } + +#endif + + /* create method header */ + + /* align stack to 16-bytes */ + +/* if (!m->isleafmethod || opt_verbosecall) */ + stackframesize = (stackframesize + 3) & ~3; + +/* else if (m->isleafmethod && (stackframesize == LA_WORD_SIZE)) */ +/* stackframesize = 0; */ + + (void) dseg_addaddress(cd, code); /* CodeinfoPointer */ + (void) dseg_adds4(cd, stackframesize * 4); /* FrameSize */ + +#if defined(ENABLE_THREADS) + /* IsSync contains the offset relative to the stack pointer for the + argument of monitor_exit used in the exception handler. Since the + offset could be zero and give a wrong meaning of the flag it is + offset by one. + */ + + if (checksync && (m->flags & ACC_SYNCHRONIZED)) + (void) dseg_adds4(cd, (rd->memuse + 1) * 4); /* IsSync */ + else +#endif + (void) dseg_adds4(cd, 0); /* IsSync */ + + (void) dseg_adds4(cd, m->isleafmethod); /* IsLeaf */ + (void) dseg_adds4(cd, INT_SAV_CNT - rd->savintreguse); /* IntSave */ + (void) dseg_adds4(cd, FLT_SAV_CNT - rd->savfltreguse); /* FltSave */ + + dseg_addlinenumbertablesize(cd); + + (void) dseg_adds4(cd, cd->exceptiontablelength); /* ExTableSize */ + + /* create exception table */ + + for (ex = cd->exceptiontable; ex != NULL; ex = ex->down) { + dseg_addtarget(cd, ex->start); + dseg_addtarget(cd, ex->end); + dseg_addtarget(cd, ex->handler); + (void) dseg_addaddress(cd, ex->catchtype.cls); + } + + /* create stack frame (if necessary) */ + + if (!m->isleafmethod) { + M_MFLR(REG_ZERO); + M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET); + } + + if (stackframesize) + M_STWU(REG_SP, REG_SP, -stackframesize * 4); + + /* save return address and used callee saved registers */ + + p = stackframesize; + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p--; M_IST(rd->savintregs[i], REG_SP, p * 4); + } + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p -= 2; M_DST(rd->savfltregs[i], REG_SP, p * 4); + } + + /* 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; + var = &(rd->locals[l][t]); + l++; + if (IS_2_WORD_TYPE(t)) /* increment local counter for 2 word types */ + l++; + if (var->type < 0) + continue; + s1 = md->params[p].regoff; + if (IS_INT_LNG_TYPE(t)) { /* integer args */ + if (IS_2_WORD_TYPE(t)) + s2 = PACK_REGS(rd->argintregs[GET_LOW_REG(s1)], + rd->argintregs[GET_HIGH_REG(s1)]); + else + s2 = rd->argintregs[s1]; + if (!md->params[p].inmemory) { /* register arguments */ + if (!(var->flags & INMEMORY)) { /* reg arg -> register */ + if (IS_2_WORD_TYPE(t)) + M_LNGMOVE(s2, var->regoff); + else + M_INTMOVE(s2, var->regoff); + + } else { /* reg arg -> spilled */ + if (IS_2_WORD_TYPE(t)) + M_LST(s2, REG_SP, var->regoff * 4); + else + M_IST(s2, REG_SP, var->regoff * 4); + } + + } else { /* stack arguments */ + if (!(var->flags & INMEMORY)) { /* stack arg -> register */ + if (IS_2_WORD_TYPE(t)) + M_LLD(var->regoff, REG_SP, (stackframesize + s1) * 4); + else + M_ILD(var->regoff, REG_SP, (stackframesize + s1) * 4); + + } else { /* stack arg -> spilled */ +#if 1 + M_ILD(REG_ITMP1, REG_SP, (stackframesize + s1) * 4); + M_IST(REG_ITMP1, REG_SP, var->regoff * 4); + if (IS_2_WORD_TYPE(t)) { + M_ILD(REG_ITMP1, REG_SP, (stackframesize + s1) * 4 +4); + M_IST(REG_ITMP1, REG_SP, var->regoff * 4 + 4); + } +#else + /* Reuse Memory Position on Caller Stack */ + var->regoff = stackframesize + s1; +#endif + } + } + + } else { /* floating args */ + if (!md->params[p].inmemory) { /* register arguments */ + s2 = rd->argfltregs[s1]; + if (!(var->flags & INMEMORY)) { /* reg arg -> register */ + M_FLTMOVE(s2, var->regoff); + + } else { /* reg arg -> spilled */ + if (IS_2_WORD_TYPE(t)) + M_DST(s2, REG_SP, var->regoff * 4); + else + M_FST(s2, REG_SP, var->regoff * 4); + } + + } else { /* stack arguments */ + if (!(var->flags & INMEMORY)) { /* stack-arg -> register */ + if (IS_2_WORD_TYPE(t)) + M_DLD(var->regoff, REG_SP, (stackframesize + s1) * 4); + + else + M_FLD(var->regoff, REG_SP, (stackframesize + s1) * 4); + + } else { /* stack-arg -> spilled */ +#if 1 + if (IS_2_WORD_TYPE(t)) { + M_DLD(REG_FTMP1, REG_SP, (stackframesize + s1) * 4); + M_DST(REG_FTMP1, REG_SP, var->regoff * 4); + var->regoff = stackframesize + s1; + + } else { + M_FLD(REG_FTMP1, REG_SP, (stackframesize + s1) * 4); + M_FST(REG_FTMP1, REG_SP, var->regoff * 4); + } +#else + /* Reuse Memory Position on Caller Stack */ + var->regoff = stackframesize + s1; +#endif + } + } + } + } /* end for */ + + /* save monitorenter argument */ + +#if defined(ENABLE_THREADS) + if (checksync && (m->flags & ACC_SYNCHRONIZED)) { + p = dseg_addaddress(cd, BUILTIN_monitorenter); + M_ALD(REG_ITMP3, REG_PV, p); + M_MTCTR(REG_ITMP3); + + /* get or test the lock object */ + + if (m->flags & ACC_STATIC) { + p = dseg_addaddress(cd, &m->class->object.header); + M_ALD(rd->argintregs[0], REG_PV, p); + } + else { + M_TST(rd->argintregs[0]); + M_BEQ(0); + codegen_add_nullpointerexception_ref(cd); + } + + M_AST(rd->argintregs[0], REG_SP, rd->memuse * 4); + M_JSR; + } +#endif + + /* call trace function */ + + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + codegen_trace_args(jd, stackframesize, false); + } + + /* end of header generation */ + + replacementpoint = jd->code->rplpoints; + + /* walk through all basic blocks */ + for (bptr = m->basicblocks; bptr != NULL; bptr = bptr->next) { + + bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase); + + if (bptr->flags >= BBREACHED) { + + /* branch resolving */ + + { + branchref *brefs; + for (brefs = bptr->branchrefs; brefs != NULL; brefs = brefs->next) { + gen_resolvebranch((u1*) cd->mcodebase + brefs->branchpos, + brefs->branchpos, + bptr->mpc); + } + } + + /* handle replacement points */ + + if (bptr->bitflags & BBFLAG_REPLACEMENT) { + replacementpoint->pc = (u1*)(ptrint)bptr->mpc; /* will be resolved later */ + + replacementpoint++; + } + + /* copy interface registers to their destination */ + + src = bptr->instack; + len = bptr->indepth; + MCODECHECK(64+len); + +#if defined(ENABLE_LSRA) + if (opt_lsra) { + while (src != NULL) { + len--; + if ((len == 0) && (bptr->type != BBTYPE_STD)) { + /* d = reg_of_var(m, src, REG_ITMP1); */ + if (!(src->flags & INMEMORY)) + d = src->regoff; + else + d = REG_ITMP1; + M_INTMOVE(REG_ITMP1, d); + emit_store(jd, NULL, src, d); + } + src = src->prev; + } + } else { +#endif + while (src != NULL) { + len--; + if ((len == 0) && (bptr->type != BBTYPE_STD)) { + d = codegen_reg_of_var(rd, 0, src, REG_ITMP1); + M_INTMOVE(REG_ITMP1, d); + emit_store(jd, NULL, src, d); + } else { + if (src->type == TYPE_LNG) + d = codegen_reg_of_var(rd, 0, src, PACK_REGS(REG_ITMP2, REG_ITMP1)); + else + d = codegen_reg_of_var(rd, 0, src, REG_IFTMP); + if ((src->varkind != STACKVAR)) { + s2 = src->type; + if (IS_FLT_DBL_TYPE(s2)) { + if (!(rd->interfaces[len][s2].flags & INMEMORY)) { + s1 = rd->interfaces[len][s2].regoff; + M_FLTMOVE(s1, d); + } else { + if (IS_2_WORD_TYPE(s2)) { + M_DLD(d, REG_SP, + rd->interfaces[len][s2].regoff * 4); + } else { + M_FLD(d, REG_SP, + rd->interfaces[len][s2].regoff * 4); + } + } + + emit_store(jd, NULL, src, d); + + } else { + if (!(rd->interfaces[len][s2].flags & INMEMORY)) { + s1 = rd->interfaces[len][s2].regoff; + if (IS_2_WORD_TYPE(s2)) + M_LNGMOVE(s1, d); + else + M_INTMOVE(s1, d); + } else { + if (IS_2_WORD_TYPE(s2)) + M_LLD(d, REG_SP, + rd->interfaces[len][s2].regoff * 4); + else + M_ILD(d, REG_SP, + rd->interfaces[len][s2].regoff * 4); + } + + emit_store(jd, NULL, src, d); + } + } + } + src = src->prev; + } + +#if defined(ENABLE_LSRA) + } +#endif + /* walk through all instructions */ + + src = bptr->instack; + len = bptr->icount; + currentline = 0; + + for (iptr = bptr->iinstr; len > 0; src = iptr->dst, len--, iptr++) { + if (iptr->line != currentline) { + dseg_addlinenumber(cd, iptr->line); + currentline = iptr->line; + } + + MCODECHECK(64); /* an instruction usually needs < 64 words */ + + switch (iptr->opc) { + case ICMD_NOP: /* ... ==> ... */ + case ICMD_INLINE_START: + case ICMD_INLINE_END: + break; + + case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + M_TST(s1); + M_BEQ(0); + codegen_add_nullpointerexception_ref(cd); + break; + + /* constant operations ************************************************/ + + case ICMD_ICONST: /* ... ==> ..., constant */ + /* op1 = 0, val.i = constant */ + + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP1); + ICONST(d, iptr->val.i); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LCONST: /* ... ==> ..., constant */ + /* op1 = 0, val.l = constant */ + + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + LCONST(d, iptr->val.l); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_FCONST: /* ... ==> ..., constant */ + /* op1 = 0, val.f = constant */ + + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP1); + a = dseg_addfloat(cd, iptr->val.f); + M_FLD(d, REG_PV, a); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_DCONST: /* ... ==> ..., constant */ + /* op1 = 0, val.d = constant */ + + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP1); + a = dseg_adddouble(cd, iptr->val.d); + M_DLD(d, REG_PV, a); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_ACONST: /* ... ==> ..., constant */ + /* op1 = 0, val.a = constant */ + + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP1); + disp = dseg_addaddress(cd, iptr->val.a); + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + codegen_addpatchref(cd, PATCHER_aconst, + ICMD_ACONST_UNRESOLVED_CLASSREF(iptr), + disp); + + if (opt_showdisassemble) + M_NOP; + } + + M_ALD(d, REG_PV, disp); + emit_store(jd, iptr, iptr->dst, d); + break; + + + /* load/store operations **********************************************/ + + case ICMD_ILOAD: /* ... ==> ..., content of local variable */ + case ICMD_ALOAD: /* op1 = local variable */ + + var = &(rd->locals[iptr->op1][iptr->opc - ICMD_ILOAD]); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP1); + if ((iptr->dst->varkind == LOCALVAR) && + (iptr->dst->varnum == iptr->op1)) + break; + if (var->flags & INMEMORY) + M_ILD(d, REG_SP, var->regoff * 4); + else + M_INTMOVE(var->regoff, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LLOAD: /* ... ==> ..., content of local variable */ + /* op1 = local variable */ + + var = &(rd->locals[iptr->op1][iptr->opc - ICMD_ILOAD]); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + if ((iptr->dst->varkind == LOCALVAR) && + (iptr->dst->varnum == iptr->op1)) + break; + if (var->flags & INMEMORY) + M_LLD(d, REG_SP, var->regoff * 4); + else + M_LNGMOVE(var->regoff, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_FLOAD: /* ... ==> ..., content of local variable */ + /* op1 = local variable */ + + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP1); + if ((iptr->dst->varkind == LOCALVAR) && + (iptr->dst->varnum == iptr->op1)) + break; + var = &(rd->locals[iptr->op1][iptr->opc - ICMD_ILOAD]); + if (var->flags & INMEMORY) + M_FLD(d, REG_SP, var->regoff * 4); + else + M_FLTMOVE(var->regoff, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_DLOAD: /* ... ==> ..., content of local variable */ + /* op1 = local variable */ + + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP1); + if ((iptr->dst->varkind == LOCALVAR) && + (iptr->dst->varnum == iptr->op1)) + break; + var = &(rd->locals[iptr->op1][iptr->opc - ICMD_ILOAD]); + if (var->flags & INMEMORY) + M_DLD(d, REG_SP, var->regoff * 4); + else + M_FLTMOVE(var->regoff, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + + case ICMD_ISTORE: /* ..., value ==> ... */ + case ICMD_ASTORE: /* op1 = local variable */ + + if ((src->varkind == LOCALVAR) && (src->varnum == iptr->op1)) + break; + var = &(rd->locals[iptr->op1][iptr->opc - ICMD_ISTORE]); + if (var->flags & INMEMORY) { + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + M_IST(s1, REG_SP, var->regoff * 4); + } else { + s1 = emit_load_s1(jd, iptr, src, var->regoff); + M_INTMOVE(s1, var->regoff); + } + break; + + case ICMD_LSTORE: /* ..., value ==> ... */ + /* op1 = local variable */ + + if ((src->varkind == LOCALVAR) && (src->varnum == iptr->op1)) + break; + var = &(rd->locals[iptr->op1][iptr->opc - ICMD_ISTORE]); + if (var->flags & INMEMORY) { + s1 = emit_load_s1(jd, iptr, src, PACK_REGS(REG_ITMP2, REG_ITMP1)); + M_LST(s1, REG_SP, var->regoff * 4); + } else { + s1 = emit_load_s1(jd, iptr, src, var->regoff); + M_LNGMOVE(s1, var->regoff); + } + break; + + case ICMD_FSTORE: /* ..., value ==> ... */ + /* op1 = local variable */ + + if ((src->varkind == LOCALVAR) && (src->varnum == iptr->op1)) + break; + var = &(rd->locals[iptr->op1][iptr->opc - ICMD_ISTORE]); + if (var->flags & INMEMORY) { + s1 = emit_load_s1(jd, iptr, src, REG_FTMP1); + M_FST(s1, REG_SP, var->regoff * 4); + } else { + s1 = emit_load_s1(jd, iptr, src, var->regoff); + M_FLTMOVE(s1, var->regoff); + } + break; + + case ICMD_DSTORE: /* ..., value ==> ... */ + /* op1 = local variable */ + + if ((src->varkind == LOCALVAR) && (src->varnum == iptr->op1)) + break; + var = &(rd->locals[iptr->op1][iptr->opc - ICMD_ISTORE]); + if (var->flags & INMEMORY) { + s1 = emit_load_s1(jd, iptr, src, REG_FTMP1); + M_DST(s1, REG_SP, var->regoff * 4); + } else { + s1 = emit_load_s1(jd, iptr, src, var->regoff); + M_FLTMOVE(s1, var->regoff); + } + break; + + + /* pop/dup/swap operations ********************************************/ + + /* attention: double and longs are only one entry in CACAO ICMDs */ + + case ICMD_POP: /* ..., value ==> ... */ + case ICMD_POP2: /* ..., value, value ==> ... */ + break; + + case ICMD_DUP: /* ..., a ==> ..., a, a */ + M_COPY(src, iptr->dst); + break; + + case ICMD_DUP_X1: /* ..., a, b ==> ..., b, a, b */ + + M_COPY(src, iptr->dst); + M_COPY(src->prev, iptr->dst->prev); + M_COPY(iptr->dst, iptr->dst->prev->prev); + break; + + case ICMD_DUP_X2: /* ..., a, b, c ==> ..., c, a, b, c */ + + M_COPY(src, iptr->dst); + M_COPY(src->prev, iptr->dst->prev); + M_COPY(src->prev->prev, iptr->dst->prev->prev); + M_COPY(iptr->dst, iptr->dst->prev->prev->prev); + break; + + case ICMD_DUP2: /* ..., a, b ==> ..., a, b, a, b */ + + M_COPY(src, iptr->dst); + M_COPY(src->prev, iptr->dst->prev); + break; + + case ICMD_DUP2_X1: /* ..., a, b, c ==> ..., b, c, a, b, c */ + + M_COPY(src, iptr->dst); + M_COPY(src->prev, iptr->dst->prev); + M_COPY(src->prev->prev, iptr->dst->prev->prev); + M_COPY(iptr->dst, iptr->dst->prev->prev->prev); + M_COPY(iptr->dst->prev, iptr->dst->prev->prev->prev->prev); + break; + + case ICMD_DUP2_X2: /* ..., a, b, c, d ==> ..., c, d, a, b, c, d */ + + M_COPY(src, iptr->dst); + M_COPY(src->prev, iptr->dst->prev); + M_COPY(src->prev->prev, iptr->dst->prev->prev); + M_COPY(src->prev->prev->prev, iptr->dst->prev->prev->prev); + M_COPY(iptr->dst, iptr->dst->prev->prev->prev->prev); + M_COPY(iptr->dst->prev, iptr->dst->prev->prev->prev->prev->prev); + break; + + case ICMD_SWAP: /* ..., a, b ==> ..., b, a */ + + M_COPY(src, iptr->dst->prev); + M_COPY(src->prev, iptr->dst); + break; + + + /* integer operations *************************************************/ + + case ICMD_INEG: /* ..., value ==> ..., - value */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_NEG(s1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LNEG: /* ..., value ==> ..., - value */ + + s1 = emit_load_s1(jd, iptr, src, PACK_REGS(REG_ITMP2, REG_ITMP1)); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + M_SUBFIC(GET_LOW_REG(s1), 0, GET_LOW_REG(d)); + M_SUBFZE(GET_HIGH_REG(s1), GET_HIGH_REG(d)); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_I2L: /* ..., value ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + M_INTMOVE(s1, GET_LOW_REG(d)); + M_SRA_IMM(GET_LOW_REG(d), 31, GET_HIGH_REG(d)); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_L2I: /* ..., value ==> ..., value */ + + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_INTMOVE(s1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_INT2BYTE: /* ..., value ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_BSEXT(s1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_INT2CHAR: /* ..., value ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_CZEXT(s1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_INT2SHORT: /* ..., value ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_SSEXT(s1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + + case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_IADD(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */ + /* val.i = constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if ((iptr->val.i >= -32768) && (iptr->val.i <= 32767)) { + M_IADD_IMM(s1, iptr->val.i, d); + } else { + ICONST(REG_ITMP2, iptr->val.i); + M_IADD(s1, REG_ITMP2, d); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + M_ADDC(s1, s2, GET_LOW_REG(d)); + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP3); /* don't use REG_ITMP2 */ + M_ADDE(s1, s2, GET_HIGH_REG(d)); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */ + /* val.l = constant */ + + s3 = iptr->val.l & 0xffffffff; + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + if ((s3 >= -32768) && (s3 <= 32767)) { + M_ADDIC(s1, s3, GET_LOW_REG(d)); + } else { + ICONST(REG_ITMP2, s3); + M_ADDC(s1, REG_ITMP2, GET_LOW_REG(d)); + } + s1 = emit_load_s1_high(jd, iptr, src, REG_ITMP1); + s3 = iptr->val.l >> 32; + if (s3 == -1) { + M_ADDME(s1, GET_HIGH_REG(d)); + } else if (s3 == 0) { + M_ADDZE(s1, GET_HIGH_REG(d)); + } else { + ICONST(REG_ITMP3, s3); /* don't use REG_ITMP2 */ + M_ADDE(s1, REG_ITMP3, GET_HIGH_REG(d)); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_ISUB(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */ + /* val.i = constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if ((iptr->val.i >= -32767) && (iptr->val.i <= 32768)) { + M_IADD_IMM(s1, -iptr->val.i, d); + } else { + ICONST(REG_ITMP2, -iptr->val.i); + M_IADD(s1, REG_ITMP2, d); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + M_SUBC(s1, s2, GET_LOW_REG(d)); + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP3); /* don't use REG_ITMP2 */ + M_SUBE(s1, s2, GET_HIGH_REG(d)); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */ + /* val.l = constant */ + + s3 = (-iptr->val.l) & 0xffffffff; + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + if ((s3 >= -32768) && (s3 <= 32767)) { + M_ADDIC(s1, s3, GET_LOW_REG(d)); + } else { + ICONST(REG_ITMP2, s3); + M_ADDC(s1, REG_ITMP2, GET_LOW_REG(d)); + } + s1 = emit_load_s1_high(jd, iptr, src, REG_ITMP1); + s3 = (-iptr->val.l) >> 32; + if (s3 == -1) + M_ADDME(s1, GET_HIGH_REG(d)); + else if (s3 == 0) + M_ADDZE(s1, GET_HIGH_REG(d)); + else { + ICONST(REG_ITMP3, s3); /* don't use REG_ITMP2 */ + M_ADDE(s1, REG_ITMP3, GET_HIGH_REG(d)); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP1); + M_TST(s2); + M_BEQ(0); + codegen_add_arithmeticexception_ref(cd); + M_LDAH(REG_ITMP3, REG_ZERO, 0x8000); + M_CMP(REG_ITMP3, s1); + M_BNE(3 + (s1 != d)); + M_CMPI(s2, -1); + M_BNE(1 + (s1 != d)); + M_INTMOVE(s1, d); + M_BR(1); + M_IDIV(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_TST(s2); + M_BEQ(0); + codegen_add_arithmeticexception_ref(cd); + M_LDAH(REG_ITMP3, REG_ZERO, 0x8000); + M_CMP(REG_ITMP3, s1); + M_BNE(4); + M_CMPI(s2, -1); + M_BNE(2); + M_CLR(d); + M_BR(3); + M_IDIV(s1, s2, REG_ITMP3); + M_IMUL(REG_ITMP3, s2, REG_ITMP3); + M_ISUB(s1, REG_ITMP3, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + case ICMD_LREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + + bte = iptr->val.a; + md = bte->md; + + s2 = emit_load_s2(jd, iptr, src, PACK_REGS(REG_ITMP2, REG_ITMP1)); + M_OR_TST(GET_HIGH_REG(s2), GET_LOW_REG(s2), REG_ITMP3); + M_BEQ(0); + codegen_add_arithmeticexception_ref(cd); + + disp = dseg_addaddress(cd, bte->fp); + M_ALD(REG_ITMP3, REG_PV, disp); + M_MTCTR(REG_ITMP3); + + s3 = PACK_REGS(rd->argintregs[GET_LOW_REG(md->params[1].regoff)], + rd->argintregs[GET_HIGH_REG(md->params[1].regoff)]); + M_LNGMOVE(s2, s3); + + s1 = emit_load_s1(jd, iptr, src->prev, PACK_REGS(REG_ITMP2, REG_ITMP1)); + s3 = PACK_REGS(rd->argintregs[GET_LOW_REG(md->params[0].regoff)], + rd->argintregs[GET_HIGH_REG(md->params[0].regoff)]); + M_LNGMOVE(s1, s3); + + M_JSR; + + /*d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_RESULT2, REG_RESULT)); //FIXME */ + /*M_LNGMOVE(PACK_REGS(REG_RESULT2, REG_RESULT), d); FIXME*/ + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_IMUL(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */ + /* val.i = constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if ((iptr->val.i >= -32768) && (iptr->val.i <= 32767)) { + M_IMUL_IMM(s1, iptr->val.i, d); + } else { + ICONST(REG_ITMP3, iptr->val.i); + M_IMUL(s1, REG_ITMP3, d); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IDIVPOW2: /* ..., value ==> ..., value << constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP3); + M_SRA_IMM(s1, iptr->val.i, d); + M_ADDZE(d, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_AND_IMM(s2, 0x1f, REG_ITMP3); + M_SLL(s1, REG_ITMP3, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */ + /* val.i = constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_SLL_IMM(s1, iptr->val.i & 0x1f, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_AND_IMM(s2, 0x1f, REG_ITMP3); + M_SRA(s1, REG_ITMP3, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */ + /* val.i = constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_SRA_IMM(s1, iptr->val.i & 0x1f, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_AND_IMM(s2, 0x1f, REG_ITMP2); + M_SRL(s1, REG_ITMP2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */ + /* val.i = constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if (iptr->val.i & 0x1f) { + M_SRL_IMM(s1, iptr->val.i & 0x1f, d); + } else { + M_INTMOVE(s1, d); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_AND(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */ + /* val.i = constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if ((iptr->val.i >= 0) && (iptr->val.i <= 65535)) { + M_AND_IMM(s1, iptr->val.i, d); + } + /* + else if (iptr->val.i == 0xffffff) { + M_RLWINM(s1, 0, 8, 31, d); + } + */ + else { + ICONST(REG_ITMP3, iptr->val.i); + M_AND(s1, REG_ITMP3, d); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LAND: /* ..., val1, val2 ==> ..., val1 & val2 */ + + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + M_AND(s1, s2, GET_LOW_REG(d)); + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP3); /* don't use REG_ITMP2 */ + M_AND(s1, s2, GET_HIGH_REG(d)); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */ + /* val.l = constant */ + + s3 = iptr->val.l & 0xffffffff; + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + if ((s3 >= 0) && (s3 <= 65535)) { + M_AND_IMM(s1, s3, GET_LOW_REG(d)); + } else { + ICONST(REG_ITMP3, s3); + M_AND(s1, REG_ITMP3, GET_LOW_REG(d)); + } + s1 = emit_load_s1_high(jd, iptr, src, REG_ITMP1); + s3 = iptr->val.l >> 32; + if ((s3 >= 0) && (s3 <= 65535)) { + M_AND_IMM(s1, s3, GET_HIGH_REG(d)); + } else { + ICONST(REG_ITMP3, s3); /* don't use REG_ITMP2 */ + M_AND(s1, REG_ITMP3, GET_HIGH_REG(d)); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */ + /* val.i = constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_MOV(s1, REG_ITMP2); + M_CMPI(s1, 0); + M_BGE(1 + 2*(iptr->val.i >= 32768)); + if (iptr->val.i >= 32768) { + M_ADDIS(REG_ZERO, iptr->val.i >> 16, REG_ITMP2); + M_OR_IMM(REG_ITMP2, iptr->val.i, REG_ITMP2); + M_IADD(s1, REG_ITMP2, REG_ITMP2); + } else { + M_IADD_IMM(s1, iptr->val.i, REG_ITMP2); + } + { + int b=0, m = iptr->val.i; + while (m >>= 1) + ++b; + M_RLWINM(REG_ITMP2, 0, 0, 30-b, REG_ITMP2); + } + M_ISUB(s1, REG_ITMP2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_OR(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IORCONST: /* ..., value ==> ..., value | constant */ + /* val.i = constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if ((iptr->val.i >= 0) && (iptr->val.i <= 65535)) { + M_OR_IMM(s1, iptr->val.i, d); + } else { + ICONST(REG_ITMP3, iptr->val.i); + M_OR(s1, REG_ITMP3, d); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LOR: /* ..., val1, val2 ==> ..., val1 | val2 */ + + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + M_OR(s1, s2, GET_LOW_REG(d)); + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP3); /* don't use REG_ITMP2 */ + M_OR(s1, s2, GET_HIGH_REG(d)); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LORCONST: /* ..., value ==> ..., value | constant */ + /* val.l = constant */ + + s3 = iptr->val.l & 0xffffffff; + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + if ((s3 >= 0) && (s3 <= 65535)) { + M_OR_IMM(s1, s3, GET_LOW_REG(d)); + } else { + ICONST(REG_ITMP3, s3); + M_OR(s1, REG_ITMP3, GET_LOW_REG(d)); + } + s1 = emit_load_s1_high(jd, iptr, src, REG_ITMP1); + s3 = iptr->val.l >> 32; + if ((s3 >= 0) && (s3 <= 65535)) { + M_OR_IMM(s1, s3, GET_HIGH_REG(d)); + } else { + ICONST(REG_ITMP3, s3); /* don't use REG_ITMP2 */ + M_OR(s1, REG_ITMP3, GET_HIGH_REG(d)); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_XOR(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */ + /* val.i = constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if ((iptr->val.i >= 0) && (iptr->val.i <= 65535)) { + M_XOR_IMM(s1, iptr->val.i, d); + } else { + ICONST(REG_ITMP3, iptr->val.i); + M_XOR(s1, REG_ITMP3, d); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */ + + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + M_XOR(s1, s2, GET_LOW_REG(d)); + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP3); /* don't use REG_ITMP2 */ + M_XOR(s1, s2, GET_HIGH_REG(d)); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */ + /* val.l = constant */ + + s3 = iptr->val.l & 0xffffffff; + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + if ((s3 >= 0) && (s3 <= 65535)) { + M_XOR_IMM(s1, s3, GET_LOW_REG(d)); + } else { + ICONST(REG_ITMP3, s3); + M_XOR(s1, REG_ITMP3, GET_LOW_REG(d)); + } + s1 = emit_load_s1_high(jd, iptr, src, REG_ITMP1); + s3 = iptr->val.l >> 32; + if ((s3 >= 0) && (s3 <= 65535)) { + M_XOR_IMM(s1, s3, GET_HIGH_REG(d)); + } else { + ICONST(REG_ITMP3, s3); /* don't use REG_ITMP2 */ + M_XOR(s1, REG_ITMP3, GET_HIGH_REG(d)); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LCMP: /* ..., val1, val2 ==> ..., val1 cmp val2 */ + /******************************************************************* + TODO: CHANGE THIS TO A VERSION THAT WORKS !!! + *******************************************************************/ + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP3); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP1); + { + int tempreg = false; + int dreg; + u1 *br1; + + if (src->prev->flags & INMEMORY) { + tempreg = tempreg || (d == REG_ITMP3) || (d == REG_ITMP2); + } else { + tempreg = tempreg || (d == GET_HIGH_REG(src->prev->regoff)) + || (d == GET_LOW_REG(src->prev->regoff)); + } + if (src->flags & INMEMORY) { + tempreg = tempreg || (d == REG_ITMP3) || (d == REG_ITMP2); + } else { + tempreg = tempreg || (d == GET_HIGH_REG(src->regoff)) + || (d == GET_LOW_REG(src->regoff)); + } + + dreg = tempreg ? REG_ITMP1 : d; + M_IADD_IMM(REG_ZERO, 1, dreg); + M_CMP(s1, s2); + M_BGT(0); + br1 = cd->mcodeptr; + M_BLT(0); + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP3); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + M_CMPU(s1, s2); + M_BGT(3); + M_BEQ(1); + M_IADD_IMM(dreg, -1, dreg); + M_IADD_IMM(dreg, -1, dreg); + gen_resolvebranch(br1, br1, cd->mcodeptr); + gen_resolvebranch(br1 + 1 * 4, br1 + 1 * 4, cd->mcodeptr - 2 * 4); + M_INTMOVE(dreg, d); + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IINC: /* ..., value ==> ..., value + constant */ + /* op1 = variable, val.i = constant */ + + var = &(rd->locals[iptr->op1][TYPE_INT]); + if (var->flags & INMEMORY) { + s1 = REG_ITMP1; + M_ILD(s1, REG_SP, var->regoff * 4); + } else + s1 = var->regoff; + { + u4 m = iptr->val.i; + if (m & 0x8000) + m += 65536; + if (m & 0xffff0000) + M_ADDIS(s1, m >> 16, s1); + if (m & 0xffff) + M_IADD_IMM(s1, m & 0xffff, s1); + } + if (var->flags & INMEMORY) + M_IST(s1, REG_SP, var->regoff * 4); + break; + + + /* floating operations ************************************************/ + + case ICMD_FNEG: /* ..., value ==> ..., - value */ + + s1 = emit_load_s1(jd, iptr, src, REG_FTMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_FMOVN(s1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_DNEG: /* ..., value ==> ..., - value */ + + s1 = emit_load_s1(jd, iptr, src, REG_FTMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_FMOVN(s1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_FADD(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_DADD(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_FSUB(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_DSUB(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_FMUL(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_DMUL(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_FDIV(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_DDIV(s1, s2, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_F2I: /* ..., value ==> ..., (int) value */ + case ICMD_D2I: + + s1 = emit_load_s1(jd, iptr, src, REG_FTMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_CLR(d); + disp = dseg_addfloat(cd, 0.0); + M_FLD(REG_FTMP2, REG_PV, disp); + M_FCMPU(s1, REG_FTMP2); + M_BNAN(4); + disp = dseg_adds4(cd, 0); + M_CVTDL_C(s1, REG_FTMP1); + M_LDA(REG_ITMP1, REG_PV, disp); + M_STFIWX(REG_FTMP1, 0, REG_ITMP1); + M_ILD(d, REG_PV, disp); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_F2D: /* ..., value ==> ..., (double) value */ + + s1 = emit_load_s1(jd, iptr, src, REG_FTMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_FLTMOVE(s1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_D2F: /* ..., value ==> ..., (double) value */ + + s1 = emit_load_s1(jd, iptr, src, REG_FTMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP3); + M_CVTDF(s1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_FCMPL: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */ + case ICMD_DCMPL: /* == => 0, < => 1, > => -1 */ + + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP1); + M_FCMPU(s2, s1); + M_IADD_IMM(REG_ZERO, -1, d); + M_BNAN(4); + M_BGT(3); + M_IADD_IMM(REG_ZERO, 0, d); + M_BGE(1); + M_IADD_IMM(REG_ZERO, 1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_FCMPG: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */ + case ICMD_DCMPG: /* == => 0, < => 1, > => -1 */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP1); + M_FCMPU(s1, s2); + M_IADD_IMM(REG_ZERO, 1, d); + M_BNAN(4); + M_BGT(3); + M_IADD_IMM(REG_ZERO, 0, d); + M_BGE(1); + M_IADD_IMM(REG_ZERO, -1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IF_FCMPEQ: /* ..., value, value ==> ... */ + case ICMD_IF_DCMPEQ: + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_FCMPU(s1, s2); + M_BNAN(1); + M_BEQ(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_FCMPNE: /* ..., value, value ==> ... */ + case ICMD_IF_DCMPNE: + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_FCMPU(s1, s2); + M_BNAN(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BNE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + + case ICMD_IF_FCMPL_LT: /* ..., value, value ==> ... */ + case ICMD_IF_DCMPL_LT: + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_FCMPU(s1, s2); + M_BNAN(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BLT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_FCMPL_GT: /* ..., value, value ==> ... */ + case ICMD_IF_DCMPL_GT: + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_FCMPU(s1, s2); + M_BNAN(1); + M_BGT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_FCMPL_LE: /* ..., value, value ==> ... */ + case ICMD_IF_DCMPL_LE: + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_FCMPU(s1, s2); + M_BNAN(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BLE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_FCMPL_GE: /* ..., value, value ==> ... */ + case ICMD_IF_DCMPL_GE: + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_FCMPU(s1, s2); + M_BNAN(1); + M_BGE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_FCMPG_LT: /* ..., value, value ==> ... */ + case ICMD_IF_DCMPG_LT: + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_FCMPU(s1, s2); + M_BNAN(1); + M_BLT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_FCMPG_GT: /* ..., value, value ==> ... */ + case ICMD_IF_DCMPG_GT: + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_FCMPU(s1, s2); + M_BNAN(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BGT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_FCMPG_LE: /* ..., value, value ==> ... */ + case ICMD_IF_DCMPG_LE: + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_FCMPU(s1, s2); + M_BNAN(1); + M_BLE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_FCMPG_GE: /* ..., value, value ==> ... */ + case ICMD_IF_DCMPG_GE: + + s1 = emit_load_s1(jd, iptr, src->prev, REG_FTMP1); + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_FCMPU(s1, s2); + M_BNAN(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BGE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + + /* memory operations **************************************************/ + + case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + gen_nullptr_check(s1); + M_ILD(d, s1, OFFSET(java_arrayheader, size)); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + M_IADD_IMM(s2, OFFSET(java_chararray, data[0]), REG_ITMP2); + M_LBZX(d, s1, REG_ITMP2); + M_BSEXT(d, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + M_SLL_IMM(s2, 1, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_chararray, data[0]), REG_ITMP2); + M_LHZX(d, s1, REG_ITMP2); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + M_SLL_IMM(s2, 1, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_shortarray, data[0]), REG_ITMP2); + M_LHAX(d, s1, REG_ITMP2); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + M_SLL_IMM(s2, 2, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_intarray, data[0]), REG_ITMP2); + M_LWZX(d, s1, REG_ITMP2); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + M_SLL_IMM(s2, 3, REG_ITMP2); + M_IADD(s1, REG_ITMP2, REG_ITMP2); + M_LLD_INTERN(d, REG_ITMP2, OFFSET(java_longarray, data[0])); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP1); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + M_SLL_IMM(s2, 2, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_floatarray, data[0]), REG_ITMP2); + M_LFSX(d, s1, REG_ITMP2); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP1); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + M_SLL_IMM(s2, 3, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_doublearray, data[0]), REG_ITMP2); + M_LFDX(d, s1, REG_ITMP2); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + M_SLL_IMM(s2, 2, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_objectarray, data[0]), REG_ITMP2); + M_LWZX(d, s1, REG_ITMP2); + emit_store(jd, iptr, iptr->dst, d); + break; + + + case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */ + + s1 = emit_load_s1(jd, iptr, src->prev->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src->prev, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, src, REG_ITMP3); + M_IADD_IMM(s2, OFFSET(java_bytearray, data[0]), REG_ITMP2); + M_STBX(s3, s1, REG_ITMP2); + break; + + case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */ + + s1 = emit_load_s1(jd, iptr, src->prev->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src->prev, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, src, REG_ITMP3); + M_SLL_IMM(s2, 1, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_chararray, data[0]), REG_ITMP2); + M_STHX(s3, s1, REG_ITMP2); + break; + + case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */ + + s1 = emit_load_s1(jd, iptr, src->prev->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src->prev, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, src, REG_ITMP3); + M_SLL_IMM(s2, 1, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_shortarray, data[0]), REG_ITMP2); + M_STHX(s3, s1, REG_ITMP2); + break; + + case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */ + + s1 = emit_load_s1(jd, iptr, src->prev->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src->prev, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, src, REG_ITMP3); + M_SLL_IMM(s2, 2, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_intarray, data[0]), REG_ITMP2); + M_STWX(s3, s1, REG_ITMP2); + break; + + case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */ + + s1 = emit_load_s1(jd, iptr, src->prev->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src->prev, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3_high(jd, iptr, src, REG_ITMP3); + M_SLL_IMM(s2, 3, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_longarray, data[0]), REG_ITMP2); + M_STWX(s3, s1, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, 4, REG_ITMP2); + s3 = emit_load_s3_low(jd, iptr, src, REG_ITMP3); + M_STWX(s3, s1, REG_ITMP2); + break; + + case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */ + + s1 = emit_load_s1(jd, iptr, src->prev->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src->prev, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, src, REG_FTMP3); + M_SLL_IMM(s2, 2, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_floatarray, data[0]), REG_ITMP2); + M_STFSX(s3, s1, REG_ITMP2); + break; + + case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */ + + s1 = emit_load_s1(jd, iptr, src->prev->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src->prev, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, src, REG_FTMP3); + M_SLL_IMM(s2, 3, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_doublearray, data[0]), REG_ITMP2); + M_STFDX(s3, s1, REG_ITMP2); + break; + + case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */ + + s1 = emit_load_s1(jd, iptr, src->prev->prev, rd->argintregs[0]); + s2 = emit_load_s2(jd, iptr, src->prev, REG_ITMP2); + if (iptr->op1 == 0) { + gen_nullptr_check(s1); + gen_bound_check; + } + s3 = emit_load_s3(jd, iptr, src, rd->argintregs[1]); + + disp = dseg_addaddress(cd, BUILTIN_canstore); + M_ALD(REG_ITMP3, REG_PV, disp); + M_MTCTR(REG_ITMP3); + + M_INTMOVE(s1, rd->argintregs[0]); + M_INTMOVE(s3, rd->argintregs[1]); + + M_JSR; + M_TST(REG_RESULT); + M_BEQ(0); + codegen_add_arraystoreexception_ref(cd); + + s1 = emit_load_s1(jd, iptr, src->prev->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src->prev, REG_ITMP2); + s3 = emit_load_s3(jd, iptr, src, REG_ITMP3); + M_SLL_IMM(s2, 2, REG_ITMP2); + M_IADD_IMM(REG_ITMP2, OFFSET(java_objectarray, data[0]), REG_ITMP2); + M_STWX(s3, s1, REG_ITMP2); + break; + + + case ICMD_GETSTATIC: /* ... ==> ..., value */ + /* op1 = type, val.a = field address */ + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + disp = dseg_addaddress(cd, NULL); + + codegen_addpatchref(cd, PATCHER_get_putstatic, + INSTRUCTION_UNRESOLVED_FIELD(iptr), disp); + + if (opt_showdisassemble) + M_NOP; + + } else { + fieldinfo *fi = INSTRUCTION_RESOLVED_FIELDINFO(iptr); + + disp = dseg_addaddress(cd, &(fi->value)); + + if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) { + codegen_addpatchref(cd, PATCHER_clinit, fi->class, disp); + + if (opt_showdisassemble) + M_NOP; + } + } + + M_ALD(REG_ITMP1, REG_PV, disp); + switch (iptr->op1) { + case TYPE_INT: + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_ILD_INTERN(d, REG_ITMP1, 0); + break; + case TYPE_LNG: + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + M_ILD_INTERN(GET_LOW_REG(d), REG_ITMP1, 4);/* keep this order */ + M_ILD_INTERN(GET_HIGH_REG(d), REG_ITMP1, 0);/*keep this order */ + break; + case TYPE_ADR: + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_ALD_INTERN(d, REG_ITMP1, 0); + break; + case TYPE_FLT: + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP1); + M_FLD_INTERN(d, REG_ITMP1, 0); + break; + case TYPE_DBL: + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP1); + M_DLD_INTERN(d, REG_ITMP1, 0); + break; + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_PUTSTATIC: /* ..., value ==> ... */ + /* op1 = type, val.a = field address */ + + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + disp = dseg_addaddress(cd, NULL); + + codegen_addpatchref(cd, PATCHER_get_putstatic, + INSTRUCTION_UNRESOLVED_FIELD(iptr), disp); + + if (opt_showdisassemble) + M_NOP; + + } else { + fieldinfo *fi = INSTRUCTION_RESOLVED_FIELDINFO(iptr); + + disp = dseg_addaddress(cd, &(fi->value)); + + if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) { + codegen_addpatchref(cd, PATCHER_clinit, fi->class, disp); + + if (opt_showdisassemble) + M_NOP; + } + } + + M_ALD(REG_ITMP1, REG_PV, disp); + switch (iptr->op1) { + case TYPE_INT: + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + M_IST_INTERN(s2, REG_ITMP1, 0); + break; + case TYPE_LNG: + s2 = emit_load_s2(jd, iptr, src, PACK_REGS(REG_ITMP2, REG_ITMP3)); + M_LST_INTERN(s2, REG_ITMP1, 0); + break; + case TYPE_ADR: + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + M_AST_INTERN(s2, REG_ITMP1, 0); + break; + case TYPE_FLT: + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_FST_INTERN(s2, REG_ITMP1, 0); + break; + case TYPE_DBL: + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + M_DST_INTERN(s2, REG_ITMP1, 0); + break; + } + break; + + + case ICMD_GETFIELD: /* ... ==> ..., value */ + /* op1 = type, val.i = field offset */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + gen_nullptr_check(s1); + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + codegen_addpatchref(cd, PATCHER_get_putfield, + INSTRUCTION_UNRESOLVED_FIELD(iptr), 0); + + if (opt_showdisassemble) + M_NOP; + + disp = 0; + + } else { + disp = INSTRUCTION_RESOLVED_FIELDINFO(iptr)->offset; + } + + switch (iptr->op1) { + case TYPE_INT: + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_ILD(d, s1, disp); + break; + case TYPE_LNG: + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + if (GET_HIGH_REG(d) == s1) { + M_ILD(GET_LOW_REG(d), s1, disp + 4); + M_ILD(GET_HIGH_REG(d), s1, disp); + } else { + M_ILD(GET_HIGH_REG(d), s1, disp); + M_ILD(GET_LOW_REG(d), s1, disp + 4); + } + break; + case TYPE_ADR: + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + M_ALD(d, s1, disp); + break; + case TYPE_FLT: + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP1); + M_FLD(d, s1, disp); + break; + case TYPE_DBL: + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FTMP1); + M_DLD(d, s1, disp); + break; + } + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_PUTFIELD: /* ..., value ==> ... */ + /* op1 = type, val.i = field offset */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + gen_nullptr_check(s1); + + if (!IS_FLT_DBL_TYPE(iptr->op1)) { + if (IS_2_WORD_TYPE(iptr->op1)) { + s2 = emit_load_s2(jd, iptr, src, PACK_REGS(REG_ITMP2, REG_ITMP3)); + } else { + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + } + } else { + s2 = emit_load_s2(jd, iptr, src, REG_FTMP2); + } + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + codegen_addpatchref(cd, PATCHER_get_putfield, + INSTRUCTION_UNRESOLVED_FIELD(iptr), 0); + + if (opt_showdisassemble) + M_NOP; + + disp = 0; + + } else { + disp = INSTRUCTION_RESOLVED_FIELDINFO(iptr)->offset; + } + + switch (iptr->op1) { + case TYPE_INT: + M_IST(s2, s1, disp); + break; + case TYPE_LNG: + M_IST(GET_LOW_REG(s2), s1, disp + 4); /* keep this order */ + M_IST(GET_HIGH_REG(s2), s1, disp); /* keep this order */ + break; + case TYPE_ADR: + M_AST(s2, s1, disp); + break; + case TYPE_FLT: + M_FST(s2, s1, disp); + break; + case TYPE_DBL: + M_DST(s2, s1, disp); + break; + } + break; + + + /* branch operations **************************************************/ + + case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + M_INTMOVE(s1, REG_ITMP1_XPTR); + +#ifdef ENABLE_VERIFIER + if (iptr->val.a) { + codegen_addpatchref(cd, PATCHER_athrow_areturn, + (unresolved_class *) iptr->val.a, 0); + + if (opt_showdisassemble) + M_NOP; + } +#endif /* ENABLE_VERIFIER */ + + disp = dseg_addaddress(cd, asm_handle_exception); + M_ALD(REG_ITMP2, REG_PV, disp); + M_MTCTR(REG_ITMP2); + + if (m->isleafmethod) M_MFLR(REG_ITMP3); /* save LR */ + M_BL(0); /* get current PC */ + M_MFLR(REG_ITMP2_XPC); + if (m->isleafmethod) M_MTLR(REG_ITMP3); /* restore LR */ + M_RTS; /* jump to CTR */ + + ALIGNCODENOP; + break; + + case ICMD_GOTO: /* ... ==> ... */ + /* op1 = target JavaVM pc */ + M_BR(0); + codegen_addreference(cd, (basicblock *) iptr->target); + ALIGNCODENOP; + break; + + case ICMD_JSR: /* ... ==> ... */ + /* op1 = target JavaVM pc */ + + if (m->isleafmethod) + M_MFLR(REG_ITMP2); + M_BL(0); + M_MFLR(REG_ITMP1); + M_IADD_IMM(REG_ITMP1, m->isleafmethod ? 4*4 : 3*4, REG_ITMP1); + if (m->isleafmethod) + M_MTLR(REG_ITMP2); + M_BR(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_RET: /* ... ==> ... */ + /* op1 = local variable */ + + var = &(rd->locals[iptr->op1][TYPE_ADR]); + if (var->flags & INMEMORY) { + M_ALD(REG_ITMP1, REG_SP, var->regoff * 4); + M_MTCTR(REG_ITMP1); + } else { + M_MTCTR(var->regoff); + } + M_RTS; + ALIGNCODENOP; + break; + + case ICMD_IFNULL: /* ..., value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + M_TST(s1); + M_BEQ(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IFNONNULL: /* ..., value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + M_TST(s1); + M_BNE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IFLT: + case ICMD_IFLE: + case ICMD_IFNE: + case ICMD_IFGT: + case ICMD_IFGE: + case ICMD_IFEQ: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.i = constant */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + if ((iptr->val.i >= -32768) && (iptr->val.i <= 32767)) + M_CMPI(s1, iptr->val.i); + else { + ICONST(REG_ITMP2, iptr->val.i); + M_CMP(s1, REG_ITMP2); + } + switch (iptr->opc) { + case ICMD_IFLT: + M_BLT(0); + break; + case ICMD_IFLE: + M_BLE(0); + break; + case ICMD_IFNE: + M_BNE(0); + break; + case ICMD_IFGT: + M_BGT(0); + break; + case ICMD_IFGE: + M_BGE(0); + break; + case ICMD_IFEQ: + M_BEQ(0); + break; + } + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + + case ICMD_IF_LEQ: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); + if (iptr->val.l == 0) { + M_OR_TST(s1, s2, REG_ITMP3); + } else if ((iptr->val.l >= 0) && (iptr->val.l <= 0xffff)) { + M_XOR_IMM(s2, 0, REG_ITMP2); + M_XOR_IMM(s1, iptr->val.l & 0xffff, REG_ITMP1); + M_OR_TST(REG_ITMP1, REG_ITMP2, REG_ITMP3); + } else { + ICONST(REG_ITMP3, iptr->val.l & 0xffffffff); + M_XOR(s1, REG_ITMP3, REG_ITMP1); + ICONST(REG_ITMP3, iptr->val.l >> 32); + M_XOR(s2, REG_ITMP3, REG_ITMP2); + M_OR_TST(REG_ITMP1, REG_ITMP2, REG_ITMP3); + } + M_BEQ(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_LLT: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); + if (iptr->val.l == 0) { + /* if high word is less than zero, the whole long is too */ + M_CMPI(s2, 0); + } else if ((iptr->val.l >= 0) && (iptr->val.l <= 0xffff)) { + M_CMPI(s2, 0); + M_BLT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BGT(2); + M_CMPUI(s1, iptr->val.l & 0xffff); + } else { + ICONST(REG_ITMP3, iptr->val.l >> 32); + M_CMP(s2, REG_ITMP3); + M_BLT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BGT(3); + ICONST(REG_ITMP3, iptr->val.l & 0xffffffff); + M_CMPU(s1, REG_ITMP3); + } + M_BLT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_LLE: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); +/* if (iptr->val.l == 0) { */ +/* M_OR(s1, s2, REG_ITMP3); */ +/* M_CMPI(REG_ITMP3, 0); */ + +/* } else */ + if ((iptr->val.l >= 0) && (iptr->val.l <= 0xffff)) { + M_CMPI(s2, 0); + M_BLT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BGT(2); + M_CMPUI(s1, iptr->val.l & 0xffff); + } else { + ICONST(REG_ITMP3, iptr->val.l >> 32); + M_CMP(s2, REG_ITMP3); + M_BLT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BGT(3); + ICONST(REG_ITMP3, iptr->val.l & 0xffffffff); + M_CMPU(s1, REG_ITMP3); + } + M_BLE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_LNE: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); + if (iptr->val.l == 0) { + M_OR_TST(s1, s2, REG_ITMP3); + } else if ((iptr->val.l >= 0) && (iptr->val.l <= 0xffff)) { + M_XOR_IMM(s2, 0, REG_ITMP2); + M_XOR_IMM(s1, iptr->val.l & 0xffff, REG_ITMP1); + M_OR_TST(REG_ITMP1, REG_ITMP2, REG_ITMP3); + } else { + ICONST(REG_ITMP3, iptr->val.l & 0xffffffff); + M_XOR(s1, REG_ITMP3, REG_ITMP1); + ICONST(REG_ITMP3, iptr->val.l >> 32); + M_XOR(s2, REG_ITMP3, REG_ITMP2); + M_OR_TST(REG_ITMP1, REG_ITMP2, REG_ITMP3); + } + M_BNE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_LGT: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); +/* if (iptr->val.l == 0) { */ +/* M_OR(s1, s2, REG_ITMP3); */ +/* M_CMPI(REG_ITMP3, 0); */ + +/* } else */ + if ((iptr->val.l >= 0) && (iptr->val.l <= 0xffff)) { + M_CMPI(s2, 0); + M_BGT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BLT(2); + M_CMPUI(s1, iptr->val.l & 0xffff); + } else { + ICONST(REG_ITMP3, iptr->val.l >> 32); + M_CMP(s2, REG_ITMP3); + M_BGT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BLT(3); + ICONST(REG_ITMP3, iptr->val.l & 0xffffffff); + M_CMPU(s1, REG_ITMP3); + } + M_BGT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_LGE: /* ..., value ==> ... */ + /* op1 = target JavaVM pc, val.l = constant */ + + s1 = emit_load_s1_low(jd, iptr, src, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); + if (iptr->val.l == 0) { + /* if high word is greater equal zero, the whole long is too */ + M_CMPI(s2, 0); + } else if ((iptr->val.l >= 0) && (iptr->val.l <= 0xffff)) { + M_CMPI(s2, 0); + M_BGT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BLT(2); + M_CMPUI(s1, iptr->val.l & 0xffff); + } else { + ICONST(REG_ITMP3, iptr->val.l >> 32); + M_CMP(s2, REG_ITMP3); + M_BGT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + M_BLT(3); + ICONST(REG_ITMP3, iptr->val.l & 0xffffffff); + M_CMPU(s1, REG_ITMP3); + } + M_BGE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ + case ICMD_IF_ACMPEQ: /* op1 = target JavaVM pc */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BEQ(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_LCMPEQ: /* ..., value, value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + /* load low-bits before the branch, so we know the distance */ + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + M_BNE(2); + M_CMP(s1, s2); + M_BEQ(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_ICMPNE: /* ..., value, value ==> ... */ + case ICMD_IF_ACMPNE: /* op1 = target JavaVM pc */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BNE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_LCMPNE: /* ..., value, value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BNE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BNE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BLT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_LCMPLT: /* ..., value, value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BLT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + /* load low-bits before the branch, so we know the distance */ + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + M_BGT(2); + M_CMPU(s1, s2); + M_BLT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BGT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_LCMPGT: /* ..., value, value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BGT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + /* load low-bits before the branch, so we know the distance */ + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + M_BLT(2); + M_CMPU(s1, s2); + M_BGT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BLE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_LCMPLE: /* ..., value, value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BLT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + /* load low-bits before the branch, so we know the distance */ + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + M_BGT(2); + M_CMPU(s1, s2); + M_BLE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BGE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IF_LCMPGE: /* ..., value, value ==> ... */ + /* op1 = target JavaVM pc */ + + s1 = emit_load_s1_high(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_high(jd, iptr, src, REG_ITMP2); + M_CMP(s1, s2); + M_BGT(0); + codegen_addreference(cd, (basicblock *) iptr->target); + /* load low-bits before the branch, so we know the distance */ + s1 = emit_load_s1_low(jd, iptr, src->prev, REG_ITMP1); + s2 = emit_load_s2_low(jd, iptr, src, REG_ITMP2); + M_BLT(2); + M_CMPU(s1, s2); + M_BGE(0); + codegen_addreference(cd, (basicblock *) iptr->target); + break; + + case ICMD_IRETURN: /* ..., retvalue ==> ... */ + + s1 = emit_load_s1(jd, iptr, src, REG_RESULT); + M_INTMOVE(s1, REG_RESULT); + goto nowperformreturn; + + case ICMD_ARETURN: /* ..., retvalue ==> ... */ + + s1 = emit_load_s1(jd, iptr, src, REG_RESULT); + M_INTMOVE(s1, REG_RESULT); + +#ifdef ENABLE_VERIFIER + if (iptr->val.a) { + codegen_addpatchref(cd, PATCHER_athrow_areturn, + (unresolved_class *) iptr->val.a, 0); + + if (opt_showdisassemble) + M_NOP; + } +#endif /* ENABLE_VERIFIER */ + goto nowperformreturn; + + case ICMD_LRETURN: /* ..., retvalue ==> ... */ + + /*s1 = emit_load_s1(jd, iptr, src, PACK_REGS(REG_RESULT2, REG_RESULT)); FIXME*/ + /*M_LNGMOVE(s1, PACK_REGS(REG_RESULT2, REG_RESULT)); FIXME*/ + goto nowperformreturn; + + case ICMD_FRETURN: /* ..., retvalue ==> ... */ + case ICMD_DRETURN: + + s1 = emit_load_s1(jd, iptr, src, REG_FRESULT); + M_FLTMOVE(s1, REG_FRESULT); + goto nowperformreturn; + + case ICMD_RETURN: /* ... ==> ... */ + +nowperformreturn: + { + s4 i, p; + + p = stackframesize; + + /* call trace function */ + + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + M_MFLR(REG_ZERO); + M_LDA(REG_SP, REG_SP, -10 * 8); + M_DST(REG_FRESULT, REG_SP, 48+0); + M_IST(REG_RESULT, REG_SP, 48+8); + M_AST(REG_ZERO, REG_SP, 48+12); + /*M_IST(REG_RESULT2, REG_SP, 48+16); FIXME*/ + + /* keep this order */ + switch (iptr->opc) { + case ICMD_IRETURN: + case ICMD_ARETURN: +#if defined(__DARWIN__) + M_MOV(REG_RESULT, rd->argintregs[2]); + M_CLR(rd->argintregs[1]); +#else + M_MOV(REG_RESULT, rd->argintregs[3]); + M_CLR(rd->argintregs[2]); +#endif + break; + + case ICMD_LRETURN: +#if defined(__DARWIN__) + /*M_MOV(REG_RESULT2, rd->argintregs[2]); FIXME */ + M_MOV(REG_RESULT, rd->argintregs[1]); +#else + /*M_MOV(REG_RESULT2, rd->argintregs[3]); FIXME*/ + M_MOV(REG_RESULT, rd->argintregs[2]); +#endif + break; + } + + disp = dseg_addaddress(cd, m); + M_ALD(rd->argintregs[0], REG_PV, disp); + + M_FLTMOVE(REG_FRESULT, rd->argfltregs[0]); + M_FLTMOVE(REG_FRESULT, rd->argfltregs[1]); + disp = dseg_addaddress(cd, builtin_displaymethodstop); + M_ALD(REG_ITMP2, REG_PV, disp); + M_MTCTR(REG_ITMP2); + M_JSR; + + M_DLD(REG_FRESULT, REG_SP, 48+0); + M_ILD(REG_RESULT, REG_SP, 48+8); + M_ALD(REG_ZERO, REG_SP, 48+12); + /*M_ILD(REG_RESULT2, REG_SP, 48+16); FIXME*/ + M_LDA(REG_SP, REG_SP, 10 * 8); + M_MTLR(REG_ZERO); + } + +#if defined(ENABLE_THREADS) + if (checksync && (m->flags & ACC_SYNCHRONIZED)) { + disp = dseg_addaddress(cd, BUILTIN_monitorexit); + M_ALD(REG_ITMP3, REG_PV, disp); + M_MTCTR(REG_ITMP3); + + /* we need to save the proper return value */ + + switch (iptr->opc) { + case ICMD_LRETURN: + /*M_IST(REG_RESULT2, REG_SP, rd->memuse * 4 + 8); FIXME*/ + /* fall through */ + case ICMD_IRETURN: + case ICMD_ARETURN: + M_IST(REG_RESULT , REG_SP, rd->memuse * 4 + 4); + break; + case ICMD_FRETURN: + M_FST(REG_FRESULT, REG_SP, rd->memuse * 4 + 4); + break; + case ICMD_DRETURN: + M_DST(REG_FRESULT, REG_SP, rd->memuse * 4 + 4); + break; + } + + M_ALD(rd->argintregs[0], REG_SP, rd->memuse * 4); + M_JSR; + + /* and now restore the proper return value */ + + switch (iptr->opc) { + case ICMD_LRETURN: + /*M_ILD(REG_RESULT2, REG_SP, rd->memuse * 4 + 8); FIXME*/ + /* fall through */ + case ICMD_IRETURN: + case ICMD_ARETURN: + M_ILD(REG_RESULT , REG_SP, rd->memuse * 4 + 4); + break; + case ICMD_FRETURN: + M_FLD(REG_FRESULT, REG_SP, rd->memuse * 4 + 4); + break; + case ICMD_DRETURN: + M_DLD(REG_FRESULT, REG_SP, rd->memuse * 4 + 4); + break; + } + } +#endif + + /* restore return address */ + + if (!m->isleafmethod) { + /* ATTENTION: Don't use REG_ZERO (r0) here, as M_ALD + may have a displacement overflow. */ + + M_ALD(REG_ITMP1, REG_SP, p * 4 + LA_LR_OFFSET); + M_MTLR(REG_ITMP1); + } + + /* restore saved registers */ + + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p--; M_ILD(rd->savintregs[i], REG_SP, p * 4); + } + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p -= 2; M_DLD(rd->savfltregs[i], REG_SP, p * 4); + } + + /* deallocate stack */ + + if (stackframesize) + M_LDA(REG_SP, REG_SP, stackframesize * 4); + + M_RET; + ALIGNCODENOP; + } + break; + + + case ICMD_TABLESWITCH: /* ..., index ==> ... */ + { + s4 i, l, *s4ptr; + void **tptr; + + tptr = (void **) iptr->target; + + s4ptr = iptr->val.a; + l = s4ptr[1]; /* low */ + i = s4ptr[2]; /* high */ + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + if (l == 0) { + M_INTMOVE(s1, REG_ITMP1); + } else if (l <= 32768) { + M_LDA(REG_ITMP1, s1, -l); + } else { + ICONST(REG_ITMP2, l); + M_ISUB(s1, REG_ITMP2, REG_ITMP1); + } + i = i - l + 1; + + /* range check */ + + M_CMPUI(REG_ITMP1, i - 1); + M_BGT(0); + codegen_addreference(cd, (basicblock *) tptr[0]); + + /* build jump table top down and use address of lowest entry */ + + /* s4ptr += 3 + i; */ + tptr += i; + + while (--i >= 0) { + dseg_addtarget(cd, (basicblock *) tptr[0]); + --tptr; + } + } + + /* length of dataseg after last dseg_addtarget is used by load */ + + M_SLL_IMM(REG_ITMP1, 2, REG_ITMP1); + M_IADD(REG_ITMP1, REG_PV, REG_ITMP2); + M_ALD(REG_ITMP2, REG_ITMP2, -(cd->dseglen)); + M_MTCTR(REG_ITMP2); + M_RTS; + ALIGNCODENOP; + break; + + + case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ + { + s4 i, l, val, *s4ptr; + void **tptr; + + tptr = (void **) iptr->target; + + s4ptr = iptr->val.a; + l = s4ptr[0]; /* default */ + i = s4ptr[1]; /* count */ + + MCODECHECK((i<<2)+8); + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + while (--i >= 0) { + s4ptr += 2; + ++tptr; + + val = s4ptr[0]; + if ((val >= -32768) && (val <= 32767)) { + M_CMPI(s1, val); + } else { + a = dseg_adds4(cd, val); + M_ILD(REG_ITMP2, REG_PV, a); + M_CMP(s1, REG_ITMP2); + } + M_BEQ(0); + codegen_addreference(cd, (basicblock *) tptr[0]); + } + + M_BR(0); + tptr = (void **) iptr->target; + codegen_addreference(cd, (basicblock *) tptr[0]); + + ALIGNCODENOP; + break; + } + + + case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ + /* op1 = arg count val.a = builtintable entry */ + + bte = iptr->val.a; + md = bte->md; + goto gen_method; + + case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ + /* op1 = arg count, val.a = method pointer */ + + case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ + case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ + case ICMD_INVOKEINTERFACE: + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + md = INSTRUCTION_UNRESOLVED_METHOD(iptr)->methodref->parseddesc.md; + lm = NULL; + } + else { + lm = INSTRUCTION_RESOLVED_METHODINFO(iptr); + md = lm->parseddesc; + } + +gen_method: + s3 = md->paramcount; + + MCODECHECK((s3 << 1) + 64); + + /* copy arguments to registers or stack location */ + + for (s3 = s3 - 1; s3 >= 0; s3--, src = src->prev) { + if (src->varkind == ARGVAR) + continue; + if (IS_INT_LNG_TYPE(src->type)) { + if (!md->params[s3].inmemory) { + if (IS_2_WORD_TYPE(src->type)) { + s1 = PACK_REGS( + rd->argintregs[GET_LOW_REG(md->params[s3].regoff)], + rd->argintregs[GET_HIGH_REG(md->params[s3].regoff)]); + d = emit_load_s1(jd, iptr, src, s1); + M_LNGMOVE(d, s1); + } else { + s1 = rd->argintregs[md->params[s3].regoff]; + d = emit_load_s1(jd, iptr, src, s1); + M_INTMOVE(d, s1); + } + + } else { + if (IS_2_WORD_TYPE(src->type)) { + d = emit_load_s1(jd, iptr, src, PACK_REGS(REG_ITMP2, REG_ITMP1)); + M_LST(d, REG_SP, md->params[s3].regoff * 4); + } else { + d = emit_load_s1(jd, iptr, src, REG_ITMP1); + M_IST(d, REG_SP, md->params[s3].regoff * 4); + } + } + + } else { + if (!md->params[s3].inmemory) { + s1 = rd->argfltregs[md->params[s3].regoff]; + d = emit_load_s1(jd, iptr, src, s1); + M_FLTMOVE(d, s1); + + } else { + d = emit_load_s1(jd, iptr, src, REG_FTMP1); + if (IS_2_WORD_TYPE(src->type)) + M_DST(d, REG_SP, md->params[s3].regoff * 4); + else + M_FST(d, REG_SP, md->params[s3].regoff * 4); + } + } + } /* end of for */ + + switch (iptr->opc) { + case ICMD_BUILTIN: + disp = dseg_addaddress(cd, bte->fp); + d = md->returntype.type; + + M_ALD(REG_PV, REG_PV, disp); /* pointer to built-in-function */ + M_MTCTR(REG_PV); + M_JSR; + disp = (s4) (cd->mcodeptr - cd->mcodebase); + M_MFLR(REG_ITMP1); + M_LDA(REG_PV, REG_ITMP1, -disp); + + /* if op1 == true, we need to check for an exception */ + + if (iptr->op1 == true) { + M_CMPI(REG_RESULT, 0); + M_BEQ(0); + codegen_add_fillinstacktrace_ref(cd); + } + break; + + case ICMD_INVOKESPECIAL: + gen_nullptr_check(rd->argintregs[0]); + M_ILD(REG_ITMP1, rd->argintregs[0], 0); /* hardware nullptr */ + /* fall through */ + + case ICMD_INVOKESTATIC: + if (lm == NULL) { + unresolved_method *um = INSTRUCTION_UNRESOLVED_METHOD(iptr); + + disp = dseg_addaddress(cd, NULL); + + codegen_addpatchref(cd, PATCHER_invokestatic_special, + um, disp); + + if (opt_showdisassemble) + M_NOP; + + d = md->returntype.type; + + } else { + disp = dseg_addaddress(cd, lm->stubroutine); + d = md->returntype.type; + } + + M_ALD(REG_PV, REG_PV, disp); + M_MTCTR(REG_PV); + M_JSR; + disp = (s4) (cd->mcodeptr - cd->mcodebase); + M_MFLR(REG_ITMP1); + M_LDA(REG_PV, REG_ITMP1, -disp); + break; + + case ICMD_INVOKEVIRTUAL: + gen_nullptr_check(rd->argintregs[0]); + + if (lm == NULL) { + unresolved_method *um = INSTRUCTION_UNRESOLVED_METHOD(iptr); + + codegen_addpatchref(cd, PATCHER_invokevirtual, um, 0); + + if (opt_showdisassemble) + M_NOP; + + s1 = 0; + d = md->returntype.type; + + } else { + s1 = OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * lm->vftblindex; + d = md->returntype.type; + } + + M_ALD(REG_METHODPTR, rd->argintregs[0], + OFFSET(java_objectheader, vftbl)); + M_ALD(REG_PV, REG_METHODPTR, s1); + M_MTCTR(REG_PV); + M_JSR; + disp = (s4) (cd->mcodeptr - cd->mcodebase); + M_MFLR(REG_ITMP1); + M_LDA(REG_PV, REG_ITMP1, -disp); + break; + + case ICMD_INVOKEINTERFACE: + gen_nullptr_check(rd->argintregs[0]); + + if (lm == NULL) { + unresolved_method *um = INSTRUCTION_UNRESOLVED_METHOD(iptr); + + codegen_addpatchref(cd, PATCHER_invokeinterface, um, 0); + + if (opt_showdisassemble) + M_NOP; + + s1 = 0; + s2 = 0; + d = md->returntype.type; + + } else { + s1 = OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr*) * lm->class->index; + + s2 = sizeof(methodptr) * (lm - lm->class->methods); + + d = md->returntype.type; + } + + M_ALD(REG_METHODPTR, rd->argintregs[0], + OFFSET(java_objectheader, vftbl)); + M_ALD(REG_METHODPTR, REG_METHODPTR, s1); + M_ALD(REG_PV, REG_METHODPTR, s2); + M_MTCTR(REG_PV); + M_JSR; + disp = (s4) (cd->mcodeptr - cd->mcodebase); + M_MFLR(REG_ITMP1); + M_LDA(REG_PV, REG_ITMP1, -disp); + break; + } + + /* d contains return type */ + + if (d != TYPE_VOID) { + if (IS_INT_LNG_TYPE(iptr->dst->type)) { + if (IS_2_WORD_TYPE(iptr->dst->type)) { + /*s1 = codegen_reg_of_var(rd, iptr->opc, iptr->dst, + PACK_REGS(REG_RESULT2, REG_RESULT)); FIXME*/ + /*M_LNGMOVE(PACK_REGS(REG_RESULT2, REG_RESULT), s1); FIXME*/ + } else { + s1 = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_RESULT); + M_INTMOVE(REG_RESULT, s1); + } + } else { + s1 = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_FRESULT); + M_FLTMOVE(REG_FRESULT, s1); + } + emit_store(jd, iptr, iptr->dst, s1); + } + break; + + + case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ + /* op1: 0 == array, 1 == class */ + /* 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->diffvall)); + */ + + if (iptr->op1 == 1) { + /* object type cast-check */ + + classinfo *super; + vftbl_t *supervftbl; + s4 superindex; + + super = (classinfo *) iptr->val.a; + + if (!super) { + superindex = 0; + supervftbl = NULL; + + } else { + superindex = super->index; + supervftbl = super->vftbl; + } + +#if defined(ENABLE_THREADS) + codegen_threadcritrestart(cd, cd->mcodeptr - cd->mcodebase); +#endif + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + + /* calculate interface checkcast code size */ + + s2 = 7; + if (!super) + s2 += (opt_showdisassemble ? 1 : 0); + + /* calculate class checkcast code size */ + + s3 = 8 + (s1 == REG_ITMP1); + if (!super) + s3 += (opt_showdisassemble ? 1 : 0); + + /* if class is not resolved, check which code to call */ + + if (!super) { + M_TST(s1); + M_BEQ(3 + (opt_showdisassemble ? 1 : 0) + s2 + 1 + s3); + + disp = dseg_adds4(cd, 0); /* super->flags */ + + codegen_addpatchref(cd, + PATCHER_checkcast_instanceof_flags, + (constant_classref *) iptr->target, + disp); + + if (opt_showdisassemble) + M_NOP; + + M_ILD(REG_ITMP2, REG_PV, disp); + M_AND_IMM(REG_ITMP2, ACC_INTERFACE, REG_ITMP2); + M_BEQ(s2 + 1); + } + + /* interface checkcast code */ + + if (!super || (super->flags & ACC_INTERFACE)) { + if (super) { + M_TST(s1); + M_BEQ(s2); + + } else { + codegen_addpatchref(cd, + PATCHER_checkcast_instanceof_interface, + (constant_classref *) iptr->target, + 0); + + if (opt_showdisassemble) + M_NOP; + } + + M_ALD(REG_ITMP2, s1, OFFSET(java_objectheader, vftbl)); + M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, interfacetablelength)); + M_LDATST(REG_ITMP3, REG_ITMP3, -superindex); + M_BLE(0); + codegen_add_classcastexception_ref(cd); + M_ALD(REG_ITMP3, REG_ITMP2, + OFFSET(vftbl_t, interfacetable[0]) - + superindex * sizeof(methodptr*)); + M_TST(REG_ITMP3); + M_BEQ(0); + codegen_add_classcastexception_ref(cd); + + if (!super) + M_BR(s3); + } + + /* class checkcast code */ + + if (!super || !(super->flags & ACC_INTERFACE)) { + disp = dseg_addaddress(cd, supervftbl); + + if (super) { + M_TST(s1); + M_BEQ(s3); + + } else { + codegen_addpatchref(cd, PATCHER_checkcast_class, + (constant_classref *) iptr->target, + disp); + + if (opt_showdisassemble) + M_NOP; + } + + M_ALD(REG_ITMP2, s1, OFFSET(java_objectheader, vftbl)); +#if defined(ENABLE_THREADS) + codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase); +#endif + M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, baseval)); + M_ALD(REG_ITMP2, REG_PV, disp); + if (s1 != REG_ITMP1) { + M_ILD(REG_ITMP1, REG_ITMP2, OFFSET(vftbl_t, baseval)); + M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, diffval)); +#if defined(ENABLE_THREADS) + codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); +#endif + M_ISUB(REG_ITMP3, REG_ITMP1, REG_ITMP3); + } else { + M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval)); + M_ISUB(REG_ITMP3, REG_ITMP2, REG_ITMP3); + M_ALD(REG_ITMP2, REG_PV, disp); + M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, diffval)); +#if defined(ENABLE_THREADS) + codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); +#endif + } + M_CMPU(REG_ITMP3, REG_ITMP2); + M_BGT(0); + codegen_add_classcastexception_ref(cd); + } + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, s1); + + } else { + /* array type cast-check */ + + s1 = emit_load_s1(jd, iptr, src, rd->argintregs[0]); + M_INTMOVE(s1, rd->argintregs[0]); + + disp = dseg_addaddress(cd, iptr->val.a); + + if (iptr->val.a == NULL) { + codegen_addpatchref(cd, PATCHER_builtin_arraycheckcast, + (constant_classref *) iptr->target, + disp); + + if (opt_showdisassemble) + M_NOP; + } + + M_ALD(rd->argintregs[1], REG_PV, disp); + disp = dseg_addaddress(cd, BUILTIN_arraycheckcast); + M_ALD(REG_ITMP2, REG_PV, disp); + M_MTCTR(REG_ITMP2); + M_JSR; + M_TST(REG_RESULT); + M_BEQ(0); + codegen_add_classcastexception_ref(cd); + + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, s1); + } + M_INTMOVE(s1, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */ + /* 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; + + super = (classinfo *) iptr->val.a; + + if (!super) { + superindex = 0; + supervftbl = NULL; + + } else { + superindex = super->index; + supervftbl = super->vftbl; + } + +#if defined(ENABLE_THREADS) + codegen_threadcritrestart(cd, cd->mcodeptr - cd->mcodebase); +#endif + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_ITMP2); + if (s1 == d) { + M_MOV(s1, REG_ITMP1); + s1 = REG_ITMP1; + } + + /* calculate interface instanceof code size */ + + s2 = 8; + if (!super) + s2 += (opt_showdisassemble ? 1 : 0); + + /* calculate class instanceof code size */ + + s3 = 10; + if (!super) + s3 += (opt_showdisassemble ? 1 : 0); + + M_CLR(d); + + /* if class is not resolved, check which code to call */ + + if (!super) { + M_TST(s1); + M_BEQ(3 + (opt_showdisassemble ? 1 : 0) + s2 + 1 + s3); + + disp = dseg_adds4(cd, 0); /* super->flags */ + + codegen_addpatchref(cd, PATCHER_checkcast_instanceof_flags, + (constant_classref *) iptr->target, disp); + + if (opt_showdisassemble) + M_NOP; + + M_ILD(REG_ITMP3, REG_PV, disp); + M_AND_IMM(REG_ITMP3, ACC_INTERFACE, REG_ITMP3); + M_BEQ(s2 + 1); + } + + /* interface instanceof code */ + + if (!super || (super->flags & ACC_INTERFACE)) { + if (super) { + M_TST(s1); + M_BEQ(s2); + + } else { + codegen_addpatchref(cd, + PATCHER_checkcast_instanceof_interface, + (constant_classref *) iptr->target, 0); + + if (opt_showdisassemble) + M_NOP; + } + + M_ALD(REG_ITMP1, s1, OFFSET(java_objectheader, vftbl)); + M_ILD(REG_ITMP3, REG_ITMP1, OFFSET(vftbl_t, interfacetablelength)); + M_LDATST(REG_ITMP3, REG_ITMP3, -superindex); + M_BLE(4); + M_ALD(REG_ITMP1, REG_ITMP1, + OFFSET(vftbl_t, interfacetable[0]) - + superindex * sizeof(methodptr*)); + M_TST(REG_ITMP1); + M_BEQ(1); + M_IADD_IMM(REG_ZERO, 1, d); + + if (!super) + M_BR(s3); + } + + /* class instanceof code */ + + if (!super || !(super->flags & ACC_INTERFACE)) { + disp = dseg_addaddress(cd, supervftbl); + + if (super) { + M_TST(s1); + M_BEQ(s3); + + } else { + codegen_addpatchref(cd, PATCHER_instanceof_class, + (constant_classref *) iptr->target, + disp); + + if (opt_showdisassemble) { + M_NOP; + } + } + + M_ALD(REG_ITMP1, s1, OFFSET(java_objectheader, vftbl)); + M_ALD(REG_ITMP2, REG_PV, disp); +#if defined(ENABLE_THREADS) + codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase); +#endif + M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval)); + M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, baseval)); + M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, diffval)); +#if defined(ENABLE_THREADS) + codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); +#endif + M_ISUB(REG_ITMP1, REG_ITMP3, REG_ITMP1); + M_CMPU(REG_ITMP1, REG_ITMP2); + M_CLR(d); + M_BGT(1); + M_IADD_IMM(REG_ZERO, 1, d); + } + emit_store(jd, iptr, iptr->dst, d); + } + break; + + case ICMD_MULTIANEWARRAY:/* ..., cnt1, [cnt2, ...] ==> ..., arrayref */ + /* op1 = dimension, val.a = class */ + + /* check for negative sizes and copy sizes to stack if necessary */ + + MCODECHECK((iptr->op1 << 1) + 64); + + for (s1 = iptr->op1; --s1 >= 0; src = src->prev) { + /* copy SAVEDVAR sizes to stack */ + + if (src->varkind != ARGVAR) { + s2 = emit_load_s2(jd, iptr, src, REG_ITMP1); +#if defined(__DARWIN__) + M_IST(s2, REG_SP, LA_SIZE + (s1 + INT_ARG_CNT) * 4); +#else + M_IST(s2, REG_SP, LA_SIZE + (s1 + 3) * 4); +#endif + } + } + + /* a0 = dimension count */ + + ICONST(rd->argintregs[0], iptr->op1); + + /* is patcher function set? */ + + if (iptr->val.a == NULL) { + disp = dseg_addaddress(cd, NULL); + + codegen_addpatchref(cd, PATCHER_builtin_multianewarray, + (constant_classref *) iptr->target, disp); + + if (opt_showdisassemble) + M_NOP; + + } else { + disp = dseg_addaddress(cd, iptr->val.a); + } + + /* a1 = arraydescriptor */ + + M_ALD(rd->argintregs[1], REG_PV, disp); + + /* a2 = pointer to dimensions = stack pointer */ + +#if defined(__DARWIN__) + M_LDA(rd->argintregs[2], REG_SP, LA_SIZE + INT_ARG_CNT * 4); +#else + M_LDA(rd->argintregs[2], REG_SP, LA_SIZE + 3 * 4); +#endif + + disp = dseg_addaddress(cd, BUILTIN_multianewarray); + M_ALD(REG_ITMP3, REG_PV, disp); + M_MTCTR(REG_ITMP3); + M_JSR; + + /* check for exception before result assignment */ + + M_CMPI(REG_RESULT, 0); + M_BEQ(0); + codegen_add_fillinstacktrace_ref(cd); + + d = codegen_reg_of_var(rd, iptr->opc, iptr->dst, REG_RESULT); + M_INTMOVE(REG_RESULT, d); + emit_store(jd, iptr, iptr->dst, d); + break; + + default: + *exceptionptr = + new_internalerror("Unknown ICMD %d during code generation", + iptr->opc); + return false; + } /* switch */ + + } /* for instruction */ + + /* copy values to interface registers */ + + src = bptr->outstack; + len = bptr->outdepth; + MCODECHECK(64 + len); +#if defined(ENABLE_LSRA) + if (!opt_lsra) +#endif + while (src) { + len--; + if ((src->varkind != STACKVAR)) { + s2 = src->type; + if (IS_FLT_DBL_TYPE(s2)) { + s1 = emit_load_s1(jd, iptr, src, REG_FTMP1); + if (!(rd->interfaces[len][s2].flags & INMEMORY)) + M_FLTMOVE(s1, rd->interfaces[len][s2].regoff); + else + M_DST(s1, REG_SP, rd->interfaces[len][s2].regoff * 4); + + } else { + s1 = emit_load_s1(jd, iptr, src, REG_ITMP1); + if (!(rd->interfaces[len][s2].flags & INMEMORY)) { + if (IS_2_WORD_TYPE(s2)) + M_LNGMOVE(s1, rd->interfaces[len][s2].regoff); + else + M_INTMOVE(s1, rd->interfaces[len][s2].regoff); + + } else { + if (IS_2_WORD_TYPE(s2)) + M_LST(s1, REG_SP, rd->interfaces[len][s2].regoff * 4); + else + M_IST(s1, REG_SP, rd->interfaces[len][s2].regoff * 4); + } + } + } + src = src->prev; + } + } /* if (bptr -> flags >= BBREACHED) */ + } /* for basic block */ + + dseg_createlinenumbertable(cd); + + + /* generate exception and patcher stubs */ + + { + exceptionref *eref; + patchref *pref; + u4 mcode; + u1 *savedmcodeptr; + u1 *tmpmcodeptr; + + savedmcodeptr = NULL; + + /* generate exception stubs */ + + for (eref = cd->exceptionrefs; eref != NULL; eref = eref->next) { + gen_resolvebranch(cd->mcodebase + eref->branchpos, + eref->branchpos, cd->mcodeptr - cd->mcodebase); + + MCODECHECK(100); + + /* Check if the exception is an + ArrayIndexOutOfBoundsException. If so, move index register + into REG_ITMP1. */ + + if (eref->reg != -1) + M_MOV(eref->reg, REG_ITMP1); + + /* calcuate exception address */ + + M_LDA(REG_ITMP2_XPC, REG_PV, eref->branchpos - 4); + + /* move function to call into REG_ITMP3 */ + + disp = dseg_addaddress(cd, eref->function); + M_ALD(REG_ITMP3, REG_PV, disp); + + if (savedmcodeptr != NULL) { + disp = ((u4 *) savedmcodeptr) - (((u4 *) cd->mcodeptr) + 1); + M_BR(disp); + + } else { + savedmcodeptr = cd->mcodeptr; + + if (m->isleafmethod) { + M_MFLR(REG_ZERO); + M_AST(REG_ZERO, REG_SP, stackframesize * 4 + LA_LR_OFFSET); + } + + M_MOV(REG_PV, rd->argintregs[0]); + M_MOV(REG_SP, rd->argintregs[1]); + + if (m->isleafmethod) + M_MOV(REG_ZERO, rd->argintregs[2]); + else + M_ALD(rd->argintregs[2], + REG_SP, stackframesize * 4 + LA_LR_OFFSET); + + M_MOV(REG_ITMP2_XPC, rd->argintregs[3]); + M_MOV(REG_ITMP1, rd->argintregs[4]); + + M_STWU(REG_SP, REG_SP, -(LA_SIZE + 6 * 4)); + M_AST(REG_ITMP2_XPC, REG_SP, LA_SIZE + 5 * 4); + + M_MTCTR(REG_ITMP3); + M_JSR; + M_MOV(REG_RESULT, REG_ITMP1_XPTR); + + M_ALD(REG_ITMP2_XPC, REG_SP, LA_SIZE + 5 * 4); + M_IADD_IMM(REG_SP, LA_SIZE + 6 * 4, REG_SP); + + if (m->isleafmethod) { + /* XXX FIXME: REG_ZERO can cause problems here! */ + assert(stackframesize * 4 <= 32767); + + M_ALD(REG_ZERO, REG_SP, stackframesize * 4 + LA_LR_OFFSET); + M_MTLR(REG_ZERO); + } + + disp = dseg_addaddress(cd, asm_handle_exception); + M_ALD(REG_ITMP3, REG_PV, disp); + M_MTCTR(REG_ITMP3); + M_RTS; + } + } + + + /* generate code patching stub call code */ + + for (pref = cd->patchrefs; pref != NULL; pref = pref->next) { + /* check code segment size */ + + MCODECHECK(16); + + /* Get machine code which is patched back in later. The + call is 1 instruction word long. */ + + tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos); + + mcode = *((u4 *) tmpmcodeptr); + + /* Patch in the call to call the following code (done at + compile time). */ + + savedmcodeptr = cd->mcodeptr; /* save current mcodeptr */ + cd->mcodeptr = tmpmcodeptr; /* set mcodeptr to patch position */ + + disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1); + M_BR(disp); + + cd->mcodeptr = savedmcodeptr; /* restore the current mcodeptr */ + + /* create stack frame - keep stack 16-byte aligned */ + + M_AADD_IMM(REG_SP, -8 * 4, REG_SP); + + /* calculate return address and move it onto the stack */ + + M_LDA(REG_ITMP3, REG_PV, pref->branchpos); + M_AST_INTERN(REG_ITMP3, REG_SP, 5 * 4); + + /* move pointer to java_objectheader onto stack */ + +#if defined(ENABLE_THREADS) + /* order reversed because of data segment layout */ + + (void) dseg_addaddress(cd, NULL); /* flcword */ + (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */ + disp = dseg_addaddress(cd, NULL); /* vftbl */ + + M_LDA(REG_ITMP3, REG_PV, disp); + M_AST_INTERN(REG_ITMP3, REG_SP, 4 * 4); +#else + /* do nothing */ +#endif + + /* move machine code onto stack */ + + disp = dseg_adds4(cd, mcode); + M_ILD(REG_ITMP3, REG_PV, disp); + M_IST_INTERN(REG_ITMP3, REG_SP, 3 * 4); + + /* move class/method/field reference onto stack */ + + disp = dseg_addaddress(cd, pref->ref); + M_ALD(REG_ITMP3, REG_PV, disp); + M_AST_INTERN(REG_ITMP3, REG_SP, 2 * 4); + + /* move data segment displacement onto stack */ + + disp = dseg_addaddress(cd, pref->disp); + M_ILD(REG_ITMP3, REG_PV, disp); + M_IST_INTERN(REG_ITMP3, REG_SP, 1 * 4); + + /* move patcher function pointer onto stack */ + + disp = dseg_addaddress(cd, pref->patcher); + M_ALD(REG_ITMP3, REG_PV, disp); + M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 4); + + disp = dseg_addaddress(cd, asm_wrapper_patcher); + M_ALD(REG_ITMP3, REG_PV, disp); + M_MTCTR(REG_ITMP3); + M_RTS; + } + + /* generate replacement-out stubs */ + + { + int i; + + replacementpoint = jd->code->rplpoints; + + for (i = 0; i < jd->code->rplpointcount; ++i, ++replacementpoint) { + /* check code segment size */ + + MCODECHECK(100); + + /* note start of stub code */ + + replacementpoint->outcode = (u1 *) (cd->mcodeptr - cd->mcodebase); + + /* make machine code for patching */ + + tmpmcodeptr = cd->mcodeptr; + cd->mcodeptr = (u1 *) &(replacementpoint->mcode) + 1 /* big-endian */; + + disp = (ptrint)((s4*)replacementpoint->outcode - (s4*)replacementpoint->pc) - 1; + M_BR(disp); + + cd->mcodeptr = tmpmcodeptr; + + /* create stack frame - keep 16-byte aligned */ + + M_AADD_IMM(REG_SP, -4 * 4, REG_SP); + + /* push address of `rplpoint` struct */ + + disp = dseg_addaddress(cd, replacementpoint); + M_ALD(REG_ITMP3, REG_PV, disp); + M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 4); + + /* jump to replacement function */ + + disp = dseg_addaddress(cd, asm_replacement_out); + M_ALD(REG_ITMP3, REG_PV, disp); + M_MTCTR(REG_ITMP3); + M_RTS; + } + } + } + + 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 4 * 4 + +#define COMPILERSTUB_SIZE COMPILERSTUB_DATASIZE + COMPILERSTUB_CODESIZE + + +u1 *createcompilerstub(methodinfo *m) +{ + u1 *s; /* memory to hold the stub */ + ptrint *d; + codeinfo *code; + codegendata *cd; + s4 dumpsize; + + 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; + + M_ALD_INTERN(REG_ITMP1, REG_PV, -2 * SIZEOF_VOID_P); + M_ALD_INTERN(REG_PV, REG_PV, -3 * SIZEOF_VOID_P); + M_MTCTR(REG_PV); + M_RTS; + + md_cacheflush((u1 *) d, COMPILERSTUB_SIZE); + +#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. + +*******************************************************************************/ + +u1 *createnativestub(functionptr f, jitdata *jd, methoddesc *nmd) +{ + methodinfo *m; + codeinfo *code; + codegendata *cd; + registerdata *rd; + s4 stackframesize; /* size of stackframe if needed */ + methoddesc *md; + s4 nativeparams; + s4 i, j; /* count variables */ + s4 t; + s4 s1, s2, disp; + s4 funcdisp; + + /* get required compiler data */ + + m = jd->m; + code = jd->code; + cd = jd->cd; + rd = jd->rd; + + /* set some variables */ + + md = m->parseddesc; + nativeparams = (m->flags & ACC_STATIC) ? 2 : 1; + + /* calculate stackframe size */ + + stackframesize = + sizeof(stackframeinfo) / SIZEOF_VOID_P + + sizeof(localref_table) / SIZEOF_VOID_P + + 4 + /* 4 stackframeinfo arguments (darwin)*/ + nmd->paramcount * 2 + /* assume all arguments are doubles */ + nmd->memuse; + + stackframesize = (stackframesize + 3) & ~3; /* keep stack 16-byte aligned */ + + /* create method header */ + + (void) dseg_addaddress(cd, code); /* CodeinfoPointer */ + (void) dseg_adds4(cd, stackframesize * 4); /* FrameSize */ + (void) dseg_adds4(cd, 0); /* IsSync */ + (void) dseg_adds4(cd, 0); /* IsLeaf */ + (void) dseg_adds4(cd, 0); /* IntSave */ + (void) dseg_adds4(cd, 0); /* FltSave */ + (void) dseg_addlinenumbertablesize(cd); + (void) dseg_adds4(cd, 0); /* ExTableSize */ + + /* generate code */ + + M_MFLR(REG_ZERO); + M_AST_INTERN(REG_ZERO, REG_SP, LA_LR_OFFSET); + M_STWU(REG_SP, REG_SP, -(stackframesize * 4)); + + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + /* parent_argbase == stackframesize * 4 */ + codegen_trace_args(jd, stackframesize * 4 , true); + + /* get function address (this must happen before the stackframeinfo) */ + + funcdisp = dseg_addaddress(cd, f); + +#if !defined(WITH_STATIC_CLASSPATH) + if (f == NULL) { + codegen_addpatchref(cd, PATCHER_resolve_native, m, funcdisp); + + if (opt_showdisassemble) + M_NOP; + } +#endif + + /* save integer and float argument registers */ + + j = 0; + + for (i = 0; i < md->paramcount; i++) { + t = md->paramtypes[i].type; + + if (IS_INT_LNG_TYPE(t)) { + if (!md->params[i].inmemory) { + s1 = md->params[i].regoff; + if (IS_2_WORD_TYPE(t)) { + M_IST(rd->argintregs[GET_HIGH_REG(s1)], REG_SP, LA_SIZE + 4 * 4 + j * 4); + j++; + M_IST(rd->argintregs[GET_LOW_REG(s1)], REG_SP, LA_SIZE + 4 * 4 + j * 4); + } else { + M_IST(rd->argintregs[s1], REG_SP, LA_SIZE + 4 * 4 + j * 4); + } + j++; + } + } + } + + for (i = 0; i < md->paramcount; i++) { + if (IS_FLT_DBL_TYPE(md->paramtypes[i].type)) { + if (!md->params[i].inmemory) { + s1 = md->params[i].regoff; + M_DST(rd->argfltregs[s1], REG_SP, LA_SIZE + 4 * 4 + j * 8); + j++; + } + } + } + + /* create native stack info */ + + M_AADD_IMM(REG_SP, stackframesize * 4, rd->argintregs[0]); + M_MOV(REG_PV, rd->argintregs[1]); + M_AADD_IMM(REG_SP, stackframesize * 4, rd->argintregs[2]); + M_ALD(rd->argintregs[3], REG_SP, stackframesize * 4 + LA_LR_OFFSET); + disp = dseg_addaddress(cd, codegen_start_native_call); + M_ALD(REG_ITMP1, REG_PV, disp); + M_MTCTR(REG_ITMP1); + M_JSR; + + /* restore integer and float argument registers */ + + j = 0; + + for (i = 0; i < md->paramcount; i++) { + t = md->paramtypes[i].type; + + if (IS_INT_LNG_TYPE(t)) { + if (!md->params[i].inmemory) { + s1 = md->params[i].regoff; + + if (IS_2_WORD_TYPE(t)) { + M_ILD(rd->argintregs[GET_HIGH_REG(s1)], REG_SP, LA_SIZE + 4 * 4 + j * 4); + j++; + M_ILD(rd->argintregs[GET_LOW_REG(s1)], REG_SP, LA_SIZE + 4 * 4 + j * 4); + } else { + M_ILD(rd->argintregs[s1], REG_SP, LA_SIZE + 4 * 4 + j * 4); + } + j++; + } + } + } + + for (i = 0; i < md->paramcount; i++) { + if (IS_FLT_DBL_TYPE(md->paramtypes[i].type)) { + if (!md->params[i].inmemory) { + s1 = md->params[i].regoff; + M_DLD(rd->argfltregs[s1], REG_SP, LA_SIZE + 4 * 4 + j * 8); + j++; + } + } + } + + /* 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) { + if (IS_2_WORD_TYPE(t)) + s1 = PACK_REGS( + rd->argintregs[GET_LOW_REG(md->params[i].regoff)], + rd->argintregs[GET_HIGH_REG(md->params[i].regoff)]); + else + s1 = rd->argintregs[md->params[i].regoff]; + + if (!nmd->params[j].inmemory) { + if (IS_2_WORD_TYPE(t)) { + s2 = PACK_REGS( + rd->argintregs[GET_LOW_REG(nmd->params[j].regoff)], + rd->argintregs[GET_HIGH_REG(nmd->params[j].regoff)]); + M_LNGMOVE(s1, s2); + } else { + s2 = rd->argintregs[nmd->params[j].regoff]; + M_INTMOVE(s1, s2); + } + + } else { + s2 = nmd->params[j].regoff; + if (IS_2_WORD_TYPE(t)) + M_LST(s1, REG_SP, s2 * 4); + else + M_IST(s1, REG_SP, s2 * 4); + } + + } else { + s1 = md->params[i].regoff + stackframesize; + s2 = nmd->params[j].regoff; + + M_ILD(REG_ITMP1, REG_SP, s1 * 4); + if (IS_2_WORD_TYPE(t)) + M_ILD(REG_ITMP2, REG_SP, s1 * 4 + 4); + + M_IST(REG_ITMP1, REG_SP, s2 * 4); + if (IS_2_WORD_TYPE(t)) + M_IST(REG_ITMP2, REG_SP, s2 * 4 + 4); + } + + } else { + /* We only copy spilled float arguments, as the float + argument registers keep unchanged. */ + + if (md->params[i].inmemory) { + s1 = md->params[i].regoff + stackframesize; + s2 = nmd->params[j].regoff; + + if (IS_2_WORD_TYPE(t)) { + M_DLD(REG_FTMP1, REG_SP, s1 * 4); + M_DST(REG_FTMP1, REG_SP, s2 * 4); + + } else { + M_FLD(REG_FTMP1, REG_SP, s1 * 4); + M_FST(REG_FTMP1, REG_SP, s2 * 4); + } + } + } + } + + /* put class into second argument register */ + + if (m->flags & ACC_STATIC) { + disp = dseg_addaddress(cd, m->class); + M_ALD(rd->argintregs[1], REG_PV, disp); + } + + /* put env into first argument register */ + + disp = dseg_addaddress(cd, _Jv_env); + M_ALD(rd->argintregs[0], REG_PV, disp); + + /* generate the actual native call */ + + M_ALD(REG_ITMP3, REG_PV, funcdisp); + M_MTCTR(REG_ITMP3); + M_JSR; + + /* save return value */ + + if (md->returntype.type != TYPE_VOID) { + if (IS_INT_LNG_TYPE(md->returntype.type)) { + if (IS_2_WORD_TYPE(md->returntype.type)) + /*M_IST(REG_RESULT2, REG_SP, LA_SIZE + 2 * 4); // FIXME*/ + M_IST(REG_RESULT, REG_SP, LA_SIZE + 1 * 4); + } + else { + if (IS_2_WORD_TYPE(md->returntype.type)) + M_DST(REG_FRESULT, REG_SP, LA_SIZE + 1 * 4); + else + M_FST(REG_FRESULT, REG_SP, LA_SIZE + 1 * 4); + } + } + + /* print call trace */ + + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + /* just restore the value we need, don't care about the other */ + + if (md->returntype.type != TYPE_VOID) { + if (IS_INT_LNG_TYPE(md->returntype.type)) { + if (IS_2_WORD_TYPE(md->returntype.type)) + /*M_ILD(REG_RESULT2, REG_SP, LA_SIZE + 2 * 4); FIXME*/ + M_ILD(REG_RESULT, REG_SP, LA_SIZE + 1 * 4); + } + else { + if (IS_2_WORD_TYPE(md->returntype.type)) + M_DLD(REG_FRESULT, REG_SP, LA_SIZE + 1 * 4); + else + M_FLD(REG_FRESULT, REG_SP, LA_SIZE + 1 * 4); + } + } + + M_LDA(REG_SP, REG_SP, -(LA_SIZE + (1 + 2 + 2 + 1) * 4)); + + /* keep this order */ + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: +#if defined(__DARWIN__) + M_MOV(REG_RESULT, rd->argintregs[2]); + M_CLR(rd->argintregs[1]); +#else + M_MOV(REG_RESULT, rd->argintregs[3]); + M_CLR(rd->argintregs[2]); +#endif + break; + + case TYPE_LNG: +#if defined(__DARWIN__) + /*M_MOV(REG_RESULT2, rd->argintregs[2]);FIXME*/ + M_MOV(REG_RESULT, rd->argintregs[1]); +#else + /*M_MOV(REG_RESULT2, rd->argintregs[3]);FIXME*/ + M_MOV(REG_RESULT, rd->argintregs[2]); +#endif + break; + } + + M_FLTMOVE(REG_FRESULT, rd->argfltregs[0]); + M_FLTMOVE(REG_FRESULT, rd->argfltregs[1]); + disp = dseg_addaddress(cd, m); + M_ALD(rd->argintregs[0], REG_PV, disp); + + disp = dseg_addaddress(cd, builtin_displaymethodstop); + M_ALD(REG_ITMP2, REG_PV, disp); + M_MTCTR(REG_ITMP2); + M_JSR; + + M_LDA(REG_SP, REG_SP, LA_SIZE + (1 + 2 + 2 + 1) * 4); + } + + /* remove native stackframe info */ + + M_AADD_IMM(REG_SP, stackframesize * 4, rd->argintregs[0]); + disp = dseg_addaddress(cd, codegen_finish_native_call); + M_ALD(REG_ITMP1, REG_PV, disp); + M_MTCTR(REG_ITMP1); + M_JSR; + M_MOV(REG_RESULT, REG_ITMP1_XPTR); + + /* restore return value */ + + if (md->returntype.type != TYPE_VOID) { + if (IS_INT_LNG_TYPE(md->returntype.type)) { + if (IS_2_WORD_TYPE(md->returntype.type)) + /*M_ILD(REG_RESULT2, REG_SP, LA_SIZE + 2 * 4);FIXME*/ + M_ILD(REG_RESULT, REG_SP, LA_SIZE + 1 * 4); + } + else { + if (IS_2_WORD_TYPE(md->returntype.type)) + M_DLD(REG_FRESULT, REG_SP, LA_SIZE + 1 * 4); + else + M_FLD(REG_FRESULT, REG_SP, LA_SIZE + 1 * 4); + } + } + + M_ALD(REG_ITMP2_XPC, REG_SP, stackframesize * 4 + LA_LR_OFFSET); + M_MTLR(REG_ITMP2_XPC); + M_LDA(REG_SP, REG_SP, stackframesize * 4); /* remove stackframe */ + + /* check for exception */ + + M_TST(REG_ITMP1_XPTR); + M_BNE(1); /* if no exception then return */ + + M_RET; + + /* handle exception */ + + M_IADD_IMM(REG_ITMP2_XPC, -4, REG_ITMP2_XPC); /* exception address */ + + disp = dseg_addaddress(cd, asm_handle_nat_exception); + M_ALD(REG_ITMP3, REG_PV, disp); + M_MTCTR(REG_ITMP3); + M_RTS; + + /* generate patcher stub call code */ + + { + patchref *pref; + u4 mcode; + u1 *savedmcodeptr; + u1 *tmpmcodeptr; + + for (pref = cd->patchrefs; pref != NULL; pref = pref->next) { + /* Get machine code which is patched back in later. The + call is 1 instruction word long. */ + + tmpmcodeptr = cd->mcodebase + pref->branchpos; + + mcode = *((u4 *) tmpmcodeptr); + + /* Patch in the call to call the following code (done at + compile time). */ + + savedmcodeptr = cd->mcodeptr; /* save current mcodeptr */ + cd->mcodeptr = tmpmcodeptr; /* set mcodeptr to patch position */ + + disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1); + M_BL(disp); + + cd->mcodeptr = savedmcodeptr; /* restore the current mcodeptr */ + + /* create stack frame - keep stack 16-byte aligned */ + + M_AADD_IMM(REG_SP, -8 * 4, REG_SP); + + /* move return address onto stack */ + + M_MFLR(REG_ZERO); + M_AST(REG_ZERO, REG_SP, 5 * 4); + + /* move pointer to java_objectheader onto stack */ + +#if defined(ENABLE_THREADS) + /* order reversed because of data segment layout */ + + (void) dseg_addaddress(cd, NULL); /* flcword */ + (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */ + disp = dseg_addaddress(cd, NULL); /* vftbl */ + + M_LDA(REG_ITMP3, REG_PV, disp); + M_AST(REG_ITMP3, REG_SP, 4 * 4); +#else + /* do nothing */ +#endif + + /* move machine code onto stack */ + + disp = dseg_adds4(cd, mcode); + M_ILD(REG_ITMP3, REG_PV, disp); + M_IST(REG_ITMP3, REG_SP, 3 * 4); + + /* move class/method/field reference onto stack */ + + disp = dseg_addaddress(cd, pref->ref); + M_ALD(REG_ITMP3, REG_PV, disp); + M_AST(REG_ITMP3, REG_SP, 2 * 4); + + /* move data segment displacement onto stack */ + + disp = dseg_addaddress(cd, pref->disp); + M_ILD(REG_ITMP3, REG_PV, disp); + M_IST(REG_ITMP3, REG_SP, 1 * 4); + + /* move patcher function pointer onto stack */ + + disp = dseg_addaddress(cd, pref->patcher); + M_ALD(REG_ITMP3, REG_PV, disp); + M_AST(REG_ITMP3, REG_SP, 0 * 4); + + disp = dseg_addaddress(cd, asm_wrapper_patcher); + M_ALD(REG_ITMP3, REG_PV, disp); + M_MTCTR(REG_ITMP3); + M_RTS; + } + } + + codegen_finish(jd); + + return jd->code->entrypoint; +} + + +void codegen_trace_args(jitdata *jd, s4 stackframesize, bool nativestub) +{ + methodinfo *m; + codegendata *cd; + registerdata *rd; + s4 s1, p, t, d; + int stack_off; + int stack_size; + methoddesc *md; + + /* get required compiler data */ + + m = jd->m; + cd = jd->cd; + rd = jd->rd; + + md = m->parseddesc; + + if (!nativestub) + M_MFLR(REG_ITMP3); + /* Build up Stackframe for builtin_trace_args call (a multiple of 16) */ + /* For Darwin: */ + /* LA + TRACE_ARGS_NUM u8 args + methodinfo + LR */ + /* LA_SIZE(=6*4) + 8*8 + 4 + 4 + 0(Padding) */ + /* 6 * 4 + 8 * 8 + 2 * 4 = 12 * 8 = 6 * 16 */ + /* For Linux: */ + /* LA + (TRACE_ARGS_NUM - INT_ARG_CNT/2) u8 args + methodinfo */ + /* + INT_ARG_CNT * 4 ( save integer registers) + LR + 8 + 8 (Padding) */ + /* LA_SIZE(=2*4) + 4 * 8 + 4 + 8 * 4 + 4 + 8 */ + /* 2 * 4 + 4 * 8 + 10 * 4 + 1 * 8 + 8= 12 * 8 = 6 * 16 */ + + /* in nativestubs no Place to save the LR (Link Register) would be needed */ + /* but since the stack frame has to be aligned the 4 Bytes would have to */ + /* be padded again */ + +#if defined(__DARWIN__) + stack_size = LA_SIZE + (TRACE_ARGS_NUM + 1) * 8; +#else + stack_size = 6 * 16; +#endif + M_LDA(REG_SP, REG_SP, -stack_size); + + /* Save LR */ + if (!nativestub) + M_IST(REG_ITMP3, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8 + 1 * 4); + + M_CLR(REG_ITMP1); /* clear help register */ + + /* save up to TRACE_ARGS_NUM arguments into the reserved stack space */ +#if defined(__DARWIN__) + /* Copy Params starting from first to Stack */ + /* since TRACE_ARGS == INT_ARG_CNT all used integer argument regs */ + /* are saved */ + p = 0; +#else + /* Copy Params starting from fifth to Stack (INT_ARG_CNT/2) are in */ + /* integer argument regs */ + /* all integer argument registers have to be saved */ + for (p = 0; p < 8; p++) { + d = rd->argintregs[p]; + /* save integer argument registers */ + M_IST(d, REG_SP, LA_SIZE + 4 * 8 + 4 + p * 4); + } + p = 4; +#endif + stack_off = LA_SIZE; + for (; p < md->paramcount && p < TRACE_ARGS_NUM; p++, stack_off += 8) { + t = md->paramtypes[p].type; + if (IS_INT_LNG_TYPE(t)) { + if (!md->params[p].inmemory) { /* Param in Arg Reg */ + if (IS_2_WORD_TYPE(t)) { + M_IST(rd->argintregs[GET_HIGH_REG(md->params[p].regoff)] + , REG_SP, stack_off); + M_IST(rd->argintregs[GET_LOW_REG(md->params[p].regoff)] + , REG_SP, stack_off + 4); + } else { + M_IST(REG_ITMP1, REG_SP, stack_off); + M_IST(rd->argintregs[md->params[p].regoff] + , REG_SP, stack_off + 4); + } + } else { /* Param on Stack */ + s1 = (md->params[p].regoff + stackframesize) * 4 + + stack_size; + if (IS_2_WORD_TYPE(t)) { + M_ILD(REG_ITMP2, REG_SP, s1); + M_IST(REG_ITMP2, REG_SP, stack_off); + M_ILD(REG_ITMP2, REG_SP, s1 + 4); + M_IST(REG_ITMP2, REG_SP, stack_off + 4); + } else { + M_IST(REG_ITMP1, REG_SP, stack_off); + M_ILD(REG_ITMP2, REG_SP, s1); + M_IST(REG_ITMP2, REG_SP, stack_off + 4); + } + } + } else { /* IS_FLT_DBL_TYPE(t) */ + if (!md->params[p].inmemory) { /* in Arg Reg */ + s1 = rd->argfltregs[md->params[p].regoff]; + if (!IS_2_WORD_TYPE(t)) { + M_IST(REG_ITMP1, REG_SP, stack_off); + M_FST(s1, REG_SP, stack_off + 4); + } else { + M_DST(s1, REG_SP, stack_off); + } + } else { /* on Stack */ + /* this should not happen */ + } + } + } + + /* load first 4 (==INT_ARG_CNT/2) arguments into integer registers */ +#if defined(__DARWIN__) + for (p = 0; p < 8; p++) { + d = rd->argintregs[p]; + M_ILD(d, REG_SP, LA_SIZE + p * 4); + } +#else + /* LINUX */ + /* Set integer and float argument registers vor trace_args call */ + /* offset to saved integer argument registers */ + stack_off = LA_SIZE + 4 * 8 + 4; + for (p = 0; (p < 4) && (p < md->paramcount); p++) { + t = md->paramtypes[p].type; + if (IS_INT_LNG_TYPE(t)) { + /* "stretch" int types */ + if (!IS_2_WORD_TYPE(t)) { + M_CLR(rd->argintregs[2 * p]); + M_ILD(rd->argintregs[2 * p + 1], REG_SP,stack_off); + stack_off += 4; + } else { + M_ILD(rd->argintregs[2 * p + 1], REG_SP,stack_off + 4); + M_ILD(rd->argintregs[2 * p], REG_SP,stack_off); + stack_off += 8; + } + } else { /* Float/Dbl */ + if (!md->params[p].inmemory) { /* Param in Arg Reg */ + /* use reserved Place on Stack (sp + 5 * 16) to copy */ + /* float/double arg reg to int reg */ + s1 = rd->argfltregs[md->params[p].regoff]; + if (!IS_2_WORD_TYPE(t)) { + M_FST(s1, REG_SP, 5 * 16); + M_ILD(rd->argintregs[2 * p + 1], REG_SP, 5 * 16); + M_CLR(rd->argintregs[2 * p]); + } else { + M_DST(s1, REG_SP, 5 * 16); + M_ILD(rd->argintregs[2 * p + 1], REG_SP, 5 * 16 + 4); + M_ILD(rd->argintregs[2 * p], REG_SP, 5 * 16); + } + } + } + } +#endif + + /* put methodinfo pointer on Stackframe */ + p = dseg_addaddress(cd, m); + M_ALD(REG_ITMP1, REG_PV, p); +#if defined(__DARWIN__) + M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8); +#else + M_AST(REG_ITMP1, REG_SP, LA_SIZE + 4 * 8); +#endif + p = dseg_addaddress(cd, builtin_trace_args); + M_ALD(REG_ITMP2, REG_PV, p); + M_MTCTR(REG_ITMP2); + M_JSR; + +#if defined(__DARWIN__) + /* restore integer argument registers from the reserved stack space */ + + stack_off = LA_SIZE; + for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; + p++, stack_off += 8) { + t = md->paramtypes[p].type; + + if (IS_INT_LNG_TYPE(t)) { + if (!md->params[p].inmemory) { + if (IS_2_WORD_TYPE(t)) { + M_ILD(rd->argintregs[GET_HIGH_REG(md->params[p].regoff)] + , REG_SP, stack_off); + M_ILD(rd->argintregs[GET_LOW_REG(md->params[p].regoff)] + , REG_SP, stack_off + 4); + } else { + M_ILD(rd->argintregs[md->params[p].regoff] + , REG_SP, stack_off + 4); + } + } + } + } +#else + /* LINUX */ + for (p = 0; p < 8; p++) { + d = rd->argintregs[p]; + /* save integer argument registers */ + M_ILD(d, REG_SP, LA_SIZE + 4 * 8 + 4 + p * 4); + } +#endif + + if (!nativestub) + M_ILD(REG_ITMP3, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8 + 1 * 4); + + M_LDA(REG_SP, REG_SP, stack_size); + + if (!nativestub) + M_MTLR(REG_ITMP3); +} + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/powerpc64/codegen.h b/src/vm/jit/powerpc64/codegen.h new file mode 100644 index 000000000..5546037e6 --- /dev/null +++ b/src/vm/jit/powerpc64/codegen.h @@ -0,0 +1,483 @@ +/* src/vm/jit/powerpc/codegen.h - code generation macros and definitions for + 32-bit PowerPC + + 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 + Stefan Ring + + Changes: Christian Thalinger + Christian Ullrich + + $Id: codegen.h 5081 2006-07-06 13:59:01Z tbfg $ + +*/ + + +#ifndef _CODEGEN_H +#define _CODEGEN_H + +#include "config.h" + +#include "md-abi.h" + +#include "vm/global.h" +#include "vm/jit/jit.h" +#include "vm/jit/reg.h" + + +/* additional functions and macros to generate code ***************************/ + +/* gen_nullptr_check(objreg) */ + +#define gen_nullptr_check(objreg) \ + if (checknull) { \ + M_TST((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_CMPU(s2, REG_ITMP3);\ + M_BGE(0);\ + codegen_add_arrayindexoutofboundsexception_ref(cd, s2); \ + } + + +/* MCODECHECK(icnt) */ + +#define MCODECHECK(icnt) \ + do { \ + if ((cd->mcodeptr + (icnt) * 4) > cd->mcodeend) \ + codegen_increase(cd); \ + } while (0) + + +/* M_INTMOVE: + generates an integer-move from register a to b. + if a and b are the same int-register, no code will be generated. +*/ + +#define M_INTMOVE(a,b) \ + do { \ + if ((a) != (b)) { \ + M_MOV(a, b); \ + } \ + } while (0) + +#define M_LNGMOVE(a,b) \ + do { \ + if (GET_HIGH_REG(a) == GET_LOW_REG(b)) { \ + assert((GET_LOW_REG(a) != GET_HIGH_REG(b))); \ + M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ + M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ + } else { \ + M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ + M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ + } \ + } while (0) + + +/* M_FLTMOVE: + generates a floating-point-move from register a to b. + if a and b are the same float-register, no code will be generated +*/ + +#define M_FLTMOVE(a,b) \ + do { \ + if ((a) != (b)) { \ + M_FMOV(a, b); \ + } \ + } while (0) + + +#define M_COPY(s,d) emit_copy(jd, iptr, (s), (d)) +#define ICONST(d,c) emit_iconst(cd, (d), (c)) + +#define LCONST(reg,c) \ + ICONST(GET_HIGH_REG((reg)), (s4) ((s8) (c) >> 32)); \ + ICONST(GET_LOW_REG((reg)), (s4) ((s8) (c))); + + +#define ALIGNCODENOP \ + if ((s4) ((ptrint) cd->mcodeptr & 7)) { \ + M_NOP; \ + } + + +/* macros to create code ******************************************************/ + +#define M_OP3(opcode,y,oe,rc,d,a,b) \ + do { \ + *((u4 *) cd->mcodeptr) = (((opcode) << 26) | ((d) << 21) | ((a) << 16) | ((b) << 11) | ((oe) << 10) | ((y) << 1) | (rc)); \ + cd->mcodeptr += 4; \ + } while (0) + +#define M_OP4(x,y,rc,d,a,b,c) \ + do { \ + *((u4 *) cd->mcodeptr) = (((x) << 26) | ((d) << 21) | ((a) << 16) | ((b) << 11) | ((c) << 6) | ((y) << 1) | (rc)); \ + cd->mcodeptr += 4; \ + } while (0) + +#define M_OP2_IMM(x,d,a,i) \ + do { \ + *((u4 *) cd->mcodeptr) = (((x) << 26) | ((d) << 21) | ((a) << 16) | ((i) & 0xffff)); \ + cd->mcodeptr += 4; \ + } while (0) + +#define M_BRMASK 0x0000fffc /* (((1 << 16) - 1) & ~3) */ +#define M_BRAMASK 0x03fffffc /* (((1 << 26) - 1) & ~3) */ + +#define M_BRA(x,i,a,l) \ + do { \ + *((u4 *) cd->mcodeptr) = (((x) << 26) | ((((i) * 4) + 4) & M_BRAMASK) | ((a) << 1) | (l)); \ + cd->mcodeptr += 4; \ + } while (0) + +#define M_BRAC(x,bo,bi,i,a,l) \ + do { \ + *((u4 *) cd->mcodeptr) = (((x) << 26) | ((bo) << 21) | ((bi) << 16) | (((i) * 4 + 4) & M_BRMASK) | ((a) << 1) | (l)); \ + cd->mcodeptr += 4; \ + } while (0) + + +/* instruction macros *********************************************************/ + +#define M_IADD(a,b,c) M_OP3(31, 266, 0, 0, c, a, b) +#define M_IADD_IMM(a,b,c) M_OP2_IMM(14, c, a, b) +#define M_ADDC(a,b,c) M_OP3(31, 10, 0, 0, c, a, b) +#define M_ADDIC(a,b,c) M_OP2_IMM(12, c, a, b) +#define M_ADDICTST(a,b,c) M_OP2_IMM(13, c, a, b) +#define M_ADDE(a,b,c) M_OP3(31, 138, 0, 0, c, a, b) +#define M_ADDZE(a,b) M_OP3(31, 202, 0, 0, b, a, 0) +#define M_ADDME(a,b) M_OP3(31, 234, 0, 0, b, a, 0) +#define M_ISUB(a,b,c) M_OP3(31, 40, 0, 0, c, b, a) +#define M_ISUBTST(a,b,c) M_OP3(31, 40, 0, 1, c, b, a) +#define M_SUBC(a,b,c) M_OP3(31, 8, 0, 0, c, b, a) +#define M_SUBIC(a,b,c) M_OP2_IMM(8, c, b, a) +#define M_SUBE(a,b,c) M_OP3(31, 136, 0, 0, c, b, a) +#define M_SUBZE(a,b) M_OP3(31, 200, 0, 0, b, a, 0) +#define M_SUBME(a,b) M_OP3(31, 232, 0, 0, b, a, 0) + +#define M_AND(a,b,c) M_OP3(31, 28, 0, 0, a, c, b) +#define M_AND_IMM(a,b,c) M_OP2_IMM(28, a, c, b) +#define M_ANDIS(a,b,c) M_OP2_IMM(29, a, c, b) +#define M_OR(a,b,c) M_OP3(31, 444, 0, 0, a, c, b) +#define M_OR_TST(a,b,c) M_OP3(31, 444, 0, 1, a, c, b) +#define M_OR_IMM(a,b,c) M_OP2_IMM(24, a, c, b) +#define M_ORIS(a,b,c) M_OP2_IMM(25, a, c, b) +#define M_XOR(a,b,c) M_OP3(31, 316, 0, 0, a, c, b) +#define M_XOR_IMM(a,b,c) M_OP2_IMM(26, a, c, b) +#define M_XORIS(a,b,c) M_OP2_IMM(27, a, c, b) + +#define M_SLL(a,b,c) M_OP3(31, 24, 0, 0, a, c, b) +#define M_SRL(a,b,c) M_OP3(31, 536, 0, 0, a, c, b) +#define M_SRA(a,b,c) M_OP3(31, 792, 0, 0, a, c, b) +#define M_SRA_IMM(a,b,c) M_OP3(31, 824, 0, 0, a, c, b) + +#define M_IMUL(a,b,c) M_OP3(31, 235, 0, 0, c, a, b) +#define M_IMUL_IMM(a,b,c) M_OP2_IMM(7, c, a, b) +#define M_IDIV(a,b,c) M_OP3(31, 491, 0, 0, c, a, b) + +#define M_NEG(a,b) M_OP3(31, 104, 0, 0, b, a, 0) +#define M_NOT(a,b) M_OP3(31, 124, 0, 0, a, b, a) + +#define M_SUBFIC(a,b,c) M_OP2_IMM(8, c, a, b) +#define M_SUBFZE(a,b) M_OP3(31, 200, 0, 0, b, a, 0) +#define M_RLWINM(a,b,c,d,e) M_OP4(21, d, 0, a, e, b, c) +#define M_ADDZE(a,b) M_OP3(31, 202, 0, 0, b, a, 0) +#define M_SLL_IMM(a,b,c) M_RLWINM(a,b,0,31-(b),c) +#define M_SRL_IMM(a,b,c) M_RLWINM(a,32-(b),b,31,c) +#define M_ADDIS(a,b,c) M_OP2_IMM(15, c, a, b) +#define M_STFIWX(a,b,c) M_OP3(31, 983, 0, 0, a, b, c) +#define M_LWZX(a,b,c) M_OP3(31, 23, 0, 0, a, b, c) +#define M_LHZX(a,b,c) M_OP3(31, 279, 0, 0, a, b, c) +#define M_LHAX(a,b,c) M_OP3(31, 343, 0, 0, a, b, c) +#define M_LBZX(a,b,c) M_OP3(31, 87, 0, 0, a, b, c) +#define M_LFSX(a,b,c) M_OP3(31, 535, 0, 0, a, b, c) +#define M_LFDX(a,b,c) M_OP3(31, 599, 0, 0, a, b, c) +#define M_STWX(a,b,c) M_OP3(31, 151, 0, 0, a, b, c) +#define M_STHX(a,b,c) M_OP3(31, 407, 0, 0, a, b, c) +#define M_STBX(a,b,c) M_OP3(31, 215, 0, 0, a, b, c) +#define M_STFSX(a,b,c) M_OP3(31, 663, 0, 0, a, b, c) +#define M_STFDX(a,b,c) M_OP3(31, 727, 0, 0, a, b, c) + +#define M_STWU_INTERN(a,b,disp) M_OP2_IMM(37,a,b,disp) + +#define M_STWU(a,b,disp) \ + do { \ + s4 lo = (disp) & 0x0000ffff; \ + s4 hi = ((disp) >> 16); \ + if (((disp) >= -32678) && ((disp) <= 32767)) { \ + M_STWU_INTERN(a,b,lo); \ + } else { \ + M_ADDIS(REG_ZERO,hi,REG_ITMP3); \ + M_OR_IMM(REG_ITMP3,lo,REG_ITMP3); \ + M_STWUX(REG_SP,REG_SP,REG_ITMP3); \ + } \ + } while (0) + +#define M_STWUX(a,b,c) M_OP3(31,183,0,0,a,b,c) + +#define M_LDAH(a,b,c) M_ADDIS(b, c, a) +#define M_TRAP M_OP3(31, 4, 0, 0, 31, 0, 0) + +#define M_NOP M_OR_IMM(0, 0, 0) +#define M_MOV(a,b) M_OR(a, a, b) +#define M_TST(a) M_OP3(31, 444, 0, 1, a, a, a) + +#define M_DADD(a,b,c) M_OP3(63, 21, 0, 0, c, a, b) +#define M_FADD(a,b,c) M_OP3(59, 21, 0, 0, c, a, b) +#define M_DSUB(a,b,c) M_OP3(63, 20, 0, 0, c, a, b) +#define M_FSUB(a,b,c) M_OP3(59, 20, 0, 0, c, a, b) +#define M_DMUL(a,b,c) M_OP4(63, 25, 0, c, a, 0, b) +#define M_FMUL(a,b,c) M_OP4(59, 25, 0, c, a, 0, b) +#define M_DDIV(a,b,c) M_OP3(63, 18, 0, 0, c, a, b) +#define M_FDIV(a,b,c) M_OP3(59, 18, 0, 0, c, a, b) + +#define M_FABS(a,b) M_OP3(63, 264, 0, 0, b, 0, a) +#define M_CVTDL(a,b) M_OP3(63, 14, 0, 0, b, 0, a) +#define M_CVTDL_C(a,b) M_OP3(63, 15, 0, 0, b, 0, a) +#define M_CVTDF(a,b) M_OP3(63, 12, 0, 0, b, 0, a) +#define M_FMOV(a,b) M_OP3(63, 72, 0, 0, b, 0, a) +#define M_FMOVN(a,b) M_OP3(63, 40, 0, 0, b, 0, a) +#define M_DSQRT(a,b) M_OP3(63, 22, 0, 0, b, 0, a) +#define M_FSQRT(a,b) M_OP3(59, 22, 0, 0, b, 0, a) + +#define M_FCMPU(a,b) M_OP3(63, 0, 0, 0, 0, a, b) +#define M_FCMPO(a,b) M_OP3(63, 32, 0, 0, 0, a, b) + +#define M_BLDU(a,b,c) M_OP2_IMM(34, a, b, c) +#define M_SLDU(a,b,c) M_OP2_IMM(40, a, b, c) + +#define M_ILD_INTERN(a,b,disp) M_OP2_IMM(32,a,b,disp) + +#define M_ILD(a,b,disp) \ + do { \ + s4 lo = (short) (disp); \ + s4 hi = (short) (((disp) - lo) >> 16); \ + if (hi == 0) { \ + M_ILD_INTERN(a,b,lo); \ + } else { \ + M_ADDIS(b,hi,a); \ + M_ILD_INTERN(a,a,lo); \ + } \ + } while (0) + +#define M_LLD_INTERN(a,b,disp) \ + do { \ + M_ILD_INTERN(GET_HIGH_REG(a), b, disp); \ + M_ILD_INTERN(GET_LOW_REG(a), b, disp + 4); \ + } while (0) + +#define M_LLD(a,b,disp) \ + do { \ + s4 lo = (short) (disp); \ + s4 hi = (short) (((disp) - lo) >> 16); \ + if (hi == 0) { \ + M_LLD_INTERN(a,b,lo); \ + } else { \ + M_ADDIS(b,hi,a); \ + M_LLD_INTERN(a,GET_LOW_REG(a),lo); \ + } \ + } while (0) + +#define M_ALD_INTERN(a,b,disp) M_ILD_INTERN(a,b,disp) +#define M_ALD(a,b,disp) M_ILD(a,b,disp) + +#define M_BST(a,b,c) M_OP2_IMM(38, a, b, c) +#define M_SST(a,b,c) M_OP2_IMM(44, a, b, c) + +#define M_IST_INTERN(a,b,disp) M_OP2_IMM(36,a,b,disp) + +/* Stores with displacement overflow should only happen with PUTFIELD + or on the stack. The PUTFIELD instruction does not use REG_ITMP3 + and a reg_of_var call should not use REG_ITMP3!!! */ + +#define M_IST(a,b,disp) \ + do { \ + s4 lo = (short) (disp); \ + s4 hi = (short) (((disp) - lo) >> 16); \ + if (hi == 0) { \ + M_IST_INTERN(a,b,lo); \ + } else { \ + M_ADDIS(b,hi,REG_ITMP3); \ + M_IST_INTERN(a,REG_ITMP3,lo); \ + } \ + } while (0) + +#define M_LST_INTERN(a,b,disp) \ + do { \ + M_IST_INTERN(GET_HIGH_REG(a), b, disp); \ + M_IST_INTERN(GET_LOW_REG(a), b, disp + 4); \ + } while (0) + +#define M_LST(a,b,disp) \ + do { \ + s4 lo = (short) (disp); \ + s4 hi = (short) (((disp) - lo) >> 16); \ + if (hi == 0) { \ + M_LST_INTERN(a,b,lo); \ + } else { \ + M_ADDIS(b,hi,REG_ITMP3); \ + M_LST_INTERN(a,REG_ITMP3, lo); \ + } \ + } while (0) + +#define M_AST_INTERN(a,b,disp) M_IST_INTERN(a,b,disp) +#define M_AST(a,b,disp) M_IST(a,b,disp) + +#define M_BSEXT(a,b) M_OP3(31, 954, 0, 0, a, b, 0) +#define M_SSEXT(a,b) M_OP3(31, 922, 0, 0, a, b, 0) +#define M_CZEXT(a,b) M_RLWINM(a,0,16,31,b) + +#define M_BR(a) M_BRA(18, a, 0, 0) +#define M_BL(a) M_BRA(18, a, 0, 1) +#define M_RET M_OP3(19, 16, 0, 0, 20, 0, 0) +#define M_JSR M_OP3(19, 528, 0, 1, 20, 0, 0) +#define M_RTS M_OP3(19, 528, 0, 0, 20, 0, 0) + +#define M_CMP(a,b) M_OP3(31, 0, 0, 0, 0, a, b) +#define M_CMPU(a,b) M_OP3(31, 32, 0, 0, 0, a, b) +#define M_CMPI(a,b) M_OP2_IMM(11, 0, a, b) +#define M_CMPUI(a,b) M_OP2_IMM(10, 0, a, b) + +#define M_BLT(a) M_BRAC(16, 12, 0, a, 0, 0) +#define M_BLE(a) M_BRAC(16, 4, 1, a, 0, 0) +#define M_BGT(a) M_BRAC(16, 12, 1, a, 0, 0) +#define M_BGE(a) M_BRAC(16, 4, 0, a, 0, 0) +#define M_BEQ(a) M_BRAC(16, 12, 2, a, 0, 0) +#define M_BNE(a) M_BRAC(16, 4, 2, a, 0, 0) +#define M_BNAN(a) M_BRAC(16, 12, 3, a, 0, 0) + +#define M_FLD_INTERN(a,b,disp) M_OP2_IMM(48,a,b,disp) +#define M_DLD_INTERN(a,b,disp) M_OP2_IMM(50,a,b,disp) + +#define M_FLD(a,b,disp) \ + do { \ + s4 lo = (short) (disp); \ + s4 hi = (short) (((disp) - lo) >> 16); \ + if (hi == 0) { \ + M_FLD_INTERN(a,b,lo); \ + } else { \ + M_ADDIS(b,hi,REG_ITMP3); \ + M_FLD_INTERN(a,REG_ITMP3,lo); \ + } \ + } while (0) + +#define M_DLD(a,b,disp) \ + do { \ + s4 lo = (short) (disp); \ + s4 hi = (short) (((disp) - lo) >> 16); \ + if (hi == 0) { \ + M_DLD_INTERN(a,b,lo); \ + } else { \ + M_ADDIS(b,hi,REG_ITMP3); \ + M_DLD_INTERN(a,REG_ITMP3,lo); \ + } \ + } while (0) + +#define M_FST_INTERN(a,b,disp) M_OP2_IMM(52,a,b,disp) +#define M_DST_INTERN(a,b,disp) M_OP2_IMM(54,a,b,disp) + +#define M_FST(a,b,disp) \ + do { \ + s4 lo = (short) (disp); \ + s4 hi = (short) (((disp) - lo) >> 16); \ + if (hi == 0) { \ + M_FST_INTERN(a,b,lo); \ + } else { \ + M_ADDIS(b,hi,REG_ITMP3); \ + M_FST_INTERN(a,REG_ITMP3,lo); \ + } \ + } while (0) + +#define M_DST(a,b,disp) \ + do { \ + s4 lo = (short) (disp); \ + s4 hi = (short) (((disp) - lo) >> 16); \ + if (hi == 0) { \ + M_DST_INTERN(a,b,lo); \ + } else { \ + M_ADDIS(b,hi,REG_ITMP3); \ + M_DST_INTERN(a,REG_ITMP3,lo); \ + } \ + } while (0) + +#define M_MFLR(a) M_OP3(31, 339, 0, 0, a, 8, 0) +#define M_MFXER(a) M_OP3(31, 339, 0, 0, a, 1, 0) +#define M_MFCTR(a) M_OP3(31, 339, 0, 0, a, 9, 0) +#define M_MTLR(a) M_OP3(31, 467, 0, 0, a, 8, 0) +#define M_MTXER(a) M_OP3(31, 467, 0, 0, a, 1, 0) +#define M_MTCTR(a) M_OP3(31, 467, 0, 0, a, 9, 0) + +#define M_LDA_INTERN(a,b,c) M_IADD_IMM(b, c, a) + +#define M_LDA(a,b,disp) \ + do { \ + s4 lo = (short) (disp); \ + s4 hi = (short) (((disp) - lo) >> 16); \ + if (hi == 0) { \ + M_LDA_INTERN(a,b,lo); \ + } else { \ + M_ADDIS(b,hi,a); \ + M_LDA_INTERN(a,a,lo); \ + } \ + } while (0) + + +#define M_LDATST(a,b,c) M_ADDICTST(b, c, a) +#define M_CLR(a) M_IADD_IMM(0, 0, a) +#define M_AADD_IMM(a,b,c) M_IADD_IMM(a, b, c) + + +/* function gen_resolvebranch ************************************************** + + parameters: ip ... pointer to instruction after branch (void*) + so ... offset of instruction after branch (s4) + to ... offset of branch target (s4) + +*******************************************************************************/ + +#define gen_resolvebranch(ip,so,to) \ + *((s4*)(ip)-1)=(*((s4*)(ip)-1) & ~M_BRMASK) | (((s4)((to)-(so))+4)&((((*((s4*)(ip)-1)>>26)&63)==18)?M_BRAMASK:M_BRMASK)) + +#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: + */ diff --git a/src/vm/jit/powerpc64/disass.c b/src/vm/jit/powerpc64/disass.c new file mode 100644 index 000000000..f7ad86064 --- /dev/null +++ b/src/vm/jit/powerpc64/disass.c @@ -0,0 +1,92 @@ +/* src/vm/jit/powerpc/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: Stefan Ring + Christian Thalinger + + $Id: disass.c 5081 2006-07-06 13:59:01Z tbfg $ + +*/ + + +#include "config.h" + +#include +#include + +#include "vm/types.h" + +#include "vm/global.h" +#include "vm/jit/disass.h" + + +/* disassinstr ***************************************************************** + + Outputs a disassembler listing of one machine code instruction on + `stdout'. + + code: pointer to machine code + +*******************************************************************************/ + +u1 *disassinstr(u1 *code) +{ + if (!disass_initialized) { + INIT_DISASSEMBLE_INFO(info, NULL, disass_printf); + + /* setting the struct members must be done after + INIT_DISASSEMBLE_INFO */ + + info.read_memory_func = &disass_buffer_read_memory; + + disass_initialized = true; + } + + printf("0x%08x: %08x ", (s4) code, *((s4 *) code)); + + print_insn_big_powerpc((bfd_vma) code, &info); + + printf("\n"); + + return code + 4; +} + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/src/vm/jit/powerpc64/emit.c b/src/vm/jit/powerpc64/emit.c new file mode 100644 index 000000000..ec9ad6ea1 --- /dev/null +++ b/src/vm/jit/powerpc64/emit.c @@ -0,0 +1,488 @@ +/* src/vm/jit/powerpc/emit.c - PowerPC 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 + + Changes: + + $Id: emitfuncs.c 4398 2006-01-31 23:43:08Z twisti $ + +*/ + + +#include "config.h" + +#include + +#include "vm/types.h" + +#include "md-abi.h" + +#include "vm/jit/emit.h" +#include "vm/jit/jit.h" +#include "vm/jit/powerpc/codegen.h" + + +/* code generation functions **************************************************/ + +/* emit_load_s1 **************************************************************** + + Emits a possible load of the first source operand. + +*******************************************************************************/ + +s4 emit_load_s1(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg) +{ + codegendata *cd; + s4 disp; + s4 reg; + + /* get required compiler data */ + + cd = jd->cd; + + if (src->flags & INMEMORY) { + COUNT_SPILLS; + + disp = src->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->regoff; + + return reg; +} + + +/* emit_load_s2 **************************************************************** + + Emits a possible load of the second source operand. + +*******************************************************************************/ + +s4 emit_load_s2(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg) +{ + codegendata *cd; + s4 disp; + s4 reg; + + /* get required compiler data */ + + cd = jd->cd; + + if (src->flags & INMEMORY) { + COUNT_SPILLS; + + disp = src->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->regoff; + + return reg; +} + + +/* emit_load_s3 **************************************************************** + + Emits a possible load of the third source operand. + +*******************************************************************************/ + +s4 emit_load_s3(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg) +{ + codegendata *cd; + s4 disp; + s4 reg; + + /* get required compiler data */ + + cd = jd->cd; + + if (src->flags & INMEMORY) { + COUNT_SPILLS; + + disp = src->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->regoff; + + return reg; +} + + +/* emit_load_s1_low ************************************************************ + + Emits a possible load of the low 32-bits of the first long source + operand. + +*******************************************************************************/ + +s4 emit_load_s1_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg) +{ + codegendata *cd; + s4 disp; + s4 reg; + + assert(src->type == TYPE_LNG); + + /* get required compiler data */ + + cd = jd->cd; + + if (src->flags & INMEMORY) { + COUNT_SPILLS; + + disp = src->regoff * 4; + + M_ILD(tempreg, REG_SP, disp + 4); + + reg = tempreg; + } else + reg = GET_LOW_REG(src->regoff); + + return reg; +} + + +/* emit_load_s2_low ************************************************************ + + Emits a possible load of the low 32-bits of the second long source + operand. + +*******************************************************************************/ + +s4 emit_load_s2_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg) +{ + codegendata *cd; + s4 disp; + s4 reg; + + assert(src->type == TYPE_LNG); + + /* get required compiler data */ + + cd = jd->cd; + + if (src->flags & INMEMORY) { + COUNT_SPILLS; + + disp = src->regoff * 4; + + M_ILD(tempreg, REG_SP, disp + 4); + + reg = tempreg; + } else + reg = GET_LOW_REG(src->regoff); + + return reg; +} + + +/* emit_load_s3_low ************************************************************ + + Emits a possible load of the low 32-bits of the third long source + operand. + +*******************************************************************************/ + +s4 emit_load_s3_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg) +{ + codegendata *cd; + s4 disp; + s4 reg; + + assert(src->type == TYPE_LNG); + + /* get required compiler data */ + + cd = jd->cd; + + if (src->flags & INMEMORY) { + COUNT_SPILLS; + + disp = src->regoff * 4; + + M_ILD(tempreg, REG_SP, disp + 4); + + reg = tempreg; + } else + reg = GET_LOW_REG(src->regoff); + + return reg; +} + + +/* emit_load_s1_high *********************************************************** + + Emits a possible load of the high 32-bits of the first long source + operand. + +*******************************************************************************/ + +s4 emit_load_s1_high(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg) +{ + codegendata *cd; + s4 disp; + s4 reg; + + assert(src->type == TYPE_LNG); + + /* get required compiler data */ + + cd = jd->cd; + + if (src->flags & INMEMORY) { + COUNT_SPILLS; + + disp = src->regoff * 4; + + M_ILD(tempreg, REG_SP, disp); + + reg = tempreg; + } else + reg = GET_HIGH_REG(src->regoff); + + return reg; +} + + +/* emit_load_s2_high *********************************************************** + + Emits a possible load of the high 32-bits of the second long source + operand. + +*******************************************************************************/ + +s4 emit_load_s2_high(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg) +{ + codegendata *cd; + s4 disp; + s4 reg; + + assert(src->type == TYPE_LNG); + + /* get required compiler data */ + + cd = jd->cd; + + if (src->flags & INMEMORY) { + COUNT_SPILLS; + + disp = src->regoff * 4; + + M_ILD(tempreg, REG_SP, disp); + + reg = tempreg; + } else + reg = GET_HIGH_REG(src->regoff); + + return reg; +} + + +/* emit_load_s3_high *********************************************************** + + Emits a possible load of the high 32-bits of the third long source + operand. + +*******************************************************************************/ + +s4 emit_load_s3_high(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg) +{ + codegendata *cd; + s4 disp; + s4 reg; + + assert(src->type == TYPE_LNG); + + /* get required compiler data */ + + cd = jd->cd; + + if (src->flags & INMEMORY) { + COUNT_SPILLS; + + disp = src->regoff * 4; + + M_ILD(tempreg, REG_SP, disp); + + reg = tempreg; + } else + reg = GET_HIGH_REG(src->regoff); + + return reg; +} + + +/* emit_store ****************************************************************** + + XXX + +*******************************************************************************/ + +void emit_store(jitdata *jd, instruction *iptr, stackptr dst, s4 d) +{ + codegendata *cd; + + /* get required compiler data */ + + cd = jd->cd; + + if (dst->flags & INMEMORY) { + COUNT_SPILLS; + + if (IS_FLT_DBL_TYPE(dst->type)) { + if (IS_2_WORD_TYPE(dst->type)) + M_DST(d, REG_SP, dst->regoff * 4); + else + M_FST(d, REG_SP, dst->regoff * 4); + + } else { + if (IS_2_WORD_TYPE(dst->type)) + M_LST(d, REG_SP, dst->regoff * 4); + else + M_IST(d, REG_SP, dst->regoff * 4); + } + } +} + + +/* emit_copy ******************************************************************* + + XXX + +*******************************************************************************/ + +void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst) +{ + codegendata *cd; + registerdata *rd; + s4 s1, d; + + /* get required compiler data */ + + cd = jd->cd; + rd = jd->rd; + + if (src->type == TYPE_LNG) + d = codegen_reg_of_var(rd, iptr->opc, dst, PACK_REGS(REG_ITMP2, REG_ITMP1)); + else + d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP); + + if ((src->regoff != dst->regoff) || + ((src->flags ^ dst->flags) & INMEMORY)) { + s1 = emit_load_s1(jd, iptr, src, d); + + if (s1 != d) { + if (IS_FLT_DBL_TYPE(src->type)) + M_FMOV(s1, d); + else { + if (IS_2_WORD_TYPE(src->type)) { + M_MOV(GET_LOW_REG(s1), GET_LOW_REG(d)); + M_MOV(GET_HIGH_REG(s1), GET_HIGH_REG(d)); + } else + M_MOV(s1, d); + } + } + + emit_store(jd, iptr, dst, d); + } +} + + +/* emit_iconst ***************************************************************** + + XXX + +*******************************************************************************/ + +void emit_iconst(codegendata *cd, s4 d, s4 value) +{ + s4 disp; + + if ((value >= -32768) && (value <= 32767)) + M_LDA_INTERN(d, REG_ZERO, value); + else { + disp = dseg_adds4(cd, value); + M_ILD(d, REG_PV, disp); + } +} + + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/powerpc64/linux/Makefile.am b/src/vm/jit/powerpc64/linux/Makefile.am new file mode 100644 index 000000000..5207e3d3a --- /dev/null +++ b/src/vm/jit/powerpc64/linux/Makefile.am @@ -0,0 +1,56 @@ +## src/vm/jit/powerpc64/linux/Makefile.am +## +## Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, +## C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, +## E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, +## J. Wenninger, Institut f. Computersprachen - TU Wien +## +## This file is part of CACAO. +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License as +## published by the Free Software Foundation; either version 2, or (at +## your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +## 02110-1301, USA. +## +## Contact: cacao@cacaojvm.org +## +## Authors: Christian Thalinger +## +## Changes: +## +## $Id: Makefile.am 5081 2006-07-06 13:59:01Z tbfg $ + +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/vm/jit/$(ARCH_DIR) + +LIBS = + +noinst_HEADERS = \ + md-asm.h + +noinst_LTLIBRARIES = libmd.la + +libmd_la_SOURCES = \ + md-abi.c \ + md-abi.h \ + md-os.c + + +## Local variables: +## mode: Makefile +## indent-tabs-mode: t +## c-basic-offset: 4 +## tab-width: 8 +## compile-command: "automake --add-missing" +## End: diff --git a/src/vm/jit/powerpc64/linux/md-abi.c b/src/vm/jit/powerpc64/linux/md-abi.c new file mode 100644 index 000000000..5ebf87ed7 --- /dev/null +++ b/src/vm/jit/powerpc64/linux/md-abi.c @@ -0,0 +1,273 @@ +/* src/vm/jit/powerpc64/linux/md-abi.c - functions for PowerPC64 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: Roland Lezuo + + Changes: + + $Id: md-abi.c 5081 2006-07-06 13:59:01Z tbfg $ + +*/ + + +#include "config.h" +#include "vm/types.h" + +#include "vm/jit/powerpc64/linux/md-abi.h" + +#include "vm/descriptor.h" +#include "vm/global.h" + + +#define _ALIGN(a) do { if ((a) & 1) (a)++; } while (0) + + +/* register descripton array **************************************************/ + +s4 nregdescint[] = { + /* zero, sp, TOC, a0/v0, a0/v1, a2, a3, a4, */ + REG_RES, REG_RES, REG_RES, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, + + /* a5, a6, a7, itmp1, itmp2, NO(SYS), pv, s0, */ + REG_ARG, REG_ARG, REG_ARG, REG_RES, REG_RES, REG_RES, REG_SAV, REG_SAV, + + /*itmp3, t0, t1, t2, t3, t4, t5, t6, */ + REG_RES, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, + + /* s1, s2, s3, s4, s5, s6, s7, s8, */ + REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, + + REG_END +}; + +char *regs[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", +}; + + +s4 nregdescfloat[] = { + /*ftmp3, fa0/v0, fa1, fa2, fa3, fa4, fa5, fa6, */ + REG_RES, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, + + /* fa7, ft0, ft1, ft2, ft3, ft4, fs0, fs1, */ + REG_ARG, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_SAV, REG_SAV, + + /*ftmp1, ftmp2, ft5, ft6, ft7, ft8, ft9, ft10, */ + REG_RES, REG_RES, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, + + /* fs2, fs3, fs4, fs5, fs6, fs7, fs8, fs9 */ + REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, + + REG_END +}; + +/* md_param_alloc ************************************************************** + + Allocate Arguments to Stackslots according the Calling Conventions + + --- in + md->paramcount: Number of arguments for this method + md->paramtypes[].type: Argument types + + --- out + md->params[].inmemory: Argument spilled on stack + md->params[].regoff: Stack offset or rd->arg[int|flt]regs index + md->memuse: Stackslots needed for argument spilling + md->argintreguse: max number of integer arguments used + md->argfltreguse: max number of float arguments used + +*******************************************************************************/ + +void md_param_alloc(methoddesc *md) +{ + paramdesc *pd; + s4 i; + s4 iarg; + s4 farg; + s4 stacksize; + + /* set default values */ + + iarg = 0; + farg = 0; + stacksize = LA_WORD_SIZE; + + /* 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: + if (iarg < INT_ARG_CNT) { + pd->inmemory = false; + pd->regoff = iarg; + iarg++; + } else { + pd->inmemory = true; + pd->regoff = stacksize; + stacksize++; + } + break; + case TYPE_LNG: + if (iarg < INT_ARG_CNT - 1) { + _ALIGN(iarg); + pd->inmemory = false; + /* rd->arg[int|flt]regs index !! */ + pd->regoff = PACK_REGS(iarg + 1, iarg); + iarg += 2; + } else { + _ALIGN(stacksize); + pd->inmemory = true; + pd->regoff = stacksize; + iarg = INT_ARG_CNT; + stacksize += 2; + } + break; + case TYPE_FLT: + if (farg < FLT_ARG_CNT) { + pd->inmemory = false; + pd->regoff = farg; + farg++; + } else { + pd->inmemory = true; + pd->regoff = stacksize; + stacksize++; + } + break; + case TYPE_DBL: + if (farg < FLT_ARG_CNT) { + pd->inmemory = false; + pd->regoff = farg; + farg++; + } else { + _ALIGN(stacksize); + pd->inmemory = true; + pd->regoff = stacksize; + stacksize += 2; + } + break; + } + } + + /* Since R3/R4, F1 (==A0/A1, A0) are used for passing return values, this */ + /* argument register usage has to be regarded, too */ + if (IS_INT_LNG_TYPE(md->returntype.type)) { + if (iarg < (IS_2_WORD_TYPE(md->returntype.type) ? 2 : 1)) + iarg = IS_2_WORD_TYPE(md->returntype.type) ? 2 : 1; + } else { + 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, if + possible. (R3==a00 for int/adr, R4/R3 == a01/a00 for long, F1==a00 + for float/double) + + --- in + m: Methodinfo of current method + return_type: Return Type of the Method (TYPE_INT.. TYPE_ADR) + TYPE_VOID is not allowed! + stackslot: Java Stackslot to contain the Return Value + + --- out + if precoloring was possible: + stackslot->varkind =ARGVAR + ->varnum =-1 + ->flags =0 + ->regoff =[REG_RESULT, (REG_RESULT2/REG_RESULT), REG_FRESULT] + rd->arg[flt|int]reguse set to a value according the register usage + +*******************************************************************************/ + +void md_return_alloc(methodinfo *m, registerdata *rd, s4 return_type, + stackptr stackslot) +{ + /* In Leafmethods Local Vars holding parameters are precolored to + their argument register -> so leafmethods with paramcount > 0 + could already use R3 == a00! */ + + if (!m->isleafmethod || (m->parseddesc->paramcount == 0)) { + /* Only precolor the stackslot, if it is not a SAVEDVAR <-> + has not to survive method invokations. */ + + if (!(stackslot->flags & SAVEDVAR)) { + stackslot->varkind = ARGVAR; + stackslot->varnum = -1; + stackslot->flags = 0; + + if (IS_INT_LNG_TYPE(return_type)) { + if (!IS_2_WORD_TYPE(return_type)) { + if (rd->argintreguse < 1) + rd->argintreguse = 1; + + stackslot->regoff = REG_RESULT; + + } else { + if (rd->argintreguse < 2) + rd->argintreguse = 2; + + /* stackslot->regoff = PACK_REGS(REG_RESULT2, REG_RESULT); // FIXME */ + } + + } else { /* float/double */ + if (rd->argfltreguse < 1) + rd->argfltreguse = 1; + + stackslot->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: + */ diff --git a/src/vm/jit/powerpc64/linux/md-abi.h b/src/vm/jit/powerpc64/linux/md-abi.h index fba1168ef..a7f6651ae 100644 --- a/src/vm/jit/powerpc64/linux/md-abi.h +++ b/src/vm/jit/powerpc64/linux/md-abi.h @@ -28,7 +28,7 @@ Changes: - $Id: md-abi.h 4357 2006-01-22 23:33:38Z twisti $ + $Id: md-abi.h 5081 2006-07-06 13:59:01Z tbfg $ */ @@ -42,7 +42,7 @@ #define REG_RESULT 3 /* to deliver method results */ -#define REG_PV 13 /* procedure vector, must be provided by caller */ +#define REG_PV 14 /* procedure vector, must be provided by caller */ #define REG_METHODPTR 12 /* pointer to the place from where the procedure */ /* vector has been fetched */ #define REG_ITMP1 11 /* temporary register */ diff --git a/src/vm/jit/powerpc64/linux/md-asm.h b/src/vm/jit/powerpc64/linux/md-asm.h new file mode 100644 index 000000000..36f18b240 --- /dev/null +++ b/src/vm/jit/powerpc64/linux/md-asm.h @@ -0,0 +1,222 @@ +/* src/vm/jit/powerpc64/linux/md-asm.h - assembler defines for PowerPC 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 5081 2006-07-06 13:59:01Z tbfg $ + +*/ + + +#ifndef _MD_ASM_H +#define _MD_ASM_H + +#include + + +/* register defines ***********************************************************/ + +#define zero r0 +#define sp r1 + +/* #define XXX r2 - system reserved register */ + +#define a0 r3 +#define a1 r4 +#define a2 r5 +#define a3 r6 +#define a4 r7 +#define a5 r8 +#define a6 r9 +#define a7 r10 + +#define itmp1 r11 +#define itmp2 r12 +#define pv r13 + +#define s0 r14 +#define s1 r15 + +#define itmp3 r16 +#define t0 r17 +#define t1 r18 +#define t2 r19 +#define t3 r20 +#define t4 r21 +#define t5 r22 +#define t6 r23 + +#define s2 r24 +#define s3 r25 +#define s4 r26 +#define s5 r27 +#define s6 r28 +#define s7 r29 +#define s8 r30 +#define s9 r31 + +#define v0 a0 +#define v1 a1 + +#define xptr itmp1 +#define xpc itmp2 + +#define mptr r12 +#define mptrn 12 + + +#define ftmp3 fr0 + +#define fa0 fr1 +#define fa1 fr2 +#define fa2 fr3 +#define fa3 fr4 +#define fa4 fr5 +#define fa5 fr6 +#define fa6 fr7 +#define fa7 fr8 + +#define fa8 fr9 +#define fa9 fr10 +#define fa10 fr11 +#define fa11 fr12 +#define fa12 fr13 + +#define fs0 fr14 +#define fs1 fr15 + +#define ftmp1 fr16 +#define ftmp2 fr17 + +#define ft0 fr18 +#define ft1 fr19 +#define ft2 fr20 +#define ft3 fr21 +#define ft4 fr22 +#define ft5 fr23 + +#define fs2 fr24 +#define fs3 fr25 +#define fs4 fr26 +#define fs5 fr27 +#define fs6 fr28 +#define fs7 fr29 +#define fs8 fr30 +#define fs9 fr31 + +#define fv0 fa0 + + +/* save and restore macros ****************************************************/ + +#define SAVE_ARGUMENT_REGISTERS(off) \ + stw a0,(0+(off))*4(sp); \ + stw a1,(1+(off))*4(sp); \ + stw a2,(2+(off))*4(sp); \ + stw a3,(3+(off))*4(sp); \ + stw a4,(4+(off))*4(sp); \ + stw a5,(5+(off))*4(sp); \ + stw a6,(6+(off))*4(sp); \ + stw a7,(7+(off))*4(sp); \ + \ + stfd fa0,(8+(off))*4(sp); \ + stfd fa1,(10+(off))*4(sp); \ + stfd fa2,(12+(off))*4(sp); \ + stfd fa3,(14+(off))*4(sp); \ + stfd fa4,(16+(off))*4(sp); \ + stfd fa5,(18+(off))*4(sp); \ + stfd fa6,(20+(off))*4(sp); \ + stfd fa7,(22+(off))*4(sp); + +#define RESTORE_ARGUMENT_REGISTERS(off) \ + lwz a0,(0+(off))*4(sp); \ + lwz a1,(1+(off))*4(sp); \ + lwz a2,(2+(off))*4(sp); \ + lwz a3,(3+(off))*4(sp); \ + lwz a4,(4+(off))*4(sp); \ + lwz a5,(5+(off))*4(sp); \ + lwz a6,(6+(off))*4(sp); \ + lwz a7,(7+(off))*4(sp); \ + \ + lfd fa0,(8+(off))*4(sp); \ + lfd fa1,(10+(off))*4(sp); \ + lfd fa2,(12+(off))*4(sp); \ + lfd fa3,(14+(off))*4(sp); \ + lfd fa4,(16+(off))*4(sp); \ + lfd fa5,(18+(off))*4(sp); \ + lfd fa6,(20+(off))*4(sp); \ + lfd fa7,(22+(off))*4(sp); + + +#define SAVE_TEMPORARY_REGISTERS(off) \ + stw t0,(0+(off))*4(sp); \ + stw t1,(1+(off))*4(sp); \ + stw t2,(2+(off))*4(sp); \ + stw t3,(3+(off))*4(sp); \ + stw t4,(4+(off))*4(sp); \ + stw t5,(5+(off))*4(sp); \ + stw t6,(6+(off))*4(sp); \ + \ + stfd ft0,(8+(off))*4(sp); \ + stfd ft1,(10+(off))*4(sp); \ + stfd ft2,(12+(off))*4(sp); \ + stfd ft3,(14+(off))*4(sp); \ + stfd ft4,(16+(off))*4(sp); \ + stfd ft5,(18+(off))*4(sp); + +#define RESTORE_TEMPORARY_REGISTERS(off) \ + lwz t0,(0+(off))*4(sp); \ + lwz t1,(1+(off))*4(sp); \ + lwz t2,(2+(off))*4(sp); \ + lwz t3,(3+(off))*4(sp); \ + lwz t4,(4+(off))*4(sp); \ + lwz t5,(5+(off))*4(sp); \ + lwz t6,(6+(off))*4(sp); \ + \ + lfd ft0,(8+(off))*4(sp); \ + lfd ft1,(10+(off))*4(sp); \ + lfd ft2,(12+(off))*4(sp); \ + lfd ft3,(14+(off))*4(sp); \ + lfd ft4,(16+(off))*4(sp); \ + lfd ft5,(18+(off))*4(sp); + +#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: + */ diff --git a/src/vm/jit/powerpc64/linux/md-os.c b/src/vm/jit/powerpc64/linux/md-os.c new file mode 100644 index 000000000..3b63ad6f9 --- /dev/null +++ b/src/vm/jit/powerpc64/linux/md-os.c @@ -0,0 +1,167 @@ +/* src/vm/jit/powerpc64/linux/md-os.c - machine dependent PowerPC 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: + + $Id: md-os.c 5081 2006-07-06 13:59:01Z tbfg $ + +*/ + + +#include "config.h" + +#include +#include + +#include "vm/types.h" + +#include "vm/jit/powerpc64/linux/md-abi.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/threads.h" +#endif + +#include "vm/exceptions.h" +#include "vm/signallocal.h" +#include "vm/stringlocal.h" +#include "vm/jit/asmpart.h" + +#if defined(ENABLE_PROFILING) +# include "vm/jit/profile/profile.h" +#endif + +#include "vm/jit/stacktrace.h" + + +/* md_signal_handler_sigsegv *************************************************** + + NullPointerException signal handler for hardware null pointer + check. + +*******************************************************************************/ + +void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p) {} +void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p) {} +void thread_restartcriticalsection(ucontext_t *_uc) {} + +#if 0 +void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p) +{ + ucontext_t *_uc; + mcontext_t *_mc; + u4 instr; + s4 reg; + ptrint addr; + u1 *pv; + u1 *sp; + u1 *ra; + u1 *xpc; + + _uc = (ucontext_t *) _p; + _mc = _uc->uc_mcontext.uc_regs; + + instr = *((u4 *) _mc->gregs[PT_NIP]); + reg = (instr >> 16) & 0x1f; + addr = _mc->gregs[reg]; + + if (addr == 0) { + pv = (u1 *) _mc->gregs[REG_PV]; + sp = (u1 *) _mc->gregs[REG_SP]; + ra = (u1 *) _mc->gregs[PT_LNK]; /* this is correct for leafs */ + xpc = (u1 *) _mc->gregs[PT_NIP]; + + _mc->gregs[REG_ITMP1_XPTR] = + (ptrint) stacktrace_hardware_nullpointerexception(pv, sp, ra, xpc); + + _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc; + _mc->gregs[PT_NIP] = (ptrint) asm_handle_exception; + + } else { + throw_cacao_exception_exit(string_java_lang_InternalError, + "Segmentation fault: 0x%08lx at 0x%08lx", + addr, _mc->gregs[PT_NIP]); + } +} + + +/* md_signal_handler_sigusr2 *************************************************** + + Signal handler for profiling sampling. + +*******************************************************************************/ + +void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p) +{ + threadobject *tobj; + ucontext_t *_uc; + mcontext_t *_mc; + u1 *pc; + + tobj = THREADOBJECT; + + _uc = (ucontext_t *) _p; + _mc = _uc->uc_mcontext.uc_regs; + + pc = (u1 *) _mc->gregs[PT_NIP]; + + tobj->pc = pc; +} + + +#if defined(ENABLE_THREADS) +void thread_restartcriticalsection(ucontext_t *_uc) +{ + mcontext_t *_mc; + u1 *pc; + void *critical; + + _mc = _uc->uc_mcontext.uc_regs; + + pc = (u1 *) _mc->gregs[PT_NIP]; + + critical = critical_find_restart_point(pc); + + if (critical) + _mc->gregs[PT_NIP] = (ptrint) critical; +} +#endif + +#endif + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/src/vm/jit/powerpc64/machine-instr.h b/src/vm/jit/powerpc64/machine-instr.h new file mode 100644 index 000000000..10cf5b622 --- /dev/null +++ b/src/vm/jit/powerpc64/machine-instr.h @@ -0,0 +1,41 @@ +#ifndef _MACHINE_INSTR_H +#define _MACHINE_INSTR_H + +static inline void +atomic_add(int *mem, int val) +{ + int temp; + + __asm__ __volatile__ ("\n\ +1: lwarx %0,0,%2 \n\ + add %0,%0,%1 \n\ + stwcx. %0,0,%2 \n\ + bne- 1b \n\ +" : "=&r"(temp) + : "r"(val), "r"(mem) : "cr0", "memory"); +} + +static inline long compare_and_swap(long *p, long oldval, long newval) +{ + long ret, temp; + + __asm__ __volatile__ ("\n\ +1: lwarx %0,0,%4 \n\ + subf. %1,%0,%2 \n\ + bne- 2f \n\ + or %1,%3,%3 \n\ + stwcx. %1,0,%4 \n\ + bne- 1b \n\ +2: \n\ +" : "=&r"(ret), "=&r"(temp) + : "r"(oldval), "r"(newval), "r"(p) : "cr0", "memory"); + + return ret; +} + +#define STORE_ORDER_BARRIER() __asm__ __volatile__ ("" : : : "memory"); +#define MEMORY_BARRIER_BEFORE_ATOMIC() __asm__ __volatile__ ("sync" : : : "memory"); +#define MEMORY_BARRIER_AFTER_ATOMIC() __asm__ __volatile__ ("isync" : : : "memory"); +#define MEMORY_BARRIER() __asm__ __volatile__ ( "sync" : : : "memory" ); + +#endif diff --git a/src/vm/jit/powerpc64/md.c b/src/vm/jit/powerpc64/md.c new file mode 100644 index 000000000..28750b682 --- /dev/null +++ b/src/vm/jit/powerpc64/md.c @@ -0,0 +1,312 @@ +/* src/vm/jit/powerpc/md.c - machine dependent PowerPC 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 5081 2006-07-06 13:59:01Z tbfg $ + +*/ + +#include "config.h" + +#include + +#include "vm/types.h" + +#include "md-abi.h" + +#include "vm/global.h" +#include "vm/jit/asmpart.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_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 PowerPC the return address is located in the linkage area */ + + ra = *((u1 **) (sp + framesize + LA_LR_OFFSET)); + + 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: + + 81adffd4 lwz r13,-44(r13) + 7da903a6 mtctr r13 + 4e800421 bctrl + + INVOKEVIRTUAL: + + 81830000 lwz r12,0(r3) + 81ac0000 lwz r13,0(r12) + 7da903a6 mtctr r13 + 4e800421 bctrl + + INVOKEINTERFACE: + + 81830000 lwz r12,0(r3) + 818c0000 lwz r12,0(r12) + 81ac0000 lwz r13,0(r12) + 7da903a6 mtctr r13 + 4e800421 bctrl + +*******************************************************************************/ + +u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) +{ + u4 mcode; + s4 offset; + u1 *pa; + + /* go back to the actual load instruction (3 instructions) */ + + ra = ra - 3 * 4; + + /* get first instruction word (lwz) */ + + mcode = *((u4 *) ra); + + /* check if we have 2 instructions (addis, addi) */ + + if ((mcode >> 16) == 0x3c19) { + /* XXX write a regression for this */ + assert(0); + + /* get displacement of first instruction (addis) */ + + offset = (s4) (mcode << 16); + + /* get displacement of second instruction (addi) */ + + mcode = *((u4 *) (ra + 1 * 4)); + + assert((mcode >> 16) != 0x6739); + + offset += (s2) (mcode & 0x0000ffff); + + } else { + /* get the offset from the instruction */ + + offset = (s2) (mcode & 0x0000ffff); + + /* check for load from PV */ + + if ((mcode >> 16) == 0x81ad) { + /* get the final data segment address */ + + pa = sfi->pv + offset; + + } else if ((mcode >> 16) == 0x81ac) { + /* in this case we use the passed method pointer */ + + pa = mptr + offset; + + } else { + /* catch any problems */ + + assert(0); + } + } + + return pa; +} + + +/* md_codegen_findmethod ******************************************************* + + Machine code: + + 7d6802a6 mflr r11 + 39abffe0 addi r13,r11,-32 + + or + + 7d6802a6 mflr r11 + 3dabffff addis r13,r11,-1 + 39ad68b0 addi r13,r13,26800 + +*******************************************************************************/ + +u1 *md_codegen_findmethod(u1 *ra) +{ + u1 *pv; + u4 mcode; + s4 offset; + + /* get first instruction word after jump */ + + mcode = *((u4 *) (ra + 1 * 4)); + + /* check if we have 2 instructions (addis, addi) */ + + if ((mcode >> 16) == 0x3dab) { + /* get displacement of first instruction (addis) */ + + offset = (s4) (mcode << 16); + + /* get displacement of second instruction (addi) */ + + mcode = *((u4 *) (ra + 2 * 4)); + + /* check for addi instruction */ + + assert((mcode >> 16) == 0x39ad); + + offset += (s2) (mcode & 0x0000ffff); + + } else { + /* check for addi instruction */ + + assert((mcode >> 16) == 0x39ab); + + /* get offset of first instruction (addi) */ + + offset = (s2) (mcode & 0x0000ffff); + } + + /* calculate PV via RA + offset */ + + pv = ra + offset; + + return pv; +} + + +/* md_cacheflush *************************************************************** + + Calls the system's function to flush the instruction and data + cache. + +*******************************************************************************/ + +void md_cacheflush(u1 *addr, s4 nbytes) +{ + asm_cacheflush(addr, nbytes); +} + + +/* md_icacheflush ************************************************************** + + Calls the system's function to flush the instruction cache. + +*******************************************************************************/ + +void md_icacheflush(u1 *addr, s4 nbytes) +{ + asm_cacheflush(addr, nbytes); +} + + +/* md_dcacheflush ************************************************************** + + Calls the system's function to flush the data cache. + +*******************************************************************************/ + +void md_dcacheflush(u1 *addr, s4 nbytes) +{ + asm_cacheflush(addr, nbytes); +} + + +/* md_patch_replacement_point ************************************************** + + Patch the given replacement point. + +*******************************************************************************/ + +void md_patch_replacement_point(rplpoint *rp) +{ + u8 mcode; + + /* save the current machine code */ + mcode = *(u4*)rp->pc; + + /* write the new machine code */ + *(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 + + /* flush instruction cache */ + md_icacheflush(rp->pc,4); +} + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */ diff --git a/src/vm/jit/powerpc64/patcher.c b/src/vm/jit/powerpc64/patcher.c new file mode 100644 index 000000000..34c4bddf3 --- /dev/null +++ b/src/vm/jit/powerpc64/patcher.c @@ -0,0 +1,954 @@ +/* src/vm/jit/powerpc/patcher.c - PowerPC 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 5081 2006-07-06 13:59:01Z tbfg $ + +*/ + + +#include "config.h" + +#include + +#include "vm/types.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/resolve.h" +#include "vm/references.h" +#include "vm/jit/asmpart.h" +#include "vm/jit/patcher.h" +#include "vm/jit/methodheader.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 *); + + assert(pv != NULL); + + /* get stuff from the stack */ + + xpc = (u1 *) *((ptrint *) (sp + 5 * 4)); + o = (java_objectheader *) *((ptrint *) (sp + 4 * 4)); + f = (functionptr) *((ptrint *) (sp + 0 * 4)); + + /* store PV into the patcher function position */ + + *((ptrint *) (sp + 0 * 4)) = (ptrint) pv; + + /* cast the passed function to a patcher function */ + + patcher_function = (bool (*)(u1 *)) (ptrint) f; + + /* enter a monitor on the patching position */ + + PATCHER_MONITORENTER; + + /* create the stackframeinfo */ + + stacktrace_create_extern_stackframeinfo(&sfi, pv, sp + 8 * 4, ra, 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: + + + 816dffc8 lwz r11,-56(r13) + 80ab0000 lwz r5,0(r11) + +*******************************************************************************/ + +bool patcher_get_putstatic(u1 *sp) +{ + u1 *ra; + u4 mcode; + unresolved_field *uf; + s4 disp; + u1 *pv; + fieldinfo *fi; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + uf = (unresolved_field *) *((ptrint *) (sp + 2 * 4)); + disp = *((s4 *) (sp + 1 * 4)); + pv = (u1 *) *((ptrint *) (sp + 0 * 4)); + + /* get the fieldinfo */ + + if (!(fi = resolve_field_eager(uf))) + return false; + + /* check if the field's class is initialized */ + + if (!(fi->class->state & CLASS_INITIALIZED)) + if (!initialize_class(fi->class)) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* synchronize instruction cache */ + + md_icacheflush(ra, 4); + + /* patch the field value's address */ + + *((ptrint *) (pv + disp)) = (ptrint) &(fi->value); + + /* synchronize data cache */ + + md_dcacheflush(pv + disp, SIZEOF_VOID_P); + + return true; +} + + +/* patcher_get_putfield ******************************************************** + + Machine code: + + + 811f0014 lwz r8,20(r31) + +*******************************************************************************/ + +bool patcher_get_putfield(u1 *sp) +{ + u1 *ra; + u4 mcode; + unresolved_field *uf; + u1 *pv; + fieldinfo *fi; + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + uf = (unresolved_field *) *((ptrint *) (sp + 2 * 4)); + pv = (u1 *) *((ptrint *) (sp + 1 * 4)); + + /* get the fieldinfo */ + + if (!(fi = resolve_field_eager(uf))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop */ + + if (opt_showdisassemble) + ra = ra + 4; + + /* patch the field's offset */ + + if (fi->type == TYPE_LNG) { + s2 disp; + + /* If the field has type long, we have to patch two + instructions. But we have to check which instruction is + first. We do that with the offset of the first + instruction. */ + + disp = *((u4 *) (ra + 0)); + +#if WORDS_BIGENDIAN == 1 + if (disp == 4) { + *((u4 *) (ra + 0)) |= (s2) ((fi->offset + 4) & 0x0000ffff); + *((u4 *) (ra + 4)) |= (s2) ((fi->offset + 0) & 0x0000ffff); + + } else { + *((u4 *) (ra + 0)) |= (s2) ((fi->offset + 0) & 0x0000ffff); + *((u4 *) (ra + 4)) |= (s2) ((fi->offset + 4) & 0x0000ffff); + } +#else +#error Fix me for LE +#endif + } + else { + *((u4 *) ra) |= (s2) (fi->offset & 0x0000ffff); + } + + /* synchronize instruction cache */ + + md_icacheflush(ra, 8); + + return true; +} + + +/* patcher_aconst ************************************************************** + + Machine code: + + + 806dffc4 lwz r3,-60(r13) + 81adffc0 lwz r13,-64(r13) + 7da903a6 mtctr r13 + 4e800421 bctrl + +*******************************************************************************/ + +bool patcher_aconst(u1 *sp) +{ + u1 *ra; + u4 mcode; + constant_classref *cr; + s4 disp; + u1 *pv; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 4)); + disp = *((s4 *) (sp + 1 * 4)); + pv = (u1 *) *((ptrint *) (sp + 0 * 4)); + + /* get the classinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* synchronize instruction cache */ + + md_icacheflush(ra, 4); + + /* patch the classinfo pointer */ + + *((ptrint *) (pv + disp)) = (ptrint) c; + + /* synchronize data cache */ + + md_dcacheflush(pv + disp, SIZEOF_VOID_P); + + return true; +} + + +/* patcher_builtin_multianewarray ********************************************** + + Machine code: + + + 808dffc0 lwz r4,-64(r13) + 38a10038 addi r5,r1,56 + 81adffbc lwz r13,-68(r13) + 7da903a6 mtctr r13 + 4e800421 bctrl + +*******************************************************************************/ + +bool patcher_builtin_multianewarray(u1 *sp) +{ + u1 *ra; + u4 mcode; + constant_classref *cr; + s4 disp; + u1 *pv; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 4)); + disp = *((s4 *) (sp + 1 * 4)); + pv = (u1 *) *((ptrint *) (sp + 0 * 4)); + + /* get the classinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* synchronize instruction cache */ + + md_icacheflush(ra, 4); + + /* patch the classinfo pointer */ + + *((ptrint *) (pv + disp)) = (ptrint) c; + + /* synchronize data cache */ + + md_dcacheflush(pv + disp, SIZEOF_VOID_P); + + return true; +} + + +/* patcher_builtin_arraycheckcast ********************************************** + + Machine code: + + + 808dffd8 lwz r4,-40(r13) + 81adffd4 lwz r13,-44(r13) + 7da903a6 mtctr r13 + 4e800421 bctrl + +*******************************************************************************/ + +bool patcher_builtin_arraycheckcast(u1 *sp) +{ + u1 *ra; + u4 mcode; + constant_classref *cr; + s4 disp; + u1 *pv; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 4)); + disp = *((s4 *) (sp + 1 * 4)); + pv = (u1 *) *((ptrint *) (sp + 0 * 4)); + + /* get the classinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* synchronize instruction cache */ + + md_icacheflush(ra, 4); + + /* patch the classinfo pointer */ + + *((ptrint *) (pv + disp)) = (ptrint) c; + + /* synchronize data cache */ + + md_dcacheflush(pv + disp, SIZEOF_VOID_P); + + return true; +} + + +/* patcher_invokestatic_special ************************************************ + + Machine code: + + + 81adffd8 lwz r13,-40(r13) + 7da903a6 mtctr r13 + 4e800421 bctrl + +******************************************************************************/ + +bool patcher_invokestatic_special(u1 *sp) +{ + u1 *ra; + u4 mcode; + unresolved_method *um; + s4 disp; + u1 *pv; + methodinfo *m; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + um = (unresolved_method *) *((ptrint *) (sp + 2 * 4)); + disp = *((s4 *) (sp + 1 * 4)); + pv = (u1 *) *((ptrint *) (sp + 0 * 4)); + + /* get the fieldinfo */ + + if (!(m = resolve_method_eager(um))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* synchronize instruction cache */ + + md_icacheflush(ra, 4); + + /* patch stubroutine */ + + *((ptrint *) (pv + disp)) = (ptrint) m->stubroutine; + + /* synchronize data cache */ + + md_dcacheflush(pv + disp, SIZEOF_VOID_P); + + return true; +} + + +/* patcher_invokevirtual ******************************************************* + + Machine code: + + + 81830000 lwz r12,0(r3) + 81ac0088 lwz r13,136(r12) + 7da903a6 mtctr r13 + 4e800421 bctrl + +*******************************************************************************/ + +bool patcher_invokevirtual(u1 *sp) +{ + u1 *ra; + u4 mcode; + unresolved_method *um; + methodinfo *m; + s4 disp; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + um = (unresolved_method *) *((ptrint *) (sp + 2 * 4)); + + /* get the fieldinfo */ + + if (!(m = resolve_method_eager(um))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop */ + + if (opt_showdisassemble) + ra = ra + 4; + + /* patch vftbl index */ + + disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex); + + *((s4 *) (ra + 4)) |= (disp & 0x0000ffff); + + /* synchronize instruction cache */ + + md_icacheflush(ra, 2 * 4); + + return true; +} + + +/* patcher_invokeinterface ***************************************************** + + Machine code: + + + 81830000 lwz r12,0(r3) + 818cffd0 lwz r12,-48(r12) + 81ac000c lwz r13,12(r12) + 7da903a6 mtctr r13 + 4e800421 bctrl + +*******************************************************************************/ + +bool patcher_invokeinterface(u1 *sp) +{ + u1 *ra; + u4 mcode; + unresolved_method *um; + methodinfo *m; + s4 disp; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + um = (unresolved_method *) *((ptrint *) (sp + 2 * 4)); + + /* get the fieldinfo */ + + if (!(m = resolve_method_eager(um))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop */ + + if (opt_showdisassemble) + ra = ra + 4; + + /* patch interfacetable index */ + + disp = OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr*) * m->class->index; + + /* XXX TWISTI: check displacement */ + + *((s4 *) (ra + 1 * 4)) |= (disp & 0x0000ffff); + + /* patch method offset */ + + disp = sizeof(methodptr) * (m - m->class->methods); + + /* XXX TWISTI: check displacement */ + + *((s4 *) (ra + 2 * 4)) |= (disp & 0x0000ffff); + + /* synchronize instruction cache */ + + md_icacheflush(ra, 3 * 4); + + return true; +} + + +/* patcher_checkcast_instanceof_flags ****************************************** + + Machine code: + + + 818dff7c lwz r12,-132(r13) + +*******************************************************************************/ + +bool patcher_checkcast_instanceof_flags(u1 *sp) +{ + u1 *ra; + u4 mcode; + constant_classref *cr; + s4 disp; + u1 *pv; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 4)); + disp = *((s4 *) (sp + 1 * 4)); + pv = (u1 *) *((ptrint *) (sp + 0 * 4)); + + /* get the fieldinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* synchronize instruction cache */ + + md_icacheflush(ra, 4); + + /* patch class flags */ + + *((s4 *) (pv + disp)) = (s4) c->flags; + + /* synchronize data cache */ + + md_dcacheflush(pv + disp, SIZEOF_VOID_P); + + return true; +} + + +/* patcher_checkcast_instanceof_interface ************************************** + + Machine code: + + + 81870000 lwz r12,0(r7) + 800c0010 lwz r0,16(r12) + 34000000 addic. r0,r0,0 + 408101fc ble- 0x3002e518 + 800c0000 lwz r0,0(r12) + +*******************************************************************************/ + +bool patcher_checkcast_instanceof_interface(u1 *sp) +{ + u1 *ra; + u4 mcode; + constant_classref *cr; + classinfo *c; + s4 disp; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 4)); + + /* get the fieldinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* if we show disassembly, we have to skip the nop */ + + if (opt_showdisassemble) + ra = ra + 4; + + /* patch super class index */ + + disp = -(c->index); + + *((s4 *) (ra + 2 * 4)) |= (disp & 0x0000ffff); + + disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*); + + *((s4 *) (ra + 4 * 4)) |= (disp & 0x0000ffff); + + /* synchronize instruction cache */ + + md_icacheflush(ra, 5 * 4); + + return true; +} + + +/* patcher_checkcast_class ***************************************************** + + Machine code: + + + 81870000 lwz r12,0(r7) + 800c0014 lwz r0,20(r12) + 818dff78 lwz r12,-136(r13) + +*******************************************************************************/ + +bool patcher_checkcast_class(u1 *sp) +{ + u1 *ra; + u4 mcode; + constant_classref *cr; + s4 disp; + u1 *pv; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 4)); + disp = *((s4 *) (sp + 1 * 4)); + pv = (u1 *) *((ptrint *) (sp + 0 * 4)); + + /* get the fieldinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* synchronize instruction cache */ + + md_icacheflush(ra, 4); + + /* patch super class' vftbl */ + + *((ptrint *) (pv + disp)) = (ptrint) c->vftbl; + + /* synchronize data cache */ + + md_dcacheflush(pv + disp, SIZEOF_VOID_P); + + return true; +} + + +/* patcher_instanceof_class **************************************************** + + Machine code: + + + 817d0000 lwz r11,0(r29) + 818dff8c lwz r12,-116(r13) + +*******************************************************************************/ + +bool patcher_instanceof_class(u1 *sp) +{ + u1 *ra; + u4 mcode; + constant_classref *cr; + s4 disp; + u1 *pv; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + cr = (constant_classref *) *((ptrint *) (sp + 2 * 4)); + disp = *((s4 *) (sp + 1 * 4)); + pv = (u1 *) *((ptrint *) (sp + 0 * 4)); + + /* get the fieldinfo */ + + if (!(c = resolve_classref_eager(cr))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* synchronize instruction cache */ + + md_icacheflush(ra, 4); + + /* patch super class' vftbl */ + + *((ptrint *) (pv + disp)) = (ptrint) c->vftbl; + + /* synchronize data cache */ + + md_dcacheflush(pv + disp, SIZEOF_VOID_P); + + return true; +} + + +/* patcher_clinit ************************************************************** + + XXX + +*******************************************************************************/ + +bool patcher_clinit(u1 *sp) +{ + u1 *ra; + u4 mcode; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + c = (classinfo *) *((ptrint *) (sp + 2 * 4)); + + /* check if the class is initialized */ + + if (!(c->state & CLASS_INITIALIZED)) + if (!initialize_class(c)) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* synchronize instruction cache */ + + md_icacheflush(ra, 4); + + return true; +} + + +/* patcher_athrow_areturn ****************************************************** + + Machine code: + + + +*******************************************************************************/ + +#ifdef ENABLE_VERIFIER +bool patcher_athrow_areturn(u1 *sp) +{ + u1 *ra; + u4 mcode; + unresolved_class *uc; + classinfo *c; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + uc = (unresolved_class *) *((ptrint *) (sp + 2 * 4)); + + /* resolve the class */ + + if (!resolve_class(uc, resolveEager, false, &c)) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* synchronize instruction cache */ + + md_icacheflush(ra, 4); + + return true; +} +#endif /* ENABLE_VERIFIER */ + + +/* patcher_resolve_native ****************************************************** + + XXX + +*******************************************************************************/ + +#if !defined(WITH_STATIC_CLASSPATH) +bool patcher_resolve_native(u1 *sp) +{ + u1 *ra; + u4 mcode; + methodinfo *m; + s4 disp; + u1 *pv; + functionptr f; + + /* get stuff from the stack */ + + ra = (u1 *) *((ptrint *) (sp + 5 * 4)); + mcode = *((u4 *) (sp + 3 * 4)); + m = (methodinfo *) *((ptrint *) (sp + 2 * 4)); + disp = *((s4 *) (sp + 1 * 4)); + pv = (u1 *) *((ptrint *) (sp + 0 * 4)); + + /* calculate and set the new return address */ + + ra = ra - 1 * 4; + *((ptrint *) (sp + 5 * 4)) = (ptrint) ra; + + /* resolve native function */ + + if (!(f = native_resolve_function(m))) + return false; + + /* patch back original code */ + + *((u4 *) ra) = mcode; + + /* synchronize instruction cache */ + + md_icacheflush(ra, 4); + + /* patch native function pointer */ + + *((ptrint *) (pv + disp)) = (ptrint) f; + + /* synchronize data cache */ + + md_dcacheflush(pv + disp, SIZEOF_VOID_P); + + 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: + */