--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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 <assert.h>
+#include <stdio.h>
+#include <signal.h>
+
+#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:
+ */