--- /dev/null
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include "Dalvik.h"
+
+#ifndef _DALVIK_VM_COMPILER_CODEGEN_ARM_CALLOUT_HELPER_H
+#define _DALVIK_VM_COMPILER_CODEGEN_ARM_CALLOUT_HELPER_H
+
+/*
+ * Declare/comment prototypes of all native callout functions invoked by the
+ * JIT'ed code here and use the LOAD_FUNC_ADDR macro to load the address into
+ * a register. In this way we have a centralized place to find out all native
+ * helper functions and we can grep for LOAD_FUNC_ADDR to find out all the
+ * callsites.
+ */
+
+/* Load a statically compiled function address as a constant */
+#define LOAD_FUNC_ADDR(cUnit, reg, addr) loadConstant(cUnit, reg, addr)
+
+/* Conversions */
+float __aeabi_i2f(int op1); // OP_INT_TO_FLOAT
+int __aeabi_f2iz(float op1); // OP_FLOAT_TO_INT
+float __aeabi_d2f(double op1); // OP_DOUBLE_TO_FLOAT
+double __aeabi_f2d(float op1); // OP_FLOAT_TO_DOUBLE
+double __aeabi_i2d(int op1); // OP_INT_TO_DOUBLE
+int __aeabi_d2iz(double op1); // OP_DOUBLE_TO_INT
+float __aeabi_l2f(long op1); // OP_LONG_TO_FLOAT
+double __aeabi_l2d(long op1); // OP_LONG_TO_DOUBLE
+s8 dvmJitf2l(float op1); // OP_FLOAT_TO_LONG
+s8 dvmJitd2l(double op1); // OP_DOUBLE_TO_LONG
+
+/* Single-precision FP arithmetics */
+float __aeabi_fadd(float a, float b); // OP_ADD_FLOAT[_2ADDR]
+float __aeabi_fsub(float a, float b); // OP_SUB_FLOAT[_2ADDR]
+float __aeabi_fdiv(float a, float b); // OP_DIV_FLOAT[_2ADDR]
+float __aeabi_fmul(float a, float b); // OP_MUL_FLOAT[_2ADDR]
+float fmodf(float a, float b); // OP_REM_FLOAT[_2ADDR]
+
+/* Double-precision FP arithmetics */
+double __aeabi_dadd(double a, double b); // OP_ADD_DOUBLE[_2ADDR]
+double __aeabi_dsub(double a, double b); // OP_SUB_DOUBLE[_2ADDR]
+double __aeabi_ddiv(double a, double b); // OP_DIV_DOUBLE[_2ADDR]
+double __aeabi_dmul(double a, double b); // OP_MUL_DOUBLE[_2ADDR]
+double fmod(double a, double b); // OP_REM_DOUBLE[_2ADDR]
+
+/* Integer arithmetics */
+int __aeabi_idivmod(int op1, int op2); // OP_REM_INT[_2ADDR|_LIT8|_LIT16]
+int __aeabi_idiv(int op1, int op2); // OP_DIV_INT[_2ADDR|_LIT8|_LIT16]
+
+/* Long long arithmetics - OP_REM_LONG[_2ADDR] & OP_DIV_LONG[_2ADDR] */
+long long __aeabi_ldivmod(long long op1, long long op2);
+
+/* Originally declared in Sync.h */
+bool dvmUnlockObject(struct Thread* self, struct Object* obj); //OP_MONITOR_EXIT
+
+/* Originally declared in oo/TypeCheck.h */
+bool dvmCanPutArrayElement(const ClassObject* elemClass, // OP_APUT_OBJECT
+ const ClassObject* arrayClass);
+int dvmInstanceofNonTrivial(const ClassObject* instance, // OP_CHECK_CAST &&
+ const ClassObject* clazz); // OP_INSTANCE_OF
+
+/* Originally declared in oo/Array.h */
+ArrayObject* dvmAllocArrayByClass(ClassObject* arrayClass, // OP_NEW_ARRAY
+ size_t length, int allocFlags);
+
+/* Originally declared in interp/InterpDefs.h */
+bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject,// OP_FILL_ARRAY_DATA
+ const u2* arrayData);
+
+/* Switch dispatch offset calculation for OP_PACKED_SWITCH & OP_SPARSE_SWITCH */
+static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc);
+static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc);
+
+/*
+ * Resolve interface callsites - OP_INVOKE_INTERFACE & OP_INVOKE_INTERFACE_RANGE
+ *
+ * Originally declared in mterp/common/FindInterface.h and only comment it here
+ * due to the INLINE attribute.
+ *
+ * INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
+ * u4 methodIdx, const Method* method, DvmDex* methodClassDex)
+ */
+
+/* Originally declared in alloc/Alloc.h */
+Object* dvmAllocObject(ClassObject* clazz, int flags); // OP_NEW_INSTANCE
+
+/*
+ * Functions declared in gDvmInlineOpsTable[] are used for
+ * OP_EXECUTE_INLINE & OP_EXECUTE_INLINE_RANGE.
+ *
+ * org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod
+ * javaLangString_charAt
+ * javaLangString_compareTo
+ * javaLangString_equals
+ * javaLangString_indexOf_I
+ * javaLangString_indexOf_II
+ * javaLangString_length
+ * javaLangMath_abs_int
+ * javaLangMath_abs_long
+ * javaLangMath_abs_float
+ * javaLangMath_abs_double
+ * javaLangMath_min_int
+ * javaLangMath_max_int
+ * javaLangMath_sqrt
+ * javaLangMath_cos
+ * javaLangMath_sin
+ */
+double sqrt(double x); // INLINE_MATH_SQRT
+
+/*
+ * The following functions are invoked through the compiler templates (declared
+ * in compiler/template/armv5te/footer.S:
+ *
+ * __aeabi_cdcmple // CMPG_DOUBLE
+ * __aeabi_cfcmple // CMPG_FLOAT
+ * dvmLockObject // MONITOR_ENTER
+ */
+
+#endif /* _DALVIK_VM_COMPILER_CODEGEN_ARM_CALLOUT_HELPER_H */
rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
}
- loadConstant(cUnit, r2, (int)funct);
+ LOAD_FUNC_ADDR(cUnit, r2, (int)funct);
opReg(cUnit, kOpBlx, r2);
dvmCompilerClobberCallRegs(cUnit);
if (tgtSize == 1) {
RegLocation rlResult;
void* funct;
- /* TODO: use a proper include file to define these */
- float __aeabi_fadd(float a, float b);
- float __aeabi_fsub(float a, float b);
- float __aeabi_fdiv(float a, float b);
- float __aeabi_fmul(float a, float b);
- float fmodf(float a, float b);
-
switch (mir->dalvikInsn.opCode) {
case OP_ADD_FLOAT_2ADDR:
case OP_ADD_FLOAT:
dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
loadValueDirectFixed(cUnit, rlSrc1, r0);
loadValueDirectFixed(cUnit, rlSrc2, r1);
- loadConstant(cUnit, r2, (int)funct);
+ LOAD_FUNC_ADDR(cUnit, r2, (int)funct);
opReg(cUnit, kOpBlx, r2);
dvmCompilerClobberCallRegs(cUnit);
rlResult = dvmCompilerGetReturn(cUnit);
RegLocation rlResult;
void* funct;
- /* TODO: use a proper include file to define these */
- double __aeabi_dadd(double a, double b);
- double __aeabi_dsub(double a, double b);
- double __aeabi_ddiv(double a, double b);
- double __aeabi_dmul(double a, double b);
- double fmod(double a, double b);
-
switch (mir->dalvikInsn.opCode) {
case OP_ADD_DOUBLE_2ADDR:
case OP_ADD_DOUBLE:
return true;
}
dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
- loadConstant(cUnit, rlr, (int)funct);
+ LOAD_FUNC_ADDR(cUnit, rlr, (int)funct);
loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
opReg(cUnit, kOpBlx, rlr);
{
OpCode opCode = mir->dalvikInsn.opCode;
- float __aeabi_i2f( int op1 );
- int __aeabi_f2iz( float op1 );
- float __aeabi_d2f( double op1 );
- double __aeabi_f2d( float op1 );
- double __aeabi_i2d( int op1 );
- int __aeabi_d2iz( double op1 );
- float __aeabi_l2f( long op1 );
- double __aeabi_l2d( long op1 );
- s8 dvmJitf2l( float op1 );
- s8 dvmJitd2l( double op1 );
-
switch (opCode) {
case OP_INT_TO_FLOAT:
return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
/* Get object to store */
loadValueDirectFixed(cUnit, rlSrc, r0);
- loadConstant(cUnit, r2, (int)dvmCanPutArrayElement);
+ LOAD_FUNC_ADDR(cUnit, r2, (int)dvmCanPutArrayElement);
/* Are we storing null? If so, avoid check */
opRegImm(cUnit, kOpCmp, r0, 0);
bool callOut = false;
void *callTgt;
int retReg = r0;
- /* TODO - find proper .h file to declare these */
- long long __aeabi_ldivmod(long long op1, long long op2);
switch (mir->dalvikInsn.opCode) {
case OP_NOT_LONG:
int tReg = dvmCompilerAllocTemp(cUnit);
rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
- loadConstantValue(cUnit, tReg, 0);
+ loadConstantNoClobber(cUnit, tReg, 0);
opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
tReg, rlSrc2.lowReg);
opRegReg(cUnit, kOpSbc, tReg, rlSrc2.highReg);
// Adjust return regs in to handle case of rem returning r2/r3
dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
- loadConstant(cUnit, rlr, (int) callTgt);
+ LOAD_FUNC_ADDR(cUnit, rlr, (int) callTgt);
loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
opReg(cUnit, kOpBlx, rlr);
dvmCompilerClobberCallRegs(cUnit);
RegLocation rlResult;
bool shiftOp = false;
- /* TODO - find proper .h file to declare these */
- int __aeabi_idivmod(int op1, int op2);
- int __aeabi_idiv(int op1, int op2);
-
switch (mir->dalvikInsn.opCode) {
case OP_NEG_INT:
op = kOpNeg;
RegLocation rlResult;
dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
loadValueDirectFixed(cUnit, rlSrc2, r1);
- loadConstant(cUnit, r2, (int) callTgt);
+ LOAD_FUNC_ADDR(cUnit, r2, (int) callTgt);
loadValueDirectFixed(cUnit, rlSrc1, r0);
if (checkZero) {
genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER);
#endif
} else {
- loadConstant(cUnit, r2, (int)dvmUnlockObject);
+ LOAD_FUNC_ADDR(cUnit, r2, (int)dvmUnlockObject);
/* Do the call */
opReg(cUnit, kOpBlx, r2);
opRegImm(cUnit, kOpCmp, r0, 0); /* Did we throw? */
case OP_CONST:
case OP_CONST_4: {
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
- loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
+ loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
storeValue(cUnit, rlDest, rlResult);
break;
}
//TUNING: single routine to load constant pair for support doubles
//TUNING: load 0/-1 separately to avoid load dependency
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
- loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
+ loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
rlResult.lowReg, 31);
storeValueWide(cUnit, rlDest, rlResult);
switch (mir->dalvikInsn.opCode) {
case OP_CONST_HIGH16: {
- loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB << 16);
+ loadConstantNoClobber(cUnit, rlResult.lowReg,
+ mir->dalvikInsn.vB << 16);
storeValue(cUnit, rlDest, rlResult);
break;
}
assert(strPtr != NULL);
rlDest = dvmCompilerGetDest(cUnit, mir, 0);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
- loadConstantValue(cUnit, rlResult.lowReg, (int) strPtr );
+ loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr );
storeValue(cUnit, rlDest, rlResult);
break;
}
assert(classPtr != NULL);
rlDest = dvmCompilerGetDest(cUnit, mir, 0);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
- loadConstantValue(cUnit, rlResult.lowReg, (int) classPtr );
+ loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr );
storeValue(cUnit, rlDest, rlResult);
break;
}
assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
genExportPC(cUnit, mir);
- loadConstant(cUnit, r2, (int)dvmAllocObject);
+ LOAD_FUNC_ADDR(cUnit, r2, (int)dvmAllocObject);
loadConstant(cUnit, r0, (int) classPtr);
loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
opReg(cUnit, kOpBlx, r2);
*/
/* r0 now contains object->clazz */
loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
- loadConstant(cUnit, r2, (int)dvmInstanceofNonTrivial);
+ LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInstanceofNonTrivial);
opRegReg(cUnit, kOpCmp, r0, r1);
ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
opReg(cUnit, kOpBlx, r2);
if (dalvikOpCode == OP_CONST_WIDE_16) {
rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
- loadConstantValue(cUnit, rlResult.lowReg, BBBB);
+ loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
//TUNING: do high separately to avoid load dependency
opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
storeValueWide(cUnit, rlDest, rlResult);
} else if (dalvikOpCode == OP_CONST_16) {
rlDest = dvmCompilerGetDest(cUnit, mir, 0);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
- loadConstantValue(cUnit, rlResult.lowReg, BBBB);
+ loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
storeValue(cUnit, rlDest, rlResult);
} else
return true;
int shiftOp = false;
bool isDiv = false;
- int __aeabi_idivmod(int op1, int op2);
- int __aeabi_idiv(int op1, int op2);
-
switch (dalvikOpCode) {
case OP_RSUB_INT_LIT8:
case OP_RSUB_INT: {
dvmCompilerClobber(cUnit, r0);
if ((dalvikOpCode == OP_DIV_INT_LIT8) ||
(dalvikOpCode == OP_DIV_INT_LIT16)) {
- loadConstant(cUnit, r2, (int)__aeabi_idiv);
+ LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idiv);
isDiv = true;
} else {
- loadConstant(cUnit, r2, (int)__aeabi_idivmod);
+ LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idivmod);
isDiv = false;
}
loadConstant(cUnit, r1, lit);
genExportPC(cUnit, mir);
loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */
loadConstant(cUnit, r0, (int) classPtr );
- loadConstant(cUnit, r3, (int)dvmAllocArrayByClass);
+ LOAD_FUNC_ADDR(cUnit, r3, (int)dvmAllocArrayByClass);
/*
* "len < 0": bail to the interpreter to re-execute the
* instruction
/* r1 now contains object->clazz */
loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
/* r1 now contains object->clazz */
- loadConstant(cUnit, r3, (int)dvmInstanceofNonTrivial);
+ LOAD_FUNC_ADDR(cUnit, r3, (int)dvmInstanceofNonTrivial);
loadConstant(cUnit, r0, 1); /* Assume true */
opRegReg(cUnit, kOpCmp, r1, r2);
ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
* chaining cell for case default [8 bytes]
* noChain exit
*/
-s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
+static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
{
int size;
int firstKey;
}
/* See comments for findPackedSwitchIndex */
-s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
+static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
{
int size;
const int *keys;
dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
genExportPC(cUnit, mir);
loadValueDirectFixed(cUnit, rlSrc, r0);
- loadConstant(cUnit, r2, (int)dvmInterpHandleFillArrayData);
+ LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInterpHandleFillArrayData);
loadConstant(cUnit, r1,
(int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
opReg(cUnit, kOpBlx, r2);
u2 size = switchData[1];
if (dalvikOpCode == OP_PACKED_SWITCH) {
- loadConstant(cUnit, r4PC, (int)findPackedSwitchIndex);
+ LOAD_FUNC_ADDR(cUnit, r4PC, (int)findPackedSwitchIndex);
} else {
- loadConstant(cUnit, r4PC, (int)findSparseSwitchIndex);
+ LOAD_FUNC_ADDR(cUnit, r4PC, (int)findSparseSwitchIndex);
}
/* r0 <- Addr of the switch data */
loadConstant(cUnit, r0,
* calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
* ->pResMethods[BBBB]->methodIndex]
*/
- /* TODO - not excersized in RunPerf.jar */
case OP_INVOKE_SUPER:
case OP_INVOKE_SUPER_RANGE: {
int mIndex = cUnit->method->clazz->pDvmDex->
/* r3 = pDvmDex */
loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
- loadConstant(cUnit, r7,
- (intptr_t) dvmFindInterfaceMethodInCache);
+ LOAD_FUNC_ADDR(cUnit, r7,
+ (intptr_t) dvmFindInterfaceMethodInCache);
opReg(cUnit, kOpBlx, r7);
/* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
dvmCompilerClobber(cUnit, r7);
opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset);
opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
- loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
+ LOAD_FUNC_ADDR(cUnit, r4PC, (int)inLineTable[operation].func);
genExportPC(cUnit, mir);
for (i=0; i < dInsn->vA; i++) {
loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i);
//TUNING: We're using core regs here - not optimal when target is a double
RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
- loadConstantValue(cUnit, rlResult.lowReg,
- mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
- loadConstantValue(cUnit, rlResult.highReg,
- (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
+ loadConstantNoClobber(cUnit, rlResult.lowReg,
+ mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
+ loadConstantNoClobber(cUnit, rlResult.highReg,
+ (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
storeValueWide(cUnit, rlDest, rlResult);
return false;
}