Merge "Try to work around Mac OS 10.5 lossage." into ics-mr1-plus-art
diff --git a/build/Android.common.mk b/build/Android.common.mk
index d09ad63..bc1825e 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -102,18 +102,9 @@
src/oatexec.cc
LIBART_COMMON_SRC_FILES := \
- src/assembler.cc \
- src/assembler_arm.cc \
- src/assembler_x86.cc \
src/atomic.cc.arm \
- src/calling_convention.cc \
- src/calling_convention_arm.cc \
- src/calling_convention_x86.cc \
src/card_table.cc \
src/constants.cc \
- src/context.cc \
- src/context_arm.cc.arm \
- src/context_x86.cc \
src/check_jni.cc \
src/class_linker.cc \
src/class_loader.cc \
@@ -165,8 +156,6 @@
src/logging.cc \
src/mark_stack.cc \
src/mark_sweep.cc \
- src/managed_register_arm.cc \
- src/managed_register_x86.cc \
src/mem_map.cc \
src/memory_region.cc \
src/monitor.cc \
@@ -184,15 +173,12 @@
src/reflection.cc \
src/runtime.cc \
src/runtime_support.cc \
- src/runtime_support_common.cc \
src/scoped_thread_list_lock.cc \
src/signal_catcher.cc \
src/space.cc \
src/stack.cc \
src/stringpiece.cc \
src/stringprintf.cc \
- src/stub_arm.cc \
- src/stub_x86.cc \
src/sun_misc_Unsafe.cc \
src/thread.cc \
src/thread_list.cc \
@@ -206,6 +192,31 @@
src/compiler_llvm/inferred_reg_category_map.cc \
src/compiler_llvm/runtime_support_llvm.cc \
src/compiler_llvm/utils_llvm.cc
+else
+LIBART_COMMON_SRC_FILES += \
+ src/oat/runtime/arm/stub_arm.cc \
+ src/oat/runtime/context.cc \
+ src/oat/runtime/support_alloc.cc \
+ src/oat/runtime/support_cast.cc \
+ src/oat/runtime/support_debug.cc \
+ src/oat/runtime/support_dexcache.cc \
+ src/oat/runtime/support_field.cc \
+ src/oat/runtime/support_fillarray.cc \
+ src/oat/runtime/support_invoke.cc \
+ src/oat/runtime/support_jni.cc \
+ src/oat/runtime/support_locks.cc \
+ src/oat/runtime/support_math.cc \
+ src/oat/runtime/support_proxy.cc \
+ src/oat/runtime/support_stubs.cc \
+ src/oat/runtime/support_thread.cc \
+ src/oat/runtime/support_throw.cc \
+ src/oat/runtime/support_trace.cc \
+ src/oat/runtime/x86/stub_x86.cc \
+ src/oat/utils/arm/assembler_arm.cc \
+ src/oat/utils/arm/managed_register_arm.cc \
+ src/oat/utils/assembler.cc \
+ src/oat/utils/x86/assembler_x86.cc \
+ src/oat/utils/x86/managed_register_x86.cc
endif
LIBART_TARGET_SRC_FILES := \
@@ -217,13 +228,24 @@
src/thread_android.cc
ifeq ($(TARGET_ARCH),arm)
-LIBART_TARGET_SRC_FILES += src/runtime_support_arm.S src/thread_arm.cc
+LIBART_TARGET_SRC_FILES += \
+ src/oat/runtime/arm/context_arm.cc.arm \
+ src/oat/runtime/arm/oat_support_entrypoints_arm.cc \
+ src/oat/runtime/arm/runtime_support_arm.S \
+ src/thread_arm.cc
else # TARGET_ARCH != arm
ifeq ($(TARGET_ARCH),x86)
-LIBART_TARGET_SRC_FILES += src/runtime_support_x86.S src/thread_x86.cc
+LIBART_TARGET_SRC_FILES += \
+ src/oat/runtime/x86/context_x86.cc \
+ src/oat/runtime/x86/oat_support_entrypoints_x86.cc \
+ src/oat/runtime/x86/runtime_support_x86.S \
+ src/thread_x86.cc
else # TARGET_ARCH != x86
ifeq ($(TARGET_ARCH),mips)
-LIBART_TARGET_SRC_FILES += src/runtime_support_mips.S src/thread_mips.cc
+LIBART_TARGET_SRC_FILES += \
+ src/oat/runtime/mips/oat_support_entrypoints_mips.cc \
+ src/oat/runtime/mips/runtime_support_mips.S \
+ src/thread_mips.cc
else # TARGET_ARCH != mips
$(error unsupported TARGET_ARCH=$(TARGET_ARCH))
endif # TARGET_ARCH != mips
@@ -238,7 +260,11 @@
src/thread_linux.cc
ifeq ($(HOST_ARCH),x86)
-LIBART_HOST_SRC_FILES += src/runtime_support_x86.S src/thread_x86.cc
+LIBART_HOST_SRC_FILES += \
+ src/oat/runtime/x86/oat_support_entrypoints_x86.cc \
+ src/oat/runtime/x86/context_x86.cc \
+ src/oat/runtime/x86/runtime_support_x86.S \
+ src/thread_x86.cc
else # HOST_ARCH != x86
$(error unsupported HOST_ARCH=$(HOST_ARCH))
endif # HOST_ARCH != x86
@@ -262,8 +288,8 @@
src/intern_table_test.cc \
src/jni_internal_test.cc \
src/jni_compiler_test.cc \
- src/managed_register_arm_test.cc \
- src/managed_register_x86_test.cc \
+ src/oat/utils/arm/managed_register_arm_test.cc \
+ src/oat/utils/x86/managed_register_x86_test.cc \
src/mutex_test.cc \
src/oat_test.cc \
src/object_test.cc \
@@ -283,7 +309,7 @@
TEST_HOST_SRC_FILES := \
$(TEST_COMMON_SRC_FILES) \
- src/assembler_x86_test.cc
+ src/oat/utils/x86/assembler_x86_test.cc
# subdirectories of test/ which are used as inputs for gtests
TEST_DEX_DIRECTORIES := \
diff --git a/build/Android.libart-compiler.mk b/build/Android.libart-compiler.mk
index 7140dbd..88b280a 100644
--- a/build/Android.libart-compiler.mk
+++ b/build/Android.libart-compiler.mk
@@ -22,15 +22,18 @@
src/compiler/SSATransformation.cc \
src/compiler/Utility.cc \
src/compiler/codegen/RallocUtil.cc \
- src/jni_compiler.cc
+ src/oat/jni/calling_convention.cc \
+ src/oat/jni/jni_compiler.cc \
+ src/oat/jni/arm/calling_convention_arm.cc \
+ src/oat/jni/x86/calling_convention_x86.cc
LIBART_COMPILER_ARM_SRC_FILES += \
$(LIBART_COMPILER_COMMON_SRC_FILES) \
- src/jni_internal_arm.cc \
src/compiler/codegen/arm/ArchUtility.cc \
src/compiler/codegen/arm/ArmRallocUtil.cc \
src/compiler/codegen/arm/Assemble.cc \
- src/compiler/codegen/arm/armv7-a/Codegen.cc
+ src/compiler/codegen/arm/armv7-a/Codegen.cc \
+ src/oat/jni/arm/jni_internal_arm.cc
LIBART_COMPILER_MIPS_SRC_FILES += \
$(LIBART_COMPILER_COMMON_SRC_FILES) \
@@ -41,11 +44,11 @@
LIBART_COMPILER_X86_SRC_FILES += \
$(LIBART_COMPILER_COMMON_SRC_FILES) \
- src/jni_internal_x86.cc \
src/compiler/codegen/x86/ArchUtility.cc \
src/compiler/codegen/x86/X86RallocUtil.cc \
src/compiler/codegen/x86/Assemble.cc \
- src/compiler/codegen/x86/x86/Codegen.cc
+ src/compiler/codegen/x86/x86/Codegen.cc \
+ src/oat/jni/x86/jni_internal_x86.cc
# $(1): target or host
# $(2): ndebug or debug
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index c9509b7..dd33d1b 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -57,7 +57,7 @@
$(HOST_CORE_IMG_OUT): $(HOST_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY)
@echo "host dex2oat: $@ ($?)"
@mkdir -p $(dir $@)
- $(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) --oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(IMG_HOST_BASE_ADDRESS) # --instruction-set=X86
+ $(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) --oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(IMG_HOST_BASE_ADDRESS) --instruction-set=X86
$(TARGET_CORE_IMG_OUT): $(TARGET_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY)
@echo "target dex2oat: $@ ($?)"
diff --git a/build/Android.oattest.mk b/build/Android.oattest.mk
index ab10d83..0ccf106 100644
--- a/build/Android.oattest.mk
+++ b/build/Android.oattest.mk
@@ -67,7 +67,7 @@
.PHONY: test-art-host-oat-$(1)
test-art-host-oat-$(1): $(ART_TEST_OUT)/oat-test-dex-$(1).jar $(HOST_CORE_IMG_OUT)
mkdir -p /tmp/android-data/test-art-host-oat-$(1)
- $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --dex-file=$(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar --oat-file=$(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar.oat # --instruction-set=X86
+ $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --dex-file=$(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar --oat-file=$(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar.oat --instruction-set=X86
ANDROID_DATA=/tmp/android-data/test-art-host-oat-$(1) \
ANDROID_ROOT=$(HOST_OUT) \
LD_LIBRARY_PATH=$(HOST_OUT_SHARED_LIBRARIES) \
diff --git a/src/compiler.cc b/src/compiler.cc
index 0bf4673..5507c36 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -22,7 +22,6 @@
#include <sys/mman.h>
#include <unistd.h>
-#include "assembler.h"
#include "class_linker.h"
#include "class_loader.h"
#include "dex_cache.h"
@@ -1276,7 +1275,7 @@
uint64_t start_ns = NanoTime();
if ((access_flags & kAccNative) != 0) {
- compiled_method = (*jni_compiler_)(*this, access_flags, method_idx, class_loader, dex_file);
+ compiled_method = (*jni_compiler_)(*this, access_flags, method_idx, dex_file);
CHECK(compiled_method != NULL);
} else if ((access_flags & kAccAbstract) != 0) {
} else {
diff --git a/src/compiler.h b/src/compiler.h
index 5f4e5ca..fcb9f7f 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -326,7 +326,6 @@
typedef CompiledMethod* (*JniCompilerFn)(Compiler& compiler,
uint32_t access_flags, uint32_t method_idx,
- const ClassLoader* class_loader,
const DexFile& dex_file);
JniCompilerFn jni_compiler_;
typedef CompiledInvokeStub* (*CreateInvokeStubFn)(Compiler& compiler, bool is_static,
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index a440555..25fc89e 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -515,7 +515,6 @@
kThrowDivZero,
kThrowArrayBounds,
kThrowVerificationError,
- kThrowNegArraySize,
kThrowNoSuchMethod,
kThrowStackOverflow,
};
diff --git a/src/compiler/codegen/GenCommon.cc b/src/compiler/codegen/GenCommon.cc
index 0b0d100..54b8e5f 100644
--- a/src/compiler/codegen/GenCommon.cc
+++ b/src/compiler/codegen/GenCommon.cc
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "oat/runtime/oat_support_entrypoints.h"
+
namespace art {
/*
@@ -490,9 +492,9 @@
cUnit->dex_cache,
*cUnit->dex_file,
type_idx)) {
- funcOffset = OFFSETOF_MEMBER(Thread, pAllocArrayFromCode);
+ funcOffset = ENTRYPOINT_OFFSET(pAllocArrayFromCode);
} else {
- funcOffset= OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck);
+ funcOffset= ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck);
}
callRuntimeHelperImmMethodRegLocation(cUnit, funcOffset, type_idx, rlSrc);
RegLocation rlResult = oatGetReturn(cUnit, false);
@@ -516,10 +518,9 @@
cUnit->dex_cache,
*cUnit->dex_file,
typeIdx)) {
- funcOffset = OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode);
+ funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode);
} else {
- funcOffset = OFFSETOF_MEMBER(Thread,
- pCheckAndAllocArrayFromCodeWithAccessCheck);
+ funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck);
}
callRuntimeHelperImmMethodImm(cUnit, funcOffset, typeIdx, elems);
oatFreeTemp(cUnit, rARG2);
@@ -666,7 +667,7 @@
LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
loadConstant(cUnit, rARG0, ssbIndex);
callRuntimeHelperImm(cUnit,
- OFFSETOF_MEMBER(Thread, pInitializeStaticStorage),
+ ENTRYPOINT_OFFSET(pInitializeStaticStorage),
ssbIndex);
#if defined(TARGET_MIPS)
// For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
@@ -703,9 +704,9 @@
oatFreeTemp(cUnit, rBase);
} else {
oatFlushAllRegs(cUnit); // Everything to home locations
- int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
- (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
- : OFFSETOF_MEMBER(Thread, pSet32Static));
+ int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Static) :
+ (isObject ? ENTRYPOINT_OFFSET(pSetObjStatic)
+ : ENTRYPOINT_OFFSET(pSet32Static));
callRuntimeHelperImmRegLocation(cUnit, setterOffset, fieldIdx, rlSrc);
}
}
@@ -763,7 +764,7 @@
// TUNING: fast path should fall through
LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
callRuntimeHelperImm(cUnit,
- OFFSETOF_MEMBER(Thread, pInitializeStaticStorage),
+ ENTRYPOINT_OFFSET(pInitializeStaticStorage),
ssbIndex);
#if defined(TARGET_MIPS)
// For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
@@ -794,9 +795,9 @@
}
} else {
oatFlushAllRegs(cUnit); // Everything to home locations
- int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
- (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
- : OFFSETOF_MEMBER(Thread, pGet32Static));
+ int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Static) :
+ (isObject ? ENTRYPOINT_OFFSET(pGetObjStatic)
+ : ENTRYPOINT_OFFSET(pGet32Static));
callRuntimeHelperImm(cUnit, getterOffset, fieldIdx);
if (isLongOrDouble) {
RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
@@ -817,7 +818,7 @@
#else
LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rINVOKE_TGT, 0, NULL);
loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pDebugMe), rINVOKE_TGT);
+ ENTRYPOINT_OFFSET(pDebugMe), rINVOKE_TGT);
LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
branchOver->target = (LIR*)target;
#endif
@@ -825,8 +826,7 @@
void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
{
- callRuntimeHelperImmImm(cUnit, OFFSETOF_MEMBER(Thread,
- pThrowVerificationErrorFromCode),
+ callRuntimeHelperImmImm(cUnit, ENTRYPOINT_OFFSET(pThrowVerificationErrorFromCode),
mir->dalvikInsn.vA, mir->dalvikInsn.vB);
}
@@ -843,10 +843,9 @@
oatAppendLIR(cUnit, lab);
#if defined(TARGET_X86)
opThreadMem(cUnit, kOpBlx,
- OFFSETOF_MEMBER(Thread, pTestSuspendFromCode));
+ ENTRYPOINT_OFFSET(pTestSuspendFromCode));
#else
- int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
- pTestSuspendFromCode));
+ int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
opReg(cUnit, kOpBlx, rTgt);
#endif
opUnconditionalBranch(cUnit, resumeLab);
@@ -889,7 +888,7 @@
int v2 = lab->operands[3];
switch (lab->operands[0]) {
case kThrowNullPointer:
- funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
+ funcOffset = ENTRYPOINT_OFFSET(pThrowNullPointerFromCode);
break;
case kThrowArrayBounds:
if (v2 != rARG0) {
@@ -910,30 +909,25 @@
opRegCopy(cUnit, rARG0, v1);
}
}
- funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
+ funcOffset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode);
break;
case kThrowDivZero:
- funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
+ funcOffset = ENTRYPOINT_OFFSET(pThrowDivZeroFromCode);
break;
case kThrowVerificationError:
loadConstant(cUnit, rARG0, v1);
loadConstant(cUnit, rARG1, v2);
funcOffset =
- OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
- break;
- case kThrowNegArraySize:
- opRegCopy(cUnit, rARG0, v1);
- funcOffset =
- OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
+ ENTRYPOINT_OFFSET(pThrowVerificationErrorFromCode);
break;
case kThrowNoSuchMethod:
opRegCopy(cUnit, rARG0, v1);
funcOffset =
- OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
+ ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode);
break;
case kThrowStackOverflow:
funcOffset =
- OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
+ ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode);
// Restore stack alignment
opRegImm(cUnit, kOpAdd, rSP,
(cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
@@ -1018,9 +1012,9 @@
storeValue(cUnit, rlDest, rlResult);
}
} else {
- int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
- (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
- : OFFSETOF_MEMBER(Thread, pGet32Instance));
+ int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Instance) :
+ (isObject ? ENTRYPOINT_OFFSET(pGetObjInstance)
+ : ENTRYPOINT_OFFSET(pGet32Instance));
callRuntimeHelperImmRegLocation(cUnit, getterOffset, fieldIdx, rlObj);
if (isLongOrDouble) {
RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
@@ -1074,9 +1068,9 @@
}
}
} else {
- int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Instance) :
- (isObject ? OFFSETOF_MEMBER(Thread, pSetObjInstance)
- : OFFSETOF_MEMBER(Thread, pSet32Instance));
+ int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Instance) :
+ (isObject ? ENTRYPOINT_OFFSET(pSetObjInstance)
+ : ENTRYPOINT_OFFSET(pSet32Instance));
callRuntimeHelperImmRegLocationRegLocation(cUnit, setterOffset,
fieldIdx, rlObj, rlSrc);
}
@@ -1096,8 +1090,7 @@
// Call out to helper which resolves type and verifies access.
// Resolved type returned in rRET0.
callRuntimeHelperImmReg(cUnit,
- OFFSETOF_MEMBER(Thread,
- pInitializeTypeAndVerifyAccessFromCode),
+ ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
type_idx, rlMethod.lowReg);
RegLocation rlResult = oatGetReturn(cUnit, false);
storeValue(cUnit, rlDest, rlResult);
@@ -1127,8 +1120,7 @@
// TUNING: move slow path to end & remove unconditional branch
LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
// Call out to helper, which will return resolved type in rARG0
- callRuntimeHelperImmReg(cUnit, OFFSETOF_MEMBER(Thread,
- pInitializeTypeFromCode),
+ callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
type_idx, rlMethod.lowReg);
RegLocation rlResult = oatGetReturn(cUnit, false);
storeValue(cUnit, rlDest, rlResult);
@@ -1165,8 +1157,7 @@
Method::DexCacheStringsOffset().Int32Value(), rARG0);
// Might call out to helper, which will return resolved string in rRET0
#if !defined(TARGET_X86)
- int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
- pResolveStringFromCode));
+ int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode));
#endif
loadWordDisp(cUnit, rRET0, offset_of_string, rARG0);
loadConstant(cUnit, rARG1, string_idx);
@@ -1188,8 +1179,7 @@
LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
branch->target = target;
#else
- callRuntimeHelperRegReg(cUnit, OFFSETOF_MEMBER(Thread,
- pResolveStringFromCode),
+ callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode),
rARG2, rARG1);
#endif
genBarrier(cUnit);
@@ -1218,10 +1208,10 @@
int funcOffset;
if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) {
- funcOffset = OFFSETOF_MEMBER(Thread, pAllocObjectFromCode);
+ funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCode);
} else {
funcOffset =
- OFFSETOF_MEMBER(Thread, pAllocObjectFromCodeWithAccessCheck);
+ ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck);
}
callRuntimeHelperImmMethod(cUnit, funcOffset, type_idx);
RegLocation rlResult = oatGetReturn(cUnit, false);
@@ -1231,7 +1221,7 @@
void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
{
oatFlushAllRegs(cUnit);
- callRuntimeHelperRegLocation(cUnit, OFFSETOF_MEMBER(Thread, pDeliverException), rlSrc);
+ callRuntimeHelperRegLocation(cUnit, ENTRYPOINT_OFFSET(pDeliverException), rlSrc);
}
void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
@@ -1250,7 +1240,7 @@
// Check we have access to type_idx and if not throw IllegalAccessError,
// returns Class* in rARG0
callRuntimeHelperImm(cUnit,
- OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
+ ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
type_idx);
opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
@@ -1270,8 +1260,7 @@
LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
// Not resolved
// Call out to helper, which will return resolved type in rRET0
- callRuntimeHelperImm(cUnit, OFFSETOF_MEMBER(Thread,
- pInitializeTypeFromCode),
+ callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
type_idx);
opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
@@ -1288,8 +1277,7 @@
/* rARG0 is ref, rARG1 is ref->klass_, rARG2 is class */
#if defined(TARGET_ARM)
/* Uses conditional nullification */
- int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
- pInstanceofNonTrivialFromCode));
+ int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
loadConstant(cUnit, rARG0, 1); // .eq case - load true
@@ -1301,15 +1289,14 @@
loadConstant(cUnit, rARG0, 1); // assume true
LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
#if !defined(TARGET_X86)
- int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
- pInstanceofNonTrivialFromCode));
+ int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
oatFreeTemp(cUnit, rTgt);
#else
opRegCopy(cUnit, rARG0, rARG2);
opThreadMem(cUnit, kOpBlx,
- OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode));
+ ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
#endif
#endif
oatClobberCalleeSave(cUnit);
@@ -1339,8 +1326,7 @@
// returns Class* in rRET0
// InitializeTypeAndVerifyAccess(idx, method)
callRuntimeHelperImmReg(cUnit,
- OFFSETOF_MEMBER(Thread,
- pInitializeTypeAndVerifyAccessFromCode),
+ ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
type_idx, rARG1);
opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
} else {
@@ -1360,7 +1346,7 @@
// Call out to helper, which will return resolved type in rARG0
// InitializeTypeFromCode(idx, method)
callRuntimeHelperImmReg(cUnit,
- OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode),
+ ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
type_idx, rARG1);
opRegCopy(cUnit, classReg, rARG0); // Align usage with fast path
// Rejoin code paths
@@ -1378,12 +1364,10 @@
/* rARG1 now contains object->klass_ */
#if defined(TARGET_MIPS) || defined(TARGET_X86)
LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
- callRuntimeHelperRegReg(cUnit, OFFSETOF_MEMBER(Thread,
- pCheckCastFromCode),
+ callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode),
rARG1, rARG2);
#else // defined(TARGET_ARM)
- int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
- pCheckCastFromCode));
+ int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode));
opRegReg(cUnit, kOpCmp, rARG1, classReg);
LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
opRegCopy(cUnit, rARG0, rARG1);
@@ -1418,8 +1402,7 @@
genNullCheck(cUnit, rlArray.sRegLow, rARG1, mir);
/* Get the array's class */
loadWordDisp(cUnit, rARG1, Object::ClassOffset().Int32Value(), rARG1);
- callRuntimeHelperRegReg(cUnit, OFFSETOF_MEMBER(Thread,
- pCanPutArrayElementFromCode),
+ callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode),
rARG0, rARG1);
oatFreeTemp(cUnit, rARG0);
oatFreeTemp(cUnit, rARG1);
@@ -1725,15 +1708,15 @@
switch (mir->dalvikInsn.opcode) {
case Instruction::SHL_LONG:
case Instruction::SHL_LONG_2ADDR:
- funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
+ funcOffset = ENTRYPOINT_OFFSET(pShlLong);
break;
case Instruction::SHR_LONG:
case Instruction::SHR_LONG_2ADDR:
- funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
+ funcOffset = ENTRYPOINT_OFFSET(pShrLong);
break;
case Instruction::USHR_LONG:
case Instruction::USHR_LONG_2ADDR:
- funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
+ funcOffset = ENTRYPOINT_OFFSET(pUshrLong);
break;
default:
LOG(FATAL) << "Unexpected case";
@@ -1784,7 +1767,7 @@
checkZero = true;
op = kOpDiv;
callOut = true;
- funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
+ funcOffset = ENTRYPOINT_OFFSET(pIdiv);
retReg = rRET0;
break;
/* NOTE: returns in rARG1 */
@@ -1793,7 +1776,7 @@
checkZero = true;
op = kOpRem;
callOut = true;
- funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
+ funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
retReg = rRET1;
break;
case Instruction::AND_INT:
@@ -2108,10 +2091,10 @@
oatClobber(cUnit, rARG0);
if ((dalvikOpcode == Instruction::DIV_INT_LIT8) ||
(dalvikOpcode == Instruction::DIV_INT_LIT16)) {
- funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
+ funcOffset = ENTRYPOINT_OFFSET(pIdiv);
isDiv = true;
} else {
- funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
+ funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
isDiv = false;
}
callRuntimeHelperRegImm(cUnit, funcOffset, rARG0, lit);
@@ -2173,7 +2156,7 @@
#elif defined(TARGET_X86)
callOut = true;
retReg = rRET0;
- funcOffset = OFFSETOF_MEMBER(Thread, pLadd);
+ funcOffset = ENTRYPOINT_OFFSET(pLadd);
#else
firstOp = kOpAdd;
secondOp = kOpAdc;
@@ -2186,7 +2169,7 @@
#elif defined(TARGET_X86)
callOut = true;
retReg = rRET0;
- funcOffset = OFFSETOF_MEMBER(Thread, pLsub);
+ funcOffset = ENTRYPOINT_OFFSET(pLsub);
#endif
firstOp = kOpSub;
secondOp = kOpSbc;
@@ -2195,14 +2178,14 @@
case Instruction::MUL_LONG_2ADDR:
callOut = true;
retReg = rRET0;
- funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
+ funcOffset = ENTRYPOINT_OFFSET(pLmul);
break;
case Instruction::DIV_LONG:
case Instruction::DIV_LONG_2ADDR:
callOut = true;
checkZero = true;
retReg = rRET0;
- funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
+ funcOffset = ENTRYPOINT_OFFSET(pLdivmod);
break;
/* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
// FIXME: is true, or could be made true, or other targets?
@@ -2210,7 +2193,7 @@
case Instruction::REM_LONG_2ADDR:
callOut = true;
checkZero = true;
- funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
+ funcOffset = ENTRYPOINT_OFFSET(pLdivmod);
retReg = rARG2;
break;
case Instruction::AND_LONG_2ADDR:
@@ -2218,7 +2201,7 @@
#if defined(TARGET_X86)
callOut = true;
retReg = rRET0;
- funcOffset = OFFSETOF_MEMBER(Thread, pLand);
+ funcOffset = ENTRYPOINT_OFFSET(pLand);
#endif
firstOp = kOpAnd;
secondOp = kOpAnd;
@@ -2228,7 +2211,7 @@
#if defined(TARGET_X86)
callOut = true;
retReg = rRET0;
- funcOffset = OFFSETOF_MEMBER(Thread, pLor);
+ funcOffset = ENTRYPOINT_OFFSET(pLor);
#endif
firstOp = kOpOr;
secondOp = kOpOr;
@@ -2238,7 +2221,7 @@
#if defined(TARGET_X86)
callOut = true;
retReg = rRET0;
- funcOffset = OFFSETOF_MEMBER(Thread, pLxor);
+ funcOffset = ENTRYPOINT_OFFSET(pLxor);
#endif
firstOp = kOpXor;
secondOp = kOpXor;
@@ -2332,23 +2315,23 @@
switch (mir->dalvikInsn.opcode) {
case Instruction::ADD_FLOAT_2ADDR:
case Instruction::ADD_FLOAT:
- funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
+ funcOffset = ENTRYPOINT_OFFSET(pFadd);
break;
case Instruction::SUB_FLOAT_2ADDR:
case Instruction::SUB_FLOAT:
- funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
+ funcOffset = ENTRYPOINT_OFFSET(pFsub);
break;
case Instruction::DIV_FLOAT_2ADDR:
case Instruction::DIV_FLOAT:
- funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
+ funcOffset = ENTRYPOINT_OFFSET(pFdiv);
break;
case Instruction::MUL_FLOAT_2ADDR:
case Instruction::MUL_FLOAT:
- funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
+ funcOffset = ENTRYPOINT_OFFSET(pFmul);
break;
case Instruction::REM_FLOAT_2ADDR:
case Instruction::REM_FLOAT:
- funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
+ funcOffset = ENTRYPOINT_OFFSET(pFmodf);
break;
case Instruction::NEG_FLOAT: {
genNegFloat(cUnit, rlDest, rlSrc1);
@@ -2375,23 +2358,23 @@
switch (mir->dalvikInsn.opcode) {
case Instruction::ADD_DOUBLE_2ADDR:
case Instruction::ADD_DOUBLE:
- funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
+ funcOffset = ENTRYPOINT_OFFSET(pDadd);
break;
case Instruction::SUB_DOUBLE_2ADDR:
case Instruction::SUB_DOUBLE:
- funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
+ funcOffset = ENTRYPOINT_OFFSET(pDsub);
break;
case Instruction::DIV_DOUBLE_2ADDR:
case Instruction::DIV_DOUBLE:
- funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
+ funcOffset = ENTRYPOINT_OFFSET(pDdiv);
break;
case Instruction::MUL_DOUBLE_2ADDR:
case Instruction::MUL_DOUBLE:
- funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
+ funcOffset = ENTRYPOINT_OFFSET(pDmul);
break;
case Instruction::REM_DOUBLE_2ADDR:
case Instruction::REM_DOUBLE:
- funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
+ funcOffset = ENTRYPOINT_OFFSET(pFmod);
break;
case Instruction::NEG_DOUBLE: {
genNegDouble(cUnit, rlDest, rlSrc1);
@@ -2413,34 +2396,34 @@
switch (opcode) {
case Instruction::INT_TO_FLOAT:
- return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
+ return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pI2f),
1, 1);
case Instruction::FLOAT_TO_INT:
- return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
+ return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pF2iz),
1, 1);
case Instruction::DOUBLE_TO_FLOAT:
- return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
+ return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pD2f),
2, 1);
case Instruction::FLOAT_TO_DOUBLE:
- return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
+ return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pF2d),
1, 2);
case Instruction::INT_TO_DOUBLE:
- return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
+ return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pI2d),
1, 2);
case Instruction::DOUBLE_TO_INT:
- return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
+ return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pD2iz),
2, 1);
case Instruction::FLOAT_TO_LONG:
- return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
- pF2l), 1, 2);
+ return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pF2l),
+ 1, 2);
case Instruction::LONG_TO_FLOAT:
- return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
+ return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pL2f),
2, 1);
case Instruction::DOUBLE_TO_LONG:
- return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
- pD2l), 2, 2);
+ return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pD2l),
+ 2, 2);
case Instruction::LONG_TO_DOUBLE:
- return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
+ return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pL2d),
2, 2);
default:
return true;
@@ -2492,12 +2475,11 @@
#if defined(TARGET_X86)
UNIMPLEMENTED(FATAL);
#else
- int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
- pTestSuspendFromCode));
+ int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
opReg(cUnit, kOpBlx, rTgt);
// Refresh rSUSPEND
loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode),
+ ENTRYPOINT_OFFSET(pUpdateDebuggerFromCode),
rSUSPEND);
#endif
} else {
diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/GenInvoke.cc
index e4feb4d..8a9d1f5 100644
--- a/src/compiler/codegen/GenInvoke.cc
+++ b/src/compiler/codegen/GenInvoke.cc
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "oat/runtime/oat_support_entrypoints.h"
+
namespace art {
/*
@@ -301,7 +303,7 @@
uintptr_t unused, uintptr_t unused2,
InvokeType unused3)
{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
+ int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
}
@@ -309,7 +311,7 @@
uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
uintptr_t unused2, InvokeType unused3)
{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
+ int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
}
@@ -317,7 +319,7 @@
uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
uintptr_t unused2, InvokeType unused3)
{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
+ int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
}
@@ -325,7 +327,7 @@
uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
uintptr_t unused2, InvokeType unused3)
{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
+ int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
}
@@ -337,7 +339,7 @@
uint32_t dexIdx, uint32_t unused, uintptr_t unused2,
uintptr_t unused3, InvokeType unused4)
{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
+ int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
}
@@ -346,7 +348,7 @@
uint32_t unused, uintptr_t unused2,
uintptr_t unused3, InvokeType unused4)
{
- int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
+ int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
}
@@ -553,14 +555,14 @@
// Generate memcpy
opRegRegImm(cUnit, kOpAdd, rARG0, rSP, outsOffset);
opRegRegImm(cUnit, kOpAdd, rARG1, rSP, startOffset);
- callRuntimeHelperRegRegImm(cUnit, OFFSETOF_MEMBER(Thread, pMemcpy),
+ callRuntimeHelperRegRegImm(cUnit, ENTRYPOINT_OFFSET(pMemcpy),
rARG0, rARG1, (numArgs - 3) * 4);
#else
if (numArgs >= 20) {
// Generate memcpy
opRegRegImm(cUnit, kOpAdd, rARG0, rSP, outsOffset);
opRegRegImm(cUnit, kOpAdd, rARG1, rSP, startOffset);
- callRuntimeHelperRegRegImm(cUnit, OFFSETOF_MEMBER(Thread, pMemcpy),
+ callRuntimeHelperRegRegImm(cUnit, ENTRYPOINT_OFFSET(pMemcpy),
rARG0, rARG1, (numArgs - 3) * 4);
} else {
// Use vldm/vstm pair using rARG3 as a temp
@@ -820,7 +822,7 @@
} else {
loadValueDirectFixed(cUnit, rlStart, regStart);
}
- int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pIndexOf));
+ int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pIndexOf));
genNullCheck(cUnit, rlObj.sRegLow, regPtr, mir);
LIR* launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (int)mir, type);
oatInsertGrowableList(cUnit, &cUnit->intrinsicLaunchpads,
@@ -852,7 +854,7 @@
RegLocation rlCmp = oatGetSrc(cUnit, mir, 1);
loadValueDirectFixed(cUnit, rlThis, regThis);
loadValueDirectFixed(cUnit, rlCmp, regCmp);
- int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pStringCompareTo));
+ int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pStringCompareTo));
genNullCheck(cUnit, rlThis.sRegLow, regThis, mir);
//TUNING: check if rlCmp.sRegLow is already null checked
LIR* launchPad = rawLIR(cUnit, 0, kPseudoIntrinsicRetry, (int)mir, type);
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index c24b856..9326faf 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -22,6 +22,8 @@
*
*/
+#include "oat/runtime/oat_support_entrypoints.h"
+
namespace art {
void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
@@ -112,7 +114,7 @@
if (cUnit->genDebugger) {
// Refresh update debugger callout
loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
+ ENTRYPOINT_OFFSET(pUpdateDebuggerFromCode), rSUSPEND);
genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
}
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 4319ec8..9477d2c 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -23,6 +23,7 @@
*/
#include "oat_compilation_unit.h"
+#include "oat/runtime/oat_support_entrypoints.h"
namespace art {
@@ -491,7 +492,7 @@
oatFlushAllRegs(cUnit); /* Everything to home location */
loadValueDirectFixed(cUnit, rlSrc, r0);
loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
+ ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode), rLR);
// Materialize a pointer to the fill data image
newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
oatClobberCalleeSave(cUnit);
@@ -565,7 +566,7 @@
opRegImm(cUnit, kOpCmp, r1, 0);
opIT(cUnit, kArmCondNe, "T");
// Go expensive route - artLockObjectFromCode(self, obj);
- loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
+ loadWordDisp(cUnit, rSELF, ENTRYPOINT_OFFSET(pLockObjectFromCode),
rLR);
oatClobberCalleeSave(cUnit);
opReg(cUnit, kOpBlx, rLR);
@@ -596,7 +597,7 @@
opIT(cUnit, kArmCondEq, "EE");
storeWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
// Go expensive route - UnlockObjectFromCode(obj);
- loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
+ loadWordDisp(cUnit, rSELF, ENTRYPOINT_OFFSET(pUnlockObjectFromCode),
rLR);
oatClobberCalleeSave(cUnit);
opReg(cUnit, kOpBlx, rLR);
diff --git a/src/compiler/codegen/mips/ArchFactory.cc b/src/compiler/codegen/mips/ArchFactory.cc
index b7f055d..5e41400 100644
--- a/src/compiler/codegen/mips/ArchFactory.cc
+++ b/src/compiler/codegen/mips/ArchFactory.cc
@@ -22,6 +22,8 @@
*
*/
+#include "oat/runtime/oat_support_entrypoints.h"
+
namespace art {
bool genAddLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
@@ -191,7 +193,7 @@
if (cUnit->genDebugger) {
// Refresh update debugger callout
loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
+ ENTRYPOINT_OFFSET(pUpdateDebuggerFromCode), rSUSPEND);
genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
}
diff --git a/src/compiler/codegen/mips/FP/MipsFP.cc b/src/compiler/codegen/mips/FP/MipsFP.cc
index 6524641..948ded6 100644
--- a/src/compiler/codegen/mips/FP/MipsFP.cc
+++ b/src/compiler/codegen/mips/FP/MipsFP.cc
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "oat/runtime/oat_support_entrypoints.h"
+
namespace art {
bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
@@ -191,18 +193,18 @@
switch (mir->dalvikInsn.opcode) {
case Instruction::CMPL_FLOAT:
- offset = OFFSETOF_MEMBER(Thread, pCmplFloat);
+ offset = ENTRYPOINT_OFFSET(pCmplFloat);
wide = false;
break;
case Instruction::CMPG_FLOAT:
- offset = OFFSETOF_MEMBER(Thread, pCmpgFloat);
+ offset = ENTRYPOINT_OFFSET(pCmpgFloat);
wide = false;
break;
case Instruction::CMPL_DOUBLE:
- offset = OFFSETOF_MEMBER(Thread, pCmplDouble);
+ offset = ENTRYPOINT_OFFSET(pCmplDouble);
break;
case Instruction::CMPG_DOUBLE:
- offset = OFFSETOF_MEMBER(Thread, pCmpgDouble);
+ offset = ENTRYPOINT_OFFSET(pCmpgDouble);
break;
default:
return true;
diff --git a/src/compiler/codegen/mips/Mips32/Gen.cc b/src/compiler/codegen/mips/Mips32/Gen.cc
index bf65ba6..b810f98 100644
--- a/src/compiler/codegen/mips/Mips32/Gen.cc
+++ b/src/compiler/codegen/mips/Mips32/Gen.cc
@@ -22,6 +22,8 @@
*
*/
+#include "oat/runtime/oat_support_entrypoints.h"
+
namespace art {
void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
@@ -245,8 +247,7 @@
genBarrier(cUnit);
newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
// Now, fill the branch delay slot with the helper load
- int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
- pHandleFillArrayDataFromCode));
+ int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode));
genBarrier(cUnit); // Scheduling barrier
// Construct BaseLabel and set up table base register
@@ -291,7 +292,7 @@
oatLockCallTemps(cUnit); // Prepare for explicit register usage
genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
// Go expensive route - artLockObjectFromCode(self, obj);
- int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pLockObjectFromCode));
+ int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pLockObjectFromCode));
oatClobberCalleeSave(cUnit);
opReg(cUnit, kOpBlx, rTgt);
}
@@ -306,7 +307,7 @@
oatLockCallTemps(cUnit); // Prepare for explicit register usage
genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
// Go expensive route - UnlockObjectFromCode(obj);
- int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode));
+ int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pUnlockObjectFromCode));
oatClobberCalleeSave(cUnit);
opReg(cUnit, kOpBlx, rTgt);
}
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index ff4123a..0a203e9 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -64,35 +64,6 @@
// Exception
//----------------------------------------------------------------------------
-static std::string MethodNameFromIndex(const Method* method,
- uint32_t ref,
- verifier::VerifyErrorRefType ref_type,
- bool access) {
- CHECK_EQ(static_cast<int>(ref_type),
- static_cast<int>(verifier::VERIFY_ERROR_REF_METHOD));
-
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- const DexFile& dex_file =
- class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
-
- const DexFile::MethodId& id = dex_file.GetMethodId(ref);
- std::string class_name(
- PrettyDescriptor(dex_file.GetMethodDeclaringClassDescriptor(id))
- );
- const char* method_name = dex_file.StringDataByIdx(id.name_idx_);
- if (!access) {
- return class_name + "." + method_name;
- }
-
- std::string result;
- result += "tried to access method ";
- result += class_name + "." + method_name + ":" +
- dex_file.CreateMethodSignature(id.proto_idx_, NULL);
- result += " from class ";
- result += PrettyDescriptor(method->GetDeclaringClass());
- return result;
-}
-
bool art_is_exception_pending_from_code() {
return Thread::Current()->IsExceptionPending();
}
diff --git a/src/debugger.cc b/src/debugger.cc
index 5a9a462..70f9c8e 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -23,7 +23,7 @@
#include "class_linker.h"
#include "class_loader.h"
#include "dex_verifier.h" // For Instruction.
-#include "context.h"
+#include "oat/runtime/context.h"
#include "object_utils.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 3c2235a..e52992c 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -17,7 +17,6 @@
#include <sys/mman.h>
#include "UniquePtr.h"
-#include "assembler.h"
#include "class_linker.h"
#include "common_test.h"
#include "dex_file.h"
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 7a78814..a61bc9f 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -17,7 +17,6 @@
#include <sys/mman.h>
#include "UniquePtr.h"
-#include "assembler.h"
#include "class_linker.h"
#include "common_test.h"
#include "dex_file.h"
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index dba933a..949217b 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -26,7 +26,6 @@
#include "ScopedLocalRef.h"
#include "UniquePtr.h"
-#include "assembler.h"
#include "class_linker.h"
#include "class_loader.h"
#include "jni.h"
diff --git a/src/calling_convention_arm.cc b/src/oat/jni/arm/calling_convention_arm.cc
similarity index 98%
rename from src/calling_convention_arm.cc
rename to src/oat/jni/arm/calling_convention_arm.cc
index 924b291..75c0380 100644
--- a/src/calling_convention_arm.cc
+++ b/src/oat/jni/arm/calling_convention_arm.cc
@@ -16,7 +16,7 @@
#include "calling_convention_arm.h"
#include "logging.h"
-#include "managed_register_arm.h"
+#include "oat/utils/arm/managed_register_arm.h"
namespace art {
namespace arm {
diff --git a/src/calling_convention_arm.h b/src/oat/jni/arm/calling_convention_arm.h
similarity index 93%
rename from src/calling_convention_arm.h
rename to src/oat/jni/arm/calling_convention_arm.h
index f03429f..cb1d6a9 100644
--- a/src/calling_convention_arm.h
+++ b/src/oat/jni/arm/calling_convention_arm.h
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#ifndef ART_SRC_CALLING_CONVENTION_ARM_H_
-#define ART_SRC_CALLING_CONVENTION_ARM_H_
+#ifndef ART_SRC_OAT_JNI_ARM_CALLING_CONVENTION_ARM_H_
+#define ART_SRC_OAT_JNI_ARM_CALLING_CONVENTION_ARM_H_
-#include "calling_convention.h"
+#include "oat/jni/calling_convention.h"
namespace art {
namespace arm {
@@ -87,4 +87,4 @@
} // namespace arm
} // namespace art
-#endif // ART_SRC_CALLING_CONVENTION_ARM_H_
+#endif // ART_SRC_OAT_JNI_ARM_CALLING_CONVENTION_ARM_H_
diff --git a/src/jni_internal_arm.cc b/src/oat/jni/arm/jni_internal_arm.cc
similarity index 96%
rename from src/jni_internal_arm.cc
rename to src/oat/jni/arm/jni_internal_arm.cc
index 476c623..2227742 100644
--- a/src/jni_internal_arm.cc
+++ b/src/oat/jni/arm/jni_internal_arm.cc
@@ -19,9 +19,10 @@
#include <algorithm>
#include "asm_support.h"
-#include "assembler.h"
#include "compiled_method.h"
#include "compiler.h"
+#include "oat/utils/arm/assembler_arm.h"
+#include "oat/utils/assembler.h"
#include "object.h"
namespace art {
@@ -162,6 +163,7 @@
} // namespace arm
} // namespace art
-extern "C" art::CompiledInvokeStub* ArtCreateInvokeStub(art::Compiler& compiler, bool is_static, const char* shorty, uint32_t shorty_len) {
+extern "C" art::CompiledInvokeStub* ArtCreateInvokeStub(art::Compiler& /*compiler*/, bool is_static,
+ const char* shorty, uint32_t shorty_len) {
return art::arm::CreateInvokeStub(is_static, shorty, shorty_len);
}
diff --git a/src/calling_convention.cc b/src/oat/jni/calling_convention.cc
similarity index 97%
rename from src/calling_convention.cc
rename to src/oat/jni/calling_convention.cc
index 396c9dd..e7b9cc8 100644
--- a/src/calling_convention.cc
+++ b/src/oat/jni/calling_convention.cc
@@ -16,8 +16,8 @@
#include "calling_convention.h"
-#include "calling_convention_arm.h"
-#include "calling_convention_x86.h"
+#include "oat/jni/arm/calling_convention_arm.h"
+#include "oat/jni/x86/calling_convention_x86.h"
#include "logging.h"
#include "utils.h"
diff --git a/src/calling_convention.h b/src/oat/jni/calling_convention.h
similarity index 97%
rename from src/calling_convention.h
rename to src/oat/jni/calling_convention.h
index 3a0eb5a..7e42904 100644
--- a/src/calling_convention.h
+++ b/src/oat/jni/calling_convention.h
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#ifndef ART_SRC_CALLING_CONVENTION_H_
-#define ART_SRC_CALLING_CONVENTION_H_
+#ifndef ART_SRC_OAT_JNI_CALLING_CONVENTION_H_
+#define ART_SRC_OAT_JNI_CALLING_CONVENTION_H_
#include <vector>
-#include "managed_register.h"
+#include "oat/utils/managed_register.h"
#include "stack_indirect_reference_table.h"
#include "thread.h"
@@ -284,4 +284,4 @@
} // namespace art
-#endif // ART_SRC_CALLING_CONVENTION_H_
+#endif // ART_SRC_OAT_JNI_CALLING_CONVENTION_H_
diff --git a/src/jni_compiler.cc b/src/oat/jni/jni_compiler.cc
similarity index 98%
rename from src/jni_compiler.cc
rename to src/oat/jni/jni_compiler.cc
index 08d3109..30341c2 100644
--- a/src/jni_compiler.cc
+++ b/src/oat/jni/jni_compiler.cc
@@ -17,7 +17,6 @@
#include <sys/mman.h>
#include <vector>
-#include "assembler.h"
#include "calling_convention.h"
#include "class_linker.h"
#include "compiled_method.h"
@@ -26,7 +25,9 @@
#include "jni_internal.h"
#include "logging.h"
#include "macros.h"
-#include "managed_register.h"
+#include "oat/runtime/oat_support_entrypoints.h"
+#include "oat/utils/assembler.h"
+#include "oat/utils/managed_register.h"
#include "thread.h"
#include "UniquePtr.h"
@@ -171,7 +172,6 @@
//
CompiledMethod* ArtJniCompileMethodInternal(Compiler& compiler,
uint32_t access_flags, uint32_t method_idx,
- const ClassLoader* class_loader,
const DexFile& dex_file) {
CHECK((access_flags & kAccNative) != 0);
const bool is_static = (access_flags & kAccStatic) != 0;
@@ -505,12 +505,12 @@
if (jni_conv->IsCurrentParamInRegister()) {
__ GetCurrentThread(jni_conv->CurrentParamRegister());
__ Call(jni_conv->CurrentParamRegister(),
- Offset(OFFSETOF_MEMBER(Thread, pDecodeJObjectInThread)),
+ Offset(ENTRYPOINT_OFFSET(pDecodeJObjectInThread)),
jni_conv->InterproceduralScratchRegister());
} else {
__ GetCurrentThread(jni_conv->CurrentParamStackOffset(),
jni_conv->InterproceduralScratchRegister());
- __ Call(ThreadOffset(OFFSETOF_MEMBER(Thread, pDecodeJObjectInThread)),
+ __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pDecodeJObjectInThread)),
jni_conv->InterproceduralScratchRegister());
}
@@ -565,7 +565,6 @@
extern "C" art::CompiledMethod* ArtJniCompileMethod(art::Compiler& compiler,
uint32_t access_flags, uint32_t method_idx,
- const art::ClassLoader* class_loader,
const art::DexFile& dex_file) {
- return ArtJniCompileMethodInternal(compiler, access_flags, method_idx, class_loader, dex_file);
+ return ArtJniCompileMethodInternal(compiler, access_flags, method_idx, dex_file);
}
diff --git a/src/calling_convention_x86.cc b/src/oat/jni/x86/calling_convention_x86.cc
similarity index 98%
rename from src/calling_convention_x86.cc
rename to src/oat/jni/x86/calling_convention_x86.cc
index 15f4495..1f66d71 100644
--- a/src/calling_convention_x86.cc
+++ b/src/oat/jni/x86/calling_convention_x86.cc
@@ -15,8 +15,9 @@
*/
#include "calling_convention_x86.h"
+
#include "logging.h"
-#include "managed_register_x86.h"
+#include "oat/utils/x86/managed_register_x86.h"
#include "utils.h"
namespace art {
diff --git a/src/calling_convention_x86.h b/src/oat/jni/x86/calling_convention_x86.h
similarity index 92%
rename from src/calling_convention_x86.h
rename to src/oat/jni/x86/calling_convention_x86.h
index 4bca318..e32b8fd 100644
--- a/src/calling_convention_x86.h
+++ b/src/oat/jni/x86/calling_convention_x86.h
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#ifndef ART_SRC_CALLING_CONVENTION_X86_H_
-#define ART_SRC_CALLING_CONVENTION_X86_H_
+#ifndef ART_SRC_OAT_JNI_X86_CALLING_CONVENTION_X86_H_
+#define ART_SRC_OAT_JNI_X86_CALLING_CONVENTION_X86_H_
-#include "calling_convention.h"
+#include "oat/jni/calling_convention.h"
namespace art {
namespace x86 {
@@ -83,4 +83,4 @@
} // namespace x86
} // namespace art
-#endif // ART_SRC_CALLING_CONVENTION_X86_H_
+#endif // ART_SRC_OAT_JNI_X86_CALLING_CONVENTION_X86_H_
diff --git a/src/jni_internal_x86.cc b/src/oat/jni/x86/jni_internal_x86.cc
similarity index 96%
rename from src/jni_internal_x86.cc
rename to src/oat/jni/x86/jni_internal_x86.cc
index 86d7749..6abeb49 100644
--- a/src/jni_internal_x86.cc
+++ b/src/oat/jni/x86/jni_internal_x86.cc
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-#include "assembler.h"
#include "compiled_method.h"
#include "compiler.h"
+#include "oat/utils/assembler.h"
+#include "oat/utils/x86/assembler_x86.h"
#include "object.h"
namespace art {
@@ -162,6 +163,7 @@
} // namespace x86
} // namespace art
-extern "C" art::CompiledInvokeStub* ArtCreateInvokeStub(art::Compiler& compiler, bool is_static, const char* shorty, uint32_t shorty_len) {
+extern "C" art::CompiledInvokeStub* ArtCreateInvokeStub(art::Compiler& /*compiler*/, bool is_static,
+ const char* shorty, uint32_t shorty_len) {
return art::x86::CreateInvokeStub(is_static, shorty, shorty_len);
}
diff --git a/src/context_arm.cc b/src/oat/runtime/arm/context_arm.cc
similarity index 95%
rename from src/context_arm.cc
rename to src/oat/runtime/arm/context_arm.cc
index d0bc6c7..28f1db9 100644
--- a/src/context_arm.cc
+++ b/src/oat/runtime/arm/context_arm.cc
@@ -17,7 +17,6 @@
#include "context_arm.h"
#include "object.h"
-#include "runtime_support.h"
namespace art {
namespace arm {
@@ -62,12 +61,10 @@
}
}
+extern "C" void art_do_long_jump(uint32_t*, uint32_t*);
+
void ArmContext::DoLongJump() {
-#if defined(__arm__)
art_do_long_jump(&gprs_[0], &fprs_[S0]);
-#else
- UNIMPLEMENTED(FATAL);
-#endif
}
} // namespace arm
diff --git a/src/context_arm.h b/src/oat/runtime/arm/context_arm.h
similarity index 86%
rename from src/context_arm.h
rename to src/oat/runtime/arm/context_arm.h
index 9ee0754..216d282 100644
--- a/src/context_arm.h
+++ b/src/oat/runtime/arm/context_arm.h
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#ifndef ART_SRC_CONTEXT_ARM_H_
-#define ART_SRC_CONTEXT_ARM_H_
+#ifndef ART_SRC_OAT_RUNTIME_ARM_CONTEXT_ARM_H_
+#define ART_SRC_OAT_RUNTIME_ARM_CONTEXT_ARM_H_
#include "constants_arm.h"
-#include "context.h"
+#include "oat/runtime/context.h"
namespace art {
namespace arm {
@@ -54,4 +54,4 @@
} // namespace arm
} // namespace art
-#endif // ART_SRC_CONTEXT_ARM_H_
+#endif // ART_SRC_OAT_RUNTIME_ARM_CONTEXT_ARM_H_
diff --git a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
new file mode 100644
index 0000000..fcff424
--- /dev/null
+++ b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2012 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 "oat/runtime/oat_support_entrypoints.h"
+
+namespace art {
+
+// Alloc entrypoints.
+extern "C" void* art_alloc_array_from_code(uint32_t, void*, int32_t);
+extern "C" void* art_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
+extern "C" void* art_alloc_object_from_code(uint32_t type_idx, void* method);
+extern "C" void* art_alloc_object_from_code_with_access_check(uint32_t type_idx, void* method);
+extern "C" void* art_check_and_alloc_array_from_code(uint32_t, void*, int32_t);
+extern "C" void* art_check_and_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
+
+// Cast entrypoints.
+extern uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class);
+extern "C" void art_can_put_array_element_from_code(void*, void*);
+extern "C" void art_check_cast_from_code(void*, void*);
+
+// Debug entrypoints.
+extern void DebugMe(Method* method, uint32_t info);
+extern "C" void art_update_debugger(void*, void*, int32_t, void*);
+
+// DexCache entrypoints.
+extern "C" void* art_initialize_static_storage_from_code(uint32_t, void*);
+extern "C" void* art_initialize_type_from_code(uint32_t, void*);
+extern "C" void* art_initialize_type_and_verify_access_from_code(uint32_t, void*);
+extern "C" void* art_resolve_string_from_code(void*, uint32_t);
+
+// Field entrypoints.
+extern "C" int art_set32_instance_from_code(uint32_t, void*, int32_t);
+extern "C" int art_set32_static_from_code(uint32_t, int32_t);
+extern "C" int art_set64_instance_from_code(uint32_t, void*, int64_t);
+extern "C" int art_set64_static_from_code(uint32_t, int64_t);
+extern "C" int art_set_obj_instance_from_code(uint32_t, void*, void*);
+extern "C" int art_set_obj_static_from_code(uint32_t, void*);
+extern "C" int32_t art_get32_instance_from_code(uint32_t, void*);
+extern "C" int32_t art_get32_static_from_code(uint32_t);
+extern "C" int64_t art_get64_instance_from_code(uint32_t, void*);
+extern "C" int64_t art_get64_static_from_code(uint32_t);
+extern "C" void* art_get_obj_instance_from_code(uint32_t, void*);
+extern "C" void* art_get_obj_static_from_code(uint32_t);
+
+// FillArray entrypoint.
+extern "C" void art_handle_fill_data_from_code(void*, void*);
+
+// JNI entrypoints.
+extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
+extern void* FindNativeMethod(Thread* thread);
+
+// Lock entrypoints.
+extern "C" void art_lock_object_from_code(void*);
+extern "C" void art_unlock_object_from_code(void*);
+
+// Math entrypoints.
+extern int32_t CmpgDouble(double a, double b);
+extern int32_t CmplDouble(double a, double b);
+extern int32_t CmpgFloat(float a, float b);
+extern int32_t CmplFloat(float a, float b);
+
+// Math conversions.
+extern "C" float __aeabi_i2f(int32_t op1); // INT_TO_FLOAT
+extern "C" int32_t __aeabi_f2iz(float op1); // FLOAT_TO_INT
+extern "C" float __aeabi_d2f(double op1); // DOUBLE_TO_FLOAT
+extern "C" double __aeabi_f2d(float op1); // FLOAT_TO_DOUBLE
+extern "C" double __aeabi_i2d(int32_t op1); // INT_TO_DOUBLE
+extern "C" int32_t __aeabi_d2iz(double op1); // DOUBLE_TO_INT
+extern "C" float __aeabi_l2f(int64_t op1); // LONG_TO_FLOAT
+extern "C" double __aeabi_l2d(int64_t op1); // LONG_TO_DOUBLE
+extern int64_t D2L(double d);
+extern int64_t F2L(float f);
+
+// Single-precision FP arithmetics.
+extern "C" float __aeabi_fadd(float a, float b); // ADD_FLOAT[_2ADDR]
+extern "C" float __aeabi_fsub(float a, float b); // SUB_FLOAT[_2ADDR]
+extern "C" float __aeabi_fdiv(float a, float b); // DIV_FLOAT[_2ADDR]
+extern "C" float __aeabi_fmul(float a, float b); // MUL_FLOAT[_2ADDR]
+extern "C" float fmodf(float a, float b); // REM_FLOAT[_2ADDR]
+
+// Double-precision FP arithmetics.
+extern "C" double __aeabi_dadd(double a, double b); // ADD_DOUBLE[_2ADDR]
+extern "C" double __aeabi_dsub(double a, double b); // SUB_DOUBLE[_2ADDR]
+extern "C" double __aeabi_ddiv(double a, double b); // DIV_DOUBLE[_2ADDR]
+extern "C" double __aeabi_dmul(double a, double b); // MUL_DOUBLE[_2ADDR]
+extern "C" double fmod(double a, double b); // REM_DOUBLE[_2ADDR]
+
+// Integer arithmetics.
+extern "C" int __aeabi_idivmod(int32_t op1, int32_t op2); // REM_INT[_2ADDR|_LIT8|_LIT16]
+extern "C" int __aeabi_idiv(int32_t op1, int32_t op2); // DIV_INT[_2ADDR|_LIT8|_LIT16]
+
+// Long long arithmetics - REM_LONG[_2ADDR] and DIV_LONG[_2ADDR]
+extern "C" long long __aeabi_ldivmod(long long op1, long long op2);
+extern "C" long long __aeabi_lmul(long long op1, long long op2);
+extern "C" uint64_t art_shl_long(uint64_t, uint32_t);
+extern "C" uint64_t art_shr_long(uint64_t, uint32_t);
+extern "C" uint64_t art_ushr_long(uint64_t, uint32_t);
+
+// Intrinsic entrypoints.
+extern "C" int32_t __memcmp16(void*, void*, int32_t);
+extern "C" int32_t art_indexof(void*, uint32_t, uint32_t, uint32_t);
+extern "C" int32_t art_string_compareto(void*, void*);
+
+// Invoke entrypoints.
+const void* UnresolvedDirectMethodTrampolineFromCode(Method*, Method**, Thread*,
+ Runtime::TrampolineType);
+extern "C" void art_invoke_direct_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_interface_trampoline(uint32_t, void*);
+extern "C" void art_invoke_interface_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_static_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_super_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
+
+// Thread entrypoints.
+extern void CheckSuspendFromCode(Thread* thread);
+extern "C" void art_test_suspend();
+
+// Throw entrypoints.
+extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
+extern "C" void art_deliver_exception_from_code(void*);
+extern "C" void art_throw_array_bounds_from_code(int32_t index, int32_t limit);
+extern "C" void art_throw_div_zero_from_code();
+extern "C" void art_throw_no_such_method_from_code(int32_t method_idx);
+extern "C" void art_throw_null_pointer_exception_from_code();
+extern "C" void art_throw_stack_overflow_from_code(void*);
+extern "C" void art_throw_verification_error_from_code(int32_t src1, int32_t ref);
+
+// Trace entrypoints.
+extern "C" void art_trace_entry_from_code(void*);
+extern "C" void art_trace_exit_from_code();
+
+void InitEntryPoints(EntryPoints* points) {
+ // Alloc
+ points->pAllocArrayFromCode = art_alloc_array_from_code;
+ points->pAllocArrayFromCodeWithAccessCheck = art_alloc_array_from_code_with_access_check;
+ points->pAllocObjectFromCode = art_alloc_object_from_code;
+ points->pAllocObjectFromCodeWithAccessCheck = art_alloc_object_from_code_with_access_check;
+ points->pCheckAndAllocArrayFromCode = art_check_and_alloc_array_from_code;
+ points->pCheckAndAllocArrayFromCodeWithAccessCheck = art_check_and_alloc_array_from_code_with_access_check;
+
+ // Cast
+ points->pInstanceofNonTrivialFromCode = IsAssignableFromCode;
+ points->pCanPutArrayElementFromCode = art_can_put_array_element_from_code;
+ points->pCheckCastFromCode = art_check_cast_from_code;
+
+ // Debug
+ points->pDebugMe = DebugMe;
+ points->pUpdateDebuggerFromCode = NULL; // Controlled by SetDebuggerUpdatesEnabled.
+
+ // DexCache
+ points->pInitializeStaticStorage = art_initialize_static_storage_from_code;
+ points->pInitializeTypeAndVerifyAccessFromCode = art_initialize_type_and_verify_access_from_code;
+ points->pInitializeTypeFromCode = art_initialize_type_from_code;
+ points->pResolveStringFromCode = art_resolve_string_from_code;
+
+ // Field
+ points->pSet32Instance = art_set32_instance_from_code;
+ points->pSet32Static = art_set32_static_from_code;
+ points->pSet64Instance = art_set64_instance_from_code;
+ points->pSet64Static = art_set64_static_from_code;
+ points->pSetObjInstance = art_set_obj_instance_from_code;
+ points->pSetObjStatic = art_set_obj_static_from_code;
+ points->pGet32Instance = art_get32_instance_from_code;
+ points->pGet64Instance = art_get64_instance_from_code;
+ points->pGetObjInstance = art_get_obj_instance_from_code;
+ points->pGet32Static = art_get32_static_from_code;
+ points->pGet64Static = art_get64_static_from_code;
+ points->pGetObjStatic = art_get_obj_static_from_code;
+
+ // FillArray
+ points->pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
+
+ // JNI
+ points->pDecodeJObjectInThread = DecodeJObjectInThread;
+ points->pFindNativeMethod = FindNativeMethod;
+
+ // Locks
+ points->pLockObjectFromCode = art_lock_object_from_code;
+ points->pUnlockObjectFromCode = art_unlock_object_from_code;
+
+ // Math
+ points->pCmpgDouble = CmpgDouble;
+ points->pCmpgFloat = CmpgFloat;
+ points->pCmplDouble = CmplDouble;
+ points->pCmplFloat = CmplFloat;
+ points->pDadd = __aeabi_dadd;
+ points->pDdiv = __aeabi_ddiv;
+ points->pDmul = __aeabi_dmul;
+ points->pDsub = __aeabi_dsub;
+ points->pF2d = __aeabi_f2d;
+ points->pFmod = fmod;
+ points->pI2d = __aeabi_i2d;
+ points->pL2d = __aeabi_l2d;
+ points->pD2f = __aeabi_d2f;
+ points->pFadd = __aeabi_fadd;
+ points->pFdiv = __aeabi_fdiv;
+ points->pFmodf = fmodf;
+ points->pFmul = __aeabi_fmul;
+ points->pFsub = __aeabi_fsub;
+ points->pI2f = __aeabi_i2f;
+ points->pL2f = __aeabi_l2f;
+ points->pD2iz = __aeabi_d2iz;
+ points->pF2iz = __aeabi_f2iz;
+ points->pIdiv = __aeabi_idivmod;
+ points->pIdivmod = __aeabi_idivmod;
+ points->pD2l = D2L;
+ points->pF2l = F2L;
+ points->pLadd = NULL;
+ points->pLand = NULL;
+ points->pLdivmod = __aeabi_ldivmod;
+ points->pLmul = __aeabi_lmul;
+ points->pLor = NULL;
+ points->pLsub = NULL;
+ points->pLxor = NULL;
+ points->pShlLong = art_shl_long;
+ points->pShrLong = art_shr_long;
+ points->pUshrLong = art_ushr_long;
+
+ // Intrinsics
+ points->pIndexOf = art_indexof;
+ points->pMemcmp16 = __memcmp16;
+ points->pStringCompareTo = art_string_compareto;
+ points->pMemcpy = memcpy;
+
+ // Invocation
+ points->pUnresolvedDirectMethodTrampolineFromCode = UnresolvedDirectMethodTrampolineFromCode;
+ points->pInvokeDirectTrampolineWithAccessCheck = art_invoke_direct_trampoline_with_access_check;
+ points->pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
+ points->pInvokeInterfaceTrampolineWithAccessCheck = art_invoke_interface_trampoline_with_access_check;
+ points->pInvokeStaticTrampolineWithAccessCheck = art_invoke_static_trampoline_with_access_check;
+ points->pInvokeSuperTrampolineWithAccessCheck = art_invoke_super_trampoline_with_access_check;
+ points->pInvokeVirtualTrampolineWithAccessCheck = art_invoke_virtual_trampoline_with_access_check;
+
+ // Thread
+ points->pCheckSuspendFromCode = CheckSuspendFromCode;
+ points->pTestSuspendFromCode = art_test_suspend;
+
+ // Throws
+ points->pDeliverException = art_deliver_exception_from_code;
+ points->pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;
+ points->pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code;
+ points->pThrowDivZeroFromCode = art_throw_div_zero_from_code;
+ points->pThrowNoSuchMethodFromCode = art_throw_no_such_method_from_code;
+ points->pThrowNullPointerFromCode = art_throw_null_pointer_exception_from_code;
+ points->pThrowStackOverflowFromCode = art_throw_stack_overflow_from_code;
+ points->pThrowVerificationErrorFromCode = art_throw_verification_error_from_code;
+};
+
+void ChangeDebuggerEntryPoint(EntryPoints* points, bool enabled) {
+ points->pUpdateDebuggerFromCode = (enabled ? art_update_debugger : NULL);
+}
+
+bool IsTraceExitPc(uintptr_t pc) {
+ uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_trace_exit_from_code);
+ return pc == trace_exit;
+}
+
+void* GetLogTraceEntryPoint() {
+ return reinterpret_cast<void*>(art_trace_entry_from_code);
+}
+
+} // namespace art
diff --git a/src/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
similarity index 90%
rename from src/runtime_support_arm.S
rename to src/oat/runtime/arm/runtime_support_arm.S
index 653465a..5446919 100644
--- a/src/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -1,17 +1,20 @@
#include "asm_support.h"
- .balign 4
-
/* Deliver the given exception */
.extern artDeliverExceptionFromCode
/* Deliver an exception pending on a thread */
.extern artDeliverPendingException
+ /* Cache alignment for function entry */
+.macro ALIGN_FUNCTION_ENTRY
+ .balign 16
+.endm
+
/*
* Macro that sets up the callee save frame to conform with
* Runtime::CreateCalleeSaveMethod(kSaveAll)
*/
-.macro SETUP_CALLEE_SAVE_FRAME
+.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
push {r4-r11, lr} @ 9 words of callee saves
vpush {s0-s31}
sub sp, #12 @ 3 words of space, bottom word will hold Method*
@@ -58,117 +61,81 @@
* exception is Thread::Current()->exception_
*/
.macro DELIVER_PENDING_EXCEPTION
- SETUP_CALLEE_SAVE_FRAME @ save callee saves for throw
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME @ save callee saves for throw
mov r0, r9 @ pass Thread::Current
mov r1, sp @ pass SP
b artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
.endm
- .global art_update_debugger
- .extern artUpdateDebuggerFromCode
- /*
- * On entry, r0 and r1 must be preserved, r2 is dex PC
- */
-art_update_debugger:
- mov r3, r0 @ stash away r0 so that it's saved as if it were an argument
- SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
- mov r0, r2 @ arg0 is dex PC
- mov r1, rSELF @ arg1 is Thread*
- mov r2, sp @ arg2 is sp
- bl artUpdateDebuggerFromCode @ artUpdateDebuggerFromCode(int32_t, Thread*, Method**)
- RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
- mov r0, r3 @ restore original r0
- bx lr
+.macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
+ .global \c_name
+ .extern \cxx_name
+ ALIGN_FUNCTION_ENTRY
+\c_name:
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
+ mov r0, r9 @ pass Thread::Current
+ mov r1, sp @ pass SP
+ b \cxx_name @ \cxx_name(Thread*, SP)
+.endm
- .global art_do_long_jump
- /*
- * On entry r0 is uint32_t* gprs_ and r1 is uint32_t* fprs_
- */
-art_do_long_jump:
- vldm r1, {s0-s31} @ load all fprs from argument fprs_
- ldr r2, [r0, #60] @ r2 = r15 (PC from gprs_ 60=4*15)
- add r0, r0, #12 @ increment r0 to skip gprs_[0..2] 12=4*3
- ldm r0, {r3-r14} @ load remaining gprs from argument gprs_
- mov r0, #0 @ clear result registers r0 and r1
- mov r1, #0
- bx r2 @ do long jump
-
- .global art_deliver_exception_from_code
- /*
- * Called by managed code, saves most registers (forms basis of long jump context) and passes
- * the bottom of the stack. artDeliverExceptionFromCode will place the callee save Method* at
- * the bottom of the thread. On entry r0 holds Throwable*
- */
-art_deliver_exception_from_code:
- SETUP_CALLEE_SAVE_FRAME
+.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
+ .global \c_name
+ .extern \cxx_name
+ ALIGN_FUNCTION_ENTRY
+\c_name:
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
mov r1, r9 @ pass Thread::Current
mov r2, sp @ pass SP
- b artDeliverExceptionFromCode @ artDeliverExceptionFromCode(Throwable*, Thread*, SP)
+ b \cxx_name @ \cxx_name(Thread*, SP)
+.endm
- .global art_throw_null_pointer_exception_from_code
- .extern artThrowNullPointerExceptionFromCode
- /*
- * Called by managed code to create and deliver a NullPointerException
- */
-art_throw_null_pointer_exception_from_code:
- SETUP_CALLEE_SAVE_FRAME
- mov r0, r9 @ pass Thread::Current
- mov r1, sp @ pass SP
- b artThrowNullPointerExceptionFromCode @ artThrowNullPointerExceptionFromCode(Thread*, SP)
-
- .global art_throw_div_zero_from_code
- .extern artThrowDivZeroFromCode
- /*
- * Called by managed code to create and deliver an ArithmeticException
- */
-art_throw_div_zero_from_code:
- SETUP_CALLEE_SAVE_FRAME
- mov r0, r9 @ pass Thread::Current
- mov r1, sp @ pass SP
- b artThrowDivZeroFromCode @ artThrowDivZeroFromCode(Thread*, SP)
-
- .global art_throw_array_bounds_from_code
- .extern artThrowArrayBoundsFromCode
- /*
- * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException
- */
-art_throw_array_bounds_from_code:
- SETUP_CALLEE_SAVE_FRAME
+.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
+ .global \c_name
+ .extern \cxx_name
+ ALIGN_FUNCTION_ENTRY
+\c_name:
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
mov r2, r9 @ pass Thread::Current
mov r3, sp @ pass SP
- b artThrowArrayBoundsFromCode @ artThrowArrayBoundsFromCode(index, limit, Thread*, SP)
+ b \cxx_name @ \cxx_name(Thread*, SP)
+.endm
- .global art_throw_stack_overflow_from_code
- .extern artThrowStackOverflowFromCode
-art_throw_stack_overflow_from_code:
- SETUP_CALLEE_SAVE_FRAME
- mov r1, r9 @ pass Thread::Current
- mov r2, sp @ pass SP
- b artThrowStackOverflowFromCode @ artThrowStackOverflowFromCode(method, Thread*, SP)
+ /*
+ * Called by managed code, saves callee saves and then calls artThrowException
+ * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception.
+ */
+ONE_ARG_RUNTIME_EXCEPTION art_deliver_exception_from_code, artDeliverExceptionFromCode
- .global art_throw_neg_array_size_from_code
- .extern artThrowNegArraySizeFromCode
-art_throw_neg_array_size_from_code:
- SETUP_CALLEE_SAVE_FRAME
- mov r1, r9 @ pass Thread::Current
- mov r2, sp @ pass SP
- b artThrowNegArraySizeFromCode @ artThrowNegArraySizeFromCode(size, Thread*, SP)
+ /*
+ * Called by managed code to create and deliver a NullPointerException.
+ */
+NO_ARG_RUNTIME_EXCEPTION art_throw_null_pointer_exception_from_code, artThrowNullPointerExceptionFromCode
- .global art_throw_no_such_method_from_code
- .extern artThrowNoSuchMethodFromCode
-art_throw_no_such_method_from_code:
- SETUP_CALLEE_SAVE_FRAME
- mov r1, r9 @ pass Thread::Current
- mov r2, sp @ pass SP
- b artThrowNoSuchMethodFromCode @ artThrowNoSuchMethodFromCode(method_idx, Thread*, SP)
+ /*
+ * Called by managed code to create and deliver an ArithmeticException.
+ */
+NO_ARG_RUNTIME_EXCEPTION art_throw_div_zero_from_code, artThrowDivZeroFromCode
- .global art_throw_verification_error_from_code
- .extern artThrowVerificationErrorFromCode
-art_throw_verification_error_from_code:
- SETUP_CALLEE_SAVE_FRAME
- mov r2, r9 @ pass Thread::Current
- mov r3, sp @ pass SP
- b artThrowVerificationErrorFromCode @ artThrowVerificationErrorFromCode(kind, ref, Thread*, SP)
+ /*
+ * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
+ * index, arg2 holds limit.
+ */
+TWO_ARG_RUNTIME_EXCEPTION art_throw_array_bounds_from_code, artThrowArrayBoundsFromCode
+
+ /*
+ * Called by managed code to create and deliver a StackOverflowError.
+ */
+NO_ARG_RUNTIME_EXCEPTION art_throw_stack_overflow_from_code, artThrowStackOverflowFromCode
+
+ /*
+ * Called by managed code to create and deliver a NoSuchMethodError.
+ */
+ONE_ARG_RUNTIME_EXCEPTION art_throw_no_such_method_from_code, artThrowNoSuchMethodFromCode
+
+ /*
+ * Called by managed code to create and deliver verification errors. Arg1 is kind, arg2 is ref.
+ */
+TWO_ARG_RUNTIME_EXCEPTION art_throw_verification_error_from_code, artThrowVerificationErrorFromCode
/*
* All generated callsites for interface invokes and invocation slow paths will load arguments
@@ -189,6 +156,7 @@
.macro INVOKE_TRAMPOLINE c_name, cxx_name
.global \c_name
.extern \cxx_name
+ ALIGN_FUNCTION_ENTRY
\c_name:
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC
ldr r2, [sp, #48] @ pass caller Method*
@@ -210,11 +178,43 @@
INVOKE_TRAMPOLINE art_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
INVOKE_TRAMPOLINE art_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
+ .global art_update_debugger
+ .extern artUpdateDebuggerFromCode
+ /*
+ * On entry, r0 and r1 must be preserved, r2 is dex PC
+ */
+ ALIGN_FUNCTION_ENTRY
+art_update_debugger:
+ mov r3, r0 @ stash away r0 so that it's saved as if it were an argument
+ SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ mov r0, r2 @ arg0 is dex PC
+ mov r1, rSELF @ arg1 is Thread*
+ mov r2, sp @ arg2 is sp
+ bl artUpdateDebuggerFromCode @ artUpdateDebuggerFromCode(int32_t, Thread*, Method**)
+ RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ mov r0, r3 @ restore original r0
+ bx lr
+
+ .global art_do_long_jump
+ /*
+ * On entry r0 is uint32_t* gprs_ and r1 is uint32_t* fprs_
+ */
+ ALIGN_FUNCTION_ENTRY
+art_do_long_jump:
+ vldm r1, {s0-s31} @ load all fprs from argument fprs_
+ ldr r2, [r0, #60] @ r2 = r15 (PC from gprs_ 60=4*15)
+ add r0, r0, #12 @ increment r0 to skip gprs_[0..2] 12=4*3
+ ldm r0, {r3-r14} @ load remaining gprs from argument gprs_
+ mov r0, #0 @ clear result registers r0 and r1
+ mov r1, #0
+ bx r2 @ do long jump
+
.global art_work_around_app_jni_bugs
.extern artWorkAroundAppJniBugs
/*
* Entry point of native methods when JNI bug compatibility is enabled.
*/
+ ALIGN_FUNCTION_ENTRY
art_work_around_app_jni_bugs:
@ save registers that may contain arguments and LR that will be crushed by a call
push {r0-r3, lr}
@@ -233,6 +233,7 @@
* Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
* failure.
*/
+ ALIGN_FUNCTION_ENTRY
art_handle_fill_data_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC
mov r2, r9 @ pass Thread::Current
@@ -246,8 +247,9 @@
.global art_lock_object_from_code
.extern artLockObjectFromCode
/*
- * Entry from managed code that calls artLockObjectFromCode, may block for GC
+ * Entry from managed code that calls artLockObjectFromCode, may block for GC.
*/
+ ALIGN_FUNCTION_ENTRY
art_lock_object_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case we block
mov r1, r9 @ pass Thread::Current
@@ -260,6 +262,7 @@
/*
* Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
*/
+ ALIGN_FUNCTION_ENTRY
art_unlock_object_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC
mov r1, r9 @ pass Thread::Current
@@ -275,6 +278,7 @@
/*
* Entry from managed code that calls artCheckCastFromCode and delivers exception on failure.
*/
+ ALIGN_FUNCTION_ENTRY
art_check_cast_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC
mov r2, r9 @ pass Thread::Current
@@ -291,6 +295,7 @@
* Entry from managed code that calls artCanPutArrayElementFromCode and delivers exception on
* failure.
*/
+ ALIGN_FUNCTION_ENTRY
art_can_put_array_element_from_code:
cmp r0, #0 @ return if element == NULL
bxeq lr
@@ -310,6 +315,7 @@
* initializer and deliver the exception on error. On success the static storage base is
* returned.
*/
+ ALIGN_FUNCTION_ENTRY
art_initialize_static_storage_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r2, r9 @ pass Thread::Current
@@ -326,6 +332,7 @@
/*
* Entry from managed code when dex cache misses for a type_idx
*/
+ ALIGN_FUNCTION_ENTRY
art_initialize_type_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r2, r9 @ pass Thread::Current
@@ -341,8 +348,9 @@
.extern artInitializeTypeAndVerifyAccessFromCode
/*
* Entry from managed code when type_idx needs to be checked for access and dex cache may also
- * miss
+ * miss.
*/
+ ALIGN_FUNCTION_ENTRY
art_initialize_type_and_verify_access_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r2, r9 @ pass Thread::Current
@@ -357,8 +365,9 @@
.global art_get32_static_from_code
.extern artGet32StaticFromCode
/*
- * Called by managed code to resolve a static field and load a 32-bit primitive value
+ * Called by managed code to resolve a static field and load a 32-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_get32_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
ldr r1, [sp, #32] @ pass referrer
@@ -374,8 +383,9 @@
.global art_get64_static_from_code
.extern artGet64StaticFromCode
/*
- * Called by managed code to resolve a static field and load a 64-bit primitive value
+ * Called by managed code to resolve a static field and load a 64-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_get64_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
ldr r1, [sp, #32] @ pass referrer
@@ -391,8 +401,9 @@
.global art_get_obj_static_from_code
.extern artGetObjStaticFromCode
/*
- * Called by managed code to resolve a static field and load an object reference
+ * Called by managed code to resolve a static field and load an object reference.
*/
+ ALIGN_FUNCTION_ENTRY
art_get_obj_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
ldr r1, [sp, #32] @ pass referrer
@@ -408,8 +419,9 @@
.global art_get32_instance_from_code
.extern artGet32InstanceFromCode
/*
- * Called by managed code to resolve an instance field and load a 32-bit primitive value
+ * Called by managed code to resolve an instance field and load a 32-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_get32_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
ldr r2, [sp, #32] @ pass referrer
@@ -425,8 +437,9 @@
.global art_get64_instance_from_code
.extern artGet64InstanceFromCode
/*
- * Called by managed code to resolve an instance field and load a 64-bit primitive value
+ * Called by managed code to resolve an instance field and load a 64-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_get64_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
ldr r2, [sp, #32] @ pass referrer
@@ -442,8 +455,9 @@
.global art_get_obj_instance_from_code
.extern artGetObjInstanceFromCode
/*
- * Called by managed code to resolve an instance field and load an object reference
+ * Called by managed code to resolve an instance field and load an object reference.
*/
+ ALIGN_FUNCTION_ENTRY
art_get_obj_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
ldr r2, [sp, #32] @ pass referrer
@@ -459,8 +473,9 @@
.global art_set32_static_from_code
.extern artSet32StaticFromCode
/*
- * Called by managed code to resolve a static field and store a 32-bit primitive value
+ * Called by managed code to resolve a static field and store a 32-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_set32_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
ldr r2, [sp, #32] @ pass referrer
@@ -475,8 +490,9 @@
.global art_set64_static_from_code
.extern artSet32StaticFromCode
/*
- * Called by managed code to resolve a static field and store a 64-bit primitive value
+ * Called by managed code to resolve a static field and store a 64-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_set64_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
ldr r1, [sp, #32] @ pass referrer
@@ -493,8 +509,9 @@
.global art_set_obj_static_from_code
.extern artSetObjStaticFromCode
/*
- * Called by managed code to resolve a static field and store an object reference
+ * Called by managed code to resolve a static field and store an object reference.
*/
+ ALIGN_FUNCTION_ENTRY
art_set_obj_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
ldr r2, [sp, #32] @ pass referrer
@@ -509,8 +526,9 @@
.global art_set32_instance_from_code
.extern artSet32InstanceFromCode
/*
- * Called by managed code to resolve an instance field and store a 32-bit primitive value
+ * Called by managed code to resolve an instance field and store a 32-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_set32_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
ldr r3, [sp, #32] @ pass referrer
@@ -527,8 +545,9 @@
.global art_set64_instance_from_code
.extern artSet32InstanceFromCode
/*
- * Called by managed code to resolve an instance field and store a 64-bit primitive value
+ * Called by managed code to resolve an instance field and store a 64-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_set64_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r12, sp @ save SP
@@ -544,8 +563,9 @@
.global art_set_obj_instance_from_code
.extern artSetObjInstanceFromCode
/*
- * Called by managed code to resolve an instance field and store an object reference
+ * Called by managed code to resolve an instance field and store an object reference.
*/
+ ALIGN_FUNCTION_ENTRY
art_set_obj_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
ldr r3, [sp, #32] @ pass referrer
@@ -567,6 +587,7 @@
* R1 holds the string index. The fast path check for hit in strings cache has already been
* performed.
*/
+ ALIGN_FUNCTION_ENTRY
art_resolve_string_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r2, r9 @ pass Thread::Current
@@ -583,6 +604,7 @@
/*
* Called by managed code to allocate an object
*/
+ ALIGN_FUNCTION_ENTRY
art_alloc_object_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r2, r9 @ pass Thread::Current
@@ -597,8 +619,9 @@
.extern artAllocObjectFromCodeWithAccessCheck
/*
* Called by managed code to allocate an object when the caller doesn't know whether it has
- * access to the created type
+ * access to the created type.
*/
+ ALIGN_FUNCTION_ENTRY
art_alloc_object_from_code_with_access_check:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r2, r9 @ pass Thread::Current
@@ -612,8 +635,9 @@
.global art_alloc_array_from_code
.extern artAllocArrayFromCode
/*
- * Called by managed code to allocate an array
+ * Called by managed code to allocate an array.
*/
+ ALIGN_FUNCTION_ENTRY
art_alloc_array_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r3, r9 @ pass Thread::Current
@@ -629,8 +653,9 @@
.extern artAllocArrayFromCodeWithAccessCheck
/*
* Called by managed code to allocate an array when the caller doesn't know whether it has
- * access to the created type
+ * access to the created type.
*/
+ ALIGN_FUNCTION_ENTRY
art_alloc_array_from_code_with_access_check:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r3, r9 @ pass Thread::Current
@@ -645,8 +670,9 @@
.global art_check_and_alloc_array_from_code
.extern artCheckAndAllocArrayFromCode
/*
- * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY
+ * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
*/
+ ALIGN_FUNCTION_ENTRY
art_check_and_alloc_array_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r3, r9 @ pass Thread::Current
@@ -661,8 +687,9 @@
.global art_check_and_alloc_array_from_code_with_access_check
.extern artCheckAndAllocArrayFromCodeWithAccessCheck
/*
- * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY
+ * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
*/
+ ALIGN_FUNCTION_ENTRY
art_check_and_alloc_array_from_code_with_access_check:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r3, r9 @ pass Thread::Current
@@ -677,8 +704,9 @@
.global art_test_suspend
.extern artTestSuspendFromCode
/*
- * Called by managed code when the value in rSUSPEND has been decremented to 0
+ * Called by managed code when the value in rSUSPEND has been decremented to 0.
*/
+ ALIGN_FUNCTION_ENTRY
art_test_suspend:
ldr r0, [rSELF, #THREAD_SUSPEND_COUNT_OFFSET]
mov rSUSPEND, #SUSPEND_CHECK_INTERVAL @ reset rSUSPEND to SUSPEND_CHECK_INTERVAL
@@ -694,8 +722,9 @@
.extern artProxyInvokeHandler
/*
* Called by managed code that is attempting to call a method on a proxy class. On entry
- * r0 holds the proxy method; r1, r2 and r3 may contain arguments
+ * r0 holds the proxy method; r1, r2 and r3 may contain arguments.
*/
+ ALIGN_FUNCTION_ENTRY
art_proxy_invoke_handler:
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
str r0, [sp, #0] @ place proxy method at bottom of frame
@@ -713,8 +742,9 @@
.global art_trace_entry_from_code
.extern artTraceMethodEntryFromCode
/*
- * Routine that intercepts method calls
+ * Routine that intercepts method calls.
*/
+ ALIGN_FUNCTION_ENTRY
art_trace_entry_from_code:
push {r0-r3} @ save arguments (4 words)
mov r1, r9 @ pass Thread::Current
@@ -728,8 +758,9 @@
.global art_trace_exit_from_code
.extern artTraceMethodExitFromCode
/*
- * Routine that intercepts method returns
+ * Routine that intercepts method returns.
*/
+ ALIGN_FUNCTION_ENTRY
art_trace_exit_from_code:
push {r0-r1} @ save return value
blx artTraceMethodExitFromCode @ ()
@@ -738,7 +769,6 @@
bx lr @ return
.global art_shl_long
-art_shl_long:
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
@@ -750,6 +780,8 @@
* r2: shift count
*/
/* shl-long vAA, vBB, vCC */
+ ALIGN_FUNCTION_ENTRY
+art_shl_long:
and r2, r2, #63 @ r2<- r2 & 0x3f
mov r1, r1, asl r2 @ r1<- r1 << r2
rsb r3, r2, #32 @ r3<- 32 - r2
@@ -759,9 +791,7 @@
mov r0, r0, asl r2 @ r0<- r0 << r2
bx lr
- .balign 4
.global art_shr_long
-art_shr_long:
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
@@ -773,6 +803,8 @@
* r2: shift count
*/
/* shr-long vAA, vBB, vCC */
+ ALIGN_FUNCTION_ENTRY
+art_shr_long:
and r2, r2, #63 @ r0<- r0 & 0x3f
mov r0, r0, lsr r2 @ r0<- r2 >> r2
rsb r3, r2, #32 @ r3<- 32 - r2
@@ -782,9 +814,7 @@
mov r1, r1, asr r2 @ r1<- r1 >> r2
bx lr
- .balign 4
.global art_ushr_long
-art_ushr_long:
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
@@ -796,6 +826,8 @@
* r2: shift count
*/
/* ushr-long vAA, vBB, vCC */
+ ALIGN_FUNCTION_ENTRY
+art_ushr_long:
and r2, r2, #63 @ r0<- r0 & 0x3f
mov r0, r0, lsr r2 @ r0<- r2 >> r2
rsb r3, r2, #32 @ r3<- 32 - r2
diff --git a/src/stub_arm.cc b/src/oat/runtime/arm/stub_arm.cc
similarity index 93%
rename from src/stub_arm.cc
rename to src/oat/runtime/arm/stub_arm.cc
index 29d6bb2..d6426e8 100644
--- a/src/stub_arm.cc
+++ b/src/oat/runtime/arm/stub_arm.cc
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#include "assembler_arm.h"
#include "jni_internal.h"
+#include "oat/utils/arm/assembler_arm.h"
+#include "oat/runtime/oat_support_entrypoints.h"
#include "object.h"
#include "stack_indirect_reference_table.h"
@@ -42,7 +43,7 @@
// DCHECK_EQ(save, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetCoreSpillMask());
__ PushList(save);
__ LoadFromOffset(kLoadWord, R12, TR,
- OFFSETOF_MEMBER(Thread, pUnresolvedDirectMethodTrampolineFromCode));
+ ENTRYPOINT_OFFSET(pUnresolvedDirectMethodTrampolineFromCode));
__ mov(R2, ShifterOperand(TR)); // Pass Thread::Current() in R2
__ LoadImmediate(R3, type);
__ IncreaseFrameSize(8); // 2 words of space for alignment
@@ -87,7 +88,7 @@
__ mov(R1, ShifterOperand(R9)); // Pass Thread::Current() in R1
__ mov(R2, ShifterOperand(SP)); // Pass SP in R2
// Call to throw AbstractMethodError
- __ LoadFromOffset(kLoadWord, R12, TR, OFFSETOF_MEMBER(Thread, pThrowAbstractMethodErrorFromCode));
+ __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pThrowAbstractMethodErrorFromCode));
__ mov(PC, ShifterOperand(R12)); // Leaf call to routine that never returns
__ bkpt(0);
@@ -111,7 +112,7 @@
__ AddConstant(SP, -12); // Ensure 16-byte alignment
__ mov(R0, ShifterOperand(R9)); // Pass Thread::Current() in R0
// Call FindNativeMethod
- __ LoadFromOffset(kLoadWord, R12, TR, OFFSETOF_MEMBER(Thread, pFindNativeMethod));
+ __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pFindNativeMethod));
__ blx(R12);
__ mov(R12, ShifterOperand(R0)); // Save result of FindNativeMethod in R12
__ AddConstant(SP, 12); // Restore registers (including outgoing arguments)
diff --git a/src/oat/runtime/callee_save_frame.h b/src/oat/runtime/callee_save_frame.h
new file mode 100644
index 0000000..96811ce
--- /dev/null
+++ b/src/oat/runtime/callee_save_frame.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+#ifndef ART_SRC_OAT_RUNTIME_CALLEE_SAVE_FRAME_H_
+#define ART_SRC_OAT_RUNTIME_CALLEE_SAVE_FRAME_H_
+
+#include "thread.h"
+
+namespace art {
+
+class Method;
+
+// Place a special frame at the TOS that will save the callee saves for the given type
+static void FinishCalleeSaveFrameSetup(Thread* self, Method** sp, Runtime::CalleeSaveType type) {
+ // Be aware the store below may well stomp on an incoming argument
+ *sp = Runtime::Current()->GetCalleeSaveMethod(type);
+ self->SetTopOfStack(sp, 0);
+ self->VerifyStack();
+}
+
+} // namespace art
+
+#endif // ART_SRC_OAT_RUNTIME_CALLEE_SAVE_FRAME_H_
diff --git a/src/context.cc b/src/oat/runtime/context.cc
similarity index 92%
rename from src/context.cc
rename to src/oat/runtime/context.cc
index 330ed1e..998e762 100644
--- a/src/context.cc
+++ b/src/oat/runtime/context.cc
@@ -16,8 +16,8 @@
#include "context.h"
-#include "context_arm.h"
-#include "context_x86.h"
+#include "arm/context_arm.h"
+#include "x86/context_x86.h"
namespace art {
diff --git a/src/context.h b/src/oat/runtime/context.h
similarity index 95%
rename from src/context.h
rename to src/oat/runtime/context.h
index 82e8315..b8852d5 100644
--- a/src/context.h
+++ b/src/oat/runtime/context.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_SRC_CONTEXT_H_
-#define ART_SRC_CONTEXT_H_
+#ifndef ART_SRC_OAT_RUNTIME_CONTEXT_H_
+#define ART_SRC_OAT_RUNTIME_CONTEXT_H_
#include <stddef.h>
#include <stdint.h>
@@ -99,4 +99,4 @@
} // namespace art
-#endif // ART_SRC_CONTEXT_H_
+#endif // ART_SRC_OAT_RUNTIME_CONTEXT_H_
diff --git a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
new file mode 100644
index 0000000..e20332a
--- /dev/null
+++ b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2012 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 "oat/runtime/oat_support_entrypoints.h"
+
+namespace art {
+
+// Alloc entrypoints.
+extern "C" void* art_alloc_array_from_code(uint32_t, void*, int32_t);
+extern "C" void* art_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
+extern "C" void* art_alloc_object_from_code(uint32_t type_idx, void* method);
+extern "C" void* art_alloc_object_from_code_with_access_check(uint32_t type_idx, void* method);
+extern "C" void* art_check_and_alloc_array_from_code(uint32_t, void*, int32_t);
+extern "C" void* art_check_and_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
+
+// Cast entrypoints.
+extern uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class);
+extern "C" void art_can_put_array_element_from_code(void*, void*);
+extern "C" void art_check_cast_from_code(void*, void*);
+
+// Debug entrypoints.
+extern void DebugMe(Method* method, uint32_t info);
+extern "C" void art_update_debugger(void*, void*, int32_t, void*);
+
+// DexCache entrypoints.
+extern "C" void* art_initialize_static_storage_from_code(uint32_t, void*);
+extern "C" void* art_initialize_type_from_code(uint32_t, void*);
+extern "C" void* art_initialize_type_and_verify_access_from_code(uint32_t, void*);
+extern "C" void* art_resolve_string_from_code(void*, uint32_t);
+
+// Field entrypoints.
+extern "C" int art_set32_instance_from_code(uint32_t, void*, int32_t);
+extern "C" int art_set32_static_from_code(uint32_t, int32_t);
+extern "C" int art_set64_instance_from_code(uint32_t, void*, int64_t);
+extern "C" int art_set64_static_from_code(uint32_t, int64_t);
+extern "C" int art_set_obj_instance_from_code(uint32_t, void*, void*);
+extern "C" int art_set_obj_static_from_code(uint32_t, void*);
+extern "C" int32_t art_get32_instance_from_code(uint32_t, void*);
+extern "C" int32_t art_get32_static_from_code(uint32_t);
+extern "C" int64_t art_get64_instance_from_code(uint32_t, void*);
+extern "C" int64_t art_get64_static_from_code(uint32_t);
+extern "C" void* art_get_obj_instance_from_code(uint32_t, void*);
+extern "C" void* art_get_obj_static_from_code(uint32_t);
+
+// FillArray entrypoint.
+extern "C" void art_handle_fill_data_from_code(void*, void*);
+
+// JNI entrypoints.
+extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
+extern void* FindNativeMethod(Thread* thread);
+
+// Lock entrypoints.
+extern "C" void art_lock_object_from_code(void*);
+extern "C" void art_unlock_object_from_code(void*);
+
+// Math entrypoints.
+extern int32_t CmpgDouble(double a, double b);
+extern int32_t CmplDouble(double a, double b);
+extern int32_t CmpgFloat(float a, float b);
+extern int32_t CmplFloat(float a, float b);
+
+// Math conversions.
+extern "C" float __floatsisf(int op1); // INT_TO_FLOAT
+extern "C" int32_t __fixsfsi(float op1); // FLOAT_TO_INT
+extern "C" float __truncdfsf2(double op1); // DOUBLE_TO_FLOAT
+extern "C" double __extendsfdf2(float op1); // FLOAT_TO_DOUBLE
+extern "C" double __floatsidf(int op1); // INT_TO_DOUBLE
+extern "C" int32_t __fixdfsi(double op1); // DOUBLE_TO_INT
+extern "C" float __floatdisf(int64_t op1); // LONG_TO_FLOAT
+extern "C" double __floatdidf(int64_t op1); // LONG_TO_DOUBLE
+extern "C" int64_t __fixsfdi(float op1); // FLOAT_TO_LONG
+extern "C" int64_t __fixdfdi(double op1); // DOUBLE_TO_LONG
+extern int64_t D2L(double d);
+extern int64_t F2L(float f);
+
+// Single-precision FP arithmetics.
+extern "C" float __addsf3(float a, float b); // ADD_FLOAT[_2ADDR]
+extern "C" float __subsf3(float a, float b); // SUB_FLOAT[_2ADDR]
+extern "C" float __divsf3(float a, float b); // DIV_FLOAT[_2ADDR]
+extern "C" float __mulsf3(float a, float b); // MUL_FLOAT[_2ADDR]
+extern "C" float fmodf(float a, float b); // REM_FLOAT[_2ADDR]
+
+// Double-precision FP arithmetics.
+extern "C" double __adddf3(double a, double b); // ADD_DOUBLE[_2ADDR]
+extern "C" double __subdf3(double a, double b); // SUB_DOUBLE[_2ADDR]
+extern "C" double __divdf3(double a, double b); // DIV_DOUBLE[_2ADDR]
+extern "C" double __muldf3(double a, double b); // MUL_DOUBLE[_2ADDR]
+extern "C" double fmod(double a, double b); // REM_DOUBLE[_2ADDR]
+
+// Long long arithmetics - REM_LONG[_2ADDR] and DIV_LONG[_2ADDR]
+extern "C" long long __divdi3(int64_t op1, int64_t op2);
+extern "C" long long __moddi3(int64_t op1, int64_t op2);
+extern "C" uint64_t art_shl_long(uint64_t, uint32_t);
+extern "C" uint64_t art_shr_long(uint64_t, uint32_t);
+extern "C" uint64_t art_ushr_long(uint64_t, uint32_t);
+
+// Intrinsic entrypoints.
+extern "C" int32_t __memcmp16(void*, void*, int32_t);
+extern "C" int32_t art_indexof(void*, uint32_t, uint32_t, uint32_t);
+extern "C" int32_t art_string_compareto(void*, void*);
+
+// Invoke entrypoints.
+const void* UnresolvedDirectMethodTrampolineFromCode(Method*, Method**, Thread*,
+ Runtime::TrampolineType);
+extern "C" void art_invoke_direct_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_interface_trampoline(uint32_t, void*);
+extern "C" void art_invoke_interface_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_static_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_super_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
+
+// Thread entrypoints.
+extern void CheckSuspendFromCode(Thread* thread);
+extern "C" void art_test_suspend();
+
+// Throw entrypoints.
+extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
+extern "C" void art_deliver_exception_from_code(void*);
+extern "C" void art_throw_array_bounds_from_code(int32_t index, int32_t limit);
+extern "C" void art_throw_div_zero_from_code();
+extern "C" void art_throw_no_such_method_from_code(int32_t method_idx);
+extern "C" void art_throw_null_pointer_exception_from_code();
+extern "C" void art_throw_stack_overflow_from_code(void*);
+extern "C" void art_throw_verification_error_from_code(int32_t src1, int32_t ref);
+
+// Trace entrypoints.
+extern "C" void art_trace_entry_from_code(void*);
+extern "C" void art_trace_exit_from_code();
+
+void InitEntryPoints(EntryPoints* points) {
+ // Alloc
+ points->pAllocArrayFromCode = art_alloc_array_from_code;
+ points->pAllocArrayFromCodeWithAccessCheck = art_alloc_array_from_code_with_access_check;
+ points->pAllocObjectFromCode = art_alloc_object_from_code;
+ points->pAllocObjectFromCodeWithAccessCheck = art_alloc_object_from_code_with_access_check;
+ points->pCheckAndAllocArrayFromCode = art_check_and_alloc_array_from_code;
+ points->pCheckAndAllocArrayFromCodeWithAccessCheck = art_check_and_alloc_array_from_code_with_access_check;
+
+ // Cast
+ points->pInstanceofNonTrivialFromCode = IsAssignableFromCode;
+ points->pCanPutArrayElementFromCode = art_can_put_array_element_from_code;
+ points->pCheckCastFromCode = art_check_cast_from_code;
+
+ // Debug
+ points->pDebugMe = DebugMe;
+ points->pUpdateDebuggerFromCode = NULL; // Controlled by SetDebuggerUpdatesEnabled.
+
+ // DexCache
+ points->pInitializeStaticStorage = art_initialize_static_storage_from_code;
+ points->pInitializeTypeAndVerifyAccessFromCode = art_initialize_type_and_verify_access_from_code;
+ points->pInitializeTypeFromCode = art_initialize_type_from_code;
+ points->pResolveStringFromCode = art_resolve_string_from_code;
+
+ // Field
+ points->pSet32Instance = art_set32_instance_from_code;
+ points->pSet32Static = art_set32_static_from_code;
+ points->pSet64Instance = art_set64_instance_from_code;
+ points->pSet64Static = art_set64_static_from_code;
+ points->pSetObjInstance = art_set_obj_instance_from_code;
+ points->pSetObjStatic = art_set_obj_static_from_code;
+ points->pGet32Instance = art_get32_instance_from_code;
+ points->pGet64Instance = art_get64_instance_from_code;
+ points->pGetObjInstance = art_get_obj_instance_from_code;
+ points->pGet32Static = art_get32_static_from_code;
+ points->pGet64Static = art_get64_static_from_code;
+ points->pGetObjStatic = art_get_obj_static_from_code;
+
+ // FillArray
+ points->pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
+
+ // JNI
+ points->pDecodeJObjectInThread = DecodeJObjectInThread;
+ points->pFindNativeMethod = FindNativeMethod;
+
+ // Locks
+ points->pLockObjectFromCode = art_lock_object_from_code;
+ points->pUnlockObjectFromCode = art_unlock_object_from_code;
+
+ // Math
+ points->pCmpgDouble = CmpgDouble;
+ points->pCmpgFloat = CmpgFloat;
+ points->pCmplDouble = CmplDouble;
+ points->pCmplFloat = CmplFloat;
+ points->pDadd = __adddf3;
+ points->pDdiv = __subdf3;
+ points->pDmul = __muldf3;
+ points->pDsub = __subdf3;
+ points->pF2d = __extendsfdf2;
+ points->pFmod = fmod;
+ points->pI2d = __floatsidf;
+ points->pL2d = __floatdidf;
+ points->pD2f = __truncdfsf2;
+ points->pFadd = __addsf3;
+ points->pFdiv = __divsf3;
+ points->pFmodf = fmodf;
+ points->pFmul = __mulsf3;
+ points->pFsub = __subsf3;
+ points->pI2f = __floatsisf;
+ points->pL2f = __floatdisf;
+ points->pD2iz = __fixdfsi;
+ points->pF2iz = __fixsfi;
+ points->pIdiv = NULL;
+ points->pIdivmod = NULL;
+ points->pD2l = D2L;
+ points->pF2l = F2L;
+ points->pLadd = NULL;
+ points->pLand = NULL;
+ points->pLdivmod = NULL;
+ points->pLmul = NULL;
+ points->pLor = NULL;
+ points->pLsub = NULL;
+ points->pLxor = NULL;
+ points->pShlLong = art_shl_long;
+ points->pShrLong = art_shr_long;
+ points->pUshrLong = art_ushr_long;
+
+ // Intrinsics
+ points->pIndexOf = art_indexof;
+ points->pMemcmp16 = __memcmp16;
+ points->pStringCompareTo = art_string_compareto;
+ points->pMemcpy = memcpy;
+
+ // Invocation
+ points->pUnresolvedDirectMethodTrampolineFromCode = UnresolvedDirectMethodTrampolineFromCode;
+ points->pInvokeDirectTrampolineWithAccessCheck = art_invoke_direct_trampoline_with_access_check;
+ points->pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
+ points->pInvokeInterfaceTrampolineWithAccessCheck = art_invoke_interface_trampoline_with_access_check;
+ points->pInvokeStaticTrampolineWithAccessCheck = art_invoke_static_trampoline_with_access_check;
+ points->pInvokeSuperTrampolineWithAccessCheck = art_invoke_super_trampoline_with_access_check;
+ points->pInvokeVirtualTrampolineWithAccessCheck = art_invoke_virtual_trampoline_with_access_check;
+
+ // Thread
+ points->pCheckSuspendFromCode = CheckSuspendFromCode;
+ points->pTestSuspendFromCode = art_test_suspend;
+
+ // Throws
+ points->pDeliverException = art_deliver_exception_from_code;
+ points->pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;
+ points->pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code;
+ points->pThrowDivZeroFromCode = art_throw_div_zero_from_code;
+ points->pThrowNoSuchMethodFromCode = art_throw_no_such_method_from_code;
+ points->pThrowNullPointerFromCode = art_throw_null_pointer_exception_from_code;
+ points->pThrowStackOverflowFromCode = art_throw_stack_overflow_from_code;
+ points->pThrowVerificationErrorFromCode = art_throw_verification_error_from_code;
+};
+
+void ChangeDebuggerEntryPoint(EntryPoints* points, bool enabled) {
+ points->pUpdateDebuggerFromCode = (enabled ? art_update_debugger : NULL);
+}
+
+bool IsTraceExitPc(uintptr_t pc) {
+ UNIMPLEMENTED(FATAL);
+ return false;
+}
+
+void* GetLogTraceEntryPoint() {
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+}
+
+} // namespace art
diff --git a/src/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
similarity index 90%
rename from src/runtime_support_mips.S
rename to src/oat/runtime/mips/runtime_support_mips.S
index 3323564..65431e3 100644
--- a/src/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -7,12 +7,17 @@
/* Deliver an exception pending on a thread */
.extern artDeliverPendingException
+ /* Cache alignment for function entry */
+.macro ALIGN_FUNCTION_ENTRY
+ .balign 16
+.endm
+
/*
* Macro that sets up the callee save frame to conform with
* Runtime::CreateCalleeSaveMethod(kSaveAll)
* callee-save: s0-s8 + ra, 10 total + 2 words
*/
-.macro SETUP_CALLEE_SAVE_FRAME
+.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
addiu sp, sp, 48
sw ra, 44(sp)
sw s8, 40(sp)
@@ -91,7 +96,7 @@
* exception is Thread::Current()->exception_
*/
.macro DELIVER_PENDING_EXCEPTION
- SETUP_CALLEE_SAVE_FRAME @ save callee saves for throw
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME @ save callee saves for throw
move a0, rSELF @ pass Thread::Current
b artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
move a1, sp @ pass SP
@@ -133,6 +138,7 @@
/*
* On entry, a0 and a1 must be preserved, a2 is dex PC
*/
+ ALIGN_FUNCTION_ENTRY
art_update_debugger:
move a3, a0 @ stash away a0 so that it's saved as if it were an argument
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
@@ -149,6 +155,7 @@
* On entry a0 is uint32_t* gprs_ and a1 is uint32_t* fprs_
* FIXME: just guessing about the shape of the jmpbuf. Where will pc be?
*/
+ ALIGN_FUNCTION_ENTRY
art_do_long_jump:
l.s f0, 0(a1)
l.s f1, 4(a1)
@@ -223,8 +230,9 @@
* the bottom of the stack. artDeliverExceptionFromCode will place the callee save Method* at
* the bottom of the thread. On entry r0 holds Throwable*
*/
+ ALIGN_FUNCTION_ENTRY
art_deliver_exception_from_code:
- SETUP_CALLEE_SAVE_FRAME
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
move a1, rSELF @ pass Thread::Current
b artDeliverExceptionFromCode @ artDeliverExceptionFromCode(Throwable*, Thread*, SP)
move a2, sp @ pass SP
@@ -234,8 +242,9 @@
/*
* Called by managed code to create and deliver a NullPointerException
*/
+ ALIGN_FUNCTION_ENTRY
art_throw_null_pointer_exception_from_code:
- SETUP_CALLEE_SAVE_FRAME
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
move a0, rSELF @ pass Thread::Current
b artThrowNullPointerExceptionFromCode @ artThrowNullPointerExceptionFromCode(Thread*, SP)
move a1, sp @ pass SP
@@ -245,8 +254,9 @@
/*
* Called by managed code to create and deliver an ArithmeticException
*/
+ ALIGN_FUNCTION_ENTRY
art_throw_div_zero_from_code:
- SETUP_CALLEE_SAVE_FRAME
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
move a0, rSELF @ pass Thread::Current
b artThrowDivZeroFromCode @ artThrowDivZeroFromCode(Thread*, SP)
move a1, sp @ pass SP
@@ -256,40 +266,57 @@
/*
* Called by managed code to create and deliver an ArrayIndexOutOfBoundsException
*/
+ ALIGN_FUNCTION_ENTRY
art_throw_array_bounds_from_code:
- SETUP_CALLEE_SAVE_FRAME
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
move a2, rSELF @ pass Thread::Current
b artThrowArrayBoundsFromCode @ artThrowArrayBoundsFromCode(index, limit, Thread*, SP)
move a3, sp @ pass SP
.global art_throw_stack_overflow_from_code
.extern artThrowStackOverflowFromCode
+ /*
+ * Called by managed code to create and deliver a StackOverflowError.
+ */
+ ALIGN_FUNCTION_ENTRY
art_throw_stack_overflow_from_code:
- SETUP_CALLEE_SAVE_FRAME
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
move a1, rSELF @ pass Thread::Current
b artThrowStackOverflowFromCode @ artThrowStackOverflowFromCode(method, Thread*, SP)
move a2, sp @ pass SP
.global art_throw_neg_array_size_from_code
.extern artThrowNegArraySizeFromCode
+ /*
+ * Called by managed code to create and deliver a NegativeArraySizeException.
+ */
+ ALIGN_FUNCTION_ENTRY
art_throw_neg_array_size_from_code:
- SETUP_CALLEE_SAVE_FRAME
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
move a1, rSELF @ pass Thread::Current
b artThrowNegArraySizeFromCode @ artThrowNegArraySizeFromCode(size, Thread*, SP)
move a2, sp @ pass SP
.global art_throw_no_such_method_from_code
.extern artThrowNoSuchMethodFromCode
+ /*
+ * Called by managed code to create and deliver a NoSuchMethodError.
+ */
+ ALIGN_FUNCTION_ENTRY
art_throw_no_such_method_from_code:
- SETUP_CALLEE_SAVE_FRAME
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
move a1, rSELF @ pass Thread::Current
b artThrowNoSuchMethodFromCode @ artThrowNoSuchMethodFromCode(method_idx, Thread*, SP)
move a2, sp @ pass SP
.global art_throw_verification_error_from_code
.extern artThrowVerificationErrorFromCode
+ /*
+ * Called by managed code to create and deliver verification errors.
+ */
+ ALIGN_FUNCTION_ENTRY
art_throw_verification_error_from_code:
- SETUP_CALLEE_SAVE_FRAME
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
move a2, rSELF @ pass Thread::Current
b artThrowVerificationErrorFromCode @ artThrowVerificationErrorFromCode(kind, ref, Thread*, SP)
move a3, sp @ pass SP
@@ -342,6 +369,7 @@
/*
* Entry point of native methods when JNI bug compatibility is enabled.
*/
+ ALIGN_FUNCTION_ENTRY
art_work_around_app_jni_bugs:
@ save registers that may contain arguments and LR that will be crushed by a call
addiu sp, sp, -32
@@ -368,6 +396,7 @@
* Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
* failure.
*/
+ ALIGN_FUNCTION_ENTRY
art_handle_fill_data_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC
move a2, rSELF @ pass Thread::Current
@@ -384,10 +413,11 @@
.global art_lock_object_from_code
.extern artLockObjectFromCode
/*
- * Entry from managed code that calls artLockObjectFromCode, may block for GC
+ * Entry from managed code that calls artLockObjectFromCode, may block for GC.
*/
+ ALIGN_FUNCTION_ENTRY
art_lock_object_from_code:
- SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case we block
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case we block
move a1, rSELF @ pass Thread::Current
jal artLockObjectFromCode @ (Object* obj, Thread*, SP)
move a2, sp @ pass SP
@@ -398,11 +428,12 @@
/*
* Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
*/
+ ALIGN_FUNCTION_ENTRY
art_unlock_object_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC
- move a1, rSELF @ pass Thread::Current
- jal artUnlockObjectFromCode @ (Object* obj, Thread*, SP)
- move a2, sp @ pass SP
+ move a1, rSELF @ pass Thread::Current
+ jal artUnlockObjectFromCode @ (Object* obj, Thread*, SP)
+ move a2, sp @ pass SP
RETURN_IF_ZERO
.global art_check_cast_from_code
@@ -410,11 +441,12 @@
/*
* Entry from managed code that calls artCheckCastFromCode and delivers exception on failure.
*/
+ ALIGN_FUNCTION_ENTRY
art_check_cast_from_code:
- SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC
- move a2, rSELF @ pass Thread::Current
- jal artCheckCastFromCode @ (Class* a, Class* b, Thread*, SP)
- move a3, sp @ pass SP
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC
+ move a2, rSELF @ pass Thread::Current
+ jal artCheckCastFromCode @ (Class* a, Class* b, Thread*, SP)
+ move a3, sp @ pass SP
RETURN_IF_ZERO
.global art_can_put_array_element_from_code
@@ -423,8 +455,9 @@
* Entry from managed code that calls artCanPutArrayElementFromCode and delivers exception on
* failure.
*/
+ ALIGN_FUNCTION_ENTRY
art_can_put_array_element_from_code:
- bnez a0, 1f @ return if element == NULL
+ bnez a0, 1f @ return if element == NULL
nop
jr ra
nop
@@ -442,8 +475,9 @@
* initializer and deliver the exception on error. On success the static storage base is
* returned.
*/
+ ALIGN_FUNCTION_ENTRY
art_initialize_static_storage_from_code:
- SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
move a2, rSELF @ pass Thread::Current
@ artInitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
jal artInitializeStaticStorageFromCode
@@ -453,8 +487,9 @@
.global art_initialize_type_from_code
.extern artInitializeTypeFromCode
/*
- * Entry from managed code when dex cache misses for a type_idx
+ * Entry from managed code when dex cache misses for a type_idx.
*/
+ ALIGN_FUNCTION_ENTRY
art_initialize_type_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
move a2, rSELF @ pass Thread::Current
@@ -467,8 +502,9 @@
.extern artInitializeTypeAndVerifyAccessFromCode
/*
* Entry from managed code when type_idx needs to be checked for access and dex cache may also
- * miss
+ * miss.
*/
+ ALIGN_FUNCTION_ENTRY
art_initialize_type_and_verify_access_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
move a2, rSELF @ pass Thread::Current
@@ -480,8 +516,9 @@
.global art_get32_static_from_code
.extern artGet32StaticFromCode
/*
- * Called by managed code to resolve a static field and load a 32-bit primitive value
+ * Called by managed code to resolve a static field and load a 32-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_get32_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
lw a1, 48(sp) @ pass referrer's Method*
@@ -493,8 +530,9 @@
.global art_get64_static_from_code
.extern artGet64StaticFromCode
/*
- * Called by managed code to resolve a static field and load a 64-bit primitive value
+ * Called by managed code to resolve a static field and load a 64-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_get64_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
lw a1, 48(sp) @ pass referrer's Method*
@@ -506,8 +544,9 @@
.global art_get_obj_static_from_code
.extern artGetObjStaticFromCode
/*
- * Called by managed code to resolve a static field and load an object reference
+ * Called by managed code to resolve a static field and load an object reference.
*/
+ ALIGN_FUNCTION_ENTRY
art_get_obj_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
lw a1, 48(sp) @ pass referrer's Method*
@@ -519,8 +558,9 @@
.global art_get32_instance_from_code
.extern artGet32InstanceFromCode
/*
- * Called by managed code to resolve an instance field and load a 32-bit primitive value
+ * Called by managed code to resolve an instance field and load a 32-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_get32_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
lw a2, 48(sp) @ pass referrer's Method*
@@ -532,8 +572,9 @@
.global art_get64_instance_from_code
.extern artGet64InstanceFromCode
/*
- * Called by managed code to resolve an instance field and load a 64-bit primitive value
+ * Called by managed code to resolve an instance field and load a 64-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_get64_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
lw a2, 48(sp) @ pass referrer's Method*
@@ -545,8 +586,9 @@
.global art_get_obj_instance_from_code
.extern artGetObjInstanceFromCode
/*
- * Called by managed code to resolve an instance field and load an object reference
+ * Called by managed code to resolve an instance field and load an object reference.
*/
+ ALIGN_FUNCTION_ENTRY
art_get_obj_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
lw a2, 48(sp) @ pass referrer's Method*
@@ -558,8 +600,9 @@
.global art_set32_static_from_code
.extern artSet32StaticFromCode
/*
- * Called by managed code to resolve a static field and store a 32-bit primitive value
+ * Called by managed code to resolve a static field and store a 32-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_set32_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
lw a2, 48(sp) @ pass referrer's Method*
@@ -571,9 +614,9 @@
.global art_set64_static_from_code
.extern artSet32StaticFromCode
/*
- * Called by managed code to resolve a static field and store a 64-bit primitive value
+ * Called by managed code to resolve a static field and store a 64-bit primitive value.
*/
-
+ ALIGN_FUNCTION_ENTRY
art_set64_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
lw a1, 48(sp) @ pass referrer's Method*
@@ -588,8 +631,9 @@
.global art_set_obj_static_from_code
.extern artSetObjStaticFromCode
/*
- * Called by managed code to resolve a static field and store an object reference
+ * Called by managed code to resolve a static field and store an object reference.
*/
+ ALIGN_FUNCTION_ENTRY
art_set_obj_static_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
lw a2, 48(sp) @ pass referrer's Method*
@@ -601,8 +645,9 @@
.global art_set32_instance_from_code
.extern artSet32InstanceFromCode
/*
- * Called by managed code to resolve an instance field and store a 32-bit primitive value
+ * Called by managed code to resolve an instance field and store a 32-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_set32_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
lw a4, 48(sp) @ pass referrer's Method*
@@ -617,8 +662,9 @@
.global art_set64_instance_from_code
.extern artSet32InstanceFromCode
/*
- * Called by managed code to resolve an instance field and store a 64-bit primitive value
+ * Called by managed code to resolve an instance field and store a 64-bit primitive value.
*/
+ ALIGN_FUNCTION_ENTRY
art_set64_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
move t0, sp @ save SP
@@ -632,8 +678,9 @@
.global art_set_obj_instance_from_code
.extern artSetObjInstanceFromCode
/*
- * Called by managed code to resolve an instance field and store an object reference
+ * Called by managed code to resolve an instance field and store an object reference.
*/
+ ALIGN_FUNCTION_ENTRY
art_set_obj_instance_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
lw a3, 48(sp) @ pass referrer's Method*
@@ -653,6 +700,7 @@
* R1 holds the string index. The fast path check for hit in strings cache has already been
* performed.
*/
+ ALIGN_FUNCTION_ENTRY
art_resolve_string_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
move a2, rSELF @ pass Thread::Current
@@ -664,8 +712,9 @@
.global art_alloc_object_from_code
.extern artAllocObjectFromCode
/*
- * Called by managed code to allocate an object
+ * Called by managed code to allocate an object.
*/
+ ALIGN_FUNCTION_ENTRY
art_alloc_object_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
move a2, rSELF @ pass Thread::Current
@@ -677,8 +726,9 @@
.extern artAllocObjectFromCodeWithAccessCheck
/*
* Called by managed code to allocate an object when the caller doesn't know whether it has
- * access to the created type
+ * access to the created type.
*/
+ ALIGN_FUNCTION_ENTRY
art_alloc_object_from_code_with_access_check:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
move a2, rSELF @ pass Thread::Current
@@ -689,8 +739,9 @@
.global art_alloc_array_from_code
.extern artAllocArrayFromCode
/*
- * Called by managed code to allocate an array
+ * Called by managed code to allocate an array.
*/
+ ALIGN_FUNCTION_ENTRY
art_alloc_array_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
move a3, r9 @ pass Thread::Current
@@ -703,8 +754,9 @@
.extern artAllocArrayFromCodeWithAccessCheck
/*
* Called by managed code to allocate an array when the caller doesn't know whether it has
- * access to the created type
+ * access to the created type.
*/
+ ALIGN_FUNCTION_ENTRY
art_alloc_array_from_code_with_access_check:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
move a3, rSELF @ pass Thread::Current
@@ -716,8 +768,9 @@
.global art_check_and_alloc_array_from_code
.extern artCheckAndAllocArrayFromCode
/*
- * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY
+ * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
*/
+ ALIGN_FUNCTION_ENTRY
art_check_and_alloc_array_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
move a3, rSELF @ pass Thread::Current
@@ -729,8 +782,9 @@
.global art_check_and_alloc_array_from_code_with_access_check
.extern artCheckAndAllocArrayFromCodeWithAccessCheck
/*
- * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY
+ * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
*/
+ ALIGN_FUNCTION_ENTRY
art_check_and_alloc_array_from_code_with_access_check:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
move a3, rSELF @ pass Thread::Current
@@ -742,8 +796,9 @@
.global art_test_suspend
.extern artTestSuspendFromCode
/*
- * Called by managed code when the value in rSUSPEND has been decremented to 0
+ * Called by managed code when the value in rSUSPEND has been decremented to 0.
*/
+ ALIGN_FUNCTION_ENTRY
art_test_suspend:
lw a0, THREAD_SUSPEND_COUNT_OFFSET(rSELF)
bnez a0, 1f
@@ -761,8 +816,9 @@
.extern artProxyInvokeHandler
/*
* Called by managed code that is attempting to call a method on a proxy class. On entry
- * r0 holds the proxy method; r1, r2 and r3 may contain arguments
+ * r0 holds the proxy method; r1, r2 and r3 may contain arguments.
*/
+ ALIGN_FUNCTION_ENTRY
art_proxy_invoke_handler:
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
sw a0, 0(sp) @ place proxy method at bottom of frame
@@ -775,7 +831,7 @@
lw v0, 12(sp)
lw v1, 14(sp)
bnez r0, 1f
- addui sp, sp, 48 @ pop frame
+ addui sp, sp, 48 @ pop frame
jr ra
nop
1:
@@ -786,6 +842,7 @@
/*
* Routine that intercepts method calls
*/
+ ALIGN_FUNCTION_ENTRY
art_trace_entry_from_code:
addui sp, sp, -16
sw a0, 0(sp)
@@ -809,6 +866,7 @@
/*
* Routine that intercepts method returns
*/
+ ALIGN_FUNCTION_ENTRY
art_trace_exit_from_code:
addui sp, sp, -16
sw v0, 0(sp)
@@ -821,7 +879,6 @@
addui sp, sp, 16
.global art_shl_long
-art_shl_long:
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
@@ -832,6 +889,8 @@
* a1: high word
* a2: shift count
*/
+ ALIGN_FUNCTION_ENTRY
+art_shl_long:
/* shl-long vAA, vBB, vCC */
sll v0, a0, a2 @ rlo<- alo << (shift&31)
not v1, a2 @ rhi<- 31-shift (shift is 5b)
@@ -844,9 +903,7 @@
jr ra
movn v0, zero, a2 @ rlo<- 0 (if shift&0x20)
- .balign 4
.global art_shr_long
-art_shr_long:
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
@@ -857,6 +914,8 @@
* a1: high word
* a2: shift count
*/
+ ALIGN_FUNCTION_ENTRY
+art_shr_long:
sra v1, a1, a2 @ rhi<- ahi >> (shift&31)
srl v0, a0, a2 @ rlo<- alo >> (shift&31)
sra a3, a1, 31 @ a3<- sign(ah)
@@ -869,9 +928,7 @@
jr ra
movn v1, a3, a2 @ rhi<- sign(ahi) (if shift&0x20)
- .balign 4
.global art_ushr_long
-art_ushr_long:
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
@@ -883,6 +940,8 @@
* r2: shift count
*/
/* ushr-long vAA, vBB, vCC */
+ ALIGN_FUNCTION_ENTRY
+art_ushr_long:
sra v1, a1, a2 @ rhi<- ahi >> (shift&31)
srl v0, a0, a2 @ rlo<- alo >> (shift&31)
sra a3, a1, 31 @ a3<- sign(ah)
diff --git a/src/oat/runtime/oat_support_entrypoints.h b/src/oat/runtime/oat_support_entrypoints.h
new file mode 100644
index 0000000..0e59dd8
--- /dev/null
+++ b/src/oat/runtime/oat_support_entrypoints.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef ART_SRC_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_
+#define ART_SRC_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_
+
+#include "runtime.h"
+
+#define ENTRYPOINT_OFFSET(x) \
+ (static_cast<uintptr_t>(OFFSETOF_MEMBER(Thread, entrypoints_)) + \
+ static_cast<uintptr_t>(OFFSETOF_MEMBER(EntryPoints, x)))
+
+namespace art {
+
+class Class;
+class Method;
+class Thread;
+
+struct PACKED EntryPoints {
+ // Alloc
+ void* (*pAllocArrayFromCode)(uint32_t, void*, int32_t);
+ void* (*pAllocArrayFromCodeWithAccessCheck)(uint32_t, void*, int32_t);
+ void* (*pAllocObjectFromCode)(uint32_t, void*);
+ void* (*pAllocObjectFromCodeWithAccessCheck)(uint32_t, void*);
+ void* (*pCheckAndAllocArrayFromCode)(uint32_t, void*, int32_t);
+ void* (*pCheckAndAllocArrayFromCodeWithAccessCheck)(uint32_t, void*, int32_t);
+
+ // Cast
+ uint32_t (*pInstanceofNonTrivialFromCode)(const Class*, const Class*);
+ void (*pCanPutArrayElementFromCode)(void*, void*);
+ void (*pCheckCastFromCode)(void*, void*);
+
+ // Debug
+ void (*pDebugMe)(Method*, uint32_t);
+ void (*pUpdateDebuggerFromCode)(void*, void*, int32_t, void*);
+
+ // DexCache
+ void* (*pInitializeStaticStorage)(uint32_t, void*);
+ void* (*pInitializeTypeAndVerifyAccessFromCode)(uint32_t, void*);
+ void* (*pInitializeTypeFromCode)(uint32_t, void*);
+ void* (*pResolveStringFromCode)(void*, uint32_t);
+
+ // Field
+ int (*pSet32Instance)(uint32_t, void*, int32_t); // field_idx, obj, src
+ int (*pSet32Static)(uint32_t, int32_t);
+ int (*pSet64Instance)(uint32_t, void*, int64_t);
+ int (*pSet64Static)(uint32_t, int64_t);
+ int (*pSetObjInstance)(uint32_t, void*, void*);
+ int (*pSetObjStatic)(uint32_t, void*);
+ int32_t (*pGet32Instance)(uint32_t, void*);
+ int32_t (*pGet32Static)(uint32_t);
+ int64_t (*pGet64Instance)(uint32_t, void*);
+ int64_t (*pGet64Static)(uint32_t);
+ void* (*pGetObjInstance)(uint32_t, void*);
+ void* (*pGetObjStatic)(uint32_t);
+
+ // FillArray
+ void (*pHandleFillArrayDataFromCode)(void*, void*);
+
+ // JNI
+ Object* (*pDecodeJObjectInThread)(Thread* thread, jobject obj);
+ void* (*pFindNativeMethod)(Thread* thread);
+
+ // Locks
+ void (*pLockObjectFromCode)(void*);
+ void (*pUnlockObjectFromCode)(void*);
+
+ // Math
+ int32_t (*pCmpgDouble)(double, double);
+ int32_t (*pCmpgFloat)(float, float);
+ int32_t (*pCmplDouble)(double, double);
+ int32_t (*pCmplFloat)(float, float);
+ double (*pDadd)(double, double);
+ double (*pDdiv)(double, double);
+ double (*pDmul)(double, double);
+ double (*pDsub)(double, double);
+ double (*pF2d)(float);
+ double (*pFmod)(double, double);
+ double (*pI2d)(int);
+ double (*pL2d)(int64_t);
+ float (*pD2f)(double);
+ float (*pFadd)(float, float);
+ float (*pFdiv)(float, float);
+ float (*pFmodf)(float, float);
+ float (*pFmul)(float, float);
+ float (*pFsub)(float, float);
+ float (*pI2f)(int32_t);
+ float (*pL2f)(int64_t);
+ int32_t (*pD2iz)(double);
+ int32_t (*pF2iz)(float);
+ int32_t (*pIdiv)(int32_t, int32_t);
+ int32_t (*pIdivmod)(int32_t, int32_t);
+ int64_t (*pD2l)(double);
+ int64_t (*pF2l)(float);
+ int64_t (*pLadd)(int64_t, int64_t);
+ int64_t (*pLand)(int64_t, int64_t);
+ int64_t (*pLdivmod)(int64_t, int64_t);
+ int64_t (*pLmul)(int64_t, int64_t);
+ int64_t (*pLor)(int64_t, int64_t);
+ int64_t (*pLsub)(int64_t, int64_t);
+ int64_t (*pLxor)(int64_t, int64_t);
+ uint64_t (*pShlLong)(uint64_t, uint32_t);
+ uint64_t (*pShrLong)(uint64_t, uint32_t);
+ uint64_t (*pUshrLong)(uint64_t, uint32_t);
+
+ // Intrinsics
+ int32_t (*pIndexOf)(void*, uint32_t, uint32_t, uint32_t);
+ int32_t (*pMemcmp16)(void*, void*, int32_t);
+ int32_t (*pStringCompareTo)(void*, void*);
+ void* (*pMemcpy)(void*, const void*, size_t);
+
+ // Invocation
+ Method* (*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
+ const void* (*pUnresolvedDirectMethodTrampolineFromCode)(Method*, Method**, Thread*,
+ Runtime::TrampolineType);
+ void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*);
+ void (*pInvokeInterfaceTrampoline)(uint32_t, void*);
+ void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*);
+ void (*pInvokeStaticTrampolineWithAccessCheck)(uint32_t, void*);
+ void (*pInvokeSuperTrampolineWithAccessCheck)(uint32_t, void*);
+ void (*pInvokeVirtualTrampolineWithAccessCheck)(uint32_t, void*);
+
+ // Thread
+ void (*pCheckSuspendFromCode)(Thread*); // Stub that is called when the suspend count is non-zero
+ void (*pTestSuspendFromCode)(); // Stub that is periodically called to test the suspend count
+
+ // Throws
+ void (*pDeliverException)(void*);
+ void (*pThrowAbstractMethodErrorFromCode)(Method* m, Thread* thread, Method** sp);
+ void (*pThrowArrayBoundsFromCode)(int32_t, int32_t);
+ void (*pThrowDivZeroFromCode)();
+ void (*pThrowNoSuchMethodFromCode)(int32_t);
+ void (*pThrowNullPointerFromCode)();
+ void (*pThrowStackOverflowFromCode)(void*);
+ void (*pThrowVerificationErrorFromCode)(int32_t, int32_t);
+};
+
+// Initialize an entry point data structure.
+void InitEntryPoints(EntryPoints* points);
+
+// Change the debugger entry point in the data structure.
+void ChangeDebuggerEntryPoint(EntryPoints* points, bool enabled);
+
+// Is the given return_pc the trace exit return pc?
+bool IsTraceExitPc(uintptr_t pc);
+
+// Return address of stub that logs method entries.
+void* GetLogTraceEntryPoint();
+
+} // namespace art
+
+#endif // ART_SRC_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_
diff --git a/src/oat/runtime/support_alloc.cc b/src/oat/runtime/support_alloc.cc
new file mode 100644
index 0000000..d9394d2
--- /dev/null
+++ b/src/oat/runtime/support_alloc.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012 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 "callee_save_frame.h"
+#include "runtime_support.h"
+
+namespace art {
+
+extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return AllocObjectFromCode(type_idx, method, self, false);
+}
+
+extern "C" Object* artAllocObjectFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return AllocObjectFromCode(type_idx, method, self, true);
+}
+
+extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return AllocArrayFromCode(type_idx, method, component_count, self, false);
+}
+
+extern "C" Array* artAllocArrayFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
+ int32_t component_count,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return AllocArrayFromCode(type_idx, method, component_count, self, true);
+}
+
+extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
+ int32_t component_count, Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, false);
+}
+
+extern "C" Array* artCheckAndAllocArrayFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
+ int32_t component_count,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, true);
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_cast.cc b/src/oat/runtime/support_cast.cc
new file mode 100644
index 0000000..987e764
--- /dev/null
+++ b/src/oat/runtime/support_cast.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 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 "callee_save_frame.h"
+#include "runtime_support.h"
+
+namespace art {
+
+// Assignable test for code, won't throw. Null and equality tests already performed
+uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class) {
+ DCHECK(klass != NULL);
+ DCHECK(ref_class != NULL);
+ return klass->IsAssignableFrom(ref_class) ? 1 : 0;
+}
+
+// Check whether it is safe to cast one class to the other, throw exception and return -1 on failure
+extern "C" int artCheckCastFromCode(const Class* a, const Class* b, Thread* self, Method** sp) {
+ DCHECK(a->IsClass()) << PrettyClass(a);
+ DCHECK(b->IsClass()) << PrettyClass(b);
+ if (LIKELY(b->IsAssignableFrom(a))) {
+ return 0; // Success
+ } else {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
+ "%s cannot be cast to %s",
+ PrettyDescriptor(a).c_str(),
+ PrettyDescriptor(b).c_str());
+ return -1; // Failure
+ }
+}
+
+// Tests whether 'element' can be assigned into an array of type 'array_class'.
+// Returns 0 on success and -1 if an exception is pending.
+extern "C" int artCanPutArrayElementFromCode(const Object* element, const Class* array_class,
+ Thread* self, Method** sp) {
+ DCHECK(array_class != NULL);
+ // element can't be NULL as we catch this is screened in runtime_support
+ Class* element_class = element->GetClass();
+ Class* component_type = array_class->GetComponentType();
+ if (LIKELY(component_type->IsAssignableFrom(element_class))) {
+ return 0; // Success
+ } else {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
+ "%s cannot be stored in an array of type %s",
+ PrettyDescriptor(element_class).c_str(),
+ PrettyDescriptor(array_class).c_str());
+ return -1; // Failure
+ }
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_debug.cc b/src/oat/runtime/support_debug.cc
new file mode 100644
index 0000000..2803e27
--- /dev/null
+++ b/src/oat/runtime/support_debug.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 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 "callee_save_frame.h"
+#include "debugger.h"
+
+namespace art {
+
+/*
+ * Report location to debugger. Note: dex_pc is the current offset within
+ * the method. However, because the offset alone cannot distinguish between
+ * method entry and offset 0 within the method, we'll use an offset of -1
+ * to denote method entry.
+ */
+extern "C" void artUpdateDebuggerFromCode(int32_t dex_pc, Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
+ Dbg::UpdateDebugger(dex_pc, self, sp);
+}
+
+// Temporary debugging hook for compiler.
+extern void DebugMe(Method* method, uint32_t info) {
+ LOG(INFO) << "DebugMe";
+ if (method != NULL) {
+ LOG(INFO) << PrettyMethod(method);
+ }
+ LOG(INFO) << "Info: " << info;
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_dexcache.cc b/src/oat/runtime/support_dexcache.cc
new file mode 100644
index 0000000..e5f2f82
--- /dev/null
+++ b/src/oat/runtime/support_dexcache.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 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 "callee_save_frame.h"
+#include "runtime_support.h"
+
+namespace art {
+
+extern "C" Class* artInitializeStaticStorageFromCode(uint32_t type_idx, const Method* referrer,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return ResolveVerifyAndClinit(type_idx, referrer, self, true, true);
+}
+
+extern "C" Class* artInitializeTypeFromCode(uint32_t type_idx, const Method* referrer, Thread* self,
+ Method** sp) {
+ // Called when method->dex_cache_resolved_types_[] misses
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return ResolveVerifyAndClinit(type_idx, referrer, self, false, false);
+}
+
+extern "C" Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx,
+ const Method* referrer, Thread* self,
+ Method** sp) {
+ // Called when caller isn't guaranteed to have access to a type and the dex cache may be
+ // unpopulated
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return ResolveVerifyAndClinit(type_idx, referrer, self, false, true);
+}
+
+extern "C" String* artResolveStringFromCode(Method* referrer, int32_t string_idx,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return ResolveStringFromCode(referrer, string_idx);
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_field.cc b/src/oat/runtime/support_field.cc
new file mode 100644
index 0000000..77fe618
--- /dev/null
+++ b/src/oat/runtime/support_field.cc
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2012 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 "callee_save_frame.h"
+#include "runtime_support.h"
+
+#include <stdint.h>
+
+namespace art {
+
+extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
+ Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
+ if (LIKELY(field != NULL)) {
+ return field->Get32(NULL);
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int32_t));
+ if (LIKELY(field != NULL)) {
+ return field->Get32(NULL);
+ }
+ return 0; // Will throw exception by checking with Thread::Current
+}
+
+extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, const Method* referrer,
+ Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
+ if (LIKELY(field != NULL)) {
+ return field->Get64(NULL);
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int64_t));
+ if (LIKELY(field != NULL)) {
+ return field->Get64(NULL);
+ }
+ return 0; // Will throw exception by checking with Thread::Current
+}
+
+extern "C" Object* artGetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
+ Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
+ if (LIKELY(field != NULL)) {
+ return field->GetObj(NULL);
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, self, true, false, false, sizeof(Object*));
+ if (LIKELY(field != NULL)) {
+ return field->GetObj(NULL);
+ }
+ return NULL; // Will throw exception by checking with Thread::Current
+}
+
+extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, Object* obj,
+ const Method* referrer, Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
+ if (LIKELY(field != NULL && obj != NULL)) {
+ return field->Get32(obj);
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int32_t));
+ if (LIKELY(field != NULL)) {
+ if (UNLIKELY(obj == NULL)) {
+ ThrowNullPointerExceptionForFieldAccess(self, field, true);
+ } else {
+ return field->Get32(obj);
+ }
+ }
+ return 0; // Will throw exception by checking with Thread::Current
+}
+
+extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, Object* obj,
+ const Method* referrer, Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
+ if (LIKELY(field != NULL && obj != NULL)) {
+ return field->Get64(obj);
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int64_t));
+ if (LIKELY(field != NULL)) {
+ if (UNLIKELY(obj == NULL)) {
+ ThrowNullPointerExceptionForFieldAccess(self, field, true);
+ } else {
+ return field->Get64(obj);
+ }
+ }
+ return 0; // Will throw exception by checking with Thread::Current
+}
+
+extern "C" Object* artGetObjInstanceFromCode(uint32_t field_idx, Object* obj,
+ const Method* referrer, Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
+ if (LIKELY(field != NULL && obj != NULL)) {
+ return field->GetObj(obj);
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, self, false, false, false, sizeof(Object*));
+ if (LIKELY(field != NULL)) {
+ if (UNLIKELY(obj == NULL)) {
+ ThrowNullPointerExceptionForFieldAccess(self, field, true);
+ } else {
+ return field->GetObj(obj);
+ }
+ }
+ return NULL; // Will throw exception by checking with Thread::Current
+}
+
+extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value,
+ const Method* referrer, Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
+ if (LIKELY(field != NULL)) {
+ field->Set32(NULL, new_value);
+ return 0; // success
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int32_t));
+ if (LIKELY(field != NULL)) {
+ field->Set32(NULL, new_value);
+ return 0; // success
+ }
+ return -1; // failure
+}
+
+extern "C" int artSet64StaticFromCode(uint32_t field_idx, const Method* referrer,
+ uint64_t new_value, Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
+ if (LIKELY(field != NULL)) {
+ field->Set64(NULL, new_value);
+ return 0; // success
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int64_t));
+ if (LIKELY(field != NULL)) {
+ field->Set64(NULL, new_value);
+ return 0; // success
+ }
+ return -1; // failure
+}
+
+extern "C" int artSetObjStaticFromCode(uint32_t field_idx, Object* new_value,
+ const Method* referrer, Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
+ if (LIKELY(field != NULL)) {
+ if (LIKELY(!FieldHelper(field).IsPrimitiveType())) {
+ field->SetObj(NULL, new_value);
+ return 0; // success
+ }
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, self, true, false, true, sizeof(Object*));
+ if (LIKELY(field != NULL)) {
+ field->SetObj(NULL, new_value);
+ return 0; // success
+ }
+ return -1; // failure
+}
+
+extern "C" int artSet32InstanceFromCode(uint32_t field_idx, Object* obj, uint32_t new_value,
+ const Method* referrer, Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
+ if (LIKELY(field != NULL && obj != NULL)) {
+ field->Set32(obj, new_value);
+ return 0; // success
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int32_t));
+ if (LIKELY(field != NULL)) {
+ if (UNLIKELY(obj == NULL)) {
+ ThrowNullPointerExceptionForFieldAccess(self, field, false);
+ } else {
+ field->Set32(obj, new_value);
+ return 0; // success
+ }
+ }
+ return -1; // failure
+}
+
+extern "C" int artSet64InstanceFromCode(uint32_t field_idx, Object* obj, uint64_t new_value,
+ Thread* self, Method** sp) {
+ Method* callee_save = Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsOnly);
+ Method* referrer = sp[callee_save->GetFrameSizeInBytes() / sizeof(Method*)];
+ Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
+ if (LIKELY(field != NULL && obj != NULL)) {
+ field->Set64(obj, new_value);
+ return 0; // success
+ }
+ *sp = callee_save;
+ self->SetTopOfStack(sp, 0);
+ field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int64_t));
+ if (LIKELY(field != NULL)) {
+ if (UNLIKELY(obj == NULL)) {
+ ThrowNullPointerExceptionForFieldAccess(self, field, false);
+ } else {
+ field->Set64(obj, new_value);
+ return 0; // success
+ }
+ }
+ return -1; // failure
+}
+
+extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, Object* obj, Object* new_value,
+ const Method* referrer, Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
+ if (LIKELY(field != NULL && obj != NULL)) {
+ field->SetObj(obj, new_value);
+ return 0; // success
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, self, false, false, true, sizeof(Object*));
+ if (LIKELY(field != NULL)) {
+ if (UNLIKELY(obj == NULL)) {
+ ThrowNullPointerExceptionForFieldAccess(self, field, false);
+ } else {
+ field->SetObj(obj, new_value);
+ return 0; // success
+ }
+ }
+ return -1; // failure
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_fillarray.cc b/src/oat/runtime/support_fillarray.cc
new file mode 100644
index 0000000..eb1c46c
--- /dev/null
+++ b/src/oat/runtime/support_fillarray.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 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 "callee_save_frame.h"
+#include "object.h"
+
+namespace art {
+
+/*
+ * Fill the array with predefined constant values, throwing exceptions if the array is null or
+ * not of sufficient length.
+ *
+ * NOTE: When dealing with a raw dex file, the data to be copied uses
+ * little-endian ordering. Require that oat2dex do any required swapping
+ * so this routine can get by with a memcpy().
+ *
+ * Format of the data:
+ * ushort ident = 0x0300 magic value
+ * ushort width width of each element in the table
+ * uint size number of elements in the table
+ * ubyte data[size*width] table of data values (may contain a single-byte
+ * padding at the end)
+ */
+extern "C" int artHandleFillArrayDataFromCode(Array* array, const uint16_t* table,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ DCHECK_EQ(table[0], 0x0300);
+ if (UNLIKELY(array == NULL)) {
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
+ "null array in fill array");
+ return -1; // Error
+ }
+ DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
+ uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
+ if (UNLIKELY(static_cast<int32_t>(size) > array->GetLength())) {
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
+ "failed array fill. length=%d; index=%d", array->GetLength(), size);
+ return -1; // Error
+ }
+ uint16_t width = table[1];
+ uint32_t size_in_bytes = size * width;
+ memcpy((char*)array + Array::DataOffset(width).Int32Value(), (char*)&table[4], size_in_bytes);
+ return 0; // Success
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_invoke.cc b/src/oat/runtime/support_invoke.cc
new file mode 100644
index 0000000..14040ce
--- /dev/null
+++ b/src/oat/runtime/support_invoke.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2012 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 "callee_save_frame.h"
+#include "runtime_support.h"
+
+namespace art {
+
+static uint64_t artInvokeCommon(uint32_t method_idx, Object* this_object, Method* caller_method,
+ Thread* self, Method** sp, bool access_check, InvokeType type){
+ Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type);
+ if (UNLIKELY(method == NULL)) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
+ if (UNLIKELY(this_object == NULL && type != kDirect && type != kStatic)) {
+ ThrowNullPointerExceptionForMethodAccess(self, caller_method, method_idx, type);
+ return 0; // failure
+ }
+ method = FindMethodFromCode(method_idx, this_object, caller_method, self, access_check, type);
+ if (UNLIKELY(method == NULL)) {
+ CHECK(self->IsExceptionPending());
+ return 0; // failure
+ }
+ }
+ DCHECK(!self->IsExceptionPending());
+ const void* code = method->GetCode();
+
+ // When we return, the caller will branch to this address, so it had better not be 0!
+ CHECK(code != NULL) << PrettyMethod(method);
+
+ uint32_t method_uint = reinterpret_cast<uint32_t>(method);
+ uint64_t code_uint = reinterpret_cast<uint32_t>(code);
+ uint64_t result = ((code_uint << 32) | method_uint);
+ return result;
+}
+
+// See comments in runtime_support_asm.S
+extern "C" uint64_t artInvokeInterfaceTrampoline(uint32_t method_idx, Object* this_object,
+ Method* caller_method, Thread* self,
+ Method** sp) {
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, false, kInterface);
+}
+
+extern "C" uint64_t artInvokeInterfaceTrampolineWithAccessCheck(uint32_t method_idx,
+ Object* this_object,
+ Method* caller_method, Thread* self,
+ Method** sp) {
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kInterface);
+}
+
+
+extern "C" uint64_t artInvokeDirectTrampolineWithAccessCheck(uint32_t method_idx,
+ Object* this_object,
+ Method* caller_method, Thread* self,
+ Method** sp) {
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kDirect);
+}
+
+extern "C" uint64_t artInvokeStaticTrampolineWithAccessCheck(uint32_t method_idx,
+ Object* this_object,
+ Method* caller_method, Thread* self,
+ Method** sp) {
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kStatic);
+}
+
+extern "C" uint64_t artInvokeSuperTrampolineWithAccessCheck(uint32_t method_idx,
+ Object* this_object,
+ Method* caller_method, Thread* self,
+ Method** sp) {
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kSuper);
+}
+
+extern "C" uint64_t artInvokeVirtualTrampolineWithAccessCheck(uint32_t method_idx,
+ Object* this_object,
+ Method* caller_method, Thread* self,
+ Method** sp) {
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kVirtual);
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_jni.cc b/src/oat/runtime/support_jni.cc
new file mode 100644
index 0000000..d74f78f
--- /dev/null
+++ b/src/oat/runtime/support_jni.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * 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 "object.h"
+#include "object_utils.h"
+#include "thread.h"
+
+namespace art {
+
+// Used by the JNI dlsym stub to find the native method to invoke if none is registered.
+extern void* FindNativeMethod(Thread* self) {
+ DCHECK(Thread::Current() == self);
+
+ Method* method = const_cast<Method*>(self->GetCurrentMethod());
+ DCHECK(method != NULL);
+
+ // Lookup symbol address for method, on failure we'll return NULL with an
+ // exception set, otherwise we return the address of the method we found.
+ void* native_code = self->GetJniEnv()->vm->FindCodeForNativeMethod(method);
+ if (native_code == NULL) {
+ DCHECK(self->IsExceptionPending());
+ return NULL;
+ } else {
+ // Register so that future calls don't come here
+ method->RegisterNative(self, native_code);
+ return native_code;
+ }
+}
+
+// Return value helper for jobject return types, used for JNI return values.
+extern Object* DecodeJObjectInThread(Thread* thread, jobject obj) {
+ if (thread->IsExceptionPending()) {
+ return NULL;
+ }
+ return thread->DecodeJObject(obj);
+}
+
+static void WorkAroundJniBugsForJobject(intptr_t* arg_ptr) {
+ intptr_t value = *arg_ptr;
+ Object** value_as_jni_rep = reinterpret_cast<Object**>(value);
+ Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL;
+ CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep)) << value_as_work_around_rep;
+ *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep);
+}
+
+extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp) {
+ DCHECK(Thread::Current() == self);
+ // TODO: this code is specific to ARM
+ // On entry the stack pointed by sp is:
+ // | arg3 | <- Calling JNI method's frame (and extra bit for out args)
+ // | LR |
+ // | R3 | arg2
+ // | R2 | arg1
+ // | R1 | jclass/jobject
+ // | R0 | JNIEnv
+ // | unused |
+ // | unused |
+ // | unused | <- sp
+ Method* jni_method = self->GetTopOfStack().GetMethod();
+ DCHECK(jni_method->IsNative()) << PrettyMethod(jni_method);
+ intptr_t* arg_ptr = sp + 4; // pointer to r1 on stack
+ // Fix up this/jclass argument
+ WorkAroundJniBugsForJobject(arg_ptr);
+ arg_ptr++;
+ // Fix up jobject arguments
+ MethodHelper mh(jni_method);
+ int reg_num = 2; // Current register being processed, -1 for stack arguments.
+ for (uint32_t i = 1; i < mh.GetShortyLength(); i++) {
+ char shorty_char = mh.GetShorty()[i];
+ if (shorty_char == 'L') {
+ WorkAroundJniBugsForJobject(arg_ptr);
+ }
+ if (shorty_char == 'J' || shorty_char == 'D') {
+ if (reg_num == 2) {
+ arg_ptr = sp + 8; // skip to out arguments
+ reg_num = -1;
+ } else if (reg_num == 3) {
+ arg_ptr = sp + 10; // skip to out arguments plus 2 slots as long must be aligned
+ reg_num = -1;
+ } else {
+ DCHECK(reg_num == -1);
+ if ((reinterpret_cast<intptr_t>(arg_ptr) & 7) == 4) {
+ arg_ptr += 3; // unaligned, pad and move through stack arguments
+ } else {
+ arg_ptr += 2; // aligned, move through stack arguments
+ }
+ }
+ } else {
+ if (reg_num == 2) {
+ arg_ptr++; // move through register arguments
+ reg_num++;
+ } else if (reg_num == 3) {
+ arg_ptr = sp + 8; // skip to outgoing stack arguments
+ reg_num = -1;
+ } else {
+ DCHECK(reg_num == -1);
+ arg_ptr++; // move through stack arguments
+ }
+ }
+ }
+ // Load expected destination, see Method::RegisterNative
+ const void* code = reinterpret_cast<const void*>(jni_method->GetGcMapRaw());
+ if (UNLIKELY(code == NULL)) {
+ code = Runtime::Current()->GetJniDlsymLookupStub()->GetData();
+ jni_method->RegisterNative(self, code);
+ }
+ return code;
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_locks.cc b/src/oat/runtime/support_locks.cc
new file mode 100644
index 0000000..30fc567
--- /dev/null
+++ b/src/oat/runtime/support_locks.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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 "callee_save_frame.h"
+#include "object.h"
+
+namespace art {
+
+extern "C" int artUnlockObjectFromCode(Object* obj, Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ DCHECK(obj != NULL); // Assumed to have been checked before entry
+ // MonitorExit may throw exception
+ return obj->MonitorExit(self) ? 0 /* Success */ : -1 /* Failure */;
+}
+
+extern "C" void artLockObjectFromCode(Object* obj, Thread* thread, Method** sp) {
+ FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsOnly);
+ DCHECK(obj != NULL); // Assumed to have been checked before entry
+ obj->MonitorEnter(thread); // May block
+ DCHECK(thread->HoldsLock(obj));
+ // Only possible exception is NPE and is handled before entry
+ DCHECK(!thread->IsExceptionPending());
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_math.cc b/src/oat/runtime/support_math.cc
new file mode 100644
index 0000000..cb5f705
--- /dev/null
+++ b/src/oat/runtime/support_math.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * 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 <stdint.h>
+
+namespace art {
+
+int CmplFloat(float a, float b) {
+ if (a == b) {
+ return 0;
+ } else if (a < b) {
+ return -1;
+ } else if (a > b) {
+ return 1;
+ }
+ return -1;
+}
+
+int CmpgFloat(float a, float b) {
+ if (a == b) {
+ return 0;
+ } else if (a < b) {
+ return -1;
+ } else if (a > b) {
+ return 1;
+ }
+ return 1;
+}
+
+int CmpgDouble(double a, double b) {
+ if (a == b) {
+ return 0;
+ } else if (a < b) {
+ return -1;
+ } else if (a > b) {
+ return 1;
+ }
+ return 1;
+}
+
+int CmplDouble(double a, double b) {
+ if (a == b) {
+ return 0;
+ } else if (a < b) {
+ return -1;
+ } else if (a > b) {
+ return 1;
+ }
+ return -1;
+}
+
+/*
+ * Float/double conversion requires clamping to min and max of integer form. If
+ * target doesn't support this normally, use these.
+ */
+int64_t D2L(double d) {
+ static const double kMaxLong = (double) (int64_t) 0x7fffffffffffffffULL;
+ static const double kMinLong = (double) (int64_t) 0x8000000000000000ULL;
+ if (d >= kMaxLong) {
+ return (int64_t) 0x7fffffffffffffffULL;
+ } else if (d <= kMinLong) {
+ return (int64_t) 0x8000000000000000ULL;
+ } else if (d != d) { // NaN case
+ return 0;
+ } else {
+ return (int64_t) d;
+ }
+}
+
+int64_t F2L(float f) {
+ static const float kMaxLong = (float) (int64_t) 0x7fffffffffffffffULL;
+ static const float kMinLong = (float) (int64_t) 0x8000000000000000ULL;
+ if (f >= kMaxLong) {
+ return (int64_t) 0x7fffffffffffffffULL;
+ } else if (f <= kMinLong) {
+ return (int64_t) 0x8000000000000000ULL;
+ } else if (f != f) { // NaN case
+ return 0;
+ } else {
+ return (int64_t) f;
+ }
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_proxy.cc b/src/oat/runtime/support_proxy.cc
new file mode 100644
index 0000000..a9c7ebe
--- /dev/null
+++ b/src/oat/runtime/support_proxy.cc
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * 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 "object.h"
+#include "object_utils.h"
+#include "reflection.h"
+#include "thread.h"
+
+#include "ScopedLocalRef.h"
+
+namespace art {
+
+static void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) {
+ ScopedLocalRef<jclass> jlr_UTE_class(env,
+ env->FindClass("java/lang/reflect/UndeclaredThrowableException"));
+ if (jlr_UTE_class.get() == NULL) {
+ LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\"";
+ } else {
+ jmethodID jlre_UTE_constructor = env->GetMethodID(jlr_UTE_class.get(), "<init>",
+ "(Ljava/lang/Throwable;)V");
+ jthrowable jexception = AddLocalReference<jthrowable>(env, exception);
+ ScopedLocalRef<jthrowable> jlr_UTE(env,
+ reinterpret_cast<jthrowable>(env->NewObject(jlr_UTE_class.get(), jlre_UTE_constructor,
+ jexception)));
+ int rc = env->Throw(jlr_UTE.get());
+ if (rc != JNI_OK) {
+ LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\"";
+ }
+ }
+ CHECK(self->IsExceptionPending());
+}
+
+// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
+// which is responsible for recording callee save registers. We explicitly handlerize incoming
+// reference arguments (so they survive GC) and create a boxed argument array. Finally we invoke
+// the invocation handler which is a field within the proxy object receiver.
+extern "C" void artProxyInvokeHandler(Method* proxy_method, Object* receiver,
+ Thread* self, byte* stack_args) {
+ // Register the top of the managed stack
+ Method** proxy_sp = reinterpret_cast<Method**>(stack_args - 12);
+ DCHECK_EQ(*proxy_sp, proxy_method);
+ self->SetTopOfStack(proxy_sp, 0);
+ // TODO: ARM specific
+ DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), 48u);
+ // Start new JNI local reference state
+ JNIEnvExt* env = self->GetJniEnv();
+ ScopedJniEnvLocalRefState env_state(env);
+ // Create local ref. copies of proxy method and the receiver
+ jobject rcvr_jobj = AddLocalReference<jobject>(env, receiver);
+ jobject proxy_method_jobj = AddLocalReference<jobject>(env, proxy_method);
+
+ // Placing into local references incoming arguments from the caller's register arguments,
+ // replacing original Object* with jobject
+ MethodHelper proxy_mh(proxy_method);
+ const size_t num_params = proxy_mh.NumArgs();
+ size_t args_in_regs = 0;
+ for (size_t i = 1; i < num_params; i++) { // skip receiver
+ args_in_regs = args_in_regs + (proxy_mh.IsParamALongOrDouble(i) ? 2 : 1);
+ if (args_in_regs > 2) {
+ args_in_regs = 2;
+ break;
+ }
+ }
+ size_t cur_arg = 0; // current stack location to read
+ size_t param_index = 1; // skip receiver
+ while (cur_arg < args_in_regs && param_index < num_params) {
+ if (proxy_mh.IsParamAReference(param_index)) {
+ Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
+ jobject jobj = AddLocalReference<jobject>(env, obj);
+ *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
+ }
+ cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
+ param_index++;
+ }
+ // Placing into local references incoming arguments from the caller's stack arguments
+ cur_arg += 11; // skip callee saves, LR, Method* and out arg spills for R1 to R3
+ while (param_index < num_params) {
+ if (proxy_mh.IsParamAReference(param_index)) {
+ Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
+ jobject jobj = AddLocalReference<jobject>(env, obj);
+ *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
+ }
+ cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
+ param_index++;
+ }
+ // Set up arguments array and place in local IRT during boxing (which may allocate/GC)
+ jvalue args_jobj[3];
+ args_jobj[0].l = rcvr_jobj;
+ args_jobj[1].l = proxy_method_jobj;
+ // Args array, if no arguments then NULL (don't include receiver in argument count)
+ args_jobj[2].l = NULL;
+ ObjectArray<Object>* args = NULL;
+ if ((num_params - 1) > 0) {
+ args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(num_params - 1);
+ if (args == NULL) {
+ CHECK(self->IsExceptionPending());
+ return;
+ }
+ args_jobj[2].l = AddLocalReference<jobjectArray>(env, args);
+ }
+ // Convert proxy method into expected interface method
+ Method* interface_method = proxy_method->FindOverriddenMethod();
+ DCHECK(interface_method != NULL);
+ DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
+ args_jobj[1].l = AddLocalReference<jobject>(env, interface_method);
+ // Box arguments
+ cur_arg = 0; // reset stack location to read to start
+ // reset index, will index into param type array which doesn't include the receiver
+ param_index = 0;
+ ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes();
+ if (param_types == NULL) {
+ CHECK(self->IsExceptionPending());
+ return;
+ }
+ // Check number of parameter types agrees with number from the Method - less 1 for the receiver.
+ DCHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
+ while (cur_arg < args_in_regs && param_index < (num_params - 1)) {
+ Class* param_type = param_types->Get(param_index);
+ Object* obj;
+ if (!param_type->IsPrimitive()) {
+ obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
+ } else {
+ JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
+ if (cur_arg == 1 && (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble())) {
+ // long/double split over regs and stack, mask in high half from stack arguments
+ uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args + (13 * kPointerSize));
+ val.j = (val.j & 0xffffffffULL) | (high_half << 32);
+ }
+ BoxPrimitive(param_type->GetPrimitiveType(), val);
+ if (self->IsExceptionPending()) {
+ return;
+ }
+ obj = val.l;
+ }
+ args->Set(param_index, obj);
+ cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
+ param_index++;
+ }
+ // Placing into local references incoming arguments from the caller's stack arguments
+ cur_arg += 11; // skip callee saves, LR, Method* and out arg spills for R1 to R3
+ while (param_index < (num_params - 1)) {
+ Class* param_type = param_types->Get(param_index);
+ Object* obj;
+ if (!param_type->IsPrimitive()) {
+ obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
+ } else {
+ JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
+ BoxPrimitive(param_type->GetPrimitiveType(), val);
+ if (self->IsExceptionPending()) {
+ return;
+ }
+ obj = val.l;
+ }
+ args->Set(param_index, obj);
+ cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
+ param_index++;
+ }
+ // Get the InvocationHandler method and the field that holds it within the Proxy object
+ static jmethodID inv_hand_invoke_mid = NULL;
+ static jfieldID proxy_inv_hand_fid = NULL;
+ if (proxy_inv_hand_fid == NULL) {
+ ScopedLocalRef<jclass> proxy(env, env->FindClass("java/lang/reflect/Proxy"));
+ proxy_inv_hand_fid = env->GetFieldID(proxy.get(), "h", "Ljava/lang/reflect/InvocationHandler;");
+ ScopedLocalRef<jclass> inv_hand_class(env, env->FindClass("java/lang/reflect/InvocationHandler"));
+ inv_hand_invoke_mid = env->GetMethodID(inv_hand_class.get(), "invoke",
+ "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
+ }
+ DCHECK(env->IsInstanceOf(rcvr_jobj, env->FindClass("java/lang/reflect/Proxy")));
+ jobject inv_hand = env->GetObjectField(rcvr_jobj, proxy_inv_hand_fid);
+ // Call InvocationHandler.invoke
+ jobject result = env->CallObjectMethodA(inv_hand, inv_hand_invoke_mid, args_jobj);
+ // Place result in stack args
+ if (!self->IsExceptionPending()) {
+ Object* result_ref = self->DecodeJObject(result);
+ if (result_ref != NULL) {
+ JValue result_unboxed;
+ bool unboxed_okay = UnboxPrimitive(result_ref, proxy_mh.GetReturnType(), result_unboxed, "result");
+ if (!unboxed_okay) {
+ self->ClearException();
+ self->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
+ "Couldn't convert result of type %s to %s",
+ PrettyTypeOf(result_ref).c_str(),
+ PrettyDescriptor(proxy_mh.GetReturnType()).c_str());
+ return;
+ }
+ *reinterpret_cast<JValue*>(stack_args) = result_unboxed;
+ } else {
+ *reinterpret_cast<jobject*>(stack_args) = NULL;
+ }
+ } else {
+ // In the case of checked exceptions that aren't declared, the exception must be wrapped by
+ // a UndeclaredThrowableException.
+ Throwable* exception = self->GetException();
+ self->ClearException();
+ if (!exception->IsCheckedException()) {
+ self->SetException(exception);
+ } else {
+ SynthesizedProxyClass* proxy_class =
+ down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
+ int throws_index = -1;
+ size_t num_virt_methods = proxy_class->NumVirtualMethods();
+ for (size_t i = 0; i < num_virt_methods; i++) {
+ if (proxy_class->GetVirtualMethod(i) == proxy_method) {
+ throws_index = i;
+ break;
+ }
+ }
+ CHECK_NE(throws_index, -1);
+ ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
+ Class* exception_class = exception->GetClass();
+ bool declares_exception = false;
+ for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
+ Class* declared_exception = declared_exceptions->Get(i);
+ declares_exception = declared_exception->IsAssignableFrom(exception_class);
+ }
+ if (declares_exception) {
+ self->SetException(exception);
+ } else {
+ ThrowNewUndeclaredThrowableException(self, env, exception);
+ }
+ }
+ }
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc
new file mode 100644
index 0000000..cb224e8
--- /dev/null
+++ b/src/oat/runtime/support_stubs.cc
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * 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 "callee_save_frame.h"
+#include "dex_instruction.h"
+#include "object.h"
+#include "object_utils.h"
+
+// Architecture specific assembler helper to deliver exception.
+extern "C" void art_deliver_exception_from_code(void*);
+
+namespace art {
+
+// Lazily resolve a method. Called by stub code.
+const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp, Thread* thread,
+ Runtime::TrampolineType type) {
+ // TODO: this code is specific to ARM
+ // On entry the stack pointed by sp is:
+ // | argN | |
+ // | ... | |
+ // | arg4 | |
+ // | arg3 spill | | Caller's frame
+ // | arg2 spill | |
+ // | arg1 spill | |
+ // | Method* | ---
+ // | LR |
+ // | ... | callee saves
+ // | R3 | arg3
+ // | R2 | arg2
+ // | R1 | arg1
+ // | R0 |
+ // | Method* | <- sp
+ uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize);
+ DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
+ Method** caller_sp = reinterpret_cast<Method**>(reinterpret_cast<byte*>(sp) + 48);
+ uintptr_t caller_pc = regs[10];
+ FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
+ // Start new JNI local reference state
+ JNIEnvExt* env = thread->GetJniEnv();
+ ScopedJniEnvLocalRefState env_state(env);
+
+ // Compute details about the called method (avoid GCs)
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ Method* caller = *caller_sp;
+ bool is_static;
+ bool is_virtual;
+ uint32_t dex_method_idx;
+ const char* shorty;
+ uint32_t shorty_len;
+ if (type == Runtime::kUnknownMethod) {
+ DCHECK(called->IsRuntimeMethod());
+ // less two as return address may span into next dex instruction
+ uint32_t dex_pc = caller->ToDexPC(caller_pc - 2);
+ const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
+ CHECK_LT(dex_pc, code->insns_size_in_code_units_);
+ const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
+ Instruction::Code instr_code = instr->Opcode();
+ is_static = (instr_code == Instruction::INVOKE_STATIC) ||
+ (instr_code == Instruction::INVOKE_STATIC_RANGE);
+ is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
+ (instr_code == Instruction::INVOKE_VIRTUAL_RANGE) ||
+ (instr_code == Instruction::INVOKE_SUPER) ||
+ (instr_code == Instruction::INVOKE_SUPER_RANGE);
+ DCHECK(is_static || is_virtual || (instr_code == Instruction::INVOKE_DIRECT) ||
+ (instr_code == Instruction::INVOKE_DIRECT_RANGE));
+ DecodedInstruction dec_insn(instr);
+ dex_method_idx = dec_insn.vB;
+ shorty = linker->MethodShorty(dex_method_idx, caller, &shorty_len);
+ } else {
+ DCHECK(!called->IsRuntimeMethod());
+ is_static = type == Runtime::kStaticMethod;
+ is_virtual = false;
+ dex_method_idx = called->GetDexMethodIndex();
+ MethodHelper mh(called);
+ shorty = mh.GetShorty();
+ shorty_len = mh.GetShortyLength();
+ }
+ // Discover shorty (avoid GCs)
+ size_t args_in_regs = 0;
+ for (size_t i = 1; i < shorty_len; i++) {
+ char c = shorty[i];
+ args_in_regs = args_in_regs + (c == 'J' || c == 'D' ? 2 : 1);
+ if (args_in_regs > 3) {
+ args_in_regs = 3;
+ break;
+ }
+ }
+ // Place into local references incoming arguments from the caller's register arguments
+ size_t cur_arg = 1; // skip method_idx in R0, first arg is in R1
+ if (!is_static) {
+ Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
+ cur_arg++;
+ if (args_in_regs < 3) {
+ // If we thought we had fewer than 3 arguments in registers, account for the receiver
+ args_in_regs++;
+ }
+ AddLocalReference<jobject>(env, obj);
+ }
+ size_t shorty_index = 1; // skip return value
+ // Iterate while arguments and arguments in registers (less 1 from cur_arg which is offset to skip
+ // R0)
+ while ((cur_arg - 1) < args_in_regs && shorty_index < shorty_len) {
+ char c = shorty[shorty_index];
+ shorty_index++;
+ if (c == 'L') {
+ Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
+ AddLocalReference<jobject>(env, obj);
+ }
+ cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
+ }
+ // Place into local references incoming arguments from the caller's stack arguments
+ cur_arg += 11; // skip LR, Method* and spills for R1 to R3 and callee saves
+ while (shorty_index < shorty_len) {
+ char c = shorty[shorty_index];
+ shorty_index++;
+ if (c == 'L') {
+ Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
+ AddLocalReference<jobject>(env, obj);
+ }
+ cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
+ }
+ // Resolve method filling in dex cache
+ if (type == Runtime::kUnknownMethod) {
+ called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
+ }
+ const void* code = NULL;
+ if (LIKELY(!thread->IsExceptionPending())) {
+ if (LIKELY(called->IsDirect() == !is_virtual)) {
+ // Ensure that the called method's class is initialized.
+ Class* called_class = called->GetDeclaringClass();
+ linker->EnsureInitialized(called_class, true);
+ if (LIKELY(called_class->IsInitialized())) {
+ code = called->GetCode();
+ } else if (called_class->IsInitializing()) {
+ if (is_static) {
+ // Class is still initializing, go to oat and grab code (trampoline must be left in place
+ // until class is initialized to stop races between threads).
+ code = linker->GetOatCodeFor(called);
+ } else {
+ // No trampoline for non-static methods.
+ code = called->GetCode();
+ }
+ } else {
+ DCHECK(called_class->IsErroneous());
+ }
+ } else {
+ // Direct method has been made virtual
+ thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
+ "Expected direct method but found virtual: %s",
+ PrettyMethod(called, true).c_str());
+ }
+ }
+ if (UNLIKELY(code == NULL)) {
+ // Something went wrong in ResolveMethod or EnsureInitialized,
+ // go into deliver exception with the pending exception in r0
+ code = reinterpret_cast<void*>(art_deliver_exception_from_code);
+ regs[0] = reinterpret_cast<uintptr_t>(thread->GetException());
+ thread->ClearException();
+ } else {
+ // Expect class to at least be initializing.
+ DCHECK(called->GetDeclaringClass()->IsInitializing());
+ // Don't want infinite recursion.
+ DCHECK(code != Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod)->GetData());
+ // Set up entry into main method
+ regs[0] = reinterpret_cast<uintptr_t>(called);
+ }
+ return code;
+}
+
+// Called by the AbstractMethodError. Called by stub code.
+extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp) {
+ FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
+ thread->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
+ "abstract method \"%s\"", PrettyMethod(method).c_str());
+ thread->DeliverException();
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_thread.cc b/src/oat/runtime/support_thread.cc
new file mode 100644
index 0000000..ed04673
--- /dev/null
+++ b/src/oat/runtime/support_thread.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * 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 "callee_save_frame.h"
+#include "thread.h"
+#include "thread_list.h"
+
+namespace art {
+
+void CheckSuspendFromCode(Thread* thread) {
+ // Called when thread->suspend_count_ != 0
+ Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
+}
+
+extern "C" void artTestSuspendFromCode(Thread* thread, Method** sp) {
+ // Called when suspend count check value is 0 and thread->suspend_count_ != 0
+ FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsOnly);
+ Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_throw.cc b/src/oat/runtime/support_throw.cc
new file mode 100644
index 0000000..9f46b2b
--- /dev/null
+++ b/src/oat/runtime/support_throw.cc
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * 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 "callee_save_frame.h"
+#include "dex_verifier.h"
+#include "object.h"
+#include "object_utils.h"
+#include "runtime_support.h"
+#include "thread.h"
+
+namespace art {
+
+// Deliver an exception that's pending on thread helping set up a callee save frame on the way.
+extern "C" void artDeliverPendingExceptionFromCode(Thread* thread, Method** sp) {
+ FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
+ thread->DeliverException();
+}
+
+// Called by generated call to throw an exception.
+extern "C" void artDeliverExceptionFromCode(Throwable* exception, Thread* thread, Method** sp) {
+ /*
+ * exception may be NULL, in which case this routine should
+ * throw NPE. NOTE: this is a convenience for generated code,
+ * which previously did the null check inline and constructed
+ * and threw a NPE if NULL. This routine responsible for setting
+ * exception_ in thread and delivering the exception.
+ */
+ FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
+ if (exception == NULL) {
+ thread->ThrowNewException("Ljava/lang/NullPointerException;", "throw with null exception");
+ } else {
+ thread->SetException(exception);
+ }
+ thread->DeliverException();
+}
+
+// Called by generated call to throw a NPE exception.
+extern "C" void artThrowNullPointerExceptionFromCode(Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+ Frame fr = self->GetTopOfStack();
+ uintptr_t throw_native_pc = fr.GetReturnPC();
+ fr.Next();
+ Method* throw_method = fr.GetMethod();
+ uint32_t dex_pc = throw_method->ToDexPC(throw_native_pc - 2);
+ const DexFile::CodeItem* code = MethodHelper(throw_method).GetCodeItem();
+ CHECK_LT(dex_pc, code->insns_size_in_code_units_);
+ const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
+ DecodedInstruction dec_insn(instr);
+ switch (instr->Opcode()) {
+ case Instruction::INVOKE_DIRECT:
+ case Instruction::INVOKE_DIRECT_RANGE:
+ ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kDirect);
+ break;
+ case Instruction::INVOKE_VIRTUAL:
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kVirtual);
+ break;
+ case Instruction::IGET:
+ case Instruction::IGET_WIDE:
+ case Instruction::IGET_OBJECT:
+ case Instruction::IGET_BOOLEAN:
+ case Instruction::IGET_BYTE:
+ case Instruction::IGET_CHAR:
+ case Instruction::IGET_SHORT: {
+ Field* field =
+ Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
+ ThrowNullPointerExceptionForFieldAccess(self, field, true /* read */);
+ break;
+ }
+ case Instruction::IPUT:
+ case Instruction::IPUT_WIDE:
+ case Instruction::IPUT_OBJECT:
+ case Instruction::IPUT_BOOLEAN:
+ case Instruction::IPUT_BYTE:
+ case Instruction::IPUT_CHAR:
+ case Instruction::IPUT_SHORT: {
+ Field* field =
+ Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
+ ThrowNullPointerExceptionForFieldAccess(self, field, false /* write */);
+ break;
+ }
+ case Instruction::AGET:
+ case Instruction::AGET_WIDE:
+ case Instruction::AGET_OBJECT:
+ case Instruction::AGET_BOOLEAN:
+ case Instruction::AGET_BYTE:
+ case Instruction::AGET_CHAR:
+ case Instruction::AGET_SHORT:
+ self->ThrowNewException("Ljava/lang/NullPointerException;",
+ "Attempt to read from null array");
+ break;
+ case Instruction::APUT:
+ case Instruction::APUT_WIDE:
+ case Instruction::APUT_OBJECT:
+ case Instruction::APUT_BOOLEAN:
+ case Instruction::APUT_BYTE:
+ case Instruction::APUT_CHAR:
+ case Instruction::APUT_SHORT:
+ self->ThrowNewException("Ljava/lang/NullPointerException;",
+ "Attempt to write to null array");
+ break;
+ default: {
+ const DexFile& dex_file = Runtime::Current()->GetClassLinker()
+ ->FindDexFile(throw_method->GetDeclaringClass()->GetDexCache());
+ std::string message("Null pointer exception during instruction '");
+ message += instr->DumpString(&dex_file);
+ message += "'";
+ self->ThrowNewException("Ljava/lang/NullPointerException;", message.c_str());
+ break;
+ }
+ }
+ self->DeliverException();
+}
+
+// Called by generated call to throw an arithmetic divide by zero exception.
+extern "C" void artThrowDivZeroFromCode(Thread* thread, Method** sp) {
+ FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
+ thread->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
+ thread->DeliverException();
+}
+
+// Called by generated call to throw an array index out of bounds exception.
+extern "C" void artThrowArrayBoundsFromCode(int index, int limit, Thread* thread, Method** sp) {
+ FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
+ thread->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
+ "length=%d; index=%d", limit, index);
+ thread->DeliverException();
+}
+
+extern "C" void artThrowStackOverflowFromCode(Thread* thread, Method** sp) {
+ FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
+ // Remove extra entry pushed onto second stack during method tracing
+ if (Runtime::Current()->IsMethodTracingActive()) {
+ TraceMethodUnwindFromCode(thread);
+ }
+ thread->SetStackEndForStackOverflow(); // Allow space on the stack for constructor to execute
+ thread->ThrowNewExceptionF("Ljava/lang/StackOverflowError;",
+ "stack size %zdkb; default stack size: %zdkb",
+ thread->GetStackSize() / KB, Runtime::Current()->GetDefaultStackSize() / KB);
+ thread->ResetDefaultStackEnd(); // Return to default stack size
+ thread->DeliverException();
+}
+
+extern "C" void artThrowNoSuchMethodFromCode(int32_t method_idx, Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+ Frame frame = self->GetTopOfStack(); // We need the calling method as context for the method_idx
+ frame.Next();
+ Method* method = frame.GetMethod();
+ self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+ MethodNameFromIndex(method, method_idx, verifier::VERIFY_ERROR_REF_METHOD, false).c_str());
+ self->DeliverException();
+}
+
+static std::string ClassNameFromIndex(Method* method, uint32_t ref,
+ verifier::VerifyErrorRefType ref_type, bool access) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
+
+ uint16_t type_idx = 0;
+ if (ref_type == verifier::VERIFY_ERROR_REF_FIELD) {
+ const DexFile::FieldId& id = dex_file.GetFieldId(ref);
+ type_idx = id.class_idx_;
+ } else if (ref_type == verifier::VERIFY_ERROR_REF_METHOD) {
+ const DexFile::MethodId& id = dex_file.GetMethodId(ref);
+ type_idx = id.class_idx_;
+ } else if (ref_type == verifier::VERIFY_ERROR_REF_CLASS) {
+ type_idx = ref;
+ } else {
+ CHECK(false) << static_cast<int>(ref_type);
+ }
+
+ std::string class_name(PrettyDescriptor(dex_file.StringByTypeIdx(type_idx)));
+ if (!access) {
+ return class_name;
+ }
+
+ std::string result;
+ result += "tried to access class ";
+ result += class_name;
+ result += " from class ";
+ result += PrettyDescriptor(method->GetDeclaringClass());
+ return result;
+}
+
+extern "C" void artThrowVerificationErrorFromCode(int32_t kind, int32_t ref, Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+ Frame frame = self->GetTopOfStack(); // We need the calling method as context to interpret 'ref'
+ frame.Next();
+ Method* method = frame.GetMethod();
+
+ verifier::VerifyErrorRefType ref_type =
+ static_cast<verifier::VerifyErrorRefType>(kind >> verifier::kVerifyErrorRefTypeShift);
+
+ const char* exception_class = "Ljava/lang/VerifyError;";
+ std::string msg;
+
+ switch (static_cast<verifier::VerifyError>(kind & ~(0xff << verifier::kVerifyErrorRefTypeShift))) {
+ case verifier::VERIFY_ERROR_NO_CLASS:
+ exception_class = "Ljava/lang/NoClassDefFoundError;";
+ msg = ClassNameFromIndex(method, ref, ref_type, false);
+ break;
+ case verifier::VERIFY_ERROR_NO_FIELD:
+ exception_class = "Ljava/lang/NoSuchFieldError;";
+ msg = FieldNameFromIndex(method, ref, ref_type, false);
+ break;
+ case verifier::VERIFY_ERROR_NO_METHOD:
+ exception_class = "Ljava/lang/NoSuchMethodError;";
+ msg = MethodNameFromIndex(method, ref, ref_type, false);
+ break;
+ case verifier::VERIFY_ERROR_ACCESS_CLASS:
+ exception_class = "Ljava/lang/IllegalAccessError;";
+ msg = ClassNameFromIndex(method, ref, ref_type, true);
+ break;
+ case verifier::VERIFY_ERROR_ACCESS_FIELD:
+ exception_class = "Ljava/lang/IllegalAccessError;";
+ msg = FieldNameFromIndex(method, ref, ref_type, true);
+ break;
+ case verifier::VERIFY_ERROR_ACCESS_METHOD:
+ exception_class = "Ljava/lang/IllegalAccessError;";
+ msg = MethodNameFromIndex(method, ref, ref_type, true);
+ break;
+ case verifier::VERIFY_ERROR_CLASS_CHANGE:
+ exception_class = "Ljava/lang/IncompatibleClassChangeError;";
+ msg = ClassNameFromIndex(method, ref, ref_type, false);
+ break;
+ case verifier::VERIFY_ERROR_INSTANTIATION:
+ exception_class = "Ljava/lang/InstantiationError;";
+ msg = ClassNameFromIndex(method, ref, ref_type, false);
+ break;
+ case verifier::VERIFY_ERROR_BAD_CLASS_SOFT:
+ case verifier::VERIFY_ERROR_BAD_CLASS_HARD:
+ // Generic VerifyError; use default exception, no message.
+ break;
+ case verifier::VERIFY_ERROR_NONE:
+ CHECK(false);
+ break;
+ }
+ self->ThrowNewException(exception_class, msg.c_str());
+ self->DeliverException();
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_trace.cc b/src/oat/runtime/support_trace.cc
new file mode 100644
index 0000000..5c6a46e
--- /dev/null
+++ b/src/oat/runtime/support_trace.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * 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 "runtime.h"
+#include "thread.h"
+#include "trace.h"
+
+namespace art {
+
+extern "C" const void* artTraceMethodEntryFromCode(Method* method, Thread* self, uintptr_t lr) {
+ Trace* tracer = Runtime::Current()->GetTracer();
+ TraceStackFrame trace_frame = TraceStackFrame(method, lr);
+ self->PushTraceStackFrame(trace_frame);
+
+ tracer->LogMethodTraceEvent(self, method, Trace::kMethodTraceEnter);
+
+ return tracer->GetSavedCodeFromMap(method);
+}
+
+extern "C" uintptr_t artTraceMethodExitFromCode() {
+ Trace* tracer = Runtime::Current()->GetTracer();
+ TraceStackFrame trace_frame = Thread::Current()->PopTraceStackFrame();
+ Method* method = trace_frame.method_;
+ uintptr_t lr = trace_frame.return_pc_;
+
+ tracer->LogMethodTraceEvent(Thread::Current(), method, Trace::kMethodTraceExit);
+
+ return lr;
+}
+
+} // namespace art
diff --git a/src/context_x86.cc b/src/oat/runtime/x86/context_x86.cc
similarity index 100%
rename from src/context_x86.cc
rename to src/oat/runtime/x86/context_x86.cc
diff --git a/src/context_x86.h b/src/oat/runtime/x86/context_x86.h
similarity index 87%
rename from src/context_x86.h
rename to src/oat/runtime/x86/context_x86.h
index 829849e..72dc719 100644
--- a/src/context_x86.h
+++ b/src/oat/runtime/x86/context_x86.h
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-#ifndef ART_SRC_CONTEXT_X86_H_
-#define ART_SRC_CONTEXT_X86_H_
-
-#include "context.h"
+#ifndef ART_SRC_OAT_RUNTIME_X86_CONTEXT_X86_H_
+#define ART_SRC_OAT_RUNTIME_X86_CONTEXT_X86_H_
#include "constants_x86.h"
+#include "oat/runtime/context.h"
namespace art {
namespace x86 {
@@ -55,4 +54,4 @@
} // namespace x86
} // namespace art
-#endif // ART_SRC_CONTEXT_X86_H_
+#endif // ART_SRC_OAT_RUNTIME_X86_CONTEXT_X86_H_
diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
new file mode 100644
index 0000000..5d525a9
--- /dev/null
+++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2012 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 "oat/runtime/oat_support_entrypoints.h"
+
+namespace art {
+
+// Alloc entrypoints.
+extern "C" void* art_alloc_array_from_code(uint32_t, void*, int32_t);
+extern "C" void* art_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
+extern "C" void* art_alloc_object_from_code(uint32_t type_idx, void* method);
+extern "C" void* art_alloc_object_from_code_with_access_check(uint32_t type_idx, void* method);
+extern "C" void* art_check_and_alloc_array_from_code(uint32_t, void*, int32_t);
+extern "C" void* art_check_and_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
+
+// Cast entrypoints.
+extern uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class);
+extern "C" void art_can_put_array_element_from_code(void*, void*);
+extern "C" void art_check_cast_from_code(void*, void*);
+
+// Debug entrypoints.
+extern void DebugMe(Method* method, uint32_t info);
+
+// DexCache entrypoints.
+extern "C" void* art_initialize_static_storage_from_code(uint32_t, void*);
+extern "C" void* art_initialize_type_from_code(uint32_t, void*);
+extern "C" void* art_initialize_type_and_verify_access_from_code(uint32_t, void*);
+extern "C" void* art_resolve_string_from_code(void*, uint32_t);
+
+// Field entrypoints.
+extern "C" int art_set32_instance_from_code(uint32_t, void*, int32_t);
+extern "C" int art_set32_static_from_code(uint32_t, int32_t);
+extern "C" int art_set64_instance_from_code(uint32_t, void*, int64_t);
+extern "C" int art_set64_static_from_code(uint32_t, int64_t);
+extern "C" int art_set_obj_instance_from_code(uint32_t, void*, void*);
+extern "C" int art_set_obj_static_from_code(uint32_t, void*);
+extern "C" int32_t art_get32_instance_from_code(uint32_t, void*);
+extern "C" int32_t art_get32_static_from_code(uint32_t);
+extern "C" int64_t art_get64_instance_from_code(uint32_t, void*);
+extern "C" int64_t art_get64_static_from_code(uint32_t);
+extern "C" void* art_get_obj_instance_from_code(uint32_t, void*);
+extern "C" void* art_get_obj_static_from_code(uint32_t);
+
+// FillArray entrypoint.
+extern "C" void art_handle_fill_data_from_code(void*, void*);
+
+// JNI entrypoints.
+extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
+extern void* FindNativeMethod(Thread* thread);
+
+// Lock entrypoints.
+extern "C" void art_lock_object_from_code(void*);
+extern "C" void art_unlock_object_from_code(void*);
+
+// Math entrypoints.
+extern int32_t CmpgDouble(double a, double b);
+extern int32_t CmplDouble(double a, double b);
+extern int32_t CmpgFloat(float a, float b);
+extern int32_t CmplFloat(float a, float b);
+extern int64_t D2L(double d);
+extern int64_t F2L(float f);
+
+// Intrinsic entrypoints.
+extern "C" int32_t __memcmp16(void*, void*, int32_t);
+extern "C" int32_t art_indexof(void*, uint32_t, uint32_t, uint32_t);
+extern "C" int32_t art_string_compareto(void*, void*);
+
+// Invoke entrypoints.
+const void* UnresolvedDirectMethodTrampolineFromCode(Method*, Method**, Thread*,
+ Runtime::TrampolineType);
+extern "C" void art_invoke_direct_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_interface_trampoline(uint32_t, void*);
+extern "C" void art_invoke_interface_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_static_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_super_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
+
+// Thread entrypoints.
+extern void CheckSuspendFromCode(Thread* thread);
+extern "C" void art_test_suspend();
+
+// Throw entrypoints.
+extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
+extern "C" void art_deliver_exception_from_code(void*);
+extern "C" void art_throw_array_bounds_from_code(int32_t index, int32_t limit);
+extern "C" void art_throw_div_zero_from_code();
+extern "C" void art_throw_no_such_method_from_code(int32_t method_idx);
+extern "C" void art_throw_null_pointer_exception_from_code();
+extern "C" void art_throw_stack_overflow_from_code(void*);
+extern "C" void art_throw_verification_error_from_code(int32_t src1, int32_t ref);
+
+void InitEntryPoints(EntryPoints* points) {
+ // Alloc
+ points->pAllocArrayFromCode = art_alloc_array_from_code;
+ points->pAllocArrayFromCodeWithAccessCheck = art_alloc_array_from_code_with_access_check;
+ points->pAllocObjectFromCode = art_alloc_object_from_code;
+ points->pAllocObjectFromCodeWithAccessCheck = art_alloc_object_from_code_with_access_check;
+ points->pCheckAndAllocArrayFromCode = art_check_and_alloc_array_from_code;
+ points->pCheckAndAllocArrayFromCodeWithAccessCheck = art_check_and_alloc_array_from_code_with_access_check;
+
+ // Cast
+ points->pInstanceofNonTrivialFromCode = IsAssignableFromCode;
+ points->pCanPutArrayElementFromCode = art_can_put_array_element_from_code;
+ points->pCheckCastFromCode = art_check_cast_from_code;
+
+ // Debug
+ points->pDebugMe = DebugMe;
+ points->pUpdateDebuggerFromCode = NULL; // Controlled by SetDebuggerUpdatesEnabled.
+
+ // DexCache
+ points->pInitializeStaticStorage = art_initialize_static_storage_from_code;
+ points->pInitializeTypeAndVerifyAccessFromCode = art_initialize_type_and_verify_access_from_code;
+ points->pInitializeTypeFromCode = art_initialize_type_from_code;
+ points->pResolveStringFromCode = art_resolve_string_from_code;
+
+ // Field
+ points->pSet32Instance = art_set32_instance_from_code;
+ points->pSet32Static = art_set32_static_from_code;
+ points->pSet64Instance = art_set64_instance_from_code;
+ points->pSet64Static = art_set64_static_from_code;
+ points->pSetObjInstance = art_set_obj_instance_from_code;
+ points->pSetObjStatic = art_set_obj_static_from_code;
+ points->pGet32Instance = art_get32_instance_from_code;
+ points->pGet64Instance = art_get64_instance_from_code;
+ points->pGetObjInstance = art_get_obj_instance_from_code;
+ points->pGet32Static = art_get32_static_from_code;
+ points->pGet64Static = art_get64_static_from_code;
+ points->pGetObjStatic = art_get_obj_static_from_code;
+
+ // FillArray
+ points->pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
+
+ // JNI
+ points->pDecodeJObjectInThread = DecodeJObjectInThread;
+ points->pFindNativeMethod = FindNativeMethod;
+
+ // Locks
+ points->pLockObjectFromCode = art_lock_object_from_code;
+ points->pUnlockObjectFromCode = art_unlock_object_from_code;
+
+ // Math
+ points->pCmpgDouble = CmpgDouble;
+ points->pCmpgFloat = CmpgFloat;
+ points->pCmplDouble = CmplDouble;
+ points->pCmplFloat = CmplFloat;
+ points->pDadd = NULL;
+ points->pDdiv = NULL;
+ points->pDmul = NULL;
+ points->pDsub = NULL;
+ points->pF2d = NULL;
+ points->pFmod = NULL;
+ points->pI2d = NULL;
+ points->pL2d = NULL;
+ points->pD2f = NULL;
+ points->pFadd = NULL;
+ points->pFdiv = NULL;
+ points->pFmodf = NULL;
+ points->pFmul = NULL;
+ points->pFsub = NULL;
+ points->pI2f = NULL;
+ points->pL2f = NULL;
+ points->pD2iz = NULL;
+ points->pF2iz = NULL;
+ points->pIdiv = NULL;
+ points->pIdivmod = NULL;
+ points->pD2l = D2L;
+ points->pF2l = F2L;
+ points->pLadd = NULL;
+ points->pLand = NULL;
+ points->pLdivmod = NULL;
+ points->pLmul = NULL;
+ points->pLor = NULL;
+ points->pLsub = NULL;
+ points->pLxor = NULL;
+ points->pShlLong = NULL;
+ points->pShrLong = NULL;
+ points->pUshrLong = NULL;
+
+ // Intrinsics
+ points->pIndexOf = art_indexof;
+ points->pMemcmp16 = __memcmp16;
+ points->pStringCompareTo = art_string_compareto;
+ points->pMemcpy = memcpy;
+
+ // Invocation
+ points->pUnresolvedDirectMethodTrampolineFromCode = UnresolvedDirectMethodTrampolineFromCode;
+ points->pInvokeDirectTrampolineWithAccessCheck = art_invoke_direct_trampoline_with_access_check;
+ points->pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
+ points->pInvokeInterfaceTrampolineWithAccessCheck = art_invoke_interface_trampoline_with_access_check;
+ points->pInvokeStaticTrampolineWithAccessCheck = art_invoke_static_trampoline_with_access_check;
+ points->pInvokeSuperTrampolineWithAccessCheck = art_invoke_super_trampoline_with_access_check;
+ points->pInvokeVirtualTrampolineWithAccessCheck = art_invoke_virtual_trampoline_with_access_check;
+
+ // Thread
+ points->pCheckSuspendFromCode = CheckSuspendFromCode;
+ points->pTestSuspendFromCode = art_test_suspend;
+
+ // Throws
+ points->pDeliverException = art_deliver_exception_from_code;
+ points->pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;
+ points->pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code;
+ points->pThrowDivZeroFromCode = art_throw_div_zero_from_code;
+ points->pThrowNoSuchMethodFromCode = art_throw_no_such_method_from_code;
+ points->pThrowNullPointerFromCode = art_throw_null_pointer_exception_from_code;
+ points->pThrowStackOverflowFromCode = art_throw_stack_overflow_from_code;
+ points->pThrowVerificationErrorFromCode = art_throw_verification_error_from_code;
+};
+
+void ChangeDebuggerEntryPoint(EntryPoints*, bool) {
+ UNIMPLEMENTED(FATAL);
+}
+
+bool IsTraceExitPc(uintptr_t) {
+ return false;
+}
+
+void* GetLogTraceEntryPoint() {
+ return NULL;
+}
+
+} // namespace art
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
new file mode 100644
index 0000000..d344c34
--- /dev/null
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -0,0 +1,321 @@
+#include "asm_support.h"
+
+#if defined(__APPLE__)
+ // Mac OS X mangles the functions with an underscore prefix
+ #define art_deliver_exception_from_code _art_deliver_exception_from_code
+ #define art_proxy_invoke_handler _art_proxy_invoke_handler
+ #define artDeliverExceptionFromCode _artDeliverExceptionFromCode
+#endif
+
+ /* Deliver the given exception */
+ .extern artDeliverExceptionFromCode
+ /* Deliver an exception pending on a thread */
+ .extern artDeliverPendingException
+
+ /* Cache alignment for function entry */
+.macro ALIGN_FUNCTION_ENTRY
+ .balign 16
+.endm
+
+ /*
+ * Macro that sets up the callee save frame to conform with
+ * Runtime::CreateCalleeSaveMethod(...)
+ */
+.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+ pushl %edi // Save callee saves (ebx is saved/restored by the upcall)
+ pushl %esi
+ pushl %ebp
+ subl $16, %esp // Grow stack by 4 words, bottom word will hold Method*
+.endm
+
+.macro RESTORE_CALLEE_SAVE_FRAME
+ addl $16, %esp // Remove padding
+ popl %ebp // Restore callee saves
+ popl %esi
+ popl %edi
+.endm
+
+ /*
+ * Macro that sets up the callee save frame to conform with
+ * Runtime::CreateCalleeSaveMethod(...)
+ */
+.macro SETUP_REF_AND_ARG_CALLEE_SAVE_FRAME
+ pushl %edi // Save callee saves
+ pushl %esi
+ pushl %ebp
+ pushl %ebx // Save args
+ pushl %edx
+ pushl %ecx
+ pushl %eax // Align stack, eax will be clobbered by Method*
+.endm
+
+.macro RESTORE_REF_AND_ARG_CALLEE_SAVE_FRAME
+ addl $16, %esp // Remove padding
+ popl %ebp // Restore callee saves
+ popl %esi
+ popl %edi
+.endm
+
+ /*
+ * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending
+ * exception is Thread::Current()->exception_.
+ */
+.macro DELIVER_PENDING_EXCEPTION
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save callee saves for throw
+ mov %esp, %ecx
+ // Outgoing argument set up
+ subl $8, %esp // Alignment padding
+ pushl %ecx // pass SP
+ pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
+ call artDeliverPendingExceptionFromCode // artDeliverExceptionFromCode(Thread*, SP)
+ int3
+.endm
+
+.macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
+ .global \c_name
+ .extern \cxx_name
+ ALIGN_FUNCTION_ENTRY
+\c_name:
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
+ mov %esp, %ecx
+ // Outgoing argument set up
+ subl $8, %esp // alignment padding
+ pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
+ pushl %ecx // pass SP
+ call \cxx_name // \cxx_name(Thread*, SP)
+ int3 // unreached
+.endm
+
+.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
+ .global \c_name
+ .extern \cxx_name
+ ALIGN_FUNCTION_ENTRY
+\c_name:
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
+ mov %esp, %ecx
+ // Outgoing argument set up
+ pushl $0 // alignment padding
+ pushl %ecx // pass SP
+ pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
+ pushl %eax // pass arg1
+ call \cxx_name // \cxx_name(arg1, Thread*, SP)
+ int3 // unreached
+.endm
+
+.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
+ .global \c_name
+ .extern \cxx_name
+ ALIGN_FUNCTION_ENTRY
+\c_name:
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
+ mov %esp, %edx
+ // Outgoing argument set up
+ pushl %edx // pass SP
+ pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
+ pushl %eax // pass arg1
+ pushl %ecx // pass arg2
+ call \cxx_name // \cxx_name(arg1, Thread*, SP)
+ int3 // unreached
+.endm
+
+ /*
+ * Called by managed code, saves callee saves and then calls artThrowException
+ * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception.
+ */
+ONE_ARG_RUNTIME_EXCEPTION art_deliver_exception_from_code, artDeliverExceptionFromCode
+
+ /*
+ * Called by managed code to create and deliver a NullPointerException.
+ */
+NO_ARG_RUNTIME_EXCEPTION art_throw_null_pointer_exception_from_code, artThrowNullPointerExceptionFromCode
+
+ /*
+ * Called by managed code to create and deliver an ArithmeticException.
+ */
+NO_ARG_RUNTIME_EXCEPTION art_throw_div_zero_from_code, artThrowDivZeroFromCode
+
+ /*
+ * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
+ * index, arg2 holds limit.
+ */
+TWO_ARG_RUNTIME_EXCEPTION art_throw_array_bounds_from_code, artThrowArrayBoundsFromCode
+
+ /*
+ * Called by managed code to create and deliver a StackOverflowError.
+ */
+NO_ARG_RUNTIME_EXCEPTION art_throw_stack_overflow_from_code, artThrowStackOverflowFromCode
+
+ /*
+ * Called by managed code to create and deliver a NoSuchMethodError.
+ */
+ONE_ARG_RUNTIME_EXCEPTION art_throw_no_such_method_from_code, artThrowNoSuchMethodFromCode
+
+ /*
+ * Called by managed code to create and deliver verification errors. Arg1 is kind, arg2 is ref.
+ */
+TWO_ARG_RUNTIME_EXCEPTION art_throw_verification_error_from_code, artThrowVerificationErrorFromCode
+
+ /*
+ * All generated callsites for interface invokes and invocation slow paths will load arguments
+ * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
+ * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the
+ * stack and call the appropriate C helper.
+ * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
+ *
+ * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
+ * of the target Method* in r0 and method->code_ in r1.
+ *
+ * If unsuccessful, the helper will return NULL/NULL. There will bea pending exception in the
+ * thread and we branch to another stub to deliver it.
+ *
+ * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
+ * pointing back to the original caller.
+ */
+.macro INVOKE_TRAMPOLINE c_name, cxx_name
+ .global \c_name
+ .extern \cxx_name
+ ALIGN_FUNCTION_ENTRY
+\c_name:
+ int3
+.endm
+
+INVOKE_TRAMPOLINE art_invoke_interface_trampoline, artInvokeInterfaceTrampoline
+INVOKE_TRAMPOLINE art_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
+
+INVOKE_TRAMPOLINE art_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
+
+ // TODO
+ .globl art_proxy_invoke_handler
+art_proxy_invoke_handler:
+ int3
+
+ .globl art_update_debugger
+art_update_debugger:
+ int3
+
+ .globl art_test_suspend
+art_test_suspend:
+ int3
+
+ .globl art_alloc_object_from_code
+art_alloc_object_from_code:
+ int3
+
+ .globl art_alloc_object_from_code_with_access_check
+art_alloc_object_from_code_with_access_check:
+ int3
+
+ .globl art_alloc_array_from_code
+art_alloc_array_from_code:
+ int3
+
+ .globl art_alloc_array_from_code_with_access_check
+art_alloc_array_from_code_with_access_check:
+ int3
+
+ .globl art_check_and_alloc_array_from_code
+art_check_and_alloc_array_from_code:
+ int3
+
+ .globl art_check_and_alloc_array_from_code_with_access_check
+art_check_and_alloc_array_from_code_with_access_check:
+ int3
+
+ .globl art_can_put_array_element_from_code
+art_can_put_array_element_from_code:
+ int3
+
+ .globl art_check_cast_from_code
+art_check_cast_from_code:
+ int3
+
+ .globl art_initialize_static_storage_from_code
+art_initialize_static_storage_from_code:
+ int3
+
+ .globl art_initialize_type_and_verify_access_from_code
+art_initialize_type_and_verify_access_from_code:
+ int3
+
+ .globl art_initialize_type_from_code
+art_initialize_type_from_code:
+ int3
+
+ .globl art_resolve_string_from_code
+art_resolve_string_from_code:
+ int3
+
+ .globl art_set32_instance_from_code
+art_set32_instance_from_code:
+ int3
+
+ .globl art_set64_instance_from_code
+art_set64_instance_from_code:
+ int3
+
+ .globl art_set_obj_instance_from_code
+art_set_obj_instance_from_code:
+ int3
+
+ .globl art_get32_instance_from_code
+art_get32_instance_from_code:
+ int3
+
+ .globl art_get64_instance_from_code
+art_get64_instance_from_code:
+ int3
+
+ .globl art_get_obj_instance_from_code
+art_get_obj_instance_from_code:
+ int3
+
+ .globl art_set32_static_from_code
+art_set32_static_from_code:
+ int3
+
+ .globl art_set64_static_from_code
+art_set64_static_from_code:
+ int3
+
+ .globl art_set_obj_static_from_code
+art_set_obj_static_from_code:
+ int3
+
+ .globl art_get32_static_from_code
+art_get32_static_from_code:
+ int3
+
+ .globl art_get64_static_from_code
+art_get64_static_from_code:
+ int3
+
+ .globl art_get_obj_static_from_code
+art_get_obj_static_from_code:
+ int3
+
+ .globl art_handle_fill_data_from_code
+art_handle_fill_data_from_code:
+ int3
+
+ .globl art_lock_object_from_code
+art_lock_object_from_code:
+ int3
+
+ .globl art_unlock_object_from_code
+art_unlock_object_from_code:
+ int3
+
+ .globl art_indexof
+art_indexof:
+ int3
+
+ .globl __memcmp16
+__memcmp16:
+ int3
+
+ .globl art_string_compareto
+art_string_compareto:
+ int3
diff --git a/src/stub_x86.cc b/src/oat/runtime/x86/stub_x86.cc
similarity index 93%
rename from src/stub_x86.cc
rename to src/oat/runtime/x86/stub_x86.cc
index b07cfea..14e4f23 100644
--- a/src/stub_x86.cc
+++ b/src/oat/runtime/x86/stub_x86.cc
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#include "assembler_x86.h"
#include "jni_internal.h"
+#include "oat/runtime/oat_support_entrypoints.h"
+#include "oat/utils/x86/assembler_x86.h"
#include "object.h"
#include "stack_indirect_reference_table.h"
@@ -60,7 +61,7 @@
__ pushl(EAX); // pass Method*
// Call to throw AbstractMethodError.
- __ Call(ThreadOffset(OFFSETOF_MEMBER(Thread, pThrowAbstractMethodErrorFromCode)),
+ __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pThrowAbstractMethodErrorFromCode)),
X86ManagedRegister::FromCpuRegister(ECX));
#if defined(ART_USE_LLVM_COMPILER)
@@ -94,7 +95,7 @@
__ pushl(Immediate(0));
__ fs()->pushl(Address::Absolute(Thread::SelfOffset())); // Thread*
- __ Call(ThreadOffset(OFFSETOF_MEMBER(Thread, pFindNativeMethod)),
+ __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pFindNativeMethod)),
X86ManagedRegister::FromCpuRegister(ECX));
__ addl(ESP, Immediate(12));
diff --git a/src/assembler_arm.cc b/src/oat/utils/arm/assembler_arm.cc
similarity index 99%
rename from src/assembler_arm.cc
rename to src/oat/utils/arm/assembler_arm.cc
index 65f8e57..2392c7d 100644
--- a/src/assembler_arm.cc
+++ b/src/oat/utils/arm/assembler_arm.cc
@@ -17,6 +17,7 @@
#include "assembler_arm.h"
#include "logging.h"
+#include "oat/runtime/oat_support_entrypoints.h"
#include "offsets.h"
#include "thread.h"
#include "utils.h"
@@ -1885,7 +1886,7 @@
__ Store(return_save_location_, return_register_, return_size_);
// Pass thread as argument
__ mov(R0, ShifterOperand(TR));
- __ LoadFromOffset(kLoadWord, R12, TR, OFFSETOF_MEMBER(Thread, pCheckSuspendFromCode));
+ __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pCheckSuspendFromCode));
// Note: assume that link register will be spilled/filled on method entry/exit
__ blx(R12);
// Reload return value
@@ -1913,7 +1914,7 @@
// Don't care about preserving R0 as this call won't return
__ mov(R0, ShifterOperand(scratch_.AsCoreRegister()));
// Set up call to Thread::Current()->pDeliverException
- __ LoadFromOffset(kLoadWord, R12, TR, OFFSETOF_MEMBER(Thread, pDeliverException));
+ __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pDeliverException));
__ blx(R12);
// Call never returns
__ bkpt(0);
diff --git a/src/assembler_arm.h b/src/oat/utils/arm/assembler_arm.h
similarity index 98%
rename from src/assembler_arm.h
rename to src/oat/utils/arm/assembler_arm.h
index c557a36..d26fc1f 100644
--- a/src/assembler_arm.h
+++ b/src/oat/utils/arm/assembler_arm.h
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-#ifndef ART_SRC_ASSEMBLER_ARM_H_
-#define ART_SRC_ASSEMBLER_ARM_H_
+#ifndef ART_SRC_OAT_UTILS_ARM_ASSEMBLER_ARM_H_
+#define ART_SRC_OAT_UTILS_ARM_ASSEMBLER_ARM_H_
-#include "assembler.h"
#include "constants.h"
-#include "managed_register_arm.h"
#include "logging.h"
+#include "oat/utils/arm/managed_register_arm.h"
+#include "oat/utils/assembler.h"
#include "offsets.h"
#include "utils.h"
#include <vector>
@@ -670,4 +670,4 @@
} // namespace arm
} // namespace art
-#endif // ART_SRC_ASSEMBLER_ARM_H_
+#endif // ART_SRC_OAT_UTILS_ARM_ASSEMBLER_ARM_H_
diff --git a/src/managed_register_arm.cc b/src/oat/utils/arm/managed_register_arm.cc
similarity index 98%
rename from src/managed_register_arm.cc
rename to src/oat/utils/arm/managed_register_arm.cc
index 272c52b..57c2305 100644
--- a/src/managed_register_arm.cc
+++ b/src/oat/utils/arm/managed_register_arm.cc
@@ -17,7 +17,6 @@
#include "managed_register_arm.h"
#include "globals.h"
-#include "calling_convention.h"
namespace art {
namespace arm {
diff --git a/src/managed_register_arm.h b/src/oat/utils/arm/managed_register_arm.h
similarity index 97%
rename from src/managed_register_arm.h
rename to src/oat/utils/arm/managed_register_arm.h
index 3576b5a..8808d2b 100644
--- a/src/managed_register_arm.h
+++ b/src/oat/utils/arm/managed_register_arm.h
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#ifndef ART_SRC_MANAGED_REGISTER_ARM_H_
-#define ART_SRC_MANAGED_REGISTER_ARM_H_
+#ifndef ART_SRC_OAT_UTILS_ARM_MANAGED_REGISTER_ARM_H_
+#define ART_SRC_OAT_UTILS_ARM_MANAGED_REGISTER_ARM_H_
#include "constants.h"
#include "logging.h"
-#include "managed_register.h"
+#include "oat/utils/managed_register.h"
namespace art {
namespace arm {
@@ -271,4 +271,4 @@
} // namespace art
-#endif // ART_SRC_MANAGED_REGISTER_ARM_H_
+#endif // ART_SRC_OAT_UTILS_ARM_MANAGED_REGISTER_ARM_H_
diff --git a/src/managed_register_arm_test.cc b/src/oat/utils/arm/managed_register_arm_test.cc
similarity index 100%
rename from src/managed_register_arm_test.cc
rename to src/oat/utils/arm/managed_register_arm_test.cc
diff --git a/src/assembler.cc b/src/oat/utils/assembler.cc
similarity index 97%
rename from src/assembler.cc
rename to src/oat/utils/assembler.cc
index 2adf30b..249a771 100644
--- a/src/assembler.cc
+++ b/src/oat/utils/assembler.cc
@@ -19,8 +19,8 @@
#include <algorithm>
#include <vector>
-#include "assembler_arm.h"
-#include "assembler_x86.h"
+#include "arm/assembler_arm.h"
+#include "x86/assembler_x86.h"
#include "globals.h"
#include "memory_region.h"
diff --git a/src/assembler.h b/src/oat/utils/assembler.h
similarity index 98%
rename from src/assembler.h
rename to src/oat/utils/assembler.h
index af9f94d..6fd150d 100644
--- a/src/assembler.h
+++ b/src/oat/utils/assembler.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_SRC_ASSEMBLER_H_
-#define ART_SRC_ASSEMBLER_H_
+#ifndef ART_SRC_OAT_UTILS_ASSEMBLER_H_
+#define ART_SRC_OAT_UTILS_ASSEMBLER_H_
#include <vector>
@@ -450,7 +450,4 @@
} // namespace art
-#include "assembler_x86.h"
-#include "assembler_arm.h"
-
-#endif // ART_SRC_ASSEMBLER_H_
+#endif // ART_SRC_OAT_UTILS_ASSEMBLER_H_
diff --git a/src/managed_register.h b/src/oat/utils/managed_register.h
similarity index 91%
rename from src/managed_register.h
rename to src/oat/utils/managed_register.h
index e9236b9..c0fbd21 100644
--- a/src/managed_register.h
+++ b/src/oat/utils/managed_register.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_SRC_MANAGED_REGISTER_H_
-#define ART_SRC_MANAGED_REGISTER_H_
+#ifndef ART_SRC_OAT_UTILS_MANAGED_REGISTER_H_
+#define ART_SRC_OAT_UTILS_MANAGED_REGISTER_H_
namespace art {
@@ -65,4 +65,4 @@
} // namespace art
-#endif // ART_SRC_MANAGED_REGISTER_H_
+#endif // ART_SRC_OAT_UTILS_MANAGED_REGISTER_H_
diff --git a/src/assembler_x86.cc b/src/oat/utils/x86/assembler_x86.cc
similarity index 99%
rename from src/assembler_x86.cc
rename to src/oat/utils/x86/assembler_x86.cc
index ea283ce..0862551 100644
--- a/src/assembler_x86.cc
+++ b/src/oat/utils/x86/assembler_x86.cc
@@ -18,6 +18,7 @@
#include "casts.h"
#include "memory_region.h"
+#include "oat/runtime/oat_support_entrypoints.h"
#include "thread.h"
namespace art {
@@ -1815,7 +1816,7 @@
__ Store(return_save_location_, return_register_, return_size_);
// Pass Thread::Current as argument
__ fs()->pushl(Address::Absolute(Thread::SelfOffset()));
- __ fs()->call(Address::Absolute(OFFSETOF_MEMBER(Thread, pCheckSuspendFromCode)));
+ __ fs()->call(Address::Absolute(ENTRYPOINT_OFFSET(pCheckSuspendFromCode)));
// Release argument
__ addl(ESP, Immediate(kPointerSize));
// Reload return value
@@ -1838,7 +1839,7 @@
// Note: the return value is dead
// Pass exception as argument in EAX
__ fs()->movl(EAX, Address::Absolute(Thread::ExceptionOffset()));
- __ fs()->call(Address::Absolute(OFFSETOF_MEMBER(Thread, pDeliverException)));
+ __ fs()->call(Address::Absolute(ENTRYPOINT_OFFSET(pDeliverException)));
// this call should never return
__ int3();
#undef __
diff --git a/src/assembler_x86.h b/src/oat/utils/x86/assembler_x86.h
similarity index 98%
rename from src/assembler_x86.h
rename to src/oat/utils/x86/assembler_x86.h
index 24a84e7..f7d26ff 100644
--- a/src/assembler_x86.h
+++ b/src/oat/utils/x86/assembler_x86.h
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#ifndef ART_SRC_ASSEMBLER_X86_H_
-#define ART_SRC_ASSEMBLER_X86_H_
+#ifndef ART_SRC_OAT_UTILS_X86_ASSEMBLER_X86_H_
+#define ART_SRC_OAT_UTILS_X86_ASSEMBLER_X86_H_
#include <vector>
-#include "assembler.h"
#include "constants.h"
#include "globals.h"
#include "managed_register_x86.h"
#include "macros.h"
+#include "oat/utils/assembler.h"
#include "offsets.h"
#include "utils.h"
@@ -666,4 +666,4 @@
} // namespace x86
} // namespace art
-#endif // ART_SRC_ASSEMBLER_X86_H_
+#endif // ART_SRC_OAT_UTILS_X86_ASSEMBLER_X86_H_
diff --git a/src/assembler_x86_test.cc b/src/oat/utils/x86/assembler_x86_test.cc
similarity index 100%
rename from src/assembler_x86_test.cc
rename to src/oat/utils/x86/assembler_x86_test.cc
diff --git a/src/managed_register_x86.cc b/src/oat/utils/x86/managed_register_x86.cc
similarity index 97%
rename from src/managed_register_x86.cc
rename to src/oat/utils/x86/managed_register_x86.cc
index 453cab7..4697d06 100644
--- a/src/managed_register_x86.cc
+++ b/src/oat/utils/x86/managed_register_x86.cc
@@ -17,13 +17,12 @@
#include "managed_register_x86.h"
#include "globals.h"
-#include "calling_convention.h"
namespace art {
namespace x86 {
// These cpu registers are never available for allocation.
-static const Register kReservedCpuRegistersArray[] = { EBP, ESP };
+static const Register kReservedCpuRegistersArray[] = { ESP };
// We reduce the number of available registers for allocation in debug-code
diff --git a/src/managed_register_x86.h b/src/oat/utils/x86/managed_register_x86.h
similarity index 96%
rename from src/managed_register_x86.h
rename to src/oat/utils/x86/managed_register_x86.h
index edbf852..33573f9 100644
--- a/src/managed_register_x86.h
+++ b/src/oat/utils/x86/managed_register_x86.h
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#ifndef ART_SRC_MANAGED_REGISTER_X86_H_
-#define ART_SRC_MANAGED_REGISTER_X86_H_
+#ifndef ART_SRC_OAT_UTILS_X86_MANAGED_REGISTER_X86_H_
+#define ART_SRC_OAT_UTILS_X86_MANAGED_REGISTER_X86_H_
#include "constants_x86.h"
-#include "managed_register.h"
+#include "oat/utils/managed_register.h"
namespace art {
namespace x86 {
@@ -209,4 +209,4 @@
} // namespace art
-#endif // ART_SRC_MANAGED_REGISTER_X86_H_
+#endif // ART_SRC_OAT_UTILS_X86_MANAGED_REGISTER_X86_H_
diff --git a/src/managed_register_x86_test.cc b/src/oat/utils/x86/managed_register_x86_test.cc
similarity index 100%
rename from src/managed_register_x86_test.cc
rename to src/oat/utils/x86/managed_register_x86_test.cc
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 2dcf5b9..52763c6 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -24,12 +24,12 @@
#include <vector>
#include "class_linker.h"
-#include "context.h"
#include "dex_instruction.h"
#include "dex_verifier.h"
#include "disassembler.h"
#include "file.h"
#include "image.h"
+#include "oat/runtime/context.h" // For VmapTable
#include "object_utils.h"
#include "os.h"
#include "runtime.h"
diff --git a/src/object.h b/src/object.h
index ad8194a..426a48c 100644
--- a/src/object.h
+++ b/src/object.h
@@ -861,8 +861,17 @@
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, fp_spill_mask_), fp_spill_mask, false);
}
+ // Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal
+ // conventions for a method of managed code.
+ bool IsRuntimeMethod() const {
+ return GetDexMethodIndex() == DexFile::kDexNoIndex16;
+ }
+
// Is this a hand crafted method used for something like describing callee saves?
bool IsCalleeSaveMethod() const {
+ if (!IsRuntimeMethod()) {
+ return false;
+ }
Runtime* runtime = Runtime::Current();
bool result = false;
for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
@@ -871,8 +880,6 @@
break;
}
}
- // Check that if we do think it is phony it looks like the callee save method
- DCHECK(!result || GetDexMethodIndex() == DexFile::kDexNoIndex16);
return result;
}
@@ -883,12 +890,6 @@
return result;
}
- // Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal
- // conventions for a method of managed code.
- bool IsRuntimeMethod() const {
- return GetDexMethodIndex() == DexFile::kDexNoIndex16;
- }
-
// Converts a native PC to a dex PC. TODO: this is a no-op
// until we associate a PC mapping table with each method.
uint32_t ToDexPC(const uintptr_t pc) const;
diff --git a/src/object_test.cc b/src/object_test.cc
index bf07aa3..de32f69 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -386,11 +386,6 @@
ASSERT_TRUE(x.get() != NULL);
ASSERT_TRUE(y.get() != NULL);
- EXPECT_EQ(1U, IsAssignableFromCode(X, x->GetClass()));
- EXPECT_EQ(0U, IsAssignableFromCode(Y, x->GetClass()));
- EXPECT_EQ(1U, IsAssignableFromCode(X, y->GetClass()));
- EXPECT_EQ(1U, IsAssignableFromCode(Y, y->GetClass()));
-
EXPECT_TRUE(x->InstanceOf(X));
EXPECT_FALSE(x->InstanceOf(Y));
EXPECT_TRUE(y->InstanceOf(X));
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index a55c55c..9072d58 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 Google Inc. All Rights Reserved.
+ * Copyright 2012 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,250 +16,98 @@
#include "runtime_support.h"
-#include "debugger.h"
-#include "dex_cache.h"
-#include "dex_verifier.h"
-#include "macros.h"
-#include "object.h"
-#include "object_utils.h"
-#include "reflection.h"
-#include "runtime_support_common.h"
-#include "trace.h"
-#include "ScopedLocalRef.h"
-
namespace art {
-// Place a special frame at the TOS that will save the callee saves for the given type
-static void FinishCalleeSaveFrameSetup(Thread* self, Method** sp, Runtime::CalleeSaveType type) {
- // Be aware the store below may well stomp on an incoming argument
- *sp = Runtime::Current()->GetCalleeSaveMethod(type);
- self->SetTopOfStack(sp, 0);
- self->VerifyStack();
+void ThrowNewIllegalAccessErrorClass(Thread* self,
+ Class* referrer,
+ Class* accessed) {
+ self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+ "illegal class access: '%s' -> '%s'",
+ PrettyDescriptor(referrer).c_str(),
+ PrettyDescriptor(accessed).c_str());
}
-/*
- * Report location to debugger. Note: dex_pc is the current offset within
- * the method. However, because the offset alone cannot distinguish between
- * method entry and offset 0 within the method, we'll use an offset of -1
- * to denote method entry.
- */
-extern "C" void artUpdateDebuggerFromCode(int32_t dex_pc, Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
- Dbg::UpdateDebugger(dex_pc, self, sp);
+void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self,
+ Class* referrer,
+ Class* accessed,
+ const Method* caller,
+ const Method* called,
+ InvokeType type) {
+ std::ostringstream type_stream;
+ type_stream << type;
+ self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+ "illegal class access ('%s' -> '%s')"
+ "in attempt to invoke %s method '%s' from '%s'",
+ PrettyDescriptor(referrer).c_str(),
+ PrettyDescriptor(accessed).c_str(),
+ type_stream.str().c_str(),
+ PrettyMethod(called).c_str(),
+ PrettyMethod(caller).c_str());
}
-// Temporary debugging hook for compiler.
-extern void DebugMe(Method* method, uint32_t info) {
- LOG(INFO) << "DebugMe";
- if (method != NULL) {
- LOG(INFO) << PrettyMethod(method);
- }
- LOG(INFO) << "Info: " << info;
+void ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
+ const Method* referrer,
+ const Method* interface_method,
+ Object* this_object) {
+ self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
+ "class '%s' does not implement interface '%s' in call to '%s' from '%s'",
+ PrettyDescriptor(this_object->GetClass()).c_str(),
+ PrettyDescriptor(interface_method->GetDeclaringClass()).c_str(),
+ PrettyMethod(interface_method).c_str(), PrettyMethod(referrer).c_str());
}
-// Return value helper for jobject return types
-extern Object* DecodeJObjectInThread(Thread* thread, jobject obj) {
- if (thread->IsExceptionPending()) {
- return NULL;
- }
- return thread->DecodeJObject(obj);
+void ThrowNewIllegalAccessErrorField(Thread* self,
+ Class* referrer,
+ Field* accessed) {
+ self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+ "Field '%s' is inaccessible to class '%s'",
+ PrettyField(accessed, false).c_str(),
+ PrettyDescriptor(referrer).c_str());
}
-extern void* FindNativeMethod(Thread* self) {
- DCHECK(Thread::Current() == self);
-
- Method* method = const_cast<Method*>(self->GetCurrentMethod());
- DCHECK(method != NULL);
-
- // Lookup symbol address for method, on failure we'll return NULL with an
- // exception set, otherwise we return the address of the method we found.
- void* native_code = self->GetJniEnv()->vm->FindCodeForNativeMethod(method);
- if (native_code == NULL) {
- DCHECK(self->IsExceptionPending());
- return NULL;
- } else {
- // Register so that future calls don't come here
- method->RegisterNative(self, native_code);
- return native_code;
- }
+void ThrowNewIllegalAccessErrorFinalField(Thread* self,
+ const Method* referrer,
+ Field* accessed) {
+ self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+ "Final field '%s' cannot be written to by method '%s'",
+ PrettyField(accessed, false).c_str(),
+ PrettyMethod(referrer).c_str());
}
-// Called by generated call to throw an exception
-extern "C" void artDeliverExceptionFromCode(Throwable* exception, Thread* thread, Method** sp) {
- /*
- * exception may be NULL, in which case this routine should
- * throw NPE. NOTE: this is a convenience for generated code,
- * which previously did the null check inline and constructed
- * and threw a NPE if NULL. This routine responsible for setting
- * exception_ in thread and delivering the exception.
- */
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
- if (exception == NULL) {
- thread->ThrowNewException("Ljava/lang/NullPointerException;", "throw with null exception");
- } else {
- thread->SetException(exception);
- }
- thread->DeliverException();
+void ThrowNewIllegalAccessErrorMethod(Thread* self,
+ Class* referrer,
+ Method* accessed) {
+ self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+ "Method '%s' is inaccessible to class '%s'",
+ PrettyMethod(accessed).c_str(),
+ PrettyDescriptor(referrer).c_str());
}
-// Deliver an exception that's pending on thread helping set up a callee save frame on the way
-extern "C" void artDeliverPendingExceptionFromCode(Thread* thread, Method** sp) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
- thread->DeliverException();
+void ThrowNullPointerExceptionForFieldAccess(Thread* self,
+ Field* field,
+ bool is_read) {
+ self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
+ "Attempt to %s field '%s' on a null object reference",
+ is_read ? "read from" : "write to",
+ PrettyField(field, true).c_str());
}
-// Called by generated call to throw a NPE exception
-extern "C" void artThrowNullPointerExceptionFromCode(Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
- Frame fr = self->GetTopOfStack();
- uintptr_t throw_native_pc = fr.GetReturnPC();
- fr.Next();
- Method* throw_method = fr.GetMethod();
- uint32_t dex_pc = throw_method->ToDexPC(throw_native_pc - 2);
- const DexFile::CodeItem* code = MethodHelper(throw_method).GetCodeItem();
- CHECK_LT(dex_pc, code->insns_size_in_code_units_);
- const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
- DecodedInstruction dec_insn(instr);
- switch (instr->Opcode()) {
- case Instruction::INVOKE_DIRECT:
- case Instruction::INVOKE_DIRECT_RANGE:
- ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kDirect);
- break;
- case Instruction::INVOKE_VIRTUAL:
- case Instruction::INVOKE_VIRTUAL_RANGE:
- ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kVirtual);
- break;
- case Instruction::IGET:
- case Instruction::IGET_WIDE:
- case Instruction::IGET_OBJECT:
- case Instruction::IGET_BOOLEAN:
- case Instruction::IGET_BYTE:
- case Instruction::IGET_CHAR:
- case Instruction::IGET_SHORT: {
- Field* field =
- Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
- ThrowNullPointerExceptionForFieldAccess(self, field, true /* read */);
- break;
- }
- case Instruction::IPUT:
- case Instruction::IPUT_WIDE:
- case Instruction::IPUT_OBJECT:
- case Instruction::IPUT_BOOLEAN:
- case Instruction::IPUT_BYTE:
- case Instruction::IPUT_CHAR:
- case Instruction::IPUT_SHORT: {
- Field* field =
- Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
- ThrowNullPointerExceptionForFieldAccess(self, field, false /* write */);
- break;
- }
- case Instruction::AGET:
- case Instruction::AGET_WIDE:
- case Instruction::AGET_OBJECT:
- case Instruction::AGET_BOOLEAN:
- case Instruction::AGET_BYTE:
- case Instruction::AGET_CHAR:
- case Instruction::AGET_SHORT:
- self->ThrowNewException("Ljava/lang/NullPointerException;",
- "Attempt to read from null array");
- break;
- case Instruction::APUT:
- case Instruction::APUT_WIDE:
- case Instruction::APUT_OBJECT:
- case Instruction::APUT_BOOLEAN:
- case Instruction::APUT_BYTE:
- case Instruction::APUT_CHAR:
- case Instruction::APUT_SHORT:
- self->ThrowNewException("Ljava/lang/NullPointerException;",
- "Attempt to write to null array");
- break;
- default: {
- const DexFile& dex_file = Runtime::Current()->GetClassLinker()
- ->FindDexFile(throw_method->GetDeclaringClass()->GetDexCache());
- std::string message("Null pointer exception during instruction '");
- message += instr->DumpString(&dex_file);
- message += "'";
- self->ThrowNewException("Ljava/lang/NullPointerException;", message.c_str());
- break;
- }
- }
- self->DeliverException();
+void ThrowNullPointerExceptionForMethodAccess(Thread* self,
+ Method* caller,
+ uint32_t method_idx,
+ InvokeType type) {
+ const DexFile& dex_file =
+ Runtime::Current()->GetClassLinker()->FindDexFile(caller->GetDeclaringClass()->GetDexCache());
+ std::ostringstream type_stream;
+ type_stream << type;
+ self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
+ "Attempt to invoke %s method '%s' on a null object reference",
+ type_stream.str().c_str(),
+ PrettyMethod(method_idx, dex_file, true).c_str());
}
-// Called by generated call to throw an arithmetic divide by zero exception
-extern "C" void artThrowDivZeroFromCode(Thread* thread, Method** sp) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
- thread->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
- thread->DeliverException();
-}
-
-// Called by generated call to throw an arithmetic divide by zero exception
-extern "C" void artThrowArrayBoundsFromCode(int index, int limit, Thread* thread, Method** sp) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
- thread->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
- "length=%d; index=%d", limit, index);
- thread->DeliverException();
-}
-
-// Called by the AbstractMethodError stub (not runtime support)
-extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp) {
-#if !defined(ART_USE_LLVM_COMPILER)
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
-#endif
- thread->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
- "abstract method \"%s\"", PrettyMethod(method).c_str());
-#if !defined(ART_USE_LLVM_COMPILER)
- thread->DeliverException();
-#endif
-}
-
-extern "C" void artThrowStackOverflowFromCode(Method* /*method*/, Thread* thread, Method** sp) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
- // Remove extra entry pushed onto second stack during method tracing
- if (Runtime::Current()->IsMethodTracingActive()) {
- TraceMethodUnwindFromCode(thread);
- }
- thread->SetStackEndForStackOverflow(); // Allow space on the stack for constructor to execute
- thread->ThrowNewExceptionF("Ljava/lang/StackOverflowError;",
- "stack size %zdkb; default stack size: %zdkb",
- thread->GetStackSize() / KB, Runtime::Current()->GetDefaultStackSize() / KB);
- thread->ResetDefaultStackEnd(); // Return to default stack size
- thread->DeliverException();
-}
-
-static std::string ClassNameFromIndex(Method* method, uint32_t ref,
- verifier::VerifyErrorRefType ref_type, bool access) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
-
- uint16_t type_idx = 0;
- if (ref_type == verifier::VERIFY_ERROR_REF_FIELD) {
- const DexFile::FieldId& id = dex_file.GetFieldId(ref);
- type_idx = id.class_idx_;
- } else if (ref_type == verifier::VERIFY_ERROR_REF_METHOD) {
- const DexFile::MethodId& id = dex_file.GetMethodId(ref);
- type_idx = id.class_idx_;
- } else if (ref_type == verifier::VERIFY_ERROR_REF_CLASS) {
- type_idx = ref;
- } else {
- CHECK(false) << static_cast<int>(ref_type);
- }
-
- std::string class_name(PrettyDescriptor(dex_file.StringByTypeIdx(type_idx)));
- if (!access) {
- return class_name;
- }
-
- std::string result;
- result += "tried to access class ";
- result += class_name;
- result += " from class ";
- result += PrettyDescriptor(method->GetDeclaringClass());
- return result;
-}
-
-static std::string FieldNameFromIndex(const Method* method, uint32_t ref,
- verifier::VerifyErrorRefType ref_type, bool access) {
+std::string FieldNameFromIndex(const Method* method, uint32_t ref,
+ verifier::VerifyErrorRefType ref_type, bool access) {
CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_FIELD));
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -280,8 +128,8 @@
return result;
}
-static std::string MethodNameFromIndex(const Method* method, uint32_t ref,
- verifier::VerifyErrorRefType ref_type, bool access) {
+std::string MethodNameFromIndex(const Method* method, uint32_t ref,
+ verifier::VerifyErrorRefType ref_type, bool access) {
CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_METHOD));
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -303,1092 +151,228 @@
return result;
}
-extern "C" void artThrowVerificationErrorFromCode(int32_t kind, int32_t ref, Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
- Frame frame = self->GetTopOfStack(); // We need the calling method as context to interpret 'ref'
- frame.Next();
- Method* method = frame.GetMethod();
-
- verifier::VerifyErrorRefType ref_type =
- static_cast<verifier::VerifyErrorRefType>(kind >> verifier::kVerifyErrorRefTypeShift);
-
- const char* exception_class = "Ljava/lang/VerifyError;";
- std::string msg;
-
- switch (static_cast<verifier::VerifyError>(kind & ~(0xff << verifier::kVerifyErrorRefTypeShift))) {
- case verifier::VERIFY_ERROR_NO_CLASS:
- exception_class = "Ljava/lang/NoClassDefFoundError;";
- msg = ClassNameFromIndex(method, ref, ref_type, false);
- break;
- case verifier::VERIFY_ERROR_NO_FIELD:
- exception_class = "Ljava/lang/NoSuchFieldError;";
- msg = FieldNameFromIndex(method, ref, ref_type, false);
- break;
- case verifier::VERIFY_ERROR_NO_METHOD:
- exception_class = "Ljava/lang/NoSuchMethodError;";
- msg = MethodNameFromIndex(method, ref, ref_type, false);
- break;
- case verifier::VERIFY_ERROR_ACCESS_CLASS:
- exception_class = "Ljava/lang/IllegalAccessError;";
- msg = ClassNameFromIndex(method, ref, ref_type, true);
- break;
- case verifier::VERIFY_ERROR_ACCESS_FIELD:
- exception_class = "Ljava/lang/IllegalAccessError;";
- msg = FieldNameFromIndex(method, ref, ref_type, true);
- break;
- case verifier::VERIFY_ERROR_ACCESS_METHOD:
- exception_class = "Ljava/lang/IllegalAccessError;";
- msg = MethodNameFromIndex(method, ref, ref_type, true);
- break;
- case verifier::VERIFY_ERROR_CLASS_CHANGE:
- exception_class = "Ljava/lang/IncompatibleClassChangeError;";
- msg = ClassNameFromIndex(method, ref, ref_type, false);
- break;
- case verifier::VERIFY_ERROR_INSTANTIATION:
- exception_class = "Ljava/lang/InstantiationError;";
- msg = ClassNameFromIndex(method, ref, ref_type, false);
- break;
- case verifier::VERIFY_ERROR_BAD_CLASS_SOFT:
- case verifier::VERIFY_ERROR_BAD_CLASS_HARD:
- // Generic VerifyError; use default exception, no message.
- break;
- case verifier::VERIFY_ERROR_NONE:
- CHECK(false);
- break;
+// Helper function to allocate array for FILLED_NEW_ARRAY.
+Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
+ Thread* self, bool access_check) {
+ if (UNLIKELY(component_count < 0)) {
+ self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count);
+ return NULL; // Failure
}
- self->ThrowNewException(exception_class, msg.c_str());
- self->DeliverException();
-}
-
-extern "C" void artThrowInternalErrorFromCode(int32_t errnum, Thread* thread, Method** sp) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
- LOG(WARNING) << "TODO: internal error detail message. errnum=" << errnum;
- thread->ThrowNewExceptionF("Ljava/lang/InternalError;", "errnum=%d", errnum);
- thread->DeliverException();
-}
-
-extern "C" void artThrowRuntimeExceptionFromCode(int32_t errnum, Thread* thread, Method** sp) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
- LOG(WARNING) << "TODO: runtime exception detail message. errnum=" << errnum;
- thread->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "errnum=%d", errnum);
- thread->DeliverException();
-}
-
-extern "C" void artThrowNoSuchMethodFromCode(int32_t method_idx, Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
- Frame frame = self->GetTopOfStack(); // We need the calling method as context for the method_idx
- frame.Next();
- Method* method = frame.GetMethod();
- self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
- MethodNameFromIndex(method, method_idx, verifier::VERIFY_ERROR_REF_METHOD, false).c_str());
- self->DeliverException();
-}
-
-extern "C" void artThrowNegArraySizeFromCode(int32_t size, Thread* thread, Method** sp) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
- LOG(WARNING) << "UNTESTED artThrowNegArraySizeFromCode";
- thread->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", size);
- thread->DeliverException();
-}
-
-const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp, Thread* thread,
- Runtime::TrampolineType type) {
- // TODO: this code is specific to ARM
- // On entry the stack pointed by sp is:
- // | argN | |
- // | ... | |
- // | arg4 | |
- // | arg3 spill | | Caller's frame
- // | arg2 spill | |
- // | arg1 spill | |
- // | Method* | ---
- // | LR |
- // | ... | callee saves
- // | R3 | arg3
- // | R2 | arg2
- // | R1 | arg1
- // | R0 |
- // | Method* | <- sp
- uintptr_t* regs = reinterpret_cast<uintptr_t*>(reinterpret_cast<byte*>(sp) + kPointerSize);
- DCHECK_EQ(48U, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
- Method** caller_sp = reinterpret_cast<Method**>(reinterpret_cast<byte*>(sp) + 48);
- uintptr_t caller_pc = regs[10];
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
- // Start new JNI local reference state
- JNIEnvExt* env = thread->GetJniEnv();
- ScopedJniEnvLocalRefState env_state(env);
-
- // Compute details about the called method (avoid GCs)
- ClassLinker* linker = Runtime::Current()->GetClassLinker();
- Method* caller = *caller_sp;
- bool is_static;
- bool is_virtual;
- uint32_t dex_method_idx;
- const char* shorty;
- uint32_t shorty_len;
- if (type == Runtime::kUnknownMethod) {
- DCHECK(called->IsRuntimeMethod());
- // less two as return address may span into next dex instruction
- uint32_t dex_pc = caller->ToDexPC(caller_pc - 2);
- const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
- CHECK_LT(dex_pc, code->insns_size_in_code_units_);
- const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
- Instruction::Code instr_code = instr->Opcode();
- is_static = (instr_code == Instruction::INVOKE_STATIC) ||
- (instr_code == Instruction::INVOKE_STATIC_RANGE);
- is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
- (instr_code == Instruction::INVOKE_VIRTUAL_RANGE) ||
- (instr_code == Instruction::INVOKE_SUPER) ||
- (instr_code == Instruction::INVOKE_SUPER_RANGE);
- DCHECK(is_static || is_virtual || (instr_code == Instruction::INVOKE_DIRECT) ||
- (instr_code == Instruction::INVOKE_DIRECT_RANGE));
- DecodedInstruction dec_insn(instr);
- dex_method_idx = dec_insn.vB;
- shorty = linker->MethodShorty(dex_method_idx, caller, &shorty_len);
- } else {
- DCHECK(!called->IsRuntimeMethod());
- is_static = type == Runtime::kStaticMethod;
- is_virtual = false;
- dex_method_idx = called->GetDexMethodIndex();
- MethodHelper mh(called);
- shorty = mh.GetShorty();
- shorty_len = mh.GetShortyLength();
- }
- // Discover shorty (avoid GCs)
- size_t args_in_regs = 0;
- for (size_t i = 1; i < shorty_len; i++) {
- char c = shorty[i];
- args_in_regs = args_in_regs + (c == 'J' || c == 'D' ? 2 : 1);
- if (args_in_regs > 3) {
- args_in_regs = 3;
- break;
+ Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
+ if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
+ klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
+ if (klass == NULL) { // Error
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return NULL; // Failure
}
}
- // Place into local references incoming arguments from the caller's register arguments
- size_t cur_arg = 1; // skip method_idx in R0, first arg is in R1
- if (!is_static) {
- Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
- cur_arg++;
- if (args_in_regs < 3) {
- // If we thought we had fewer than 3 arguments in registers, account for the receiver
- args_in_regs++;
- }
- AddLocalReference<jobject>(env, obj);
- }
- size_t shorty_index = 1; // skip return value
- // Iterate while arguments and arguments in registers (less 1 from cur_arg which is offset to skip
- // R0)
- while ((cur_arg - 1) < args_in_regs && shorty_index < shorty_len) {
- char c = shorty[shorty_index];
- shorty_index++;
- if (c == 'L') {
- Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
- AddLocalReference<jobject>(env, obj);
- }
- cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
- }
- // Place into local references incoming arguments from the caller's stack arguments
- cur_arg += 11; // skip LR, Method* and spills for R1 to R3 and callee saves
- while (shorty_index < shorty_len) {
- char c = shorty[shorty_index];
- shorty_index++;
- if (c == 'L') {
- Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
- AddLocalReference<jobject>(env, obj);
- }
- cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
- }
- // Resolve method filling in dex cache
- if (type == Runtime::kUnknownMethod) {
- called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
- }
- const void* code = NULL;
- if (LIKELY(!thread->IsExceptionPending())) {
- if (LIKELY(called->IsDirect() == !is_virtual)) {
- // Ensure that the called method's class is initialized.
- Class* called_class = called->GetDeclaringClass();
- linker->EnsureInitialized(called_class, true);
- if (LIKELY(called_class->IsInitialized())) {
- code = called->GetCode();
- } else if (called_class->IsInitializing()) {
- if (is_static) {
- // Class is still initializing, go to oat and grab code (trampoline must be left in place
- // until class is initialized to stop races between threads).
- code = linker->GetOatCodeFor(called);
- } else {
- // No trampoline for non-static methods.
- code = called->GetCode();
- }
- } else {
- DCHECK(called_class->IsErroneous());
- }
+ if (UNLIKELY(klass->IsPrimitive() && !klass->IsPrimitiveInt())) {
+ if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
+ "Bad filled array request for type %s",
+ PrettyDescriptor(klass).c_str());
} else {
- // Direct method has been made virtual
- thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
- "Expected direct method but found virtual: %s",
- PrettyMethod(called, true).c_str());
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/InternalError;",
+ "Found type %s; filled-new-array not implemented for anything but \'int\'",
+ PrettyDescriptor(klass).c_str());
}
- }
- if (UNLIKELY(code == NULL)) {
- // Something went wrong in ResolveMethod or EnsureInitialized,
- // go into deliver exception with the pending exception in r0
- code = reinterpret_cast<void*>(art_deliver_exception_from_code);
- regs[0] = reinterpret_cast<uintptr_t>(thread->GetException());
- thread->ClearException();
+ return NULL; // Failure
} else {
- // Expect class to at least be initializing.
- DCHECK(called->GetDeclaringClass()->IsInitializing());
- // Don't want infinite recursion.
- DCHECK(code != Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod)->GetData());
- // Set up entry into main method
- regs[0] = reinterpret_cast<uintptr_t>(called);
- }
- return code;
-}
-
-static void WorkAroundJniBugsForJobject(intptr_t* arg_ptr) {
- intptr_t value = *arg_ptr;
- Object** value_as_jni_rep = reinterpret_cast<Object**>(value);
- Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL;
- CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep)) << value_as_work_around_rep;
- *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep);
-}
-
-extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp) {
- DCHECK(Thread::Current() == self);
- // TODO: this code is specific to ARM
- // On entry the stack pointed by sp is:
- // | arg3 | <- Calling JNI method's frame (and extra bit for out args)
- // | LR |
- // | R3 | arg2
- // | R2 | arg1
- // | R1 | jclass/jobject
- // | R0 | JNIEnv
- // | unused |
- // | unused |
- // | unused | <- sp
- Method* jni_method = self->GetTopOfStack().GetMethod();
- DCHECK(jni_method->IsNative()) << PrettyMethod(jni_method);
- intptr_t* arg_ptr = sp + 4; // pointer to r1 on stack
- // Fix up this/jclass argument
- WorkAroundJniBugsForJobject(arg_ptr);
- arg_ptr++;
- // Fix up jobject arguments
- MethodHelper mh(jni_method);
- int reg_num = 2; // Current register being processed, -1 for stack arguments.
- for (uint32_t i = 1; i < mh.GetShortyLength(); i++) {
- char shorty_char = mh.GetShorty()[i];
- if (shorty_char == 'L') {
- WorkAroundJniBugsForJobject(arg_ptr);
+ if (access_check) {
+ Class* referrer = method->GetDeclaringClass();
+ if (UNLIKELY(!referrer->CanAccess(klass))) {
+ ThrowNewIllegalAccessErrorClass(self, referrer, klass);
+ return NULL; // Failure
+ }
}
- if (shorty_char == 'J' || shorty_char == 'D') {
- if (reg_num == 2) {
- arg_ptr = sp + 8; // skip to out arguments
- reg_num = -1;
- } else if (reg_num == 3) {
- arg_ptr = sp + 10; // skip to out arguments plus 2 slots as long must be aligned
- reg_num = -1;
+ DCHECK(klass->IsArrayClass()) << PrettyClass(klass);
+ return Array::Alloc(klass, component_count);
+ }
+}
+
+// Slow path field resolution and declaring class initialization
+Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
+ bool is_static, bool is_primitive, bool is_set, size_t expected_size) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
+ if (UNLIKELY(resolved_field == NULL)) {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind
+ return NULL; // failure
+ } else {
+ Class* fields_class = resolved_field->GetDeclaringClass();
+ Class* referring_class = referrer->GetDeclaringClass();
+ if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
+ ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
+ return NULL; // failure
+ } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
+ resolved_field->GetAccessFlags()))) {
+ ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
+ return NULL; // failure
+ } else if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
+ ThrowNewIllegalAccessErrorFinalField(self, referrer, resolved_field);
+ return NULL; // failure
+ } else {
+ FieldHelper fh(resolved_field);
+ if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
+ fh.FieldSize() != expected_size)) {
+ self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
+ "Attempted read of %zd-bit %s on field '%s'",
+ expected_size * (32 / sizeof(int32_t)),
+ is_primitive ? "primitive" : "non-primitive",
+ PrettyField(resolved_field, true).c_str());
+ return NULL; // failure
+ } else if (!is_static) {
+ // instance fields must be being accessed on an initialized class
+ return resolved_field;
} else {
- DCHECK(reg_num == -1);
- if ((reinterpret_cast<intptr_t>(arg_ptr) & 7) == 4) {
- arg_ptr += 3; // unaligned, pad and move through stack arguments
+ // If the class is already initializing, we must be inside <clinit>, or
+ // we'd still be waiting for the lock.
+ if (fields_class->IsInitializing()) {
+ return resolved_field;
+ } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true)) {
+ return resolved_field;
} else {
- arg_ptr += 2; // aligned, move through stack arguments
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind
+ return NULL; // failure
}
}
- } else {
- if (reg_num == 2) {
- arg_ptr++; // move through register arguments
- reg_num++;
- } else if (reg_num == 3) {
- arg_ptr = sp + 8; // skip to outgoing stack arguments
- reg_num = -1;
+ }
+ }
+}
+
+// Slow path method resolution
+Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
+ Thread* self, bool access_check, InvokeType type) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ bool is_direct = type == kStatic || type == kDirect;
+ Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, is_direct);
+ if (UNLIKELY(resolved_method == NULL)) {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind
+ return NULL; // failure
+ } else {
+ if (!access_check) {
+ if (is_direct) {
+ return resolved_method;
+ } else if (type == kInterface) {
+ Method* interface_method =
+ this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+ if (UNLIKELY(interface_method == NULL)) {
+ ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
+ resolved_method,
+ this_object);
+ return NULL; // failure
+ } else {
+ return interface_method;
+ }
} else {
- DCHECK(reg_num == -1);
- arg_ptr++; // move through stack arguments
+ ObjectArray<Method>* vtable;
+ uint16_t vtable_index = resolved_method->GetMethodIndex();
+ if (type == kSuper) {
+ vtable = referrer->GetDeclaringClass()->GetSuperClass()->GetVTable();
+ } else {
+ vtable = this_object->GetClass()->GetVTable();
+ }
+ // TODO: eliminate bounds check?
+ return vtable->Get(vtable_index);
+ }
+ } else {
+ Class* methods_class = resolved_method->GetDeclaringClass();
+ Class* referring_class = referrer->GetDeclaringClass();
+ if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
+ !referring_class->CanAccessMember(methods_class,
+ resolved_method->GetAccessFlags()))) {
+ // The referring class can't access the resolved method, this may occur as a result of a
+ // protected method being made public by implementing an interface that re-declares the
+ // method public. Resort to the dex file to determine the correct class for the access check
+ const DexFile& dex_file = class_linker->FindDexFile(referring_class->GetDexCache());
+ methods_class = class_linker->ResolveType(dex_file,
+ dex_file.GetMethodId(method_idx).class_idx_,
+ referring_class);
+ if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
+ ThrowNewIllegalAccessErrorClassForMethodDispatch(self, referring_class, methods_class,
+ referrer, resolved_method, type);
+ return NULL; // failure
+ } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class,
+ resolved_method->GetAccessFlags()))) {
+ ThrowNewIllegalAccessErrorMethod(self, referring_class, resolved_method);
+ return NULL; // failure
+ }
+ }
+ if (is_direct) {
+ return resolved_method;
+ } else if (type == kInterface) {
+ Method* interface_method =
+ this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+ if (UNLIKELY(interface_method == NULL)) {
+ ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
+ resolved_method,
+ this_object);
+ return NULL; // failure
+ } else {
+ return interface_method;
+ }
+ } else {
+ ObjectArray<Method>* vtable;
+ uint16_t vtable_index = resolved_method->GetMethodIndex();
+ if (type == kSuper) {
+ Class* super_class = referring_class->GetSuperClass();
+ if (LIKELY(super_class != NULL)) {
+ vtable = referring_class->GetSuperClass()->GetVTable();
+ } else {
+ vtable = NULL;
+ }
+ } else {
+ vtable = this_object->GetClass()->GetVTable();
+ }
+ if (LIKELY(vtable != NULL &&
+ vtable_index < static_cast<uint32_t>(vtable->GetLength()))) {
+ return vtable->GetWithoutChecks(vtable_index);
+ } else {
+ // Behavior to agree with that of the verifier
+ self->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
+ "attempt to invoke %s method '%s' from '%s'"
+ " using incorrect form of method dispatch",
+ (type == kSuper ? "super class" : "virtual"),
+ PrettyMethod(resolved_method).c_str(),
+ PrettyMethod(referrer).c_str());
+ return NULL; // failure
+ }
}
}
}
- // Load expected destination, see Method::RegisterNative
- const void* code = reinterpret_cast<const void*>(jni_method->GetGcMapRaw());
- if (UNLIKELY(code == NULL)) {
- code = Runtime::Current()->GetJniDlsymLookupStub()->GetData();
- jni_method->RegisterNative(self, code);
- }
- return code;
}
-
-extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
- Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
- if (LIKELY(field != NULL)) {
- return field->Get32(NULL);
- }
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int32_t));
- if (LIKELY(field != NULL)) {
- return field->Get32(NULL);
- }
- return 0; // Will throw exception by checking with Thread::Current
-}
-
-extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, const Method* referrer,
- Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
- if (LIKELY(field != NULL)) {
- return field->Get64(NULL);
- }
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int64_t));
- if (LIKELY(field != NULL)) {
- return field->Get64(NULL);
- }
- return 0; // Will throw exception by checking with Thread::Current
-}
-
-extern "C" Object* artGetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
- Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
- if (LIKELY(field != NULL)) {
- return field->GetObj(NULL);
- }
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, false, false, sizeof(Object*));
- if (LIKELY(field != NULL)) {
- return field->GetObj(NULL);
- }
- return NULL; // Will throw exception by checking with Thread::Current
-}
-
-extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, Object* obj,
- const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
- if (LIKELY(field != NULL && obj != NULL)) {
- return field->Get32(obj);
- }
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int32_t));
- if (LIKELY(field != NULL)) {
- if (UNLIKELY(obj == NULL)) {
- ThrowNullPointerExceptionForFieldAccess(self, field, true);
- } else {
- return field->Get32(obj);
- }
- }
- return 0; // Will throw exception by checking with Thread::Current
-}
-
-extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, Object* obj,
- const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
- if (LIKELY(field != NULL && obj != NULL)) {
- return field->Get64(obj);
- }
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int64_t));
- if (LIKELY(field != NULL)) {
- if (UNLIKELY(obj == NULL)) {
- ThrowNullPointerExceptionForFieldAccess(self, field, true);
- } else {
- return field->Get64(obj);
- }
- }
- return 0; // Will throw exception by checking with Thread::Current
-}
-
-extern "C" Object* artGetObjInstanceFromCode(uint32_t field_idx, Object* obj,
- const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
- if (LIKELY(field != NULL && obj != NULL)) {
- return field->GetObj(obj);
- }
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, false, false, false, sizeof(Object*));
- if (LIKELY(field != NULL)) {
- if (UNLIKELY(obj == NULL)) {
- ThrowNullPointerExceptionForFieldAccess(self, field, true);
- } else {
- return field->GetObj(obj);
- }
- }
- return NULL; // Will throw exception by checking with Thread::Current
-}
-
-extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value,
- const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
- if (LIKELY(field != NULL)) {
- field->Set32(NULL, new_value);
- return 0; // success
- }
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int32_t));
- if (LIKELY(field != NULL)) {
- field->Set32(NULL, new_value);
- return 0; // success
- }
- return -1; // failure
-}
-
-extern "C" int artSet64StaticFromCode(uint32_t field_idx, const Method* referrer,
- uint64_t new_value, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
- if (LIKELY(field != NULL)) {
- field->Set64(NULL, new_value);
- return 0; // success
- }
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int64_t));
- if (LIKELY(field != NULL)) {
- field->Set64(NULL, new_value);
- return 0; // success
- }
- return -1; // failure
-}
-
-extern "C" int artSetObjStaticFromCode(uint32_t field_idx, Object* new_value,
- const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
- if (LIKELY(field != NULL)) {
- if (LIKELY(!FieldHelper(field).IsPrimitiveType())) {
- field->SetObj(NULL, new_value);
- return 0; // success
- }
- }
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, true, false, true, sizeof(Object*));
- if (LIKELY(field != NULL)) {
- field->SetObj(NULL, new_value);
- return 0; // success
- }
- return -1; // failure
-}
-
-extern "C" int artSet32InstanceFromCode(uint32_t field_idx, Object* obj, uint32_t new_value,
- const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
- if (LIKELY(field != NULL && obj != NULL)) {
- field->Set32(obj, new_value);
- return 0; // success
- }
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int32_t));
- if (LIKELY(field != NULL)) {
- if (UNLIKELY(obj == NULL)) {
- ThrowNullPointerExceptionForFieldAccess(self, field, false);
- } else {
- field->Set32(obj, new_value);
- return 0; // success
- }
- }
- return -1; // failure
-}
-
-extern "C" int artSet64InstanceFromCode(uint32_t field_idx, Object* obj, uint64_t new_value,
- Thread* self, Method** sp) {
- Method* callee_save = Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsOnly);
- Method* referrer = sp[callee_save->GetFrameSizeInBytes() / sizeof(Method*)];
- Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
- if (LIKELY(field != NULL && obj != NULL)) {
- field->Set64(obj, new_value);
- return 0; // success
- }
- *sp = callee_save;
- self->SetTopOfStack(sp, 0);
- field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int64_t));
- if (LIKELY(field != NULL)) {
- if (UNLIKELY(obj == NULL)) {
- ThrowNullPointerExceptionForFieldAccess(self, field, false);
- } else {
- field->Set64(obj, new_value);
- return 0; // success
- }
- }
- return -1; // failure
-}
-
-extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, Object* obj, Object* new_value,
- const Method* referrer, Thread* self, Method** sp) {
- Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
- if (LIKELY(field != NULL && obj != NULL)) {
- field->SetObj(obj, new_value);
- return 0; // success
- }
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, false, false, true, sizeof(Object*));
- if (LIKELY(field != NULL)) {
- if (UNLIKELY(obj == NULL)) {
- ThrowNullPointerExceptionForFieldAccess(self, field, false);
- } else {
- field->SetObj(obj, new_value);
- return 0; // success
- }
- }
- return -1; // failure
-}
-
-extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method,
- Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return AllocObjectFromCode(type_idx, method, self, false);
-}
-
-extern "C" Object* artAllocObjectFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
- Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return AllocObjectFromCode(type_idx, method, self, true);
-}
-
-extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
- Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return AllocArrayFromCode(type_idx, method, component_count, self, false);
-}
-
-extern "C" Array* artAllocArrayFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
- int32_t component_count,
- Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return AllocArrayFromCode(type_idx, method, component_count, self, true);
-}
-
-extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
- int32_t component_count, Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, false);
-}
-
-extern "C" Array* artCheckAndAllocArrayFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
- int32_t component_count,
- Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, true);
-}
-
-// Assignable test for code, won't throw. Null and equality tests already performed
-uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class) {
- DCHECK(klass != NULL);
- DCHECK(ref_class != NULL);
- return klass->IsAssignableFrom(ref_class) ? 1 : 0;
-}
-
-// Check whether it is safe to cast one class to the other, throw exception and return -1 on failure
-extern "C" int artCheckCastFromCode(const Class* a, const Class* b, Thread* self, Method** sp) {
- DCHECK(a->IsClass()) << PrettyClass(a);
- DCHECK(b->IsClass()) << PrettyClass(b);
- if (LIKELY(b->IsAssignableFrom(a))) {
- return 0; // Success
- } else {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
- "%s cannot be cast to %s",
- PrettyDescriptor(a).c_str(),
- PrettyDescriptor(b).c_str());
- return -1; // Failure
- }
-}
-
-// Tests whether 'element' can be assigned into an array of type 'array_class'.
-// Returns 0 on success and -1 if an exception is pending.
-extern "C" int artCanPutArrayElementFromCode(const Object* element, const Class* array_class,
- Thread* self, Method** sp) {
- DCHECK(array_class != NULL);
- // element can't be NULL as we catch this is screened in runtime_support
- Class* element_class = element->GetClass();
- Class* component_type = array_class->GetComponentType();
- if (LIKELY(component_type->IsAssignableFrom(element_class))) {
- return 0; // Success
- } else {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
- "%s cannot be stored in an array of type %s",
- PrettyDescriptor(element_class).c_str(),
- PrettyDescriptor(array_class).c_str());
- return -1; // Failure
- }
-}
-
-extern "C" Class* artInitializeStaticStorageFromCode(uint32_t type_idx, const Method* referrer,
- Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return ResolveVerifyAndClinit(type_idx, referrer, self, true, true);
-}
-
-extern "C" Class* artInitializeTypeFromCode(uint32_t type_idx, const Method* referrer, Thread* self,
- Method** sp) {
- // Called when method->dex_cache_resolved_types_[] misses
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return ResolveVerifyAndClinit(type_idx, referrer, self, false, false);
-}
-
-extern "C" Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx,
- const Method* referrer, Thread* self,
- Method** sp) {
- // Called when caller isn't guaranteed to have access to a type and the dex cache may be
- // unpopulated
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return ResolveVerifyAndClinit(type_idx, referrer, self, false, true);
-}
-
-extern "C" String* artResolveStringFromCode(Method* referrer, int32_t string_idx,
- Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return ResolveStringFromCode(referrer, string_idx);
-}
-
-extern "C" int artUnlockObjectFromCode(Object* obj, Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- DCHECK(obj != NULL); // Assumed to have been checked before entry
- // MonitorExit may throw exception
- return obj->MonitorExit(self) ? 0 /* Success */ : -1 /* Failure */;
-}
-
-extern "C" void artLockObjectFromCode(Object* obj, Thread* thread, Method** sp) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsOnly);
- DCHECK(obj != NULL); // Assumed to have been checked before entry
- obj->MonitorEnter(thread); // May block
- DCHECK(thread->HoldsLock(obj));
- // Only possible exception is NPE and is handled before entry
- DCHECK(!thread->IsExceptionPending());
-}
-
-void CheckSuspendFromCode(Thread* thread) {
- // Called when thread->suspend_count_ != 0
- Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
-}
-
-extern "C" void artTestSuspendFromCode(Thread* thread, Method** sp) {
- // Called when suspend count check value is 0 and thread->suspend_count_ != 0
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsOnly);
- Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
-}
-
-/*
- * Fill the array with predefined constant values, throwing exceptions if the array is null or
- * not of sufficient length.
- *
- * NOTE: When dealing with a raw dex file, the data to be copied uses
- * little-endian ordering. Require that oat2dex do any required swapping
- * so this routine can get by with a memcpy().
- *
- * Format of the data:
- * ushort ident = 0x0300 magic value
- * ushort width width of each element in the table
- * uint size number of elements in the table
- * ubyte data[size*width] table of data values (may contain a single-byte
- * padding at the end)
- */
-extern "C" int artHandleFillArrayDataFromCode(Array* array, const uint16_t* table,
- Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- DCHECK_EQ(table[0], 0x0300);
- if (UNLIKELY(array == NULL)) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
- "null array in fill array");
- return -1; // Error
- }
- DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
- uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
- if (UNLIKELY(static_cast<int32_t>(size) > array->GetLength())) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
- "failed array fill. length=%d; index=%d", array->GetLength(), size);
- return -1; // Error
- }
- uint16_t width = table[1];
- uint32_t size_in_bytes = size * width;
- memcpy((char*)array + Array::DataOffset(width).Int32Value(), (char*)&table[4], size_in_bytes);
- return 0; // Success
-}
-
-static uint64_t artInvokeCommon(uint32_t method_idx, Object* this_object, Method* caller_method,
- Thread* self, Method** sp, bool access_check, InvokeType type) {
- Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type);
- if (UNLIKELY(method == NULL)) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
- if (UNLIKELY(this_object == NULL && type != kDirect && type != kStatic)) {
- ThrowNullPointerExceptionForMethodAccess(self, caller_method, method_idx, type);
- return 0; // failure
- }
- method = FindMethodFromCode(method_idx, this_object, caller_method, self, access_check, type);
- if (UNLIKELY(method == NULL)) {
- CHECK(self->IsExceptionPending());
- return 0; // failure
- }
- }
- DCHECK(!self->IsExceptionPending());
- const void* code = method->GetCode();
-
- // When we return, the caller will branch to this address, so it had better not be 0!
- CHECK(code != NULL) << PrettyMethod(method);
-
- uint32_t method_uint = reinterpret_cast<uint32_t>(method);
- uint64_t code_uint = reinterpret_cast<uint32_t>(code);
- uint64_t result = ((code_uint << 32) | method_uint);
- return result;
-}
-
-// See comments in runtime_support_asm.S
-extern "C" uint64_t artInvokeInterfaceTrampoline(uint32_t method_idx, Object* this_object,
- Method* caller_method, Thread* self,
- Method** sp) {
- return artInvokeCommon(method_idx, this_object, caller_method, self, sp, false, kInterface);
-}
-
-extern "C" uint64_t artInvokeInterfaceTrampolineWithAccessCheck(uint32_t method_idx,
- Object* this_object,
- Method* caller_method, Thread* self,
- Method** sp) {
- return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kInterface);
-}
-
-
-extern "C" uint64_t artInvokeDirectTrampolineWithAccessCheck(uint32_t method_idx,
- Object* this_object,
- Method* caller_method, Thread* self,
- Method** sp) {
- return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kDirect);
-}
-
-extern "C" uint64_t artInvokeStaticTrampolineWithAccessCheck(uint32_t method_idx,
- Object* this_object,
- Method* caller_method, Thread* self,
- Method** sp) {
- return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kStatic);
-}
-
-extern "C" uint64_t artInvokeSuperTrampolineWithAccessCheck(uint32_t method_idx,
- Object* this_object,
- Method* caller_method, Thread* self,
- Method** sp) {
- return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kSuper);
-}
-
-extern "C" uint64_t artInvokeVirtualTrampolineWithAccessCheck(uint32_t method_idx,
- Object* this_object,
- Method* caller_method, Thread* self,
- Method** sp) {
- return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kVirtual);
-}
-
-static void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) {
- ScopedLocalRef<jclass> jlr_UTE_class(env,
- env->FindClass("java/lang/reflect/UndeclaredThrowableException"));
- if (jlr_UTE_class.get() == NULL) {
- LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\"";
- } else {
- jmethodID jlre_UTE_constructor = env->GetMethodID(jlr_UTE_class.get(), "<init>",
- "(Ljava/lang/Throwable;)V");
- jthrowable jexception = AddLocalReference<jthrowable>(env, exception);
- ScopedLocalRef<jthrowable> jlr_UTE(env,
- reinterpret_cast<jthrowable>(env->NewObject(jlr_UTE_class.get(), jlre_UTE_constructor,
- jexception)));
- int rc = env->Throw(jlr_UTE.get());
- if (rc != JNI_OK) {
- LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\"";
- }
- }
- CHECK(self->IsExceptionPending());
-}
-
-// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
-// which is responsible for recording callee save registers. We explicitly handlerize incoming
-// reference arguments (so they survive GC) and create a boxed argument array. Finally we invoke
-// the invocation handler which is a field within the proxy object receiver.
-extern "C" void artProxyInvokeHandler(Method* proxy_method, Object* receiver,
- Thread* self, byte* stack_args) {
- // Register the top of the managed stack
- Method** proxy_sp = reinterpret_cast<Method**>(stack_args - 12);
- DCHECK_EQ(*proxy_sp, proxy_method);
- self->SetTopOfStack(proxy_sp, 0);
- // TODO: ARM specific
- DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), 48u);
- // Start new JNI local reference state
- JNIEnvExt* env = self->GetJniEnv();
- ScopedJniEnvLocalRefState env_state(env);
- // Create local ref. copies of proxy method and the receiver
- jobject rcvr_jobj = AddLocalReference<jobject>(env, receiver);
- jobject proxy_method_jobj = AddLocalReference<jobject>(env, proxy_method);
-
- // Placing into local references incoming arguments from the caller's register arguments,
- // replacing original Object* with jobject
- MethodHelper proxy_mh(proxy_method);
- const size_t num_params = proxy_mh.NumArgs();
- size_t args_in_regs = 0;
- for (size_t i = 1; i < num_params; i++) { // skip receiver
- args_in_regs = args_in_regs + (proxy_mh.IsParamALongOrDouble(i) ? 2 : 1);
- if (args_in_regs > 2) {
- args_in_regs = 2;
- break;
- }
- }
- size_t cur_arg = 0; // current stack location to read
- size_t param_index = 1; // skip receiver
- while (cur_arg < args_in_regs && param_index < num_params) {
- if (proxy_mh.IsParamAReference(param_index)) {
- Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
- jobject jobj = AddLocalReference<jobject>(env, obj);
- *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
- }
- cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
- param_index++;
- }
- // Placing into local references incoming arguments from the caller's stack arguments
- cur_arg += 11; // skip callee saves, LR, Method* and out arg spills for R1 to R3
- while (param_index < num_params) {
- if (proxy_mh.IsParamAReference(param_index)) {
- Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
- jobject jobj = AddLocalReference<jobject>(env, obj);
- *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
- }
- cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
- param_index++;
- }
- // Set up arguments array and place in local IRT during boxing (which may allocate/GC)
- jvalue args_jobj[3];
- args_jobj[0].l = rcvr_jobj;
- args_jobj[1].l = proxy_method_jobj;
- // Args array, if no arguments then NULL (don't include receiver in argument count)
- args_jobj[2].l = NULL;
- ObjectArray<Object>* args = NULL;
- if ((num_params - 1) > 0) {
- args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(num_params - 1);
- if (args == NULL) {
- CHECK(self->IsExceptionPending());
- return;
- }
- args_jobj[2].l = AddLocalReference<jobjectArray>(env, args);
- }
- // Convert proxy method into expected interface method
- Method* interface_method = proxy_method->FindOverriddenMethod();
- DCHECK(interface_method != NULL);
- DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
- args_jobj[1].l = AddLocalReference<jobject>(env, interface_method);
- // Box arguments
- cur_arg = 0; // reset stack location to read to start
- // reset index, will index into param type array which doesn't include the receiver
- param_index = 0;
- ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes();
- if (param_types == NULL) {
+Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
+ bool can_run_clinit, bool verify_access) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Class* klass = class_linker->ResolveType(type_idx, referrer);
+ if (UNLIKELY(klass == NULL)) {
CHECK(self->IsExceptionPending());
- return;
+ return NULL; // Failure - Indicate to caller to deliver exception
}
- // Check number of parameter types agrees with number from the Method - less 1 for the receiver.
- DCHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
- while (cur_arg < args_in_regs && param_index < (num_params - 1)) {
- Class* param_type = param_types->Get(param_index);
- Object* obj;
- if (!param_type->IsPrimitive()) {
- obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
- } else {
- JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
- if (cur_arg == 1 && (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble())) {
- // long/double split over regs and stack, mask in high half from stack arguments
- uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args + (13 * kPointerSize));
- val.j = (val.j & 0xffffffffULL) | (high_half << 32);
- }
- BoxPrimitive(param_type->GetPrimitiveType(), val);
- if (self->IsExceptionPending()) {
- return;
- }
- obj = val.l;
- }
- args->Set(param_index, obj);
- cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
- param_index++;
+ // Perform access check if necessary.
+ Class* referring_class = referrer->GetDeclaringClass();
+ if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) {
+ ThrowNewIllegalAccessErrorClass(self, referring_class, klass);
+ return NULL; // Failure - Indicate to caller to deliver exception
}
- // Placing into local references incoming arguments from the caller's stack arguments
- cur_arg += 11; // skip callee saves, LR, Method* and out arg spills for R1 to R3
- while (param_index < (num_params - 1)) {
- Class* param_type = param_types->Get(param_index);
- Object* obj;
- if (!param_type->IsPrimitive()) {
- obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
- } else {
- JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
- BoxPrimitive(param_type->GetPrimitiveType(), val);
- if (self->IsExceptionPending()) {
- return;
- }
- obj = val.l;
- }
- args->Set(param_index, obj);
- cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
- param_index++;
+ // If we're just implementing const-class, we shouldn't call <clinit>.
+ if (!can_run_clinit) {
+ return klass;
}
- // Get the InvocationHandler method and the field that holds it within the Proxy object
- static jmethodID inv_hand_invoke_mid = NULL;
- static jfieldID proxy_inv_hand_fid = NULL;
- if (proxy_inv_hand_fid == NULL) {
- ScopedLocalRef<jclass> proxy(env, env->FindClass("java/lang/reflect/Proxy"));
- proxy_inv_hand_fid = env->GetFieldID(proxy.get(), "h", "Ljava/lang/reflect/InvocationHandler;");
- ScopedLocalRef<jclass> inv_hand_class(env, env->FindClass("java/lang/reflect/InvocationHandler"));
- inv_hand_invoke_mid = env->GetMethodID(inv_hand_class.get(), "invoke",
- "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
+ // If we are the <clinit> of this class, just return our storage.
+ //
+ // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
+ // running.
+ if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) {
+ return klass;
}
- DCHECK(env->IsInstanceOf(rcvr_jobj, env->FindClass("java/lang/reflect/Proxy")));
- jobject inv_hand = env->GetObjectField(rcvr_jobj, proxy_inv_hand_fid);
- // Call InvocationHandler.invoke
- jobject result = env->CallObjectMethodA(inv_hand, inv_hand_invoke_mid, args_jobj);
- // Place result in stack args
- if (!self->IsExceptionPending()) {
- Object* result_ref = self->DecodeJObject(result);
- if (result_ref != NULL) {
- JValue result_unboxed;
- bool unboxed_okay = UnboxPrimitive(result_ref, proxy_mh.GetReturnType(), result_unboxed, "result");
- if (!unboxed_okay) {
- self->ClearException();
- self->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
- "Couldn't convert result of type %s to %s",
- PrettyTypeOf(result_ref).c_str(),
- PrettyDescriptor(proxy_mh.GetReturnType()).c_str());
- return;
- }
- *reinterpret_cast<JValue*>(stack_args) = result_unboxed;
- } else {
- *reinterpret_cast<jobject*>(stack_args) = NULL;
- }
- } else {
- // In the case of checked exceptions that aren't declared, the exception must be wrapped by
- // a UndeclaredThrowableException.
- Throwable* exception = self->GetException();
- self->ClearException();
- if (!exception->IsCheckedException()) {
- self->SetException(exception);
- } else {
- SynthesizedProxyClass* proxy_class =
- down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
- int throws_index = -1;
- size_t num_virt_methods = proxy_class->NumVirtualMethods();
- for (size_t i = 0; i < num_virt_methods; i++) {
- if (proxy_class->GetVirtualMethod(i) == proxy_method) {
- throws_index = i;
- break;
- }
- }
- CHECK_NE(throws_index, -1);
- ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
- Class* exception_class = exception->GetClass();
- bool declares_exception = false;
- for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
- Class* declared_exception = declared_exceptions->Get(i);
- declares_exception = declared_exception->IsAssignableFrom(exception_class);
- }
- if (declares_exception) {
- self->SetException(exception);
- } else {
- ThrowNewUndeclaredThrowableException(self, env, exception);
- }
- }
+ if (!class_linker->EnsureInitialized(klass, true)) {
+ CHECK(self->IsExceptionPending());
+ return NULL; // Failure - Indicate to caller to deliver exception
}
-}
-
-extern "C" const void* artTraceMethodEntryFromCode(Method* method, Thread* self, uintptr_t lr) {
- Trace* tracer = Runtime::Current()->GetTracer();
- TraceStackFrame trace_frame = TraceStackFrame(method, lr);
- self->PushTraceStackFrame(trace_frame);
-
- tracer->LogMethodTraceEvent(self, method, Trace::kMethodTraceEnter);
-
- return tracer->GetSavedCodeFromMap(method);
-}
-
-extern "C" uintptr_t artTraceMethodExitFromCode() {
- Trace* tracer = Runtime::Current()->GetTracer();
- TraceStackFrame trace_frame = Thread::Current()->PopTraceStackFrame();
- Method* method = trace_frame.method_;
- uintptr_t lr = trace_frame.return_pc_;
-
- tracer->LogMethodTraceEvent(Thread::Current(), method, Trace::kMethodTraceExit);
-
- return lr;
-}
-
-uint32_t TraceMethodUnwindFromCode(Thread* self) {
- Trace* tracer = Runtime::Current()->GetTracer();
- TraceStackFrame trace_frame = self->PopTraceStackFrame();
- Method* method = trace_frame.method_;
- uint32_t lr = trace_frame.return_pc_;
-
- tracer->LogMethodTraceEvent(self, method, Trace::kMethodTraceUnwind);
-
- return lr;
-}
-
-int CmplFloat(float a, float b) {
- if (a == b) {
- return 0;
- } else if (a < b) {
- return -1;
- } else if (a > b) {
- return 1;
- }
- return -1;
-}
-
-int CmpgFloat(float a, float b) {
- if (a == b) {
- return 0;
- } else if (a < b) {
- return -1;
- } else if (a > b) {
- return 1;
- }
- return 1;
-}
-
-int CmpgDouble(double a, double b) {
- if (a == b) {
- return 0;
- } else if (a < b) {
- return -1;
- } else if (a > b) {
- return 1;
- }
- return 1;
-}
-
-int CmplDouble(double a, double b) {
- if (a == b) {
- return 0;
- } else if (a < b) {
- return -1;
- } else if (a > b) {
- return 1;
- }
- return -1;
-}
-
-/*
- * Float/double conversion requires clamping to min and max of integer form. If
- * target doesn't support this normally, use these.
- */
-int64_t D2L(double d) {
- static const double kMaxLong = (double) (int64_t) 0x7fffffffffffffffULL;
- static const double kMinLong = (double) (int64_t) 0x8000000000000000ULL;
- if (d >= kMaxLong) {
- return (int64_t) 0x7fffffffffffffffULL;
- } else if (d <= kMinLong) {
- return (int64_t) 0x8000000000000000ULL;
- } else if (d != d) { // NaN case
- return 0;
- } else {
- return (int64_t) d;
- }
-}
-
-int64_t F2L(float f) {
- static const float kMaxLong = (float) (int64_t) 0x7fffffffffffffffULL;
- static const float kMinLong = (float) (int64_t) 0x8000000000000000ULL;
- if (f >= kMaxLong) {
- return (int64_t) 0x7fffffffffffffffULL;
- } else if (f <= kMinLong) {
- return (int64_t) 0x8000000000000000ULL;
- } else if (f != f) { // NaN case
- return 0;
- } else {
- return (int64_t) f;
- }
+ referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
+ return klass;
}
} // namespace art
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 35f88b5..909fb41 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -1,180 +1,195 @@
-/*
- * Copyright (C) 2011 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.
- */
+// Copyright 2012 Google Inc. All Rights Reserved.
#ifndef ART_SRC_RUNTIME_SUPPORT_H_
#define ART_SRC_RUNTIME_SUPPORT_H_
#include "class_linker.h"
+#include "dex_file.h"
+#include "dex_verifier.h"
#include "object.h"
-#include "thread_list.h"
-#include "utils.h"
+#include "object_utils.h"
+#include "thread.h"
+
+extern "C" void art_proxy_invoke_handler();
+extern "C" void art_work_around_app_jni_bugs();
namespace art {
-extern void CheckSuspendFromCode(Thread* thread);
+class Array;
+class Class;
+class Field;
+class Method;
+class Object;
+
+// Helpers to give consistent descriptive exception messages
+void ThrowNewIllegalAccessErrorClass(Thread* self, Class* referrer, Class* accessed);
+void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self, Class* referrer,
+ Class* accessed,
+ const Method* caller,
+ const Method* called,
+ InvokeType type);
+void ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
+ const Method* referrer,
+ const Method* interface_method,
+ Object* this_object);
+void ThrowNewIllegalAccessErrorField(Thread* self, Class* referrer, Field* accessed);
+void ThrowNewIllegalAccessErrorFinalField(Thread* self, const Method* referrer, Field* accessed);
+
+void ThrowNewIllegalAccessErrorMethod(Thread* self, Class* referrer, Method* accessed);
+void ThrowNullPointerExceptionForFieldAccess(Thread* self, Field* field, bool is_read);
+void ThrowNullPointerExceptionForMethodAccess(Thread* self, Method* caller, uint32_t method_idx,
+ InvokeType type);
+
+std::string FieldNameFromIndex(const Method* method, uint32_t ref,
+ verifier::VerifyErrorRefType ref_type, bool access);
+std::string MethodNameFromIndex(const Method* method, uint32_t ref,
+ verifier::VerifyErrorRefType ref_type, bool access);
+
+// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
+// cannot be resolved, throw an error. If it can, use it to create an instance.
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+static inline Object* AllocObjectFromCode(uint32_t type_idx, Method* method, Thread* self,
+ bool access_check) {
+ Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
+ Runtime* runtime = Runtime::Current();
+ if (UNLIKELY(klass == NULL)) {
+ klass = runtime->GetClassLinker()->ResolveType(type_idx, method);
+ if (klass == NULL) {
+ DCHECK(self->IsExceptionPending());
+ return NULL; // Failure
+ }
+ }
+ if (access_check) {
+ if (UNLIKELY(!klass->IsInstantiable())) {
+ self->ThrowNewException("Ljava/lang/InstantiationError;",
+ PrettyDescriptor(klass).c_str());
+ return NULL; // Failure
+ }
+ Class* referrer = method->GetDeclaringClass();
+ if (UNLIKELY(!referrer->CanAccess(klass))) {
+ ThrowNewIllegalAccessErrorClass(self, referrer, klass);
+ return NULL; // Failure
+ }
+ }
+ if (!runtime->GetClassLinker()->EnsureInitialized(klass, true)) {
+ DCHECK(self->IsExceptionPending());
+ return NULL; // Failure
+ }
+ return klass->AllocObject();
+}
+
+// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
+// it cannot be resolved, throw an error. If it can, use it to create an array.
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+static inline Array* AllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
+ Thread* self, bool access_check) {
+ if (UNLIKELY(component_count < 0)) {
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
+ component_count);
+ return NULL; // Failure
+ }
+ Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
+ if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
+ klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
+ if (klass == NULL) { // Error
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return NULL; // Failure
+ }
+ CHECK(klass->IsArrayClass()) << PrettyClass(klass);
+ }
+ if (access_check) {
+ Class* referrer = method->GetDeclaringClass();
+ if (UNLIKELY(!referrer->CanAccess(klass))) {
+ ThrowNewIllegalAccessErrorClass(self, referrer, klass);
+ return NULL; // Failure
+ }
+ }
+ return Array::Alloc(klass, component_count);
+}
+
extern Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
Thread* self, bool access_check);
-extern void DebugMe(Method* method, uint32_t info);
-extern void UpdateDebuggerFromCode(Method* method, Thread* thread , int32_t dex_pc, Method** sp);
-extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
+
extern Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
- bool is_static, bool is_primitive, bool is_set, size_t expected_size);
-extern void* FindNativeMethod(Thread* thread);
-extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
-const void* UnresolvedDirectMethodTrampolineFromCode(Method*, Method**, Thread*,
- Runtime::TrampolineType);
+ bool is_static, bool is_primitive, bool is_set,
+ size_t expected_size);
+
+// Fast path field resolution that can't throw exceptions
+static inline Field* FindFieldFast(uint32_t field_idx, const Method* referrer, bool is_primitive,
+ size_t expected_size, bool is_set) {
+ Field* resolved_field = referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
+ if (UNLIKELY(resolved_field == NULL)) {
+ return NULL;
+ }
+ Class* fields_class = resolved_field->GetDeclaringClass();
+ // Check class is initiliazed or initializing
+ if (UNLIKELY(!fields_class->IsInitializing())) {
+ return NULL;
+ }
+ Class* referring_class = referrer->GetDeclaringClass();
+ if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
+ !referring_class->CanAccessMember(fields_class,
+ resolved_field->GetAccessFlags()) ||
+ (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
+ // illegal access
+ return NULL;
+ }
+ FieldHelper fh(resolved_field);
+ if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
+ fh.FieldSize() != expected_size)) {
+ return NULL;
+ }
+ return resolved_field;
+}
+
+// Fast path method resolution that can't throw exceptions
+static inline Method* FindMethodFast(uint32_t method_idx, Object* this_object, const Method* referrer,
+ bool access_check, InvokeType type) {
+ bool is_direct = type == kStatic || type == kDirect;
+ if (UNLIKELY(this_object == NULL && !is_direct)) {
+ return NULL;
+ }
+ Method* resolved_method =
+ referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx);
+ if (UNLIKELY(resolved_method == NULL)) {
+ return NULL;
+ }
+ if (access_check) {
+ Class* methods_class = resolved_method->GetDeclaringClass();
+ Class* referring_class = referrer->GetDeclaringClass();
+ if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
+ !referring_class->CanAccessMember(methods_class,
+ resolved_method->GetAccessFlags()))) {
+ // potential illegal access
+ return NULL;
+ }
+ }
+ if (type == kInterface) { // Most common form of slow path dispatch.
+ return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+ } else if (is_direct) {
+ return resolved_method;
+ } else if (type == kSuper) {
+ return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->
+ Get(resolved_method->GetMethodIndex());
+ } else {
+ DCHECK(type == kVirtual);
+ return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
+ }
+}
+
+extern Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
+ Thread* self, bool access_check, InvokeType type);
+
extern Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
bool can_run_clinit, bool verify_access);
-extern Class* InitializeTypeFromCode(uint32_t type_idx, Method* method);
-uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class);
-void ObjectInitFromCode(Object* o);
-extern void LockObjectFromCode(Thread* thread, Object* obj);
-uint32_t TraceMethodUnwindFromCode(Thread* self);
-extern int32_t CmpgDouble(double a, double b);
-extern int32_t CmplDouble(double a, double b);
-extern int32_t CmpgFloat(float a, float b);
-extern int32_t CmplFloat(float a, float b);
-extern int64_t D2L(double d);
-extern int64_t F2L(float f);
+
+static inline String* ResolveStringFromCode(const Method* referrer, uint32_t string_idx) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ return class_linker->ResolveString(string_idx, referrer);
+}
} // namespace art
-// Helpers for both compiled code and libart.
-extern "C" void art_deliver_exception_from_code(void*);
-extern "C" void art_proxy_invoke_handler();
-extern "C" void art_update_debugger(void*, void*, int32_t, void*);
-
-#if defined(__arm__)
- /* Compiler helpers */
- extern "C" int32_t __memcmp16(void*, void*, int32_t);
- extern "C" int32_t art_indexof(void*, uint32_t, uint32_t, uint32_t);
- extern "C" int32_t art_string_compareto(void*, void*);
- extern "C" int32_t art_get32_static_from_code(uint32_t);
- extern "C" int64_t art_get64_static_from_code(uint32_t);
- extern "C" void* art_get_obj_static_from_code(uint32_t);
- extern "C" int32_t art_get32_instance_from_code(uint32_t, void*);
- extern "C" int64_t art_get64_instance_from_code(uint32_t, void*);
- extern "C" void* art_get_obj_instance_from_code(uint32_t, void*);
- extern "C" int art_set32_static_from_code(uint32_t, int32_t);
- extern "C" int art_set64_static_from_code(uint32_t, int64_t);
- extern "C" int art_set_obj_static_from_code(uint32_t, void*);
- extern "C" int art_set32_instance_from_code(uint32_t, void*, int32_t);
- extern "C" int art_set64_instance_from_code(uint32_t, void*, int64_t);
- extern "C" int art_set_obj_instance_from_code(uint32_t, void*, void*);
- extern "C" void art_can_put_array_element_from_code(void*, void*);
- extern "C" void art_check_cast_from_code(void*, void*);
- extern "C" void art_do_long_jump(uint32_t*, uint32_t*);
- extern "C" void art_handle_fill_data_from_code(void*, void*);
- extern "C" void art_invoke_direct_trampoline_with_access_check(uint32_t, void*);
- extern "C" void art_invoke_interface_trampoline(uint32_t, void*);
- extern "C" void art_invoke_interface_trampoline_with_access_check(uint32_t, void*);
- extern "C" void art_invoke_static_trampoline_with_access_check(uint32_t, void*);
- extern "C" void art_invoke_super_trampoline_with_access_check(uint32_t, void*);
- extern "C" void art_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
- extern "C" void art_lock_object_from_code(void*);
- extern "C" void art_test_suspend();
- extern "C" void art_throw_array_bounds_from_code(int32_t index, int32_t limit);
- extern "C" void art_throw_div_zero_from_code();
- extern "C" void art_throw_neg_array_size_from_code(int32_t size);
- extern "C" void art_throw_no_such_method_from_code(int32_t method_idx);
- extern "C" void art_throw_null_pointer_exception_from_code();
- extern "C" void art_throw_stack_overflow_from_code(void*);
- extern "C" void art_throw_verification_error_from_code(int32_t src1, int32_t ref);
- extern "C" void art_unlock_object_from_code(void*);
- extern "C" void* art_alloc_array_from_code(uint32_t, void*, int32_t);
- extern "C" void* art_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
- extern "C" void* art_alloc_object_from_code(uint32_t type_idx, void* method);
- extern "C" void* art_alloc_object_from_code_with_access_check(uint32_t type_idx, void* method);
- extern "C" void* art_check_and_alloc_array_from_code(uint32_t, void*, int32_t);
- extern "C" void* art_check_and_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
- extern "C" void* art_initialize_static_storage_from_code(uint32_t, void*);
- extern "C" void* art_initialize_type_from_code(uint32_t, void*);
- extern "C" void* art_initialize_type_and_verify_access_from_code(uint32_t, void*);
- extern "C" void art_trace_entry_from_code(void*);
- extern "C" void art_trace_exit_from_code();
- extern "C" void* art_resolve_string_from_code(void*, uint32_t);
- extern "C" void art_work_around_app_jni_bugs();
-
- /* Conversions */
- extern "C" float __aeabi_i2f(int32_t op1); // INT_TO_FLOAT
- extern "C" int32_t __aeabi_f2iz(float op1); // FLOAT_TO_INT
- extern "C" float __aeabi_d2f(double op1); // DOUBLE_TO_FLOAT
- extern "C" double __aeabi_f2d(float op1); // FLOAT_TO_DOUBLE
- extern "C" double __aeabi_i2d(int32_t op1); // INT_TO_DOUBLE
- extern "C" int32_t __aeabi_d2iz(double op1); // DOUBLE_TO_INT
- extern "C" float __aeabi_l2f(int64_t op1); // LONG_TO_FLOAT
- extern "C" double __aeabi_l2d(int64_t op1); // LONG_TO_DOUBLE
-
- /* Single-precision FP arithmetics */
- extern "C" float __aeabi_fadd(float a, float b); // ADD_FLOAT[_2ADDR]
- extern "C" float __aeabi_fsub(float a, float b); // SUB_FLOAT[_2ADDR]
- extern "C" float __aeabi_fdiv(float a, float b); // DIV_FLOAT[_2ADDR]
- extern "C" float __aeabi_fmul(float a, float b); // MUL_FLOAT[_2ADDR]
- extern "C" float fmodf(float a, float b); // REM_FLOAT[_2ADDR]
-
- /* Double-precision FP arithmetics */
- extern "C" double __aeabi_dadd(double a, double b); // ADD_DOUBLE[_2ADDR]
- extern "C" double __aeabi_dsub(double a, double b); // SUB_DOUBLE[_2ADDR]
- extern "C" double __aeabi_ddiv(double a, double b); // DIV_DOUBLE[_2ADDR]
- extern "C" double __aeabi_dmul(double a, double b); // MUL_DOUBLE[_2ADDR]
- extern "C" double fmod(double a, double b); // REM_DOUBLE[_2ADDR]
-
- /* Integer arithmetics */
- extern "C" int __aeabi_idivmod(int32_t op1, int32_t op2); // REM_INT[_2ADDR|_LIT8|_LIT16]
- extern "C" int __aeabi_idiv(int32_t op1, int32_t op2); // DIV_INT[_2ADDR|_LIT8|_LIT16]
-
- /* Long long arithmetics - REM_LONG[_2ADDR] and DIV_LONG[_2ADDR] */
- extern "C" long long __aeabi_ldivmod(long long op1, long long op2);
- extern "C" long long __aeabi_lmul(long long op1, long long op2);
- extern "C" uint64_t art_shl_long(uint64_t, uint32_t);
- extern "C" uint64_t art_shr_long(uint64_t, uint32_t);
- extern "C" uint64_t art_ushr_long(uint64_t, uint32_t);
-
-#endif
-
-#if defined(__mips__)
- /* Conversions */
- extern "C" float __floatsisf(int op1); // INT_TO_FLOAT
- extern "C" int32_t __fixsfsi(float op1); // FLOAT_TO_INT
- extern "C" float __truncdfsf2(double op1); // DOUBLE_TO_FLOAT
- extern "C" double __extendsfdf2(float op1); // FLOAT_TO_DOUBLE
- extern "C" double __floatsidf(int op1); // INT_TO_DOUBLE
- extern "C" int32_t __fixdfsi(double op1); // DOUBLE_TO_INT
- extern "C" float __floatdisf(int64_t op1); // LONG_TO_FLOAT
- extern "C" double __floatdidf(int64_t op1); // LONG_TO_DOUBLE
- extern "C" int64_t __fixsfdi(float op1); // FLOAT_TO_LONG
- extern "C" int64_t __fixdfdi(double op1); // DOUBLE_TO_LONG
-
- /* Single-precision FP arithmetics */
- extern "C" float __addsf3(float a, float b); // ADD_FLOAT[_2ADDR]
- extern "C" float __subsf3(float a, float b); // SUB_FLOAT[_2ADDR]
- extern "C" float __divsf3(float a, float b); // DIV_FLOAT[_2ADDR]
- extern "C" float __mulsf3(float a, float b); // MUL_FLOAT[_2ADDR]
- extern "C" float fmodf(float a, float b); // REM_FLOAT[_2ADDR]
-
- /* Double-precision FP arithmetics */
- extern "C" double __adddf3(double a, double b); // ADD_DOUBLE[_2ADDR]
- extern "C" double __subdf3(double a, double b); // SUB_DOUBLE[_2ADDR]
- extern "C" double __divdf3(double a, double b); // DIV_DOUBLE[_2ADDR]
- extern "C" double __muldf3(double a, double b); // MUL_DOUBLE[_2ADDR]
- extern "C" double fmod(double a, double b); // REM_DOUBLE[_2ADDR]
-
- /* Long long arithmetics - REM_LONG[_2ADDR] and DIV_LONG[_2ADDR] */
- extern "C" long long __divdi3(int64_t op1, int64_t op2);
- extern "C" long long __moddi3(int64_t op1, int64_t op2);
-#endif
-
#endif // ART_SRC_RUNTIME_SUPPORT_H_
diff --git a/src/runtime_support_common.cc b/src/runtime_support_common.cc
deleted file mode 100644
index 71567a3..0000000
--- a/src/runtime_support_common.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
-
-#include "runtime_support_common.h"
-
-
-namespace art {
-
-// Helper function to allocate array for FILLED_NEW_ARRAY.
-Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
- Thread* self, bool access_check) {
- if (UNLIKELY(component_count < 0)) {
- self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count);
- return NULL; // Failure
- }
- Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
- if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
- klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
- if (klass == NULL) { // Error
- DCHECK(Thread::Current()->IsExceptionPending());
- return NULL; // Failure
- }
- }
- if (UNLIKELY(klass->IsPrimitive() && !klass->IsPrimitiveInt())) {
- if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
- "Bad filled array request for type %s",
- PrettyDescriptor(klass).c_str());
- } else {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/InternalError;",
- "Found type %s; filled-new-array not implemented for anything but \'int\'",
- PrettyDescriptor(klass).c_str());
- }
- return NULL; // Failure
- } else {
- if (access_check) {
- Class* referrer = method->GetDeclaringClass();
- if (UNLIKELY(!referrer->CanAccess(klass))) {
- ThrowNewIllegalAccessErrorClass(self, referrer, klass);
- return NULL; // Failure
- }
- }
- DCHECK(klass->IsArrayClass()) << PrettyClass(klass);
- return Array::Alloc(klass, component_count);
- }
-}
-
-// Slow path field resolution and declaring class initialization
-Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
- bool is_static, bool is_primitive, bool is_set, size_t expected_size) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
- if (UNLIKELY(resolved_field == NULL)) {
- DCHECK(self->IsExceptionPending()); // Throw exception and unwind
- return NULL; // failure
- } else {
- Class* fields_class = resolved_field->GetDeclaringClass();
- Class* referring_class = referrer->GetDeclaringClass();
- if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
- ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
- return NULL; // failure
- } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
- resolved_field->GetAccessFlags()))) {
- ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
- return NULL; // failure
- } else if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
- ThrowNewIllegalAccessErrorFinalField(self, referrer, resolved_field);
- return NULL; // failure
- } else {
- FieldHelper fh(resolved_field);
- if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
- fh.FieldSize() != expected_size)) {
- self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
- "Attempted read of %zd-bit %s on field '%s'",
- expected_size * (32 / sizeof(int32_t)),
- is_primitive ? "primitive" : "non-primitive",
- PrettyField(resolved_field, true).c_str());
- return NULL; // failure
- } else if (!is_static) {
- // instance fields must be being accessed on an initialized class
- return resolved_field;
- } else {
- // If the class is already initializing, we must be inside <clinit>, or
- // we'd still be waiting for the lock.
- if (fields_class->IsInitializing()) {
- return resolved_field;
- } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true)) {
- return resolved_field;
- } else {
- DCHECK(self->IsExceptionPending()); // Throw exception and unwind
- return NULL; // failure
- }
- }
- }
- }
-}
-
-// Slow path method resolution
-Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
- Thread* self, bool access_check, InvokeType type) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- bool is_direct = type == kStatic || type == kDirect;
- Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, is_direct);
- if (UNLIKELY(resolved_method == NULL)) {
- DCHECK(self->IsExceptionPending()); // Throw exception and unwind
- return NULL; // failure
- } else {
- if (!access_check) {
- if (is_direct) {
- return resolved_method;
- } else if (type == kInterface) {
- Method* interface_method =
- this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
- if (UNLIKELY(interface_method == NULL)) {
- ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
- resolved_method,
- this_object);
- return NULL; // failure
- } else {
- return interface_method;
- }
- } else {
- ObjectArray<Method>* vtable;
- uint16_t vtable_index = resolved_method->GetMethodIndex();
- if (type == kSuper) {
- vtable = referrer->GetDeclaringClass()->GetSuperClass()->GetVTable();
- } else {
- vtable = this_object->GetClass()->GetVTable();
- }
- // TODO: eliminate bounds check?
- return vtable->Get(vtable_index);
- }
- } else {
- Class* methods_class = resolved_method->GetDeclaringClass();
- Class* referring_class = referrer->GetDeclaringClass();
- if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
- !referring_class->CanAccessMember(methods_class,
- resolved_method->GetAccessFlags()))) {
- // The referring class can't access the resolved method, this may occur as a result of a
- // protected method being made public by implementing an interface that re-declares the
- // method public. Resort to the dex file to determine the correct class for the access check
- const DexFile& dex_file = class_linker->FindDexFile(referring_class->GetDexCache());
- methods_class = class_linker->ResolveType(dex_file,
- dex_file.GetMethodId(method_idx).class_idx_,
- referring_class);
- if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
- ThrowNewIllegalAccessErrorClassForMethodDispatch(self, referring_class, methods_class,
- referrer, resolved_method, type);
- return NULL; // failure
- } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class,
- resolved_method->GetAccessFlags()))) {
- ThrowNewIllegalAccessErrorMethod(self, referring_class, resolved_method);
- return NULL; // failure
- }
- }
- if (is_direct) {
- return resolved_method;
- } else if (type == kInterface) {
- Method* interface_method =
- this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
- if (UNLIKELY(interface_method == NULL)) {
- ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
- resolved_method,
- this_object);
- return NULL; // failure
- } else {
- return interface_method;
- }
- } else {
- ObjectArray<Method>* vtable;
- uint16_t vtable_index = resolved_method->GetMethodIndex();
- if (type == kSuper) {
- Class* super_class = referring_class->GetSuperClass();
- if (LIKELY(super_class != NULL)) {
- vtable = referring_class->GetSuperClass()->GetVTable();
- } else {
- vtable = NULL;
- }
- } else {
- vtable = this_object->GetClass()->GetVTable();
- }
- if (LIKELY(vtable != NULL &&
- vtable_index < static_cast<uint32_t>(vtable->GetLength()))) {
- return vtable->GetWithoutChecks(vtable_index);
- } else {
- // Behavior to agree with that of the verifier
- self->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
- "attempt to invoke %s method '%s' from '%s'"
- " using incorrect form of method dispatch",
- (type == kSuper ? "super class" : "virtual"),
- PrettyMethod(resolved_method).c_str(),
- PrettyMethod(referrer).c_str());
- return NULL; // failure
- }
- }
- }
- }
-}
-
-Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
- bool can_run_clinit, bool verify_access) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Class* klass = class_linker->ResolveType(type_idx, referrer);
- if (UNLIKELY(klass == NULL)) {
- CHECK(self->IsExceptionPending());
- return NULL; // Failure - Indicate to caller to deliver exception
- }
- // Perform access check if necessary.
- Class* referring_class = referrer->GetDeclaringClass();
- if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) {
- ThrowNewIllegalAccessErrorClass(self, referring_class, klass);
- return NULL; // Failure - Indicate to caller to deliver exception
- }
- // If we're just implementing const-class, we shouldn't call <clinit>.
- if (!can_run_clinit) {
- return klass;
- }
- // If we are the <clinit> of this class, just return our storage.
- //
- // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
- // running.
- if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) {
- return klass;
- }
- if (!class_linker->EnsureInitialized(klass, true)) {
- CHECK(self->IsExceptionPending());
- return NULL; // Failure - Indicate to caller to deliver exception
- }
- referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
- return klass;
-}
-
-} // namespace art
diff --git a/src/runtime_support_common.h b/src/runtime_support_common.h
deleted file mode 100644
index c5121a9..0000000
--- a/src/runtime_support_common.h
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
-
-#ifndef ART_SRC_RUNTIME_SUPPORT_COMMON_H_
-#define ART_SRC_RUNTIME_SUPPORT_COMMON_H_
-
-#include "class_linker.h"
-#include "constants.h"
-#include "object.h"
-#include "object_utils.h"
-#include "thread.h"
-
-#include <stdint.h>
-
-namespace art {
-
-class Array;
-class Class;
-class Field;
-class Method;
-class Object;
-
-static inline void ThrowNewIllegalAccessErrorClass(Thread* self,
- Class* referrer,
- Class* accessed) {
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
- "illegal class access: '%s' -> '%s'",
- PrettyDescriptor(referrer).c_str(),
- PrettyDescriptor(accessed).c_str());
-}
-
-static inline void
-ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self,
- Class* referrer,
- Class* accessed,
- const Method* caller,
- const Method* called,
- InvokeType type) {
- std::ostringstream type_stream;
- type_stream << type;
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
- "illegal class access ('%s' -> '%s')"
- "in attempt to invoke %s method '%s' from '%s'",
- PrettyDescriptor(referrer).c_str(),
- PrettyDescriptor(accessed).c_str(),
- type_stream.str().c_str(),
- PrettyMethod(called).c_str(),
- PrettyMethod(caller).c_str());
-}
-
-static inline void
-ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
- const Method* referrer,
- const Method* interface_method,
- Object* this_object) {
- self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
- "class '%s' does not implement interface '%s' in call to '%s' from '%s'",
- PrettyDescriptor(this_object->GetClass()).c_str(),
- PrettyDescriptor(interface_method->GetDeclaringClass()).c_str(),
- PrettyMethod(interface_method).c_str(), PrettyMethod(referrer).c_str());
-}
-
-static inline void ThrowNewIllegalAccessErrorField(Thread* self,
- Class* referrer,
- Field* accessed) {
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
- "Field '%s' is inaccessible to class '%s'",
- PrettyField(accessed, false).c_str(),
- PrettyDescriptor(referrer).c_str());
-}
-
-static inline void ThrowNewIllegalAccessErrorFinalField(Thread* self,
- const Method* referrer,
- Field* accessed) {
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
- "Final field '%s' cannot be written to by method '%s'",
- PrettyField(accessed, false).c_str(),
- PrettyMethod(referrer).c_str());
-}
-
-static inline void ThrowNewIllegalAccessErrorMethod(Thread* self,
- Class* referrer,
- Method* accessed) {
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
- "Method '%s' is inaccessible to class '%s'",
- PrettyMethod(accessed).c_str(),
- PrettyDescriptor(referrer).c_str());
-}
-
-static inline void ThrowNullPointerExceptionForFieldAccess(Thread* self,
- Field* field,
- bool is_read) {
- self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
- "Attempt to %s field '%s' on a null object reference",
- is_read ? "read from" : "write to",
- PrettyField(field, true).c_str());
-}
-
-static inline void ThrowNullPointerExceptionForMethodAccess(Thread* self,
- Method* caller,
- uint32_t method_idx,
- InvokeType type) {
- const DexFile& dex_file =
- Runtime::Current()->GetClassLinker()->FindDexFile(caller->GetDeclaringClass()->GetDexCache());
- std::ostringstream type_stream;
- type_stream << type;
- self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
- "Attempt to invoke %s method '%s' on a null object reference",
- type_stream.str().c_str(),
- PrettyMethod(method_idx, dex_file, true).c_str());
-}
-
-// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
-// cannot be resolved, throw an error. If it can, use it to create an instance.
-// When verification/compiler hasn't been able to verify access, optionally perform an access
-// check.
-static inline Object* AllocObjectFromCode(uint32_t type_idx, Method* method, Thread* self,
- bool access_check) {
- Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
- Runtime* runtime = Runtime::Current();
- if (UNLIKELY(klass == NULL)) {
- klass = runtime->GetClassLinker()->ResolveType(type_idx, method);
- if (klass == NULL) {
- DCHECK(self->IsExceptionPending());
- return NULL; // Failure
- }
- }
- if (access_check) {
- if (UNLIKELY(!klass->IsInstantiable())) {
- self->ThrowNewException("Ljava/lang/InstantiationError;",
- PrettyDescriptor(klass).c_str());
- return NULL; // Failure
- }
- Class* referrer = method->GetDeclaringClass();
- if (UNLIKELY(!referrer->CanAccess(klass))) {
- ThrowNewIllegalAccessErrorClass(self, referrer, klass);
- return NULL; // Failure
- }
- }
- if (!runtime->GetClassLinker()->EnsureInitialized(klass, true)) {
- DCHECK(self->IsExceptionPending());
- return NULL; // Failure
- }
- return klass->AllocObject();
-}
-
-// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
-// it cannot be resolved, throw an error. If it can, use it to create an array.
-// When verification/compiler hasn't been able to verify access, optionally perform an access
-// check.
-static inline Array* AllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
- Thread* self, bool access_check) {
- if (UNLIKELY(component_count < 0)) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
- component_count);
- return NULL; // Failure
- }
- Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
- if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
- klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
- if (klass == NULL) { // Error
- DCHECK(Thread::Current()->IsExceptionPending());
- return NULL; // Failure
- }
- CHECK(klass->IsArrayClass()) << PrettyClass(klass);
- }
- if (access_check) {
- Class* referrer = method->GetDeclaringClass();
- if (UNLIKELY(!referrer->CanAccess(klass))) {
- ThrowNewIllegalAccessErrorClass(self, referrer, klass);
- return NULL; // Failure
- }
- }
- return Array::Alloc(klass, component_count);
-}
-
-extern Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
- Thread* self, bool access_check);
-
-extern Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
- bool is_static, bool is_primitive, bool is_set,
- size_t expected_size);
-
-// Fast path field resolution that can't throw exceptions
-static inline Field* FindFieldFast(uint32_t field_idx, const Method* referrer, bool is_primitive,
- size_t expected_size, bool is_set) {
- Field* resolved_field = referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
- if (UNLIKELY(resolved_field == NULL)) {
- return NULL;
- }
- Class* fields_class = resolved_field->GetDeclaringClass();
- // Check class is initiliazed or initializing
- if (UNLIKELY(!fields_class->IsInitializing())) {
- return NULL;
- }
- Class* referring_class = referrer->GetDeclaringClass();
- if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
- !referring_class->CanAccessMember(fields_class,
- resolved_field->GetAccessFlags()) ||
- (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
- // illegal access
- return NULL;
- }
- FieldHelper fh(resolved_field);
- if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
- fh.FieldSize() != expected_size)) {
- return NULL;
- }
- return resolved_field;
-}
-
-// Fast path method resolution that can't throw exceptions
-static inline Method* FindMethodFast(uint32_t method_idx, Object* this_object, const Method* referrer,
- bool access_check, InvokeType type) {
- bool is_direct = type == kStatic || type == kDirect;
- if (UNLIKELY(this_object == NULL && !is_direct)) {
- return NULL;
- }
- Method* resolved_method =
- referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx);
- if (UNLIKELY(resolved_method == NULL)) {
- return NULL;
- }
- if (access_check) {
- Class* methods_class = resolved_method->GetDeclaringClass();
- Class* referring_class = referrer->GetDeclaringClass();
- if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
- !referring_class->CanAccessMember(methods_class,
- resolved_method->GetAccessFlags()))) {
- // potential illegal access
- return NULL;
- }
- }
- if (type == kInterface) { // Most common form of slow path dispatch.
- return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
- } else if (is_direct) {
- return resolved_method;
- } else if (type == kSuper) {
- return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->
- Get(resolved_method->GetMethodIndex());
- } else {
- DCHECK(type == kVirtual);
- return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
- }
-}
-
-extern Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
- Thread* self, bool access_check, InvokeType type);
-
-extern Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
- bool can_run_clinit, bool verify_access);
-
-static inline String* ResolveStringFromCode(const Method* referrer, uint32_t string_idx) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- return class_linker->ResolveString(string_idx, referrer);
-}
-
-} // namespace art
-
-#endif // ART_SRC_RUNTIME_SUPPORT_COMMON_H_
diff --git a/src/thread.cc b/src/thread.cc
index aee684b..fa78365 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -31,11 +31,11 @@
#include "debugger.h"
#include "class_linker.h"
#include "class_loader.h"
-#include "context.h"
#include "dex_verifier.h"
#include "heap.h"
#include "jni_internal.h"
#include "monitor.h"
+#include "oat/runtime/context.h"
#include "object.h"
#include "object_utils.h"
#include "reflection.h"
@@ -76,194 +76,12 @@
}
void Thread::InitFunctionPointers() {
-#if defined(__mips)
- pShlLong = art_shl_long;
- pShrLong = art_shr_long;
- pUshrLong = art_ushr_long;
- pI2f = __floatsisf;
- pF2iz = __fixsfi;
- pD2f = __truncdfsf2;
- pF2d = __extendsfdfs;
- pD2iz = __fixdfsi;
- pL2f = __floatdisf;
- pL2d = __floatdidf;
- pFadd = __addsf3;
- pFsub = __subsf3;
- pFdiv = divsf3;
- pFmul = __mulsf3;
- pFmodf = fmodf;
- pDadd = __adddf3;
- pDsub = __subdf3;
- pDdiv = __divdf3;
- pDmul = muldf3;
- pFmod = fmod;
- pCmpgFloat = CmpgFloat;
- pCmplFloat = CmplFloat;
- pCmpgDouble = CmpgDouble;
- pCmplDouble = CmplDouble;
-#elif defined(__arm__)
- pMemcmp16 = __memcmp16;
- pIndexOf = art_indexof;
- pStringCompareTo = art_string_compareto;
- pShlLong = art_shl_long;
- pShrLong = art_shr_long;
- pUshrLong = art_ushr_long;
- pIdiv = __aeabi_idiv;
- pIdivmod = __aeabi_idivmod;
- pI2f = __aeabi_i2f;
- pF2iz = __aeabi_f2iz;
- pD2f = __aeabi_d2f;
- pF2d = __aeabi_f2d;
- pD2iz = __aeabi_d2iz;
- pL2f = __aeabi_l2f;
- pL2d = __aeabi_l2d;
- pFadd = __aeabi_fadd;
- pFsub = __aeabi_fsub;
- pFdiv = __aeabi_fdiv;
- pFmul = __aeabi_fmul;
- pFmodf = fmodf;
- pDadd = __aeabi_dadd;
- pDsub = __aeabi_dsub;
- pDdiv = __aeabi_ddiv;
- pDmul = __aeabi_dmul;
- pFmod = fmod;
- pLadd = NULL;
- pLsub = NULL;
- pLand = NULL;
- pLor = NULL;
- pLxor = NULL;
- pLdivmod = __aeabi_ldivmod;
- pLmul = __aeabi_lmul;
- pAllocArrayFromCode = art_alloc_array_from_code;
- pAllocArrayFromCodeWithAccessCheck = art_alloc_array_from_code_with_access_check;
- pAllocObjectFromCode = art_alloc_object_from_code;
- pAllocObjectFromCodeWithAccessCheck = art_alloc_object_from_code_with_access_check;
- pCanPutArrayElementFromCode = art_can_put_array_element_from_code;
- pCheckAndAllocArrayFromCode = art_check_and_alloc_array_from_code;
- pCheckAndAllocArrayFromCodeWithAccessCheck = art_check_and_alloc_array_from_code_with_access_check;
- pCheckCastFromCode = art_check_cast_from_code;
- pGet32Instance = art_get32_instance_from_code;
- pGet64Instance = art_get64_instance_from_code;
- pGetObjInstance = art_get_obj_instance_from_code;
- pGet32Static = art_get32_static_from_code;
- pGet64Static = art_get64_static_from_code;
- pGetObjStatic = art_get_obj_static_from_code;
- pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
- pInitializeStaticStorage = art_initialize_static_storage_from_code;
- pInitializeTypeFromCode = art_initialize_type_from_code;
- pInitializeTypeAndVerifyAccessFromCode = art_initialize_type_and_verify_access_from_code;
- pInvokeDirectTrampolineWithAccessCheck = art_invoke_direct_trampoline_with_access_check;
- pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
- pInvokeInterfaceTrampolineWithAccessCheck = art_invoke_interface_trampoline_with_access_check;
- pInvokeStaticTrampolineWithAccessCheck = art_invoke_static_trampoline_with_access_check;
- pInvokeSuperTrampolineWithAccessCheck = art_invoke_super_trampoline_with_access_check;
- pInvokeVirtualTrampolineWithAccessCheck = art_invoke_virtual_trampoline_with_access_check;
- pLockObjectFromCode = art_lock_object_from_code;
- pResolveStringFromCode = art_resolve_string_from_code;
- pSet32Instance = art_set32_instance_from_code;
- pSet64Instance = art_set64_instance_from_code;
- pSetObjInstance = art_set_obj_instance_from_code;
- pSet32Static = art_set32_static_from_code;
- pSet64Static = art_set64_static_from_code;
- pSetObjStatic = art_set_obj_static_from_code;
- pTestSuspendFromCode = art_test_suspend;
- pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code;
- pThrowDivZeroFromCode = art_throw_div_zero_from_code;
- pThrowNegArraySizeFromCode = art_throw_neg_array_size_from_code;
- pThrowNoSuchMethodFromCode = art_throw_no_such_method_from_code;
- pThrowNullPointerFromCode = art_throw_null_pointer_exception_from_code;
- pThrowStackOverflowFromCode = art_throw_stack_overflow_from_code;
- pThrowVerificationErrorFromCode = art_throw_verification_error_from_code;
- pUnlockObjectFromCode = art_unlock_object_from_code;
-#elif defined(__i386__)
- pShlLong = NULL;
- pShrLong = NULL;
- pUshrLong = NULL;
- pIdiv = NULL;
- pIdivmod = NULL;
- pI2f = NULL;
- pF2iz = NULL;
- pD2f = NULL;
- pF2d = NULL;
- pD2iz = NULL;
- pL2f = NULL;
- pL2d = NULL;
- pFadd = NULL;
- pFsub = NULL;
- pFdiv = NULL;
- pFmul = NULL;
- pFmodf = NULL;
- pDadd = NULL;
- pDsub = NULL;
- pDdiv = NULL;
- pDmul = NULL;
- pFmod = NULL;
- pLadd = NULL;
- pLsub = NULL;
- pLand = NULL;
- pLor = NULL;
- pLxor = NULL;
- pLdivmod = NULL;
- pLmul = NULL;
- pAllocArrayFromCode = NULL;
- pAllocArrayFromCodeWithAccessCheck = NULL;
- pAllocObjectFromCode = NULL;
- pAllocObjectFromCodeWithAccessCheck = NULL;
- pCanPutArrayElementFromCode = NULL;
- pCheckAndAllocArrayFromCode = NULL;
- pCheckAndAllocArrayFromCodeWithAccessCheck = NULL;
- pCheckCastFromCode = NULL;
- pGet32Instance = NULL;
- pGet64Instance = NULL;
- pGetObjInstance = NULL;
- pGet32Static = NULL;
- pGet64Static = NULL;
- pGetObjStatic = NULL;
- pHandleFillArrayDataFromCode = NULL;
- pInitializeStaticStorage = NULL;
- pInitializeTypeFromCode = NULL;
- pInitializeTypeAndVerifyAccessFromCode = NULL;
- pInvokeDirectTrampolineWithAccessCheck = NULL;
- pInvokeInterfaceTrampoline = NULL;
- pInvokeInterfaceTrampolineWithAccessCheck = NULL;
- pInvokeStaticTrampolineWithAccessCheck = NULL;
- pInvokeSuperTrampolineWithAccessCheck = NULL;
- pInvokeVirtualTrampolineWithAccessCheck = NULL;
- pLockObjectFromCode = NULL;
- pResolveStringFromCode = NULL;
- pSet32Instance = NULL;
- pSet64Instance = NULL;
- pSetObjInstance = NULL;
- pSet32Static = NULL;
- pSet64Static = NULL;
- pSetObjStatic = NULL;
- pTestSuspendFromCode = NULL;
- pThrowArrayBoundsFromCode = NULL;
- pThrowDivZeroFromCode = NULL;
- pThrowNegArraySizeFromCode = NULL;
- pThrowNoSuchMethodFromCode = NULL;
- pThrowNullPointerFromCode = NULL;
- pThrowStackOverflowFromCode = NULL;
- pThrowVerificationErrorFromCode = NULL;
- pUnlockObjectFromCode = NULL;
-#endif
- pF2l = F2L;
- pD2l = D2L;
- pMemcpy = memcpy;
- pCheckSuspendFromCode = CheckSuspendFromCode;
- pDebugMe = DebugMe;
- pDecodeJObjectInThread = DecodeJObjectInThread;
- pDeliverException = art_deliver_exception_from_code;
- pFindNativeMethod = FindNativeMethod;
- pInstanceofNonTrivialFromCode = IsAssignableFromCode;
- pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;
- pUnresolvedDirectMethodTrampolineFromCode = UnresolvedDirectMethodTrampolineFromCode;
- pUpdateDebuggerFromCode = NULL; // Controlled by SetDebuggerUpdatesEnabled.
+ InitEntryPoints(&entrypoints_);
}
void Thread::SetDebuggerUpdatesEnabled(bool enabled) {
LOG(INFO) << "Turning debugger updates " << (enabled ? "on" : "off") << " for " << *this;
- pUpdateDebuggerFromCode = (enabled ? art_update_debugger : NULL);
+ ChangeDebuggerEntryPoint(&entrypoints_, enabled);
}
void Thread::InitTid() {
@@ -1338,30 +1156,29 @@
void Thread::WalkStack(StackVisitor* visitor, bool include_upcalls) const {
Frame frame = GetTopOfStack();
uintptr_t pc = ManglePc(top_of_managed_stack_pc_);
-#if defined(__arm__)
uint32_t trace_stack_depth = 0;
-#endif
// TODO: enable this CHECK after native_to_managed_record_ is initialized during startup.
// CHECK(native_to_managed_record_ != NULL);
NativeToManagedRecord* record = native_to_managed_record_;
-
+ bool method_tracing_active = Runtime::Current()->IsMethodTracingActive();
while (frame.GetSP() != NULL) {
for ( ; frame.GetMethod() != NULL; frame.Next()) {
frame.GetMethod()->AssertPcIsWithinCode(pc);
bool should_continue = visitor->VisitFrame(frame, pc);
- if (!should_continue) {
+ if (UNLIKELY(!should_continue)) {
return;
}
- pc = ManglePc(frame.GetReturnPC());
- if (Runtime::Current()->IsMethodTracingActive()) {
-#if defined(__arm__)
- uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_trace_exit_from_code);
- if (ManglePc(trace_exit) == pc) {
+ uintptr_t return_pc = frame.GetReturnPC();
+ if (LIKELY(!method_tracing_active)) {
+ pc = ManglePc(return_pc);
+ } else {
+ if (IsTraceExitPc(return_pc)) {
TraceStackFrame trace_frame = GetTraceStackFrame(trace_stack_depth++);
CHECK(trace_frame.method_ == frame.GetMethod());
pc = ManglePc(trace_frame.return_pc_);
+ } else {
+ pc = ManglePc(return_pc);
}
-#endif
}
}
if (include_upcalls) {
@@ -1626,7 +1443,8 @@
class CatchBlockStackVisitor : public Thread::StackVisitor {
public:
CatchBlockStackVisitor(Class* to_find, Context* ljc)
- : to_find_(to_find), long_jump_context_(ljc), native_method_count_(0) {
+ : to_find_(to_find), long_jump_context_(ljc), native_method_count_(0),
+ method_tracing_active_(Runtime::Current()->IsMethodTracingActive()) {
#ifndef NDEBUG
handler_pc_ = 0xEBADC0DE;
handler_frame_.SetSP(reinterpret_cast<Method**>(0xEBADF00D));
@@ -1640,24 +1458,20 @@
// long jump to them
handler_pc_ = DemanglePc(pc);
handler_frame_ = fr;
- return false;
+ return false; // End stack walk.
}
uint32_t dex_pc = DexFile::kDexNoIndex;
- if (method->IsCalleeSaveMethod()) {
+ if (method->IsRuntimeMethod()) {
// ignore callee save method
+ DCHECK(method->IsCalleeSaveMethod());
} else if (method->IsNative()) {
native_method_count_++;
} else {
// Unwind stack during method tracing
- if (Runtime::Current()->IsMethodTracingActive()) {
-#if defined(__arm__)
- uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_trace_exit_from_code);
- if (ManglePc(trace_exit) == pc) {
+ if (UNLIKELY(method_tracing_active_)) {
+ if (IsTraceExitPc(DemanglePc(pc))) {
pc = ManglePc(TraceMethodUnwindFromCode(Thread::Current()));
}
-#else
- UNIMPLEMENTED(WARNING);
-#endif
}
dex_pc = method->ToDexPC(pc);
}
@@ -1666,12 +1480,12 @@
if (found_dex_pc != DexFile::kDexNoIndex) {
handler_pc_ = method->ToNativePC(found_dex_pc);
handler_frame_ = fr;
- return false;
+ return false; // End stack walk.
}
}
// Caller may be handler, fill in callee saves in context
long_jump_context_->FillCalleeSaves(fr);
- return true;
+ return true; // Continue stack walk.
}
// The type of the exception catch block to find
@@ -1684,6 +1498,8 @@
Context* long_jump_context_;
// Number of native methods passed in crawl (equates to number of SIRTs to pop)
uint32_t native_method_count_;
+ // Is method tracing active?
+ const bool method_tracing_active_;
};
void Thread::DeliverException() {
diff --git a/src/thread.h b/src/thread.h
index 32e000c..40409b6 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -32,6 +32,7 @@
#include "macros.h"
#include "mutex.h"
#include "mem_map.h"
+#include "oat/runtime/oat_support_entrypoints.h"
#include "offsets.h"
#include "runtime_stats.h"
#include "stack.h"
@@ -615,98 +616,7 @@
public:
// Runtime support function pointers
- void (*pDebugMe)(Method*, uint32_t);
- void* (*pMemcpy)(void*, const void*, size_t);
- uint64_t (*pShlLong)(uint64_t, uint32_t);
- uint64_t (*pShrLong)(uint64_t, uint32_t);
- uint64_t (*pUshrLong)(uint64_t, uint32_t);
- float (*pI2f)(int);
- int (*pF2iz)(float);
- float (*pD2f)(double);
- double (*pF2d)(float);
- double (*pI2d)(int);
- int (*pD2iz)(double);
- float (*pL2f)(int64_t);
- double (*pL2d)(int64_t);
- int64_t (*pF2l)(float);
- int64_t (*pD2l)(double);
- float (*pFadd)(float, float);
- float (*pFsub)(float, float);
- float (*pFdiv)(float, float);
- float (*pFmul)(float, float);
- float (*pFmodf)(float, float);
- double (*pDadd)(double, double);
- double (*pDsub)(double, double);
- double (*pDdiv)(double, double);
- double (*pDmul)(double, double);
- double (*pFmod)(double, double);
- int (*pIdivmod)(int, int);
- int (*pIdiv)(int, int);
- int64_t (*pLadd)(int64_t, int64_t);
- int64_t (*pLsub)(int64_t, int64_t);
- int64_t (*pLand)(int64_t, int64_t);
- int64_t (*pLor)(int64_t, int64_t);
- int64_t (*pLxor)(int64_t, int64_t);
- int64_t (*pLmul)(int64_t, int64_t);
- int64_t (*pLdivmod)(int64_t, int64_t);
- void (*pCheckSuspendFromCode)(Thread*); // Stub that is called when the suspend count is non-zero
- void (*pTestSuspendFromCode)(); // Stub that is periodically called to test the suspend count
- void* (*pAllocObjectFromCode)(uint32_t, void*);
- void* (*pAllocObjectFromCodeWithAccessCheck)(uint32_t, void*);
- void* (*pAllocArrayFromCode)(uint32_t, void*, int32_t);
- void* (*pAllocArrayFromCodeWithAccessCheck)(uint32_t, void*, int32_t);
- void (*pCanPutArrayElementFromCode)(void*, void*);
- void* (*pCheckAndAllocArrayFromCode)(uint32_t, void*, int32_t);
- void* (*pCheckAndAllocArrayFromCodeWithAccessCheck)(uint32_t, void*, int32_t);
- void (*pCheckCastFromCode)(void*, void*);
- Object* (*pDecodeJObjectInThread)(Thread* thread, jobject obj);
- void (*pDeliverException)(void*);
- Method* (*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
- void* (*pFindNativeMethod)(Thread* thread);
- int32_t (*pGet32Instance)(uint32_t, void*);
- int64_t (*pGet64Instance)(uint32_t, void*);
- void* (*pGetObjInstance)(uint32_t, void*);
- int32_t (*pGet32Static)(uint32_t);
- int64_t (*pGet64Static)(uint32_t);
- void* (*pGetObjStatic)(uint32_t);
- void (*pHandleFillArrayDataFromCode)(void*, void*);
- void* (*pInitializeStaticStorage)(uint32_t, void*);
- uint32_t (*pInstanceofNonTrivialFromCode)(const Class*, const Class*);
- void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*);
- void (*pInvokeInterfaceTrampoline)(uint32_t, void*);
- void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*);
- void (*pInvokeStaticTrampolineWithAccessCheck)(uint32_t, void*);
- void (*pInvokeSuperTrampolineWithAccessCheck)(uint32_t, void*);
- void (*pInvokeVirtualTrampolineWithAccessCheck)(uint32_t, void*);
- void* (*pInitializeTypeFromCode)(uint32_t, void*);
- void* (*pInitializeTypeAndVerifyAccessFromCode)(uint32_t, void*);
- void (*pLockObjectFromCode)(void*);
- void* (*pResolveStringFromCode)(void*, uint32_t);
- int (*pSet32Instance)(uint32_t, void*, int32_t); // field_idx, obj, src
- int (*pSet64Instance)(uint32_t, void*, int64_t);
- int (*pSetObjInstance)(uint32_t, void*, void*);
- int (*pSet32Static)(uint32_t, int32_t);
- int (*pSet64Static)(uint32_t, int64_t);
- int (*pSetObjStatic)(uint32_t, void*);
- void (*pThrowStackOverflowFromCode)(void*);
- void (*pThrowNullPointerFromCode)();
- void (*pThrowArrayBoundsFromCode)(int32_t, int32_t);
- void (*pThrowDivZeroFromCode)();
- void (*pThrowVerificationErrorFromCode)(int32_t, int32_t);
- void (*pThrowNegArraySizeFromCode)(int32_t);
- void (*pThrowNoSuchMethodFromCode)(int32_t);
- void (*pThrowAbstractMethodErrorFromCode)(Method* method, Thread* thread, Method** sp);
- void (*pUnlockObjectFromCode)(void*);
- const void* (*pUnresolvedDirectMethodTrampolineFromCode)(Method*, Method**, Thread*,
- Runtime::TrampolineType);
- void (*pUpdateDebuggerFromCode)(void*, void*, int32_t, void*);
- bool (*pCmplFloat)(float, float);
- bool (*pCmpgFloat)(float, float);
- bool (*pCmplDouble)(double, double);
- bool (*pCmpgDouble)(double, double);
- int (*pIndexOf)(void*, uint32_t, uint32_t, uint32_t);
- int (*pStringCompareTo)(void*, void*);
- int (*pMemcmp16)(void*, void*, int32_t);
+ EntryPoints entrypoints_;
private:
DISALLOW_COPY_AND_ASSIGN(Thread);
diff --git a/src/trace.cc b/src/trace.cc
index 61dd163..c38f017 100644
--- a/src/trace.cc
+++ b/src/trace.cc
@@ -21,12 +21,12 @@
#include "class_linker.h"
#include "debugger.h"
#include "dex_cache.h"
+#include "oat/runtime/oat_support_entrypoints.h"
#include "object_utils.h"
#include "os.h"
-#include "runtime_support.h"
#include "scoped_thread_list_lock.h"
#include "thread.h"
-
+#include "thread_list.h"
namespace art {
@@ -145,10 +145,7 @@
return true;
}
-#if defined(__arm__)
static void TraceRestoreStack(Thread* t, void*) {
- uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_trace_exit_from_code);
-
Frame frame = t->GetTopOfStack();
if (frame.GetSP() != 0) {
for ( ; frame.GetMethod() != 0; frame.Next()) {
@@ -157,7 +154,7 @@
}
uintptr_t pc = frame.GetReturnPC();
Method* method = frame.GetMethod();
- if (trace_exit == pc) {
+ if (IsTraceExitPc(pc)) {
TraceStackFrame trace_frame = t->PopTraceStackFrame();
frame.SetReturnPC(trace_frame.return_pc_);
CHECK(method == trace_frame.method_);
@@ -165,11 +162,6 @@
}
}
}
-#else
-static void TraceRestoreStack(Thread*, void*) {
- UNIMPLEMENTED(WARNING);
-}
-#endif
void Trace::AddSavedCodeToMap(const Method* method, const void* code) {
saved_code_map_.insert(std::make_pair(method, code));
@@ -189,18 +181,12 @@
}
}
-#if defined(__arm__)
void Trace::SaveAndUpdateCode(Method* method) {
- void* trace_stub = reinterpret_cast<void*>(art_trace_entry_from_code);
+ void* trace_stub = GetLogTraceEntryPoint();
CHECK(GetSavedCodeFromMap(method) == NULL);
AddSavedCodeToMap(method, method->GetCode());
method->SetCode(trace_stub);
}
-#else
-void Trace::SaveAndUpdateCode(Method*) {
- UNIMPLEMENTED(WARNING);
-}
-#endif
void Trace::ResetSavedCode(Method* method) {
CHECK(GetSavedCodeFromMap(method) != NULL);
@@ -445,4 +431,15 @@
}
}
+uint32_t TraceMethodUnwindFromCode(Thread* self) {
+ Trace* tracer = Runtime::Current()->GetTracer();
+ TraceStackFrame trace_frame = self->PopTraceStackFrame();
+ Method* method = trace_frame.method_;
+ uint32_t lr = trace_frame.return_pc_;
+
+ tracer->LogMethodTraceEvent(self, method, Trace::kMethodTraceUnwind);
+
+ return lr;
+}
+
} // namespace art
diff --git a/src/trace.h b/src/trace.h
index d545b14..b0366d9 100644
--- a/src/trace.h
+++ b/src/trace.h
@@ -32,6 +32,8 @@
class Method;
class Thread;
+uint32_t TraceMethodUnwindFromCode(Thread* self);
+
struct TraceStackFrame {
TraceStackFrame(Method* method, uintptr_t return_pc)
: method_(method), return_pc_(return_pc) {