/* src/vm/jit/powerpc/asmpart.S - Java-C interface functions for PowerPC
		
   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
   J. Wenninger, Institut f. Computersprachen - TU Wien

   This file is part of CACAO.

   This program is free software.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.

*/


#include "config.h"

#include "md-abi.h"
#include "md-asm.h"

#include "vm/jit/abi-asm.h"
#include "vm/jit/methodheader.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_vm_call_method_end

	.globl asm_handle_nat_exception
	.globl asm_handle_exception

	.globl asm_abstractmethoderror

	.globl asm_cacheflush


/* 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                         /* fltsave                              */
	.long   0                         /* intsave                              */
	.long   0                         /* IsLeaf                               */
	.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(sp)
	stwu    sp,-40*4(sp)              /* keep stack 16-byte aligned           */

	stw     s0,8*4(sp)                /* save used callee saved registers     */

#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(sp)
	stw     t2,19*4(sp)
	stw     t3,20*4(sp)
	stw     t4,21*4(sp)
	stw     t5,22*4(sp)
	stw     t6,23*4(sp)
	stw     t7,24*4(sp)

	stfd	ft0,26*4(sp)
	stfd	ft1,28*4(sp)
	stfd	ft2,30*4(sp)
	stfd	ft3,32*4(sp)
	stfd	ft4,34*4(sp)
	stfd	ft5,36*4(sp)
#else
	SAVE_TEMPORARY_REGISTERS(18)        /* the offset has to be even          */
#endif

	mr      pv,a0                       /* move PV into PV register           */
	mtctr   pv                          /* move PV into branch register       */

	mr      t0,a1                       /* address of data structure          */
	mr      t1,a2                       /* stack argument count               */

	mr      s0,sp                       /* save SP                            */

	lwz     a0,0*8+4(t0)                /* we are on big-endian               */
	lwz     a1,1*8+4(t0)
	lwz     a2,2*8+4(t0)
	lwz     a3,3*8+4(t0)
	lwz     a4,4*8+4(t0)
	lwz     a5,5*8+4(t0)
	lwz     a6,6*8+4(t0)
	lwz     a7,7*8+4(t0)

	lfd     fa0,8*8(t0)
	lfd     fa1,9*8(t0)
	lfd     fa2,10*8(t0)
	lfd     fa3,11*8(t0)
	lfd     fa4,12*8(t0)
	lfd     fa5,13*8(t0)
	lfd     fa6,14*8(t0)
	lfd     fa7,15*8(t0)

#if defined(__DARWIN__)
	lfd     fa8,16*8(t0)
	lfd     fa9,17*8(t0)
	lfd     fa10,18*8(t0)
	lfd     fa11,19*8(t0)
	lfd     fa12,20*8(t0)
#endif

	mr.     t1,t1
	beq     L_asm_vm_call_method_stack_copy_done

	slwi    t2,t1,3                     /* calculate stackframe size (* 8)    */

	sub     sp,sp,t2                    /* create stackframe                  */
	mr      t2,sp                       /* temporary stack pointer            */

L_asm_vm_call_method_stack_copy_loop:
#if defined(__DARWIN__)
	lwz     t3,21*8+0(t0)               /* load argument                      */
	lwz     t4,21*8+4(t0)
#else
	lwz     t3,16*8+0(t0)               /* load argument                      */
	lwz     t4,16*8+4(t0)
#endif
	stw     t3,0(t2)                    /* store argument on stack            */
	stw     t4,4(t2)

	addi    t0,t0,8                     /* load address of next argument      */
	addi    t2,t2,8                     /* increase stack pointer             */
	addi    t1,t1,-1                    /* subtract 1 argument                */
	mr.     t1,t1
	bgt     L_asm_vm_call_method_stack_copy_loop

L_asm_vm_call_method_stack_copy_done:
	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 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(sp)
	lwz     t2,19*4(sp)
	lwz     t3,20*4(sp)
	lwz     t4,21*4(sp)
	lwz     t5,22*4(sp)
	lwz     t6,23*4(sp)
	lwz     t7,24*4(sp)

	lfd     ft0,26*4(sp)
	lfd     ft1,28*4(sp)
	lfd     ft2,30*4(sp)
	lfd     ft3,32*4(sp)
	lfd     ft4,34*4(sp)
	lfd     ft5,36*4(sp)
#else
	RESTORE_TEMPORARY_REGISTERS(18)   /* the offset has to be even            */
#endif

	lwz     r0,40*4+LA_LR_OFFSET(sp)
	mtlr    r0
	addi    sp,sp,40*4
	blr

asm_vm_call_method_exception_handler:
	mr      a0,itmp1
	bl      builtin_throw_exception
	b       L_asm_vm_call_method_return

asm_vm_call_method_end:
	nop


/********************* 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              */
L_asm_handle_exception_stack_loop:
	mflr    r0
	addi    sp,sp,-(LA_SIZE+((4+6)*4))  /* allocate stack (+4 for darwin)     */
	stw     xptr,LA_SIZE+(4+0)*4(sp)    /* save exception pointer             */
	stw     xpc,LA_SIZE+(4+1)*4(sp)     /* save exception pc                  */
	stw     r0,LA_SIZE+(4+3)*4(sp)      /* save return address                */
	li      itmp3,0
	stw     itmp3,LA_SIZE+(4+4)*4(sp)   /* save maybe-leaf flag (cleared)     */

	mr      a0,r0                       /* pass return address                */
	bl      md_asm_codegen_get_pv_from_pc /* get PV from RA                   */
	stw     v0,LA_SIZE+(4+2)*4(sp)      /* save data segment pointer          */

	lwz     a0,LA_SIZE+(4+0)*4(sp)      /* pass xptr                          */
	lwz     a1,LA_SIZE+(4+1)*4(sp)      /* pass xpc                           */
	lwz     a2,LA_SIZE+(4+2)*4(sp)      /* pass PV (v0 == a0)                 */
	addi    a3,sp,LA_SIZE+((4+6)*4)     /* pass Java SP                       */

	b       L_asm_handle_exception_continue

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

	addi    sp,sp,-(LA_SIZE+(4+6)*4)    /* allocate stack                     */
	stw     xptr,LA_SIZE+(4+0)*4(sp)    /* save xptr                          */
	stw     pv,LA_SIZE+(4+2)*4(sp)      /* save PV                            */
	mflr    r0                          /* save RA                            */
	stw     r0,LA_SIZE+(4+3)*4(sp)
	li      t0,1                        /* set maybe-leaf flag                */
	stw     t0,LA_SIZE+(4+4)*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          */
	addi    a3,sp,LA_SIZE+(ARG_CNT+TMP_CNT)*8+(4+6)*4

L_asm_handle_exception_continue:
	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+0)*4(sp)    /* restore xptr                       */
	lwz     pv,LA_SIZE+(4+2)*4(sp)      /* restore PV                         */
	lwz     r0,LA_SIZE+(4+3)*4(sp)      /* restore RA                         */
	mtlr    r0
	lwz     t0,LA_SIZE+(4+4)*4(sp)      /* get maybe-leaf flag                */
	addi    sp,sp,LA_SIZE+(4+6)*4       /* free stack frame                   */

	mr.     t0,t0
	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+0)*4(sp)    /* restore xptr                       */
	lwz     pv,LA_SIZE+(4+2)*4(sp)      /* restore PV                         */
	lwz     r0,LA_SIZE+(4+3)*4(sp)      /* restore RA                         */
	mtlr    r0
	lwz     t0,LA_SIZE+(4+4)*4(sp)      /* get maybe-leaf flag                */
	addi    sp,sp,LA_SIZE+(4+6)*4       /* free stack frame                   */

	mr.     t0,t0
	beq     L_asm_handle_exception_no_leaf_stack

	addi    sp,sp,(ARG_CNT+TMP_CNT)*8   /* remove maybe-leaf stackframe       */
	li      t0,0                        /* clear the maybe-leaf flag          */

L_asm_handle_exception_no_leaf_stack:
	lwz     t1,FrameSize(pv)            /* get frame size                     */
	add     t1,sp,t1                    /* pointer to save area               */

	lwz     t2,IsLeaf(pv)               /* is leaf procedure                  */
	mr.     t2,t2
	bne     L_asm_handle_exception_no_ra_restore

	lwz     r0,LA_LR_OFFSET(t1)         /* restore ra                         */
	mtlr    r0

L_asm_handle_exception_no_ra_restore:
	mflr    xpc                         /* the new xpc is ra                  */
	mr      t4,xpc                      /* save RA                            */
	lwz     t2,IntSave(pv)              /* t2 = saved int register count      */
	bl      ex_int1
ex_int1:
	mflr    t3                          /* t3 = current pc                    */
#if defined(__DARWIN__)
	addi    t3,t3,lo16(ex_int2-ex_int1)
#else
	addi    t3,t3,(ex_int2-ex_int1)@l
#endif
	slwi    t2,t2,2                     /* t2 = register count * 4            */
	subf    t3,t2,t3                    /* t3 = IntSave - t2                  */
	mtctr   t3
	bctr

	lwz     s0,-10*8(t1)
	lwz     s1,-9*8(t1)
	lwz     s2,-8*8(t1)
	lwz     s3,-7*8(t1)
	lwz     s4,-6*8(t1)
	lwz     s5,-5*8(t1)
	lwz     s6,-4*8(t1)
	lwz     s7,-3*8(t1)
	lwz     s8,-2*8(t1)
	lwz     s9,-1*8(t1)

ex_int2:
	subf    t1,t2,t1                    /* t1 = t1 - register count * 4       */

	lwz     t2,FltSave(pv)
	bl      ex_flt1
ex_flt1:
	mflr    t3
#if defined(__DARWIN__)
	addi    t3,t3,lo16(ex_flt2-ex_flt1)
#else
	addi    t3,t3,(ex_flt2-ex_flt1)@l
#endif
	slwi    t2,t2,2                     /* t2 = register count * 4            */
	subf    t3,t2,t3                    /* t3 = FltSave - t2                  */
	mtctr   t3
	bctr

	lfd     fs0,-10*8(t1)
	lfd     fs1,-9*8(t1)
	lfd     fs2,-8*8(t1)
	lfd     fs3,-7*8(t1)
	lfd     fs4,-6*8(t1)
	lfd     fs5,-5*8(t1)
	lfd     fs6,-4*8(t1)
	lfd     fs7,-3*8(t1)
	lfd     fs8,-2*8(t1)
	lfd     fs9,-1*8(t1)

ex_flt2:
	mtlr    t4                          /* restore RA                         */
	lwz     t1,FrameSize(pv)            /* get frame size                     */
	add     sp,sp,t1                    /* unwind stack                       */
	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_cacheflush:
	add     a1,a0,a1
	rlwinm  a0,a0,0,0,26
	addi    a1,a1,31
	rlwinm  a1,a1,0,0,26
	mr      a2,a0
1:
	cmplw   a0,a1
	bge     0f
	dcbst   0,a0
	addi    a0,a0,32
	b       1b
0:
	sync
1:
	cmplw   a2,a1
	bge     0f
	icbi    0,a2
	addi    a2,a2,32
	b       1b
0:
	sync
	isync
	blr


#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_md_asm_codegen_get_pv_from_pc$stub:
	.indirect_symbol _md_asm_codegen_get_pv_from_pc
	mflr r0
	bcl 20,31,L00$_md_asm_codegen_get_pv_from_pc
L00$_md_asm_codegen_get_pv_from_pc:
	mflr r11
	addis r11,r11,ha16(L_md_asm_codegen_get_pv_from_pc$lazy_ptr - L00$_md_asm_codegen_get_pv_from_pc)
	mtlr r0
	lwzu r12,lo16(L_md_asm_codegen_get_pv_from_pc$lazy_ptr - L00$_md_asm_codegen_get_pv_from_pc)(r11)
	mtctr r12
	bctr
.data
.lazy_symbol_pointer
L_md_asm_codegen_get_pv_from_pc$lazy_ptr:
	.indirect_symbol _md_asm_codegen_get_pv_from_pc
	.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_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

#endif /* defined(__DARWIN__) */


/* disable exec-stacks ********************************************************/

#if defined(__linux__) && 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:
 */
