diff options
| author | Raghu Gandham <raghu@mips.com> | 2012-05-02 14:27:16 -0700 |
|---|---|---|
| committer | Raghu Gandham <raghu@mips.com> | 2012-05-02 14:27:16 -0700 |
| commit | a8b91c52fd8a90b784835dfe1f8898035266c4dd (patch) | |
| tree | 8a9bb58ee3b78c10cf88a3bac21b7f96d75cd1f7 /vm/arch | |
| parent | a14639df65cc0aefafcddda5aae8b591204e45f9 (diff) | |
| download | android_dalvik-a8b91c52fd8a90b784835dfe1f8898035266c4dd.tar.gz android_dalvik-a8b91c52fd8a90b784835dfe1f8898035266c4dd.tar.bz2 android_dalvik-a8b91c52fd8a90b784835dfe1f8898035266c4dd.zip | |
[MIPS] Dalvik fast interpreter support and JIT implementation
Change-Id: I9bb4f6875b7061d3ffaee73f204026cb8ba3ed39
Signed-off-by: Raghu Gandham <raghu@mips.com>
Signed-off-by: Chris Dearman <chris@mips.com>
Signed-off-by: Douglas Leung <douglas@mips.com>
Signed-off-by: Don Padgett <don@mips.com>
Diffstat (limited to 'vm/arch')
| -rw-r--r-- | vm/arch/generic/Call.cpp | 8 | ||||
| -rw-r--r-- | vm/arch/mips/CallO32.S | 282 | ||||
| -rw-r--r-- | vm/arch/mips/HintsO32.cpp | 116 |
3 files changed, 406 insertions, 0 deletions
diff --git a/vm/arch/generic/Call.cpp b/vm/arch/generic/Call.cpp index c23e7c823..28783cb4a 100644 --- a/vm/arch/generic/Call.cpp +++ b/vm/arch/generic/Call.cpp @@ -47,6 +47,14 @@ static ffi_type* getFfiType(char sigType) } } +/* We will call this generic function if there are no hints */ +#ifdef __mips__ +#define dvmPlatformInvoke dvmPlatformInvokeFFI + +extern "C" void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, + int argc, const u4* argv, const char* signature, void* func, JValue* pResult); +#endif + /* * Call "func" with the specified arguments. * diff --git a/vm/arch/mips/CallO32.S b/vm/arch/mips/CallO32.S new file mode 100644 index 000000000..e436d1e06 --- /dev/null +++ b/vm/arch/mips/CallO32.S @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2008 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. + */ + +/* + * JNI method invocation. This is used to call a C/C++ JNI method. The + * argument list has to be pushed onto the native stack according to + * local calling conventions. + * + * This version supports the MIPS O32 ABI. + */ + +/* +Function prototype: + +void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc, + const u4* argv, const char* signature, void* func, JValue* pReturn) + +The method we are calling has the form: + + return_type func(JNIEnv* pEnv, ClassObject* clazz, ...) + -or- + return_type func(JNIEnv* pEnv, Object* this, ...) + +We receive a collection of 32-bit values which correspond to arguments from +the interpreter (e.g. float occupies one, double occupies two). It's up to +us to convert these into local calling conventions. + +Please notice that argc in dvmPlatformInvoke does NOT include pEnv and clazz/this. +*/ + + .text + .align 2 + .globl dvmPlatformInvoke + .ent dvmPlatformInvoke +/* + * On entry: + * a0 JNIEnv (can be left alone) + * a1 clazz (NULL for virtual method calls, non-NULL for static) + * a2 argInfo + * a3 argc (number of 32-bit values in argv) + * MIPS reservers 16 bytes on stack even if the first 4 args are passed by + * reg a0-a3. That's different from ARM. + * [sp + 16] argv + * [sp + 20] short signature + * [sp + 24] func + * [sp + 28] pReturn + * + * For a virtual method call, the "this" reference is in argv[0]. + * + * argInfo (32-bit int) layout: + * SRRRLLLL FFFFFFFF FFFFFFFF FFFFFFFF + * + * S - if set, do things the hard way (scan the signature) + * R - return type enumeration, really only important for hardware FP + * L - number of double-words (64 bits!) of storage required on stack (0-30 words) + * F - pad flag -- if set, write a pad word to the stack + * + * With this arrangement we can efficiently push up to 24 words of arguments + * onto the stack. Anything requiring more than that -- which should happen + * rarely to never -- can do the slow signature scan. + * + * (We could pack the Fs more efficiently -- we know we never push two pads + * in a row, and the first word can never be a pad -- but there's really + * no need for it.) + * + * NOTE: if the called function has more than 4 words of arguments, gdb + * will not be able to unwind the stack past this method. The only way + * around this is to convince gdb to respect an explicit frame pointer. + */ + + /* Stack: + * High + * ____________ + * |__28______| pReturn + * |__24______| func + * |__20______| short signature + * |__16______| argv + * |__12______| reserved (a3: argc) + * |__8_______| reserved (a2: arg) + * |__4_______| reserved (a1: clazz) + *__sp on entry_->_|__0_______|_reserved (a0: JNIenv) + * |__________| saved ra + * |__________| saved fp + * |__________| saved s0 + * |__________| spare + * |__________| saved s2 + *"framepointer"->_|__________| pad for 8 bytes aligned + * |__________| other argv or pad + * |__________| other argv or pad + * |__________| other argv or pad + * |__________| other argv or pad + * |__________| other argv or pad + * |__________| other argv or pad + * |__________| reserved for a3 + * |__________| reserved for a2 + * |__________| reserved for a1 + *_____new sp___-> |__________| reserved for a0 + * (new sp: sp when call native method) + */ + + /* Register usage: + * + * s0: pReturn + * s2: Return type + * These registers should be saved to and restored from stack. + * + * t0: argv + * t9: func + * These registers do not need to be saved. + * + * We put the stack size into register s1 because we can not know the size + * of stack at the beginning. This size can be calculated with the help + * of hints in jniarginfo. + * + */ + +dvmPlatformInvoke: + .set noreorder + .cpload $t9 + .set reorder + + /* Do we have arg padding flags in "argInfo"? Check bit 31 */ + bltz $a2,.Lno_arginfo + + /* Fast path. We have hints. */ + /* save fp and ra to stack */ +#define FSIZE 24 + subu $sp,FSIZE + sw $ra,20($sp) + sw $fp,16($sp) + sw $s0,12($sp) + sw $s2,4($sp) + move $fp,$sp + + lw $t0,FSIZE+16($sp) /* t0 <- argv */ + lw $t9,FSIZE+24($sp) /* t9 <- func */ + lw $s0,FSIZE+28($sp) /* s0 <- pReturn */ + + /* Is the method static? */ + bnez $a1,1f + /* Not static: a1 <- *argv++ ("this"), argc-- */ + lw $a1,($t0) + addiu $t0,4 + addiu $a3,-1 +1: + /* expand the stack for args */ + srl $s2,$a2,28 /* s2 <- returnType */ + srl $t1,$a2,21 + andi $t1,0x78 /* t1 <- stackSize in bytes */ + + addiu $t1,16 /* include space for a0/a1/a2/a3 */ + subu $sp,$t1 + addiu $t1,$sp,8 + + /* + * t0 :argv + * t1 :sp+8(first arg position in stack except pEnv and clazz/this) + * a2 :argInfo + * a3 :argc + * sp :new stack bottom + */ + + /* first two args or one args and pad */ + blez $a3,.Largs_done + lw $t2,($t0) + addiu $t0,4 + addiu $a3,-1 + sw $t2,($t1) + addiu $t1,4 + srl $a2,1 + blez $a3,.Largs_done + + andi $t3,$a2,0x1 /* the second position is a pad? */ + bnez $t3,.Lpad0 + + lw $t2,($t0) + addiu $t0,4 + addiu $a3,-1 + sw $t2,($t1) +.Lpad0: + addiu $t1,4 + srl $a2,1 + blez $a3,.Largs_done + +.Lloop1: + /* copy other args + * $fp: sp top for args + * $t1: sp for next arg + */ + beq $t1,$fp,.Largs_done + andi $t3,$a2,0x1 + srl $a2,1 + bnez $t3,.Lpad + lw $t2,($t0) + addiu $t0,4 + sw $t2,($t1) +.Lpad: + addiu $t1,4 + b .Lloop1 + +.Largs_done: + + /* + * We have copied args into stacks. Then copy argv[0]/argv[1] into + * reg a2/a3. You may find that if argv[0] is 32 bits and argv[1] + * is 64 bits, then we do not need to set reg a3 since it is a pad. + * However, copy a3 from argv is harmless. We do not need to set + * a0(pEnv)/a1(clazz/this) since they are already there. + */ + + /* + * sp: new stack + * s0: pReturn + * s2: Return type + * + */ + lw $a2,8($sp) + lw $a3,12($sp) + + /* Linux/PIC needs $t9 points to function address. + * call the function + */ + jalr $t9 + + /* function call return */ + /* 1. check the return type + * 2. if the return type is not DALVIK_JNI_RETURN_VOID then copy v0/v1 + * to pReturn + */ + beqz $s2,.Lend /* don't set result if return type is void */ + +#ifdef __mips_hard_float + mfc1 $t0,$f0 /* Get float ($f0) or double ($f1$f0) result */ + mfc1 $t1,$f1 + sltiu $t2,$s2,3 /* set t2 if return type is float or double */ +#ifdef HAVE_LITTLE_ENDIAN + /* Note: for little endian, the double result is in $v1:$v0 and float result is in $v0 */ + movn $v0,$t0,$t2 /* If the result type is float or double overwrite $v1/$v0 */ + movn $v1,$t1,$t2 +#else + /* Note: for big endian, the double result is in $v0:$v1 and float result is in $v0 */ + movn $v1,$t0,$t2 /* If the result type is float or double overwrite $v0/$v1 */ + movn $v0,$t1,$t2 + sltiu $t3,$s2,2 /* set t3 if return type is float */ + movn $v0,$t0,$t3 /* If the result type is float overwrite $v0 */ +#endif +#endif + + /* Store the result */ + sw $v0,0($s0) + sw $v1,4($s0) + +.Lend: + /* restore saved registers */ + move $sp,$fp + lw $ra,20($sp) + lw $fp,16($sp) + lw $s0,12($sp) + lw $s2,4($sp) + addiu $sp,FSIZE + jr $ra + +/* Slow path - just tail call the generic routine */ +.Lno_arginfo: + + la $t9,dvmPlatformInvokeFFI + j $t9 + +.end dvmPlatformInvoke diff --git a/vm/arch/mips/HintsO32.cpp b/vm/arch/mips/HintsO32.cpp new file mode 100644 index 000000000..77fdfd461 --- /dev/null +++ b/vm/arch/mips/HintsO32.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2008 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. + */ + +/* + * JNI method invocation. This is used to call a C/C++ JNI method. The + * argument list has to be pushed onto the native stack according to + * local calling conventions. + * + * This version supports the MIPS O32 ABI. + */ + +/* TODO: this is candidate for consolidation of similar code from ARM. */ + +#include "Dalvik.h" +#include "libdex/DexClass.h" + +#include <stdlib.h> +#include <stddef.h> +#include <sys/stat.h> + + +/* + * The class loader will associate with each method a 32-bit info word + * (jniArgInfo) to support JNI calls. The high order 4 bits of this word + * are the same for all targets, while the lower 28 are used for hints to + * allow accelerated JNI bridge transfers. + * + * jniArgInfo (32-bit int) layout: + * + * SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH + * + * S - if set, ignore the hints and do things the hard way (scan signature) + * R - return-type enumeration + * H - target-specific hints (see below for details) + * + * This function produces mips-specific hints - specifically a description + * of padding required to keep all 64-bit parameters properly aligned. + * + * MIPS JNI hint format(Same as ARM) + * + * LLLL FFFFFFFF FFFFFFFF FFFFFFFF + * + * L - number of double-words of storage required on the stack (0-30 words) + * F - pad flag -- if set, the stack increases 8 bytes, else the stack increases 4 bytes + * after copying 32 bits args into stack. (little different from ARM) + * + * If there are too many arguments to construct valid hints, this function will + * return a result with the S bit set. + */ +u4 dvmPlatformInvokeHints(const DexProto* proto) +{ + + const char* sig = dexProtoGetShorty(proto); + int padFlags, jniHints; + char sigByte; + int stackOffset, padMask, hints; + + stackOffset = padFlags = 0; + padMask = 0x00000001; + + /* Skip past the return type */ + sig++; + + while (true) { + sigByte = *(sig++); + + if (sigByte == '\0') + break; + + if (sigByte == 'D' || sigByte == 'J') { + if ((stackOffset & 1) != 0) { + padFlags |= padMask; + stackOffset++; + padMask <<= 1; + } + stackOffset += 2; + padMask <<= 2; + } else { + stackOffset++; + padMask <<= 1; + } + } + + jniHints = 0; + + if (stackOffset > DALVIK_JNI_COUNT_SHIFT) { + /* too big for "fast" version */ + jniHints = DALVIK_JNI_NO_ARG_INFO; + } else { + assert((padFlags & (0xffffffff << DALVIK_JNI_COUNT_SHIFT)) == 0); + /* + * StackOffset includes the space for a2/a3. However we have reserved + * 16 bytes on stack in CallO32.S, so we should subtract 2 from stackOffset. + */ + stackOffset -= 2; + if (stackOffset < 0) + stackOffset = 0; + jniHints |= ((stackOffset+1) / 2) << DALVIK_JNI_COUNT_SHIFT; + jniHints |= padFlags; + } + + return jniHints; +} |
