/* src/vm/jit/arm/asmpart.S - Java-C interface functions for ARM 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 #include "vm/jit/arm/md-asm.h" #include "vm/jit/methodheader.h" .file "asmpart.S" .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_call_jit_compiler .globl asm_handle_exception .globl asm_handle_nat_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. *******************************************************************************/ .align 2 .word 0 /* FltSave */ .word 0 /* IntSave */ .word 0 /* IsLeaf */ .word 0 /* FrameSize */ .word 0 /* CodeinfoPointer */ asm_vm_call_method: asm_vm_call_method_int: asm_vm_call_method_long: /* asm_vm_call_method_float: asm_vm_call_method_double: */ SAVE_SCRATCH_REGISTERS /* save our personal scratch regs */ stmfd sp!, {v1} /* V1 is used to remember SP */ str a0, [sp, #-4]! /* store methods entrypoint */ mov v1, sp /* remember SP */ mov itmp1, a1 /* address of data structure */ mov itmp3, a2 /* stack argument count */ ldr a0, [itmp1], #8 /* load argument registers */ ldr a1, [itmp1], #8 ldr a2, [itmp1], #8 ldr a3, [itmp1], #8 cmp itmp3, #0 /* do we have stack arguments? */ ble asm_calljava_copyfinish /* no -> do not care :-) */ mov itmp2, #0 sub sp, sp, itmp3, lsl #3 /* create stackframe for arguments */ asm_calljava_copyloop: /* reorder stack arguments! */ ldr ip, [itmp1], #4 /* load argument */ str ip, [sp, itmp2] /* store argument on stack */ add itmp2, itmp2, #4 /* next stackslot */ ldr ip, [itmp1], #4 /* load argument */ str ip, [sp, itmp2] /* store argument on stack */ add itmp2, itmp2, #4 /* next stackslot */ subs itmp3, itmp3, #1 /* next argument */ bgt asm_calljava_copyloop asm_calljava_copyfinish: mov mptr, v1 /* set method pointer */ /* REMEMBER: do the method call just like in java! */ ldr ip, [mptr] /* fake virtual function call */ mov lr, pc mov pc, ip fake: sub ip, pc, #(fake - asm_vm_call_method)+8 mov sp, v1 /* restore SP */ add sp, sp, #4 /* free fake address */ ldmfd sp!, {v1} RESTORE_SCRATCH_REGS_AND_RETURN /* return to caller, restore regs */ asm_vm_call_method_exception_handler: mov a0, xptr /* exception pointer is arg1 */ bl builtin_throw_exception /* throw the exception */ mov res1, #0 /* return NULL */ mov res2, #0 /* return NULL */ mov sp, v1 /* restore SP */ add sp, sp, #4 /* free fake address */ ldmfd sp!, {v1} RESTORE_SCRATCH_REGS_AND_RETURN /* return to caller, restore regs */ asm_vm_call_method_float: mov a0,#0x51 b asm_debug asm_vm_call_method_double: mov a0,#0x52 b asm_debug asm_vm_call_method_end: /****************** function asm_call_jit_compiler ***************************** * * * Invokes the compiler for untranslated JavaVM methods. * * What this method does: * * - save args and LR * * - fire up jit_compile (pass methodinfo pointer) * * - try to find out where to write back the new method pointer * * - restore args and LR * * - check for exceptions * * - eventually write back new method pointer * * - call jit code (wich will then return to caller) * * * * These methods can call us: codegen_compilerstub & asm_calljavafunction * * ATTENTION: use REG_ITMP1 to pass methodinfo pointer to me! * * * *******************************************************************************/ #define MYSTACKSIZE (6*4) asm_call_jit_compiler: SAVE_ARGUMENT_REGISTERS /* save our argument registers & LR */ sub sp, sp, #4 /* keep stack 8-byte aligned */ mov a0, itmp1 /* pass methodinfo pointer */ mov a1, mptr /* pass method pointer */ add a2, sp, #MYSTACKSIZE /* pass Java sp */ mov a3, lr /* pass Java RA (correct for leafs) */ bl jit_asm_compile mov itmp1, res1 /* save pointer to new jit-code */ tst itmp1,itmp1 /* check for exeption */ beq L_asm_call_jit_compiler_exception add sp, sp, #4 /* keep stack 8-byte aligned */ RESTORE_ARGUMENT_REGISTERS /* load our argument registers & LR */ mov ip, itmp1 mov pc, ip /* call jit-code */ L_asm_call_jit_compiler_exception: bl exceptions_get_and_clear_exception mov xptr, res1 /* get exception */ add sp, sp, #4 /* keep stack 8-byte aligned */ RESTORE_ARGUMENT_REGISTERS /* load LR */ sub xpc, lr, #4 /* xpc = instruction that called us */ b 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: /*TODO:maybe make a macro out of it!!!*/ SAVE_ARGUMENT_REGISTERS mov a0, lr bl md_asm_codegen_get_pv_from_pc mov ip, res1 RESTORE_ARGUMENT_REGISTERS /* fall through */ asm_handle_exception: stmfd sp!, {r0 - r3} /* save possible used registers */ mov itmp3, #1 /* set maybe-leaf flag */ mov a3, #(4*4) /* prepare a3 for handle_exception */ asm_handle_exception_loop: stmfd sp!, {ip,lr} /* call exception helper here! */ mov a0, xptr /* pass exception pointer */ mov a1, xpc /* pass exception pointer */ mov a2, ip /* pass data segment pointer */ add a3, sp, a3 /* calculate Java sp into a3... */ add a3, a3, #(2*4) bl exceptions_handle_exception ldmfd sp!, {ip,lr} tst a0, a0 beq asm_handle_exception_not_catched mov xpc, a0 /* move handlerpc into xpc */ tst itmp3,itmp3 /* if this is a lead method ... */ ldmnefd sp!, {r0 - r3} /* restore argument registers */ mov pc, xpc /* jump to handler */ asm_handle_exception_not_catched: tst itmp3,itmp3 /* if this is a lead method ... */ addne sp, sp, #(4*4) /* remove maybe-leaf stackframe */ movne itmp3, #0 /* remove maybe-leaf flag */ ldr a2, [ip, #FrameSize] /* t2 = frame size */ add a0, sp, a2 /* t0 = pointer to save area */ ldr a1, [ip, #IsLeaf] /* t1 = is leaf procedure */ tst a1, a1 /* if is leaf ... */ ldreq lr, [a0, #-4]! /* ... restore RA */ mov xpc, lr /* the new xpc is RA */ ldr a1, [ip, #IntSave] /* t1 = saved int register count */ rsb a1, a1, #5 /* t1 = count of unsaved registers */ sub a1, a1, #1 add pc, pc, a1, lsl #2 /* do not load unsaved registers */ ldr v1, [a0, #-20] /* ... but restore the other ones */ ldr v2, [a0, #-16] ldr v3, [a0, #-12] ldr v4, [a0, #- 8] ldr v5, [a0, #- 4] add sp, sp, a2 /* unwind stack (using t2) */ mov a3, #0 /* prepare a3 for handle_exception */ /*TODO:maybe make a macro out of it!!!*/ SAVE_ARGUMENT_REGISTERS mov a0, lr bl md_asm_codegen_get_pv_from_pc mov ip, res1 RESTORE_ARGUMENT_REGISTERS b asm_handle_exception_loop /* asm_abstractmethoderror ***************************************************** Creates and throws an AbstractMethodError. *******************************************************************************/ asm_abstractmethoderror: stmfd sp!, {lr} /* save return address */ add a0, sp, #(1*4) /* pass java sp */ mov a1, lr /* pass exception address */ bl exceptions_asm_new_abstractmethoderror ldmfd sp!, {lr} /* restore return address */ mov xptr, res1 /* get exception pointer */ sub xpc, lr, #4 /* exception address is ra - 4 */ b asm_handle_nat_exception /********************* function asm_cacheflush ********************************* * * * TODO: document me * * * * void asm_cacheflush(void *p, s4 size); * * * *******************************************************************************/ L___ARM_NR_cacheflush: .align 2 .word __ARM_NR_cacheflush asm_cacheflush: add a1, a0, a1 mov a2, #0 #if defined(__ARM_EABI__) /* According to EABI, the syscall number should be passed via R7, see "http://wiki.debian.org/ArmEabiPort" for additional details. */ stmfd sp!, {r7} ldr r7, L___ARM_NR_cacheflush swi 0x0 ldmfd sp!, {r7} #else # if 0 /* TWISTI: required on iyonix, maybe a linux-2.4 bug */ mov a0, #0x0 mov a1, #0xff000000 # endif swi __ARM_NR_cacheflush #endif mov pc, lr /* 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: */