Home | History | Annotate | Download | only in arm
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * JNI method invocation.  This is used to call a C/C++ JNI method.  The
     19  * argument list has to be pushed onto the native stack according to
     20  * local calling conventions.
     21  *
     22  * This version supports the "old" ARM ABI.
     23  */
     24 
     25 #include <machine/cpu-features.h>
     26 
     27 #ifndef __ARM_EABI__
     28 
     29 /*
     30 Function prototype:
     31 
     32 void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
     33     const u4* argv, const char* signature, void* func, JValue* pReturn)
     34 
     35 The method we are calling has the form:
     36 
     37   return_type func(JNIEnv* pEnv, ClassObject* clazz, ...)
     38     -or-
     39   return_type func(JNIEnv* pEnv, Object* this, ...)
     40 
     41 We receive a collection of 32-bit values which correspond to arguments from
     42 the interpreter (e.g. float occupies one, double occupies two).  It's up to
     43 us to convert these into local calling conventions.
     44  */
     45 
     46 /*
     47 ARM ABI notes:
     48 
     49 r0-r3 hold first 4 args to a method
     50 r9 is given special treatment in some situations, but not for us
     51 r10 (sl) seems to be generally available
     52 r11 (fp) is used by gcc
     53 r12 (ip) is scratch -- not preserved across method calls
     54 r13 (sp) should be managed carefully in case a signal arrives
     55 r14 (lr) must be preserved
     56 r15 (pc) can be tinkered with directly
     57 
     58 r0 holds returns <= 4 bytes
     59 r0-r1 hold returns of 5-8 bytes, low word in r0
     60 
     61 Stack is "full descending".  Only the arguments that don't fit in the first 4
     62 registers are placed on the stack.  "sp" points at the first stacked argument
     63 (i.e. the 5th arg).
     64 
     65 VFP: single-precision results in s0, double-precision results in d0.
     66 
     67 Happily we don't have to do anything special here -- the args from the
     68 interpreter work directly as C/C++ args on ARM (with the "classic" ABI).
     69 */
     70 
     71     .text
     72     .align  2
     73     .global dvmPlatformInvoke
     74     .type   dvmPlatformInvoke, %function
     75 
     76 /*
     77 On entry:
     78   r0  JNIEnv
     79   r1  clazz (NULL for virtual method calls, non-NULL for static)
     80   r2  arg info (ignored)
     81   r3  argc
     82   [sp]     argv
     83   [sp,#4]  signature (ignored)
     84   [sp,#8]  func
     85   [sp,#12] pReturn
     86 */
     87 dvmPlatformInvoke:
     88     @ Standard gcc stack frame setup.  We don't need to push the original
     89     @ sp or the current pc if "-fomit-frame-pointer" is in use for the
     90     @ rest of the code.  If we don't plan to use a debugger we can speed
     91     @ this up a little.
     92     mov     ip, sp
     93     stmfd   sp!, {r4, r5, r6, fp, ip, lr, pc}
     94     sub     fp, ip, #4          @ set up fp, same way gdb does
     95 
     96     @ We need to push a variable number of arguments onto the stack.
     97     @ Rather than keep a count and pop them off after, we just hold on to
     98     @ the stack pointers.
     99     @
    100     @ In theory we don't need to keep sp -- we can do an ldmdb instead of
    101     @ an ldmia -- but we're doing the gcc frame trick where we push the
    102     @ pc on with stmfd and don't pop it off.
    103     mov     r4, ip
    104     mov     r5, sp
    105 
    106     @ argc is already in a scratch register (r3).  Put argv into one.  Note
    107     @ argv can't go into r0-r3 because we need to use it to load those.
    108     ldr     ip, [r4, #0]        @ ip <-- argv
    109 
    110     @ Is this a static method?
    111     cmp     r1, #0
    112 
    113     @ No: set r1 to *argv++, and set argc--.
    114     @ (r0=pEnv, r1=this)
    115     ldreq   r1, [ip], #4
    116     subeq   r3, r3, #1
    117 
    118     @ While we still have the use of r2/r3, copy excess args from argv
    119     @ to the stack.  We need to push the last item in argv first, and we
    120     @ want the first two items in argv to end up in r2/r3.
    121     subs    r3, r3, #2
    122     ble     .Lno_copy
    123 
    124     @ If there are N args, we want to skip 0 and 1, and push (N-1)..2.  We
    125     @ have N-2 in r3.  If we set argv=argv+1, we can count from N-2 to 1
    126     @ inclusive and get the right set of args.
    127     add     r6, ip, #4
    128 
    129 .Lcopy:
    130     @ *--sp = argv[count]
    131     ldr     r2, [r6, r3, lsl #2]
    132     str     r2, [sp, #-4]!
    133     subs    r3, r3, #1
    134     bne     .Lcopy
    135 
    136 .Lno_copy:
    137     @ Load the last two args.  These are coming out of the interpreted stack,
    138     @ and the VM preserves an overflow region at the bottom, so it should be
    139     @ safe to load two items out of argv even if we're at the end.
    140     ldr     r2, [ip]
    141     ldr     r3, [ip, #4]
    142 
    143     @ Show time.  Tuck the pc into lr and load the pc from the method
    144     @ address supplied by the caller.  The value for "pc" is offset by 8
    145     @ due to instruction prefetching.
    146     @
    147 #ifdef __ARM_HAVE_PC_INTERWORK
    148     mov     lr, pc
    149     ldr     pc, [r4, #8]
    150 #else
    151     ldr     ip, [r4, #8]
    152     blx     ip
    153 #endif
    154 
    155     @ We're back, result is in r0 or (for long/double) r0-r1.
    156     @
    157     @ In theory, we need to use the "return type" arg to figure out what
    158     @ we have and how to return it.  However, unless we have an FPU,
    159     @ all we need to do is copy r0-r1 into the JValue union.
    160     ldr     ip, [r4, #12]
    161     stmia   ip, {r0-r1}
    162 
    163 #ifdef __ARM_HAVE_PC_INTERWORK
    164     @ Restore the registers we saved and return.  Note this remaps stuff,
    165     @ so that "sp" comes from "ip", "pc" comes from "lr", and the "pc"
    166     @ we pushed on evaporates when we restore "sp".
    167     ldmfd   r5, {r4, r5, r6, fp, sp, pc}
    168 #else
    169     ldmfd   r5, {r4, r5, r6, fp, sp, lr}
    170     bx      lr
    171 #endif
    172 
    173 #endif /*__ARM_EABI__*/
    174