blob: f8b2ddc0ba0c881fbb76e54587a4227a0796d7da [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Invoking JNI native method via SH4 ABI.
* This inplementation follows the spec found in following URL.
* http://www.ecos.sourceware.org/docs-1.3.1/ref/gnupro-ref/sh/SH_ch01.html#pgfId-461254
* This version supports SH4A little endian.
*/
.text
.align 4
.type dvmPlatformInvoke, #function
.globl dvmPlatformInvoke
/*
* @param r4 void* pEnv (used as scrach after invoking method)
* @param r5 ClassObject* clazz
* @param r6 int argInfo
* @param r7 int argc
* @param r15[0] const u4 * argv
* @param r15[1] const char * shorty
* @param r15[2] void * func
* @param r15[3] JValue * pReturn
*
* @remark r0,r1 Scratch before invoking method.
* Return value after invoking method.
* @remark r2 shorty pointer
* @remark r3 argv pointer before invoking method.
* pReturn after invoking method.
* @remark r8-11 Don't touch.
* @remark r12 status of r5-7
* @remark r13 status of fr4-11
* @remark r14 Keep stack pointer.
*/
dvmPlatformInvoke:
## save preserved regsiters
mov.l r14, @-r15
mov r15, r14
add #4, r14 /* r14 = original r15 = stack pointer */
mov.l r13, @-r15
mov.l r12, @-r15
sts.l pr, @-r15
# fetch arguments
mov.l @r14, r3 /* argv */
mov.l @(4,r14), r2 /* shorty for argumnets */
mov #1, r0 /* shorty's 1st byte specify ret value type. */
add r0, r2
### initialize local variables
## r12 ... status of r6, and r7
## bit 1 << 0 : if r6 is available, it contains 1.
## bit 1 << 1 : if r7 is available, it contains 1.
## Note : r4 is always used to pass pEnv.
## r5 is always used for clazz or object
mov #3, r12 /* b0000-0111 : r5-7 avialble. */
## r13 ... status of fr4-fr11
## bit 1 << 0 : if fr4 is available, it contains 1.
## bit 1 << 1 : if fr5 is available, it contains 1.
## ...
## bit 1 << 7 : if fr11 is available, it contains 1.
mov #0xFF, r13 /* b1111-1111 : fr4-11 avialble. */
### put arguments
## ... keep pEnv in r4 as is.
## check clazz
mov #0, r0
cmp/eq r0, r5
bf arg_loop /* if r5 has clazz, keep it as is */
mov.l @r3+, r5 /* put object arg in r5 */
## other args
arg_loop:
one_arg_handled:
mov.b @r2+, r0
cmp/eq #0, r0 /* if (*shorty == '\0) */
bf process_one_arg
bra arg_end /* no argument left */
nop
process_one_arg:
## check arg type
cmp/eq #'F', r0
bt jfloat_arg
cmp/eq #'D', r0
bt jdouble_arg
cmp/eq #'J', r0
bt jlong_arg
## other 32bit arg types
mov r12, r0
cmp/eq #0, r0
bt put_32bit_on_stack /* r6-7 not available */
tst #1, r0
bt j32_arg_1
mov.l @r3+, r6 /* put one arg in r6 */
mov #1, r0 /* r6 is not available now. */
not r0, r0
and r0, r12
bra one_arg_handled
nop
j32_arg_1:
tst #2, r0
bt j32_arg_fatal_error
mov.l @r3+, r7 /* put one arg in r7 */
mov #2, r0 /* r7 is not available now. */
not r0, r0
and r0, r12
bra one_arg_handled
nop
j32_arg_fatal_error:
bra j32_arg_fatal_error
nop
jlong_arg:
mov r12, r0
cmp/eq #0, r0
bt put_64bit_on_stack /* r6-7 not available */
and #3, r0
cmp/eq #3, r0
bf put_64bit_on_stack /* consequent two registers not available. */
mov.l @r3+, r6 /* put one arg in r6 and r7 */
mov.l @r3+, r7
mov #3, r0 /* r6 and r7 are not available now. */
not r0, r0
and r0, r12
bra one_arg_handled
nop
# utility routines are placed here make short range jumps available.
put_32bit_on_stack:
mov.l @r3+, r0
mov.l r0, @-r15
bra one_arg_handled
nop
put_64bit_on_stack:
mov.l @r3+, r0
mov.l r0, @-r15 /* Pay attention that the endianness is */
mov.l @r3+, r0 /* once reversed. It is corrected when the */
mov.l r0, @-r15 /* arguments on stack are revesred before */
bra one_arg_handled /* jni call */
nop
jdouble_arg:
mov r13, r0
cmp/eq #0, r0
bt put_64bit_on_stack /* fr4-11 not available */
and #3, r0
cmp/eq #3, r0
bf jdouble_arg_1
fmov.s @r3+, fr5 /* put one arg to drX */
fmov.s @r3+, fr4
mov #3, r0 /* fr4-frX not available now. */
not r0, r0
and r0, r13
bra one_arg_handled
nop
jdouble_arg_1:
mov r13, r0
and #12, r0
cmp/eq #12, r0
bf jdouble_arg_2
fmov.s @r3+, fr7 /* put one arg to drX */
fmov.s @r3+, fr6
mov #15, r0 /* fr4-frX not available now. */
not r0, r0
and r0, r13
bra one_arg_handled
nop
jdouble_arg_2:
mov r13, r0
and #48, r0
cmp/eq #48, r0
bf jdouble_arg_3
fmov.s @r3+, fr9 /* put one arg to drX */
fmov.s @r3+, fr8
mov #63, r0 /* fr4-frX not available now. */
not r0, r0
and r0, r13
bra one_arg_handled
nop
jdouble_arg_3:
mov r13, r0
and #192, r0
cmp/eq #192, r0
bf put_64bit_on_stack
fmov.s @r3+, fr11 /* put one arg to drX */
fmov.s @r3+, fr10
mov #0, r13 /* fr4-fr11 all not available now. */
bra one_arg_handled
nop
jfloat_arg:
mov r13, r0
cmp/eq #0, r0
bt put_32bit_on_stack /* fr4-11 not available */
tst #2, r0
bt jfloat_arg_1
fmov.s @r3+, fr5 /* put one arg to frX */
mov #2, r0 /* frX not available now. */
not r0, r0
and r0, r13
bra one_arg_handled
nop
jfloat_arg_1:
tst #1, r0
bt jfloat_arg_2
fmov.s @r3+, fr4 /* put one arg to frX */
mov #1, r0 /* frX not available now. */
not r0, r0
and r0, r13
bra one_arg_handled
nop
jfloat_arg_2:
tst #8, r0
bt jfloat_arg_3
fmov.s @r3+, fr7 /* put one arg to frX */
mov #8, r0 /* frX not available now. */
not r0, r0
and r0, r13
bra one_arg_handled
nop
jfloat_arg_3:
tst #4, r0
bt jfloat_arg_4
fmov.s @r3+, fr6 /* put one arg to frX */
mov #4, r0 /* frX not available now. */
not r0, r0
and r0, r13
bra one_arg_handled
nop
jfloat_arg_4:
tst #32, r0
bt jfloat_arg_5
fmov.s @r3+, fr9 /* put one arg to frX */
mov #32, r0 /* frX not available now. */
not r0, r0
and r0, r13
bra one_arg_handled
nop
jfloat_arg_5:
tst #16, r0
bt jfloat_arg_6
fmov.s @r3+, fr8 /* put one arg to frX */
mov #16, r0 /* frX not available now. */
not r0, r0
and r0, r13
bra one_arg_handled
nop
jfloat_arg_6:
tst #128, r0
bt jfloat_arg_7
fmov.s @r3+, fr11 /* put one arg to frX */
mov #127, r0 /* frX not available now. */
not r0, r0
and r0, r13
bra one_arg_handled
nop
jfloat_arg_7:
tst #64, r0
bt jfloat_fatal_error
fmov.s @r3+, fr10 /* put one arg to frX */
mov #64, r0 /* frX not available now. */
not r0, r0
and r0, r13
bra one_arg_handled
nop
jfloat_fatal_error:
bra jfloat_fatal_error:
nop
arg_end:
### reverse the variables on stack
mov r14, r12 /* points to first arg on stack */
add #-20, r12
mov r15, r13 /* points to last arg on stack */
arg_rev_loop:
cmp/hs r12, r13 /* When r13 >= r12 (unsigned), 1->T */
bt arg_rev_end
mov.l @r12, r0
mov.l @r13, r1
mov.l r0, @r13
mov.l r1, @r12
add #-4, r12
add #4, r13
bra arg_rev_loop
nop
arg_rev_end:
### invoke the JNI function.
mov.l @(8,r14), r0
jsr @r0
nop
### pass the return value
/*
* r0 and r1 keep return value.
*/
## fetch data
mov.l @(4,r14), r2 /* reload shorty */
mov.b @r2, r2 /* first byte specifyes return value type. */
mov.l @(12,r14), r3 /* pReturn */
## check return value types
mov #'V', r4
cmp/eq r4, r2
bt end
mov #'F', r4
cmp/eq r4, r2
bt jfloat_ret
mov #'D', r4
cmp/eq r4, r2
bt jdouble_ret
mov #'J', r4
cmp/eq r4, r2
bt jlong_ret
## fall-through for other 32 bit java types.
## load return values
j32_ret:
bra end
mov.l r0, @r3 /* delay slot */
jfloat_ret:
bra end
fmov.s fr0, @r3 /* delay slot */
jdouble_ret:
fmov.s fr1, @r3
mov #4, r0
bra end
fmov.s fr0, @(r0,r3) /* delay slot */
jlong_ret:
mov.l r0, @r3
bra end
mov.l r1, @(4,r3) /* delay slot */
end:
## restore preserved registers
mov r14, r15
add #-16, r15
lds.l @r15+, pr
mov.l @r15+, r12
mov.l @r15+, r13
mov.l @r15+, r14
rts /* dvmPlatformInvoke returns void. */
nop