/* src/vm/jit/mips/asmpart.S - Java-C interface functions for MIPS

   Copyright (C) 1996-2005, 2006, 2007, 2008
   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO

   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.

*/


#include "config.h"

#include "vm/jit/mips/md-abi.h"
#include "vm/jit/mips/md-asm.h"

#include "vm/jit/abi-asm.h"
#include "vm/jit/methodheader.h"


	.text
	.set    noat


/* 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_exception
	.globl asm_handle_nat_exception

	.globl asm_abstractmethoderror


/* 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.                                                  *
*                                                                              *
*   A possibly throwed exception will be returned to the caller as function    *
*   return value, so the java method cannot return a fucntion value (this      *
*   function usually calls 'main' and '<clinit>' which do not return a         *
*   function value).                                                           *
*                                                                              *
*   C-prototype:                                                               *
*    javaobject_header *asm_calljavafunction (methodinfo *m,                   *
*         void *arg1, void *arg2, void *arg3, void *arg4);                     *
*                                                                              *
*******************************************************************************/

	.ent    asm_vm_call_method

	.align  3

#if SIZEOF_VOID_P == 8

	.word   0                           /* fltsave                            */
	.word   0                           /* intsave                            */
	.word   0                           /* isleaf                             */
	.word   0                           /* frame size                         */
	.dword  0                           /* codeinfo pointer                   */

#else /* SIZEOF_VOID_P == 8 */

	.word   0                           /* fltsave                            */
	.word   0                           /* intsave                            */
	.word   0                           /* isleaf                             */
	.word   0                           /* frame size                         */
	.word   0                           /* method pointer (pointer to name)   */

#endif /* SIZEOF_VOID_P == 8 */

asm_vm_call_method:
asm_vm_call_method_int:
asm_vm_call_method_long:
asm_vm_call_method_float:
asm_vm_call_method_double:
	.set    noreorder                 /* XXX we need to recompute pv          */

	aaddiu  sp,sp,-12*8               /* allocate stack space (only 11 needed)*/
	ast     ra,0*8(sp)                /* save return address                  */

	bal     L_asm_vm_call_method_compute_pv
	ast     pv,1*8(sp)                /* procedure vector                     */
L_asm_vm_call_method_compute_pv:
	aaddiu  pv,ra,-4*4

	ast     s0,3*8(sp)                /* save callee saved register           */
	ast     a0,4*8(sp)                /* save method PV                       */

#if SIZEOF_VOID_P == 8
	s.d     fss0,5*8(sp)              /* save non JavaABI saved flt registers */
	s.d     fss1,6*8(sp)
	s.d     fss2,7*8(sp)
	s.d     fss3,8*8(sp)
	s.d     fss4,9*8(sp)
	s.d     fss5,10*8(sp)
#endif

	move    t0,a1                     /* address of data structure            */
	move    t1,a2                     /* stack argument count                 */
	move    s0,sp                     /* save stack pointer                   */

#if SIZEOF_VOID_P == 8

	ld      a0,0*8(t0)
	ld      a1,1*8(t0)
	ld      a2,2*8(t0)
	ld      a3,3*8(t0)
	ld      a4,4*8(t0)
	ld      a5,5*8(t0)
	ld      a6,6*8(t0)
	ld      a7,7*8(t0)

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

#else /* SIZEOF_VOID_P == 8 */

# if WORDS_BIGENDIAN == 1
	lw      a0,0*8+4(t0)
	lw      a1,1*8+4(t0)
	lw      a2,2*8+4(t0)
	lw      a3,3*8+4(t0)
# else
	lw      a0,0*8(t0)
	lw      a1,1*8(t0)
	lw      a2,2*8(t0)
	lw      a3,3*8(t0)
# endif

# if !defined(ENABLE_SOFT_FLOAT)
	l.d     fa0,4*8(t0)
	l.d     fa1,5*8(t0)
# endif

#endif /* SIZEOF_VOID_P == 8 */

	beqz    t1,L_asm_vm_call_method_stack_copy_done
	nop

	sll     t2,t1,3                   /* calculate stackframe size (* 8)      */
	asubu   sp,sp,t2                  /* create stackframe                    */
	move    t2,sp                     /* temporary stack pointer              */

L_asm_vm_call_method_stack_copy_loop:
#if SIZEOF_VOID_P == 8
	ld      t3,16*8(t0)               /* load argument                        */
	sd      t3,0(t2)                  /* store argument on stack              */
#else
# if !defined(ENABLE_SOFT_FLOAT)
	lw      t3,6*8+0(t0)              /* load argument                        */
	lw      t4,6*8+4(t0)
	sw      t3,0(t2)                  /* store argument on stack              */
	sw      t4,4(t2)
# else
#  error implement me
# endif
#endif

	aaddi   t1,t1,-1                  /* subtract 1 argument                  */
	aaddi   t0,t0,8                   /* load address of next argument        */
	aaddi   t2,t2,8                   /* increase stack pointer               */

	bgtz    t1,L_asm_vm_call_method_stack_copy_loop
	nop

L_asm_vm_call_method_stack_copy_done:
	ala     mptr,4*8(s0)              /* get address of PV                    */
	ald     pv,0*8(mptr)              /* load PV                              */
	jalr    pv
	nop
L_asm_vm_call_method_recompute_pv:
#if SIZEOF_VOID_P == 8
	aaddiu  pv,ra,-76*4               /* recompute procedure vector           */
#else
	aaddiu  pv,ra,(asm_vm_call_method - L_asm_vm_call_method_recompute_pv)
#endif

	.set    reorder                   /* XXX we need to recompute pv          */

calljava_return2:
	move    sp,s0                     /* restore stack pointer                */

	ald     ra,0*8(sp)                /* restore return address               */
	ald     pv,1*8(sp)                /* restore procedure vector             */
	ald     s0,3*8(sp)

#if SIZEOF_VOID_P == 8
	l.d     fss0,5*8(sp)              /* restore non JavaABI saved flt regs   */
	l.d     fss1,6*8(sp)
	l.d     fss2,7*8(sp)
	l.d     fss3,8*8(sp)
	l.d     fss4,9*8(sp)
	l.d     fss5,10*8(sp)
#endif

	aaddiu  sp,sp,12*8                /* free stack space                     */
	j       ra                        /* return                               */

asm_vm_call_method_exception_handler:
	move    sp,s0                     /* restore stack pointer                */
#if SIZEOF_VOID_P == 4
	aaddiu  sp,sp,-4*4                /* reserve space for 1 argument         */
#endif

	move    a0,itmp1                  
	jal     builtin_throw_exception
#if SIZEOF_VOID_P == 4
	aaddiu  sp,sp,4*4
#endif
asm_vm_call_method_end:
	b       calljava_return2

	.end    asm_vm_call_method


/* 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.

*******************************************************************************/

	.ent    asm_handle_nat_exception

asm_handle_nat_exception:
L_asm_handle_exception_stack_loop:
#if SIZEOF_VOID_P == 8
	aaddiu  sp,sp,-6*8                  /* keep stack 16-byte aligned         */
	ast     xptr,0*8(sp)                /* save exception pointer             */
	ast     xpc,1*8(sp)                 /* save exception pc                  */
	ast     ra,3*8(sp)                  /* save RA                            */
	ast     zero,4*8(sp)                /* save maybe-leaf flag (cleared)     */
#else
	aaddiu  sp,sp,-(4*4+6*8)            /* allocate stack                     */
	ast     xptr,4*4+0*8(sp)            /* save exception pointer             */
	ast     xpc,4*4+1*8(sp)             /* save exception pc                  */
	ast     ra,4*4+3*8(sp)              /* save return address                */
	ast     zero,4*4+4*8(sp)            /* save maybe-leaf flag (cleared)     */
#endif

	move    a0,ra                       /* pass RA                            */
	jal     md_asm_codegen_get_pv_from_pc /* get PV from RA                   */

#if SIZEOF_VOID_P == 8
	ast     v0,2*8(sp)                  /* save PV                            */

	ald     a0,0*8(sp)                  /* pass xptr                          */
	ald     a1,1*8(sp)                  /* pass xpc                           */
	move    a2,v0                       /* pass PV                            */
	aaddiu  a3,sp,6*8                   /* pass Java SP                       */
#else
	ast     v0,4*4+2*8(sp)              /* save data segment pointer          */

	ald     a0,4*4+0*8(sp)              /* pass exception pointer             */
	ald     a1,4*4+1*8(sp)              /* pass exception pc                  */
	move    a2,v0                       /* pass data segment pointer          */
	aaddiu  a3,sp,(4*4+6*8)             /* pass Java stack pointer            */
#endif

	b       L_asm_handle_exception_continue

	.aent    asm_handle_exception

asm_handle_exception:
	aaddiu  sp,sp,-(ARG_CNT+TMP_CNT)*8  /* create maybe-leaf stackframe       */

	SAVE_ARGUMENT_REGISTERS(0)          /* we save arg and temp registers in  */
	SAVE_TEMPORARY_REGISTERS(ARG_CNT)   /* case this is a leaf method         */

#if SIZEOF_VOID_P == 8
	aaddiu  sp,sp,-6*8                  /* allocate stack                     */
	ast     xptr,0*8(sp)                /* save exception pointer             */
	ast     pv,2*8(sp)                  /* save PV                            */
	ast     ra,3*8(sp)                  /* save RA                            */
	addu    t0,zero,1                   /* set maybe-leaf flag                */
	ast     t0,4*8(sp)                  /* save maybe-leaf flag               */
#else
	aaddiu  sp,sp,-(4*4+6*8)            /* allocate stack                     */
	ast     xptr,4*4+0*8(sp)            /* save exception pointer             */
	ast     xpc,4*4+1*8(sp)             /* save exception pc                  */
	ast     pv,4*4+2*8(sp)              /* save data segment pointer          */
	ast     ra,4*4+3*8(sp)              /* save return address                */
	addu    t0,zero,1                   /* set maybe-leaf flag                */
	ast     t0,4*4+4*8(sp)              /* save maybe-leaf flag               */
#endif

	move    a0,xptr                     /* pass xptr                          */
	move    a1,xpc                      /* pass xpc                           */
	move    a2,pv                       /* pass PV                            */

#if SIZEOF_VOID_P == 8
	aaddiu  a3,sp,(ARG_CNT+TMP_CNT+6)*8 /* pass Java SP                       */
#else
	aaddiu  a3,sp,4*4+(ARG_CNT+TMP_CNT+6)*8 /* pass Java stack pointer        */
#endif

L_asm_handle_exception_continue:
	jal     exceptions_handle_exception
	
	beqz    v0,L_asm_handle_exception_not_catched

	move    xpc,v0                      /* move handlerpc into xpc            */

#if SIZEOF_VOID_P == 8
	ald     xptr,0*8(sp)                /* restore exception pointer          */
	ald     pv,2*8(sp)                  /* restore PV                         */
	ald     ra,3*8(sp)                  /* restore RA                         */
	ald     t0,4*8(sp)                  /* get maybe-leaf flag                */
	aaddiu  sp,sp,6*8                   /* free stackframe                    */
#else
	ald     xptr,4*4+0*8(sp)            /* restore exception pointer          */
	ald     pv,4*4+2*8(sp)              /* restore data segment pointer       */
	ald     ra,4*4+3*8(sp)              /* restore return address             */
	ald     t0,4*4+4*8(sp)              /* get maybe-leaf flag                */
	aaddiu  sp,sp,4*4+6*8               /* free stackframe                    */
#endif
	
	beqz    t0,L_asm_handle_exception_no_leaf

	RESTORE_ARGUMENT_REGISTERS(0)       /* if this is a leaf method, we have  */
	RESTORE_TEMPORARY_REGISTERS(ARG_CNT)/* to restore arg and temp registers  */
	
	aaddiu  sp,sp,(ARG_CNT+TMP_CNT)*8   /* remove maybe-leaf stackframe       */

L_asm_handle_exception_no_leaf:
	jr      xpc                         /* jump to the handler                */

L_asm_handle_exception_not_catched:
#if SIZEOF_VOID_P == 8
	ald     xptr,0*8(sp)                /* restore xptr                       */
	ald     pv,2*8(sp)                  /* restore PV                         */
	ald     ra,3*8(sp)                  /* restore RA                         */
	ald     t0,4*8(sp)                  /* get maybe-leaf flag                */
	aaddiu  sp,sp,6*8                   /* free stackframe                    */
#else
	ald     xptr,4*4+0*8(sp)            /* restore xptr                       */
	ald     pv,4*4+2*8(sp)              /* restore PV                         */
	ald     ra,4*4+3*8(sp)              /* restore RA                         */
	ald     t0,4*4+4*8(sp)              /* get maybe-leaf flag                */
	aaddiu  sp,sp,4*4+6*8               /* free stackframe                    */
#endif
	
	beqz    t0,L_asm_handle_exception_no_leaf_stack

	aaddiu  sp,sp,(ARG_CNT+TMP_CNT)*8   /* remove maybe-leaf stackframe       */
	move    t0,zero                     /* clear the maybe-leaf flag          */

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

	lw      t2,IsLeaf(pv)               /* is leaf procedure                  */
	bnez    t2,L_asm_handle_exception_no_ra_restore

	ald     ra,-1*8(t1)                 /* restore ra                         */
	aaddiu  t1,t1,-8                    /* t1--                               */

L_asm_handle_exception_no_ra_restore:
	move    xpc,ra                      /* the new xpc is ra                  */
	lw      t2,IntSave(pv)              /* t1 = saved int register count      */
	ala     t3,ex_int2                  /* t3 = current pc                    */
	sll     t2,t2,2                     /* t2 = register count * 4            */
	asubu   t3,t3,t2                    /* t3 = IntSave - 4 * register count  */
	jr      t3                          /* jump to save position              */

	ald     s0,-8*8(t1)
	ald     s1,-7*8(t1)
	ald     s2,-6*8(t1)
	ald     s3,-5*8(t1)
	ald     s4,-4*8(t1)
	ald     s5,-3*8(t1)
	ald     s6,-2*8(t1)
	ald     s7,-1*8(t1)

ex_int2:
	sll     t2,t2,1               /* t2 = register count * 4 * 2              */
	asubu   t1,t1,t2              /* t1 = t0 - 8 * register count             */

	lw      t2,FltSave(pv)        /* t2 = saved flt register count            */
	ala     t3,ex_flt2            /* t3 = current pc                          */
	sll     t2,t2,2               /* t2 = register count * 4                  */
	asubu   t3,t3,t2              /* t3 = ex_int_sav - 4 * register count     */
	jr      t3                          /* jump to save position              */

#if SIZEOF_VOID_P == 8
	l.d     fs0,-4*8(t1)
	l.d     fs1,-3*8(t1)
	l.d     fs2,-2*8(t1)
	l.d     fs3,-1*8(t1)
#else
# if !defined(ENABLE_SOFT_FLOAT)
	l.d     fs0,-6*8(t1)
	l.d     fs1,-5*8(t1)
	l.d     fs2,-4*8(t1)
	l.d     fs3,-3*8(t1)
	l.d     fs4,-2*8(t1)
	l.d     fs5,-1*8(t1)
# endif
#endif

ex_flt2:
	lw      t1,FrameSize(pv)            /* get frame size                     */
	aaddu   sp,sp,t1                    /* unwind stack                       */
	b       L_asm_handle_exception_stack_loop

	.end    asm_handle_nat_exception


/* asm_abstractmethoderror *****************************************************

   Creates and throws an AbstractMethodError.

*******************************************************************************/

	.ent    asm_abstractmethoderror

asm_abstractmethoderror:
	aaddiu  sp,sp,-2*8                  /* create stackframe                  */
	ast     ra,0*8(sp)                  /* save return address                */
	aaddiu  a0,sp,2*8                   /* pass java sp                       */
	move    a1,ra                       /* pass exception address             */
	jal     exceptions_asm_new_abstractmethoderror
	ald     ra,0*8(sp)                  /* restore return address             */
	aaddiu  sp,sp,2*8                   /* remove stackframe                  */

	move    xptr,v0                     /* get exception pointer              */
	aaddiu  xpc,ra,-4                   /* exception address is ra - 4        */
	b       asm_handle_nat_exception

	.end    asm_abstractmethoderror


/* 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:
 */
