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