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

   Copyright (C) 1996-2005, 2006, 2007, 2008 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.

*/


#include "config.h"

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

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


	.text
	.set    noat
	.set    noreorder


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

	.globl asm_md_init
	.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_calljavafunction (methodinfo *m,                   *
*         void *arg1, void *arg2, void *arg3, void *arg4);                     *
*                                                                              *
*******************************************************************************/

	.ent    asm_vm_call_method

	.align  3

	.long   0                           /* fltsave                            */
	.long   1                           /* intsave                            */
	.long   0                           /* isleaf                             */
	.long   0                           /* frame size                         */
	.quad   0                           /* codeinfo pointer                   */

asm_vm_call_method:
asm_vm_call_method_int:
asm_vm_call_method_long:
asm_vm_call_method_float:
asm_vm_call_method_double:
	ldgp    gp,0(pv)
	lda     sp,-5*8(sp)                 /* allocate stack space               */
	stq     ra,0*8(sp)                  /* save return address                */
	stq     gp,1*8(sp)                  /* save global pointer                */

	stq     s0,3*8(sp)
	stq     a0,4*8(sp)                  /* save method PV                     */

	mov     a1,t0                       /* address of argument array          */
	mov     a2,t1                       /* stack argument count               */
	mov     sp,s0                       /* save stack pointer                 */

	ldq     a0,0*8(t0)
	ldq     a1,1*8(t0)
	ldq     a2,2*8(t0)
	ldq     a3,3*8(t0)
	ldq     a4,4*8(t0)
	ldq     a5,5*8(t0)

	ldt     fa0,6*8(t0)
	ldt     fa1,7*8(t0)
	ldt     fa2,8*8(t0)
	ldt     fa3,9*8(t0)
	ldt     fa4,10*8(t0)
	ldt     fa5,11*8(t0)

	beq     t1,L_asm_vm_call_method_stack_copy_done

	negq    t1,t2                       /* calculate stackframe size (* 8)    */
	s8addq  t2,sp,sp                    /* create stackframe                  */
	mov     sp,t2                       /* temporary stack pointer            */

L_asm_vm_call_method_stack_copy_loop:
	ldq     t3,12*8(t0)                 /* load argument                      */
	stq     t3,0(t2)                    /* store argument on stack            */

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

	bgt     t1,L_asm_vm_call_method_stack_copy_loop

L_asm_vm_call_method_stack_copy_done:
	lda     mptr,4*8(s0)                /* get address of PV                  */
	ldq     pv,0*8(mptr)                /* load PV                            */
	jmp     ra,(pv)
L_asm_vm_call_method_recompute_pv:
	lda     pv,(asm_vm_call_method - L_asm_vm_call_method_recompute_pv)(ra)

L_asm_vm_call_method_recompute_return:
	mov     s0,sp                       /* restore stack pointer              */

	ldq     ra,0*8(sp)                  /* restore RA                         */
	ldq     gp,1*8(sp)                  /* restore global pointer             */
	ldq     s0,3*8(sp)

	lda     sp,5*8(sp)                  /* free stack space                   */
	jmp     zero,(ra)

asm_vm_call_method_exception_handler:
	mov     s0,sp                       /* restore stack pointer              */
	ldq     gp,1*8(sp)                  /* restore global pointer             */
	mov     itmp1,a0
	jsr     ra,builtin_throw_exception

asm_vm_call_method_end:					
	br      L_asm_vm_call_method_recompute_return

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

   ATTENTION: itmp3 == gp!

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

	.ent    asm_handle_nat_exception

asm_handle_nat_exception:
L_asm_handle_nat_exception:       /* required for PIC code                    */
L_asm_handle_exception_stack_loop:
	lda     sp,-6*8(sp)                 /* keep stack 16-byte aligned         */
	stq     xptr,0*8(sp)                /* save xptr                          */
	stq     xpc,1*8(sp)                 /* save xpc                           */
	stq     ra,3*8(sp)                  /* save RA                            */
	stq     zero,4*8(sp)                /* save maybe-leaf flag (cleared)     */

	mov     ra,a0                       /* pass RA                            */

	br      ra,L_asm_handle_exception_load_gp
L_asm_handle_exception_load_gp:
	ldgp    gp,0(ra)                    /* load gp                            */

	jsr     ra,md_asm_codegen_get_pv_from_pc /* get PV from RA                */
	stq     v0,2*8(sp)                  /* save PV                            */

	ldq     a0,0*8(sp)                  /* pass xptr                          */
	ldq     a1,1*8(sp)                  /* pass xpc                           */
	mov     v0,a2                       /* pass PV                            */
	addq    sp,6*8,a3                   /* pass Java SP                       */

	br      L_asm_handle_exception_continue

	.aent    asm_handle_exception

asm_handle_exception:
L_asm_handle_exception:                 /* required for PIC code              */
	lda     sp,-(ARG_CNT+TMP_CNT)*8(sp) /* create maybe-leaf stackframe       */

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

	lda     sp,-6*8(sp)                 /* keep stack 16-byte aligned         */
	stq     xptr,0*8(sp)                /* save xptr                          */
	stq     pv,2*8(sp)                  /* save PV                            */
	stq     ra,3*8(sp)                  /* save RA                            */
	lda     t0,1(zero)                  /* set maybe-leaf flag                */
	stq     t0,4*8(sp)                  /* save maybe-leaf flag               */

	br      ra,L_asm_handle_exception_load_gp_2
L_asm_handle_exception_load_gp_2:
	ldgp    gp,0(ra)                    /* load gp                            */

	mov     xptr,a0                     /* pass xptr                          */
	mov     xpc,a1                      /* pass xpc                           */
	mov     pv,a2                       /* pass PV                            */
	lda     a3,(ARG_CNT+TMP_CNT+6)*8(sp)/* pass Java SP                       */

L_asm_handle_exception_continue:
	jsr     ra,exceptions_handle_exception

	beq     v0,L_asm_handle_exception_not_catched

	mov     v0,xpc                      /* move handlerpc into xpc            */
	ldq     xptr,0*8(sp)                /* restore xptr                       */
	ldq     pv,2*8(sp)                  /* restore PV                         */
	ldq     ra,3*8(sp)                  /* restore RA                         */
	ldq     t0,4*8(sp)                  /* get maybe-leaf flag                */
	lda     sp,6*8(sp)                  /* free stack frame                   */

	beq     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  */
	
	lda     sp,(ARG_CNT+TMP_CNT)*8(sp)  /* remove maybe-leaf stackframe       */

L_asm_handle_exception_no_leaf:
	jmp     zero,(xpc)                  /* jump to the handler                */

L_asm_handle_exception_not_catched:
	ldq     xptr,0*8(sp)                /* restore xptr                       */
	ldq     pv,2*8(sp)                  /* restore PV                         */
	ldq     ra,3*8(sp)                  /* restore RA                         */
	ldq     t0,4*8(sp)                  /* get maybe-leaf flag                */
	lda     sp,6*8(sp)

	beq     t0,L_asm_handle_exception_no_leaf_stack

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

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

	ldl     t2,IsLeaf(pv)               /* is leaf procedure                  */
	bne     t2,L_asm_handle_exception_no_ra_restore

	ldq     ra,-1*8(t1)                 /* restore ra                         */
	subq    t1,8,t1                     /* t1--                               */

L_asm_handle_exception_no_ra_restore:
	mov     ra,xpc                      /* the new xpc is ra                  */
	ldl     t2,IntSave(pv)              /* t2 = saved int register count      */
	br      t3,ex_int1                  /* t3 = current pc                    */
ex_int1:
	lda     t3,(ex_int2 - ex_int1)(t3)
	negl    t2,t2                       /* negate register count              */
	s4addq  t2,t3,t3                    /* t2 = IntSave - register count * 4  */
	jmp     zero,(t3)                   /* jump to save position              */

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

ex_int2:
	s8addq  t2,t1,t1                    /* t1 = t1 - 8 * register count       */

	ldl     t2,FltSave(pv)              /* t2 = saved flt register count      */
	br      t3,ex_flt1                  /* t3 = current pc                    */
ex_flt1:
	lda     t3,(ex_flt2 - ex_flt1)(t3)
	negl    t2,t2                       /* negate register count              */
	s4addq  t2,t3,t3                    /* t2 = FltSave - 4 * register count  */
	jmp     zero,(t3)                   /* jump to save position              */

	ldt     fs0,-8*8(t1)
	ldt     fs1,-7*8(t1)
	ldt     fs2,-6*8(t1)
	ldt     fs3,-5*8(t1)
	ldt     fs4,-4*8(t1)
	ldt     fs5,-3*8(t1)
	ldt     fs6,-2*8(t1)
	ldt     fs7,-1*8(t1)

ex_flt2:
	ldl     t1,FrameSize(pv)            /* get frame size                     */
	addq    sp,t1,sp                    /* unwind stack                       */
	br      L_asm_handle_exception_stack_loop

	.end    asm_handle_nat_exception


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

   Creates and throws an AbstractMethodError.

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

	.ent    asm_abstractmethoderror

asm_abstractmethoderror:
	subq    sp,2*8,sp                   /* create stackframe                  */
	stq     ra,0*8(sp)                  /* save return address                */
	addq    sp,2*8,a0                   /* pass java sp                       */
	mov     ra,a1                       /* pass exception address             */
	jsr     ra,exceptions_asm_new_abstractmethoderror
	ldq     ra,0*8(sp)                  /* restore return address             */
	addq    sp,2*8,sp                   /* remove stackframe                  */

	mov     v0,xptr                     /* get exception pointer              */
	subq    ra,4,xpc                    /* exception address is ra - 4        */
	br      L_asm_handle_nat_exception

	.end    asm_abstractmethoderror


/* asm_md_init *****************************************************************

   Initialize machine dependent stuff.

   Determines if the byte support instruction set (21164a and higher)
   is available.

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

	.ent    asm_md_init

asm_md_init:
	.long   0x47e03c20                  /* amask   1,v0                       */
	jmp     zero,(ra)                   /* return                             */

	.end    asm_md_init


/* asm_cacheflush **************************************************************

   XXX

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

	.ent    asm_cacheflush

asm_cacheflush:
	call_pal PAL_imb              /* synchronize instruction cache            */
	jmp     zero,(ra)

	.end    asm_cacheflush


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