Merge "Fix a bunch of JDWP bugs." into dalvik-dev
diff --git a/src/asm_support.h b/src/asm_support.h
index d3e18bc..6ba23bc 100644
--- a/src/asm_support.h
+++ b/src/asm_support.h
@@ -24,13 +24,13 @@
#define rSELF r9
#define rLR r14
// Offset of field Thread::suspend_count_ verified in InitCpu
-#define THREAD_SUSPEND_COUNT_OFFSET 424
+#define THREAD_SUSPEND_COUNT_OFFSET 120
// Offset of field Thread::exception_ verified in InitCpu
-#define THREAD_EXCEPTION_OFFSET 420
+#define THREAD_EXCEPTION_OFFSET 116
#elif defined(__i386__)
// Offset of field Thread::self_ verified in InitCpu
-#define THREAD_SELF_OFFSET 412
+#define THREAD_SELF_OFFSET 108
#endif
#endif // ART_SRC_ASM_SUPPORT_H_
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index bc13cb2..e9a94a9 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -922,9 +922,9 @@
EXPECT_NE(Jj2, Aj2);
EXPECT_EQ(Kj1, Jj1);
EXPECT_EQ(Kj2, Jj2);
- EXPECT_EQ(Ai, A->FindVirtualMethodForInterface(Ii, true));
- EXPECT_EQ(Aj1, A->FindVirtualMethodForInterface(Jj1, true));
- EXPECT_EQ(Aj2, A->FindVirtualMethodForInterface(Jj2, true));
+ EXPECT_EQ(Ai, A->FindVirtualMethodForInterface(Ii));
+ EXPECT_EQ(Aj1, A->FindVirtualMethodForInterface(Jj1));
+ EXPECT_EQ(Aj2, A->FindVirtualMethodForInterface(Jj2));
EXPECT_EQ(Ai, A->FindVirtualMethodForVirtualOrInterface(Ii));
EXPECT_EQ(Aj1, A->FindVirtualMethodForVirtualOrInterface(Jj1));
EXPECT_EQ(Aj2, A->FindVirtualMethodForVirtualOrInterface(Jj2));
diff --git a/src/compiler.cc b/src/compiler.cc
index c4c8424..8210c9b 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -250,20 +250,32 @@
return referrer_class->CanAccess(resolved_class) && resolved_class->IsInstantiable();
}
+static Class* ComputeReferrerClass(CompilationUnit* cUnit) {
+ const DexFile::MethodId& referrer_method_id = cUnit->dex_file->GetMethodId(cUnit->method_idx);
+ return cUnit->class_linker->ResolveType(*cUnit->dex_file, referrer_method_id.class_idx_,
+ cUnit->dex_cache, cUnit->class_loader);
+}
+
+static Field* ComputeReferrerField(CompilationUnit* cUnit, uint32_t field_idx) {
+ return cUnit->class_linker->ResolveField(*cUnit->dex_file, field_idx, cUnit->dex_cache,
+ cUnit->class_loader, false);
+
+}
+
+static Method* ComputeReferrerMethod(CompilationUnit* cUnit, uint32_t method_idx) {
+ return cUnit->class_linker->ResolveMethod(*cUnit->dex_file, method_idx, cUnit->dex_cache,
+ cUnit->class_loader, true);
+}
+
bool Compiler::ComputeInstanceFieldInfo(uint32_t field_idx, CompilationUnit* cUnit,
int& field_offset, bool& is_volatile) const {
// Conservative defaults
field_offset = -1;
is_volatile = true;
// Try to resolve field
- Field* resolved_field =
- cUnit->class_linker->ResolveField(*cUnit->dex_file, field_idx, cUnit->dex_cache,
- cUnit->class_loader, false);
+ Field* resolved_field = ComputeReferrerField(cUnit, field_idx);
if (resolved_field != NULL) {
- const DexFile::MethodId& referrer_method_id = cUnit->dex_file->GetMethodId(cUnit->method_idx);
- Class* referrer_class =
- cUnit->class_linker->ResolveType(*cUnit->dex_file, referrer_method_id.class_idx_,
- cUnit->dex_cache, cUnit->class_loader);
+ Class* referrer_class = ComputeReferrerClass(cUnit);
// Try to resolve referring class then access check, failure to pass the
Class* fields_class = resolved_field->GetDeclaringClass();
if (referrer_class != NULL &&
@@ -292,14 +304,10 @@
is_referrers_class = false;
is_volatile = true;
// Try to resolve field
- Field* resolved_field =
- cUnit->class_linker->ResolveField(*cUnit->dex_file, field_idx, cUnit->dex_cache,
- cUnit->class_loader, true);
+ Field* resolved_field = ComputeReferrerField(cUnit, field_idx);
if (resolved_field != NULL) {
- const DexFile::MethodId& referrer_method_id = cUnit->dex_file->GetMethodId(cUnit->method_idx);
- Class* referrer_class =
- cUnit->class_linker->ResolveType(*cUnit->dex_file, referrer_method_id.class_idx_,
- cUnit->dex_cache, cUnit->class_loader);
+ DCHECK(resolved_field->IsStatic());
+ Class* referrer_class = ComputeReferrerClass(cUnit);
if (referrer_class != NULL) {
if (resolved_field->GetDeclaringClass() == referrer_class) {
is_referrers_class = true; // implies no worrying about class initialization
@@ -350,6 +358,54 @@
return false; // Incomplete knowledge needs slow path.
}
+bool Compiler::ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit,
+ bool is_interface, bool is_super,
+ int& vtable_idx) const {
+ vtable_idx = -1;
+ Method* resolved_method = ComputeReferrerMethod(cUnit, method_idx);
+ if (resolved_method != NULL) {
+ Class* referrer_class = ComputeReferrerClass(cUnit);
+ if (referrer_class != NULL) {
+ Class* methods_class = resolved_method->GetDeclaringClass();
+ if (!referrer_class->CanAccess(methods_class) ||
+ !referrer_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 = cUnit->class_linker->FindDexFile(referrer_class->GetDexCache());
+ methods_class =
+ cUnit->class_linker->ResolveType(dex_file,
+ dex_file.GetMethodId(method_idx).class_idx_,
+ referrer_class);
+
+ }
+ if (referrer_class->CanAccess(methods_class) &&
+ referrer_class->CanAccessMember(methods_class,
+ resolved_method->GetAccessFlags())) {
+ vtable_idx = resolved_method->GetMethodIndex();
+ if (is_interface || is_super) {
+ // nothing left to do for virtual/interface dispatch
+ return true;
+ } else {
+ // ensure the vtable index will be correct to dispatch in the vtable of the super class
+ Class* super_class = methods_class->GetSuperClass();
+ if (super_class != NULL && vtable_idx <= super_class->GetVTable()->GetLength()) {
+ vtable_idx = resolved_method->GetMethodIndex();
+ return true;
+ }
+ }
+ }
+ }
+ }
+ // Clean up any exception left by method/type resolution
+ Thread* thread = Thread::Current();
+ if (thread->IsExceptionPending()) {
+ thread->ClearException();
+ }
+ return false; // Incomplete knowledge needs slow path.
+}
+
// Return true if the class should be skipped during compilation. We
// never skip classes in the boot class loader. However, if we have a
// non-boot class loader and we can resolve the class in the boot
diff --git a/src/compiler.h b/src/compiler.h
index d966b02..b55960b 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -109,6 +109,10 @@
int& field_offset, int& ssb_index,
bool& is_referrers_class, bool& is_volatile) const;
+ // Can we fastpath a interface, super class or virtual method call? Computes method's vtable index
+ bool ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit, bool is_interface,
+ bool is_super, int& vtable_idx) const;
+
private:
// Checks if class specified by type_idx is one of the image_classes_
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index e4073d4..eb2c06b 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -351,19 +351,16 @@
}
}
-typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
- ArmLIR*);
+typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
+ uint32_t methodIdx);
/*
* Bit of a hack here - in leiu of a real scheduling pass,
* emit the next instruction in static & direct invoke sequences.
*/
STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
- DecodedInstruction* dInsn, int state,
- ArmLIR* rollback)
+ int state, uint32_t dexIdx, uint32_t unused)
{
- DCHECK(rollback == NULL);
- uint32_t idx = dInsn->vB;
switch(state) {
case 0: // Get the current Method* [sets r0]
loadCurrMethodDirect(cUnit, r0);
@@ -375,9 +372,9 @@
break;
case 2: // Grab target method* and target code_
loadWordDisp(cUnit, r0,
- CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
+ CodeAndDirectMethods::CodeOffsetInBytes(dexIdx), rLR);
loadWordDisp(cUnit, r0,
- CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
+ CodeAndDirectMethods::MethodOffsetInBytes(dexIdx), r0);
break;
default:
return -1;
@@ -393,22 +390,13 @@
* r1 here rather than the standard loadArgRegs.
*/
STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
- DecodedInstruction* dInsn, int state,
- ArmLIR* rollback)
+ int state, uint32_t dexIdx, uint32_t methodIdx)
{
- DCHECK(rollback == NULL);
RegLocation rlArg;
/*
* This is the fast path in which the target virtual method is
* fully resolved at compile time.
*/
- Method* baseMethod = cUnit->class_linker->ResolveMethod(*cUnit->dex_file,
- dInsn->vB,
- cUnit->dex_cache,
- cUnit->class_loader,
- false);
- CHECK(baseMethod != NULL);
- uint32_t target_idx = baseMethod->GetMethodIndex();
switch(state) {
case 0: // Get "this" [set r1]
rlArg = oatGetSrc(cUnit, mir, 0);
@@ -423,7 +411,7 @@
loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
break;
case 3: // Get target method [use rLR, set r0]
- loadWordDisp(cUnit, rLR, (target_idx * 4) +
+ loadWordDisp(cUnit, rLR, (methodIdx * 4) +
Array::DataOffset().Int32Value(), r0);
break;
case 4: // Get the target compiled code address [uses r0, sets rLR]
@@ -435,157 +423,20 @@
return state + 1;
}
-STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
- DecodedInstruction* dInsn, int state,
- ArmLIR* rollback)
-{
- RegLocation rlArg;
- ArmLIR* skipBranch;
- ArmLIR* skipTarget;
- /*
- * This handles the case in which the base method is not fully
- * resolved at compile time. We must generate code to test
- * for resolution a run time, bail to the slow path if not to
- * fill in all the tables. In the latter case, we'll restart at
- * at the beginning of the sequence.
- */
- switch(state) {
- case 0: // Get the current Method* [sets r0]
- loadCurrMethodDirect(cUnit, r0);
- break;
- case 1: // Get method->dex_cache_resolved_methods_
- loadWordDisp(cUnit, r0,
- Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
- break;
- case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
- loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
- Array::DataOffset().Int32Value(), rLR);
- break;
- case 3: // Resolved?
- skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
- // Slowest path, bail to helper, rollback and retry
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
- loadConstant(cUnit, r1, dInsn->vB);
- loadConstant(cUnit, r2, false);
- callRuntimeHelper(cUnit, rLR);
- genUnconditionalBranch(cUnit, rollback);
- // Resume normal slow path
- skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
- skipTarget->defMask = ENCODE_ALL;
- skipBranch->generic.target = (LIR*)skipTarget;
- // Get base_method->method_index [usr rLR, set r0]
- loadBaseDisp(cUnit, mir, rLR,
- Method::GetMethodIndexOffset().Int32Value(), r0,
- kUnsignedHalf, INVALID_SREG);
- // Load "this" [set r1]
- rlArg = oatGetSrc(cUnit, mir, 0);
- loadValueDirectFixed(cUnit, rlArg, r1);
- break;
- case 4:
- // Is "this" null? [use r1]
- genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
- // get this->clazz [use r1, set rLR]
- loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
- break;
- case 5:
- // get this->klass_->vtable_ [usr rLR, set rLR]
- loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
- DCHECK_EQ((Array::DataOffset().Int32Value() & 0x3), 0);
- // In load shadow fold vtable_ object header size into method_index_
- opRegImm(cUnit, kOpAdd, r0,
- Array::DataOffset().Int32Value() / 4);
- // Get target Method*
- loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
- break;
- case 6: // Get the target compiled code address [uses r0, sets rLR]
- loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
- break;
- default:
- return -1;
- }
- return state + 1;
-}
-
-STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
- DecodedInstruction* dInsn, int callState,
- NextCallInsn nextCallInsn, ArmLIR* rollback,
- bool skipThis)
-{
- int nextReg = r1;
- int nextArg = 0;
- if (skipThis) {
- nextReg++;
- nextArg++;
- }
- for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
- RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
- rlArg = oatUpdateRawLoc(cUnit, rlArg);
- if (rlArg.wide && (nextReg <= r2)) {
- loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
- nextReg++;
- nextArg++;
- } else {
- rlArg.wide = false;
- loadValueDirectFixed(cUnit, rlArg, nextReg);
- }
- callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
- }
- return callState;
-}
-
-// Interleave launch code for INVOKE_INTERFACE.
-STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
- DecodedInstruction* dInsn, int state,
- ArmLIR* rollback)
-{
- DCHECK(rollback == NULL);
- switch(state) {
- case 0: // Load trampoline target
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
- rLR);
- // Load r0 with method index
- loadConstant(cUnit, r0, dInsn->vB);
- break;
- default:
- return -1;
- }
- return state + 1;
-}
-
/*
* Interleave launch code for INVOKE_SUPER. See comments
* for nextVCallIns.
*/
STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
- DecodedInstruction* dInsn, int state,
- ArmLIR* rollback)
+ int state, uint32_t dexIdx, uint32_t methodIdx)
{
- DCHECK(rollback == NULL);
- RegLocation rlArg;
/*
* This is the fast path in which the target virtual method is
* fully resolved at compile time. Note also that this path assumes
* that the check to verify that the target method index falls
* within the size of the super's vtable has been done at compile-time.
*/
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
- dInsn->vB,
- cUnit->dex_cache,
- cUnit->class_loader,
- false);
- CHECK(baseMethod != NULL);
- Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
- ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
- Class* superClass = (declaring_class != NULL)
- ? declaring_class->GetSuperClass() : NULL;
- CHECK(superClass != NULL);
- int32_t target_idx = baseMethod->GetMethodIndex();
- CHECK(superClass->GetVTable()->GetLength() > target_idx);
- Method* targetMethod = superClass->GetVTable()->Get(target_idx);
- CHECK(targetMethod != NULL);
+ RegLocation rlArg;
switch(state) {
case 0: // Get current Method* [set r0]
loadCurrMethodDirect(cUnit, r0);
@@ -606,7 +457,7 @@
loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
break;
case 3: // Get target method [use rLR, set r0]
- loadWordDisp(cUnit, rLR, (target_idx * 4) +
+ loadWordDisp(cUnit, rLR, (methodIdx * 4) +
Array::DataOffset().Int32Value(), r0);
break;
case 4: // Get the target compiled code address [uses r0, sets rLR]
@@ -618,85 +469,95 @@
return state + 1;
}
-/* Slow-path version of nextSuperCallInsn */
-STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
- DecodedInstruction* dInsn, int state,
- ArmLIR* rollback)
+STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir,
+ bool accessCheck, bool isInterface,
+ bool isSuper, int state, uint32_t dexIdx,
+ uint32_t methodIdx)
{
- RegLocation rlArg;
- ArmLIR* skipBranch;
- ArmLIR* skipTarget;
- int tReg;
/*
* This handles the case in which the base method is not fully
- * resolved at compile time. We must generate code to test
- * for resolution a run time, bail to the slow path if not to
- * fill in all the tables. In the latter case, we'll restart at
- * at the beginning of the sequence.
+ * resolved at compile time, we bail to a runtime helper.
*/
- switch(state) {
- case 0: // Get the current Method* [sets r0]
- loadCurrMethodDirect(cUnit, r0);
- break;
- case 1: // Get method->dex_cache_resolved_methods_ [uses r0, set rLR]
- loadWordDisp(cUnit, r0,
- Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
- break;
- case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
- loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
- Array::DataOffset().Int32Value(), rLR);
- break;
- case 3: // Resolved?
- skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
- // Slowest path, bail to helper, rollback and retry
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
- loadConstant(cUnit, r1, dInsn->vB);
- loadConstant(cUnit, r2, true);
- callRuntimeHelper(cUnit, rLR);
- genUnconditionalBranch(cUnit, rollback);
- // Resume normal slow path
- skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
- skipTarget->defMask = ENCODE_ALL;
- skipBranch->generic.target = (LIR*)skipTarget;
- // Get base_method->method_index [usr rLR, set rLR]
- loadBaseDisp(cUnit, mir, rLR,
- Method::GetMethodIndexOffset().Int32Value(), rLR,
- kUnsignedHalf, INVALID_SREG);
- // Load "this" [set r1]
- rlArg = oatGetSrc(cUnit, mir, 0);
- loadValueDirectFixed(cUnit, rlArg, r1);
- // Load curMethod->declaring_class_ [uses r0, sets r0]
- loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
- r0);
- // Null this?
- genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
- // Get method->declaring_class_->super_class [usr r0, set r0]
- loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
- break;
- case 4: // Get ...->super_class_->vtable [u/s r0]
- loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
- if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
- // Range check, throw NSM on failure
- tReg = oatAllocTemp(cUnit);
- loadWordDisp(cUnit, r0, Array::LengthOffset().Int32Value(),
- tReg);
- genRegRegCheck(cUnit, kArmCondCs, rLR, tReg, mir,
- kArmThrowNoSuchMethod);
- oatFreeTemp(cUnit, tReg);
- }
- // Adjust vtable_ base past object header
- opRegImm(cUnit, kOpAdd, r0, Array::DataOffset().Int32Value());
- // Get target Method*
- loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
- break;
- case 5: // Get the target compiled code address [uses r0, sets rLR]
- loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
- break;
- default:
- return -1;
+ if (state == 0) {
+ int trampoline;
+ if (!accessCheck) {
+ DCHECK(isInterface);
+ trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
+ } else {
+ if (isInterface) {
+ trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
+ } else if (isSuper) {
+ trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
+ } else {
+ trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
+ }
+ }
+ // Load trampoline target
+ loadWordDisp(cUnit, rSELF, trampoline, rLR);
+ // Load r0 with method index
+ loadConstant(cUnit, r0, dexIdx);
+ return 1;
}
- return state + 1;
+ return -1;
+}
+
+STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+ int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+ return nextInvokeInsnSP(cUnit, mir, true, false, true, state, dexIdx,
+ methodIdx);
+}
+
+STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+ int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+ return nextInvokeInsnSP(cUnit, mir, true, false, false, state, dexIdx,
+ methodIdx);
+}
+
+/*
+ * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
+ * which will locate the target and continue on via a tail call.
+ */
+STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
+ int state, uint32_t dexIdx, uint32_t unused)
+{
+ return nextInvokeInsnSP(cUnit, mir, false, true, false, state, dexIdx, 0);
+}
+
+STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
+ MIR* mir, int state,
+ uint32_t dexIdx,
+ uint32_t unused)
+{
+ return nextInvokeInsnSP(cUnit, mir, true, true, false, state, dexIdx, 0);
+}
+
+STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
+ DecodedInstruction* dInsn, int callState,
+ NextCallInsn nextCallInsn, uint32_t dexIdx,
+ uint32_t methodIdx, bool skipThis)
+{
+ int nextReg = r1;
+ int nextArg = 0;
+ if (skipThis) {
+ nextReg++;
+ nextArg++;
+ }
+ for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
+ RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
+ rlArg = oatUpdateRawLoc(cUnit, rlArg);
+ if (rlArg.wide && (nextReg <= r2)) {
+ loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
+ nextReg++;
+ nextArg++;
+ } else {
+ rlArg.wide = false;
+ loadValueDirectFixed(cUnit, rlArg, nextReg);
+ }
+ callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+ }
+ return callState;
}
/*
@@ -709,8 +570,8 @@
STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
DecodedInstruction* dInsn, int callState,
ArmLIR** pcrLabel, bool isRange,
- NextCallInsn nextCallInsn, ArmLIR* rollback,
- bool skipThis)
+ NextCallInsn nextCallInsn, uint32_t dexIdx,
+ uint32_t methodIdx, bool skipThis)
{
RegLocation rlArg;
@@ -718,7 +579,7 @@
if (dInsn->vA == 0)
return callState;
- callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
+ callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
DCHECK_LE(dInsn->vA, 5U);
if (dInsn->vA > 3) {
@@ -739,12 +600,12 @@
reg = r3;
loadWordDisp(cUnit, rSP,
oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
- callState = nextCallInsn(cUnit, mir, dInsn, callState,
- rollback);
+ callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+ methodIdx);
}
storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
- callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
+ callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
nextUse++;
}
// Loop through the rest
@@ -764,8 +625,8 @@
} else {
loadValueDirectFixed(cUnit, rlArg, lowReg);
}
- callState = nextCallInsn(cUnit, mir, dInsn, callState,
- rollback);
+ callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+ methodIdx);
}
int outsOffset = (nextUse + 1) * 4;
if (rlArg.wide) {
@@ -775,12 +636,12 @@
storeWordDisp(cUnit, rSP, outsOffset, lowReg);
nextUse++;
}
- callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
+ callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
}
}
callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
- rollback, skipThis);
+ dexIdx, methodIdx, skipThis);
if (pcrLabel) {
*pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
@@ -806,7 +667,8 @@
STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
DecodedInstruction* dInsn, int callState,
ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
- ArmLIR* rollback, bool skipThis)
+ uint32_t dexIdx, uint32_t methodIdx,
+ bool skipThis)
{
int firstArg = dInsn->vC;
int numArgs = dInsn->vA;
@@ -814,7 +676,8 @@
// If we can treat it as non-range (Jumbo ops will use range form)
if (numArgs <= 5)
return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
- true, nextCallInsn, rollback, skipThis);
+ true, nextCallInsn, dexIdx, methodIdx,
+ skipThis);
/*
* Make sure range list doesn't span the break between in normal
* Dalvik vRegs and the ins.
@@ -867,25 +730,25 @@
} else {
// Use vldm/vstm pair using r3 as a temp
int regsLeft = std::min(numArgs - 3, 16);
- callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
+ callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
//TUNING: loosen barrier
ld->defMask = ENCODE_ALL;
setMemRefType(ld, true /* isLoad */, kDalvikReg);
- callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
+ callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
- callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
+ callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
setMemRefType(st, false /* isLoad */, kDalvikReg);
st->defMask = ENCODE_ALL;
- callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
+ callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
}
callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
- rollback, skipThis);
+ dexIdx, methodIdx, skipThis);
- callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
+ callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
if (pcrLabel) {
*pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
}
@@ -916,10 +779,10 @@
// Explicit register usage
oatLockCallTemps(cUnit);
+ uint32_t dexMethodIdx = mir->dalvikInsn.vB;
// Is this the special "Ljava/lang/Object;.<init>:()V" case?
- if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT) {
- int idx = mir->dalvikInsn.vB;
- Method* target = cUnit->dex_cache->GetResolvedMethods()->Get(idx);
+ if (direct && !range) {
+ Method* target = cUnit->dex_cache->GetResolvedMethods()->Get(dexMethodIdx);
if (target) {
if (PrettyMethod(target) == "java.lang.Object.<init>()V") {
RegLocation rlArg = oatGetSrc(cUnit, mir, 0);
@@ -936,14 +799,15 @@
if (range) {
callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
- nextCallInsn, NULL, false);
+ nextCallInsn, dexMethodIdx, 0, false);
} else {
callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
- false, nextCallInsn, NULL, false);
+ false, nextCallInsn, dexMethodIdx,
+ 0, false);
}
// Finish up any of the call sequence not interleaved in arg loading
while (callState >= 0) {
- callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
+ callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx, 0);
}
if (DISPLAY_MISSING_TARGETS) {
genShowTarget(cUnit);
@@ -952,164 +816,44 @@
oatClobberCalleeSave(cUnit);
}
-/*
- * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
- * which will locate the target and continue on via a tail call.
- */
-STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
+STATIC void genInvoke(CompilationUnit* cUnit, MIR* mir, bool isInterface,
+ bool isSuper, bool isRange)
{
DecodedInstruction* dInsn = &mir->dalvikInsn;
int callState = 0;
- ArmLIR* nullCk;
- oatFlushAllRegs(cUnit); /* Everything to home location */
-
- // Explicit register usage
- oatLockCallTemps(cUnit);
- /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
- callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
- if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
- callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
- false, nextInterfaceCallInsn, NULL,
- false);
- else
- callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
- nextInterfaceCallInsn, NULL, false);
- // Finish up any of the call sequence not interleaved in arg loading
- while (callState >= 0) {
- callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
- }
- if (DISPLAY_MISSING_TARGETS) {
- genShowTarget(cUnit);
- }
- opReg(cUnit, kOpBlx, rLR);
- oatClobberCalleeSave(cUnit);
-}
-
-STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
-{
- DecodedInstruction* dInsn = &mir->dalvikInsn;
- int callState = 0;
- ArmLIR* rollback;
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
- dInsn->vB,
- cUnit->dex_cache,
- cUnit->class_loader,
- false);
- NextCallInsn nextCallInsn;
- bool fastPath = true;
- oatFlushAllRegs(cUnit); /* Everything to home location */
-
- // Explicit register usage
- oatLockCallTemps(cUnit);
-
- // For testing, force call to artResolveMethodFromCode & ignore result
- if (EXERCISE_RESOLVE_METHOD) {
- loadCurrMethodDirect(cUnit, r0);
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
- loadConstant(cUnit, r1, dInsn->vB);
- loadConstant(cUnit, r2, true);
- callRuntimeHelper(cUnit, rLR);
- }
-
- if (SLOW_INVOKE_PATH || baseMethod == NULL) {
- Thread* thread = Thread::Current();
- if (thread->IsExceptionPending()) { // clear any exception left by resolve method
- thread->ClearException();
- }
- fastPath = false;
- } else {
- Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
- ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
- Class* superClass = (declaring_class != NULL)
- ? declaring_class->GetSuperClass() : NULL;
- if (superClass == NULL) {
- fastPath = false;
- } else {
- int32_t target_idx = baseMethod->GetMethodIndex();
- if (superClass->GetVTable()->GetLength() <= target_idx) {
- fastPath = false;
- } else {
- fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
- }
- }
- }
- if (fastPath) {
- nextCallInsn = nextSuperCallInsn;
- rollback = NULL;
- } else {
- nextCallInsn = nextSuperCallInsnSP;
- rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
- rollback->defMask = -1;
- }
- if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
- callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
- false, nextCallInsn, rollback, true);
- else
- callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
- nextCallInsn, rollback, true);
- // Finish up any of the call sequence not interleaved in arg loading
- while (callState >= 0) {
- callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
- }
- if (DISPLAY_MISSING_TARGETS) {
- genShowTarget(cUnit);
- }
- opReg(cUnit, kOpBlx, rLR);
- oatClobberCalleeSave(cUnit);
-}
-
-STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
-{
- DecodedInstruction* dInsn = &mir->dalvikInsn;
- int callState = 0;
- ArmLIR* rollback;
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Method* method = class_linker->ResolveMethod(*cUnit->dex_file,
- dInsn->vB,
- cUnit->dex_cache,
- cUnit->class_loader,
- false);
NextCallInsn nextCallInsn;
oatFlushAllRegs(cUnit); /* Everything to home location */
// Explicit register usage
oatLockCallTemps(cUnit);
- // For testing, force call to artResolveMethodFromCode & ignore result
- if (EXERCISE_RESOLVE_METHOD) {
- loadCurrMethodDirect(cUnit, r0);
- loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
- loadConstant(cUnit, r1, dInsn->vB);
- loadConstant(cUnit, r2, false);
- callRuntimeHelper(cUnit, rLR);
- }
-
- if (SLOW_INVOKE_PATH || method == NULL) {
- Thread* thread = Thread::Current();
- if (thread->IsExceptionPending()) { // clear any exception left by resolve method
- thread->ClearException();
- }
- // Slow path
- nextCallInsn = nextVCallInsnSP;
- // If we need a slow-path callout, we'll restart here
- rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
- rollback->defMask = -1;
+ uint32_t dexMethodIdx = dInsn->vB;
+ int vtableIdx;
+ bool fastPath =
+ cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, cUnit,
+ isInterface, isSuper, vtableIdx)
+ && !SLOW_INVOKE_PATH;
+ if (isInterface) {
+ nextCallInsn = fastPath ? nextInterfaceCallInsn
+ : nextInterfaceCallInsnWithAccessCheck;
+ } else if (isSuper) {
+ nextCallInsn = fastPath ? nextSuperCallInsn : nextSuperCallInsnSP;
} else {
- // Fast path
- nextCallInsn = nextVCallInsn;
- rollback = NULL;
+ nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
}
- if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
+ bool skipThis = fastPath && !isInterface;
+ if (!isRange) {
callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
- false, nextCallInsn, rollback, true);
- else
+ false, nextCallInsn, dexMethodIdx,
+ vtableIdx, skipThis);
+ } else {
callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
- nextCallInsn, rollback, true);
+ nextCallInsn, dexMethodIdx, vtableIdx,
+ skipThis);
+ }
// Finish up any of the call sequence not interleaved in arg loading
while (callState >= 0) {
- callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
+ callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx,
+ vtableIdx);
}
if (DISPLAY_MISSING_TARGETS) {
genShowTarget(cUnit);
@@ -1586,18 +1330,30 @@
break;
case OP_INVOKE_VIRTUAL:
+ genInvoke(cUnit, mir, false /*interface*/, false /*super*/,
+ false /*range*/);
+ break;
case OP_INVOKE_VIRTUAL_RANGE:
- genInvokeVirtual(cUnit, mir);
+ genInvoke(cUnit, mir, false /*interface*/, false /*super*/,
+ true /*range*/);
break;
case OP_INVOKE_SUPER:
+ genInvoke(cUnit, mir, false /*interface*/, true /*super*/,
+ false /*range*/);
+ break;
case OP_INVOKE_SUPER_RANGE:
- genInvokeSuper(cUnit, mir);
+ genInvoke(cUnit, mir, false /*interface*/, true /*super*/,
+ true /*range*/);
break;
case OP_INVOKE_INTERFACE:
+ genInvoke(cUnit, mir, true /*interface*/, false /*super*/,
+ false /*range*/);
+ break;
case OP_INVOKE_INTERFACE_RANGE:
- genInvokeInterface(cUnit, mir);
+ genInvoke(cUnit, mir, true /*interface*/, false /*super*/,
+ true /*range*/);
break;
case OP_NEG_INT:
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 3e5ebd7..dfaaf01 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -3172,7 +3172,7 @@
if (is_super) {
DCHECK(method_type == METHOD_VIRTUAL);
Class* super = method_->GetDeclaringClass()->GetSuperClass();
- if (super == NULL || res_method->GetMethodIndex() > super->GetVTable()->GetLength()) {
+ if (super == NULL || res_method->GetMethodIndex() >= super->GetVTable()->GetLength()) {
if (super == NULL) { // Only Object has no super class
Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from " << PrettyMethod(method_)
<< " to super " << PrettyMethod(res_method);
diff --git a/src/object.cc b/src/object.cc
index 6be1136..bb87698 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -909,7 +909,7 @@
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false);
}
-Method* Class::FindVirtualMethodForInterface(Method* method, bool can_throw) {
+Method* Class::FindVirtualMethodForInterface(Method* method) {
Class* declaring_class = method->GetDeclaringClass();
DCHECK(declaring_class != NULL) << PrettyClass(this);
DCHECK(declaring_class->IsInterface()) << PrettyMethod(method);
@@ -922,11 +922,6 @@
return interface_entry->GetMethodArray()->Get(method->GetMethodIndex());
}
}
- if (can_throw) {
- Thread::Current()->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
- "Class %s does not implement interface %s",
- PrettyDescriptor(this).c_str(), PrettyDescriptor(declaring_class).c_str());
- }
return NULL;
}
@@ -1346,7 +1341,7 @@
std::string Throwable::Dump() const {
std::string result(PrettyTypeOf(this));
result += ": ";
- String* msg = GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), false);
+ String* msg = GetDetailMessage();
if (msg != NULL) {
result += msg->ToModifiedUtf8();
}
diff --git a/src/object.h b/src/object.h
index 19ca325..738d2b0 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1015,7 +1015,7 @@
template<class T>
T* ObjectArray<T>::Get(int32_t i) const {
- if (!IsValidIndex(i)) {
+ if (UNLIKELY(!IsValidIndex(i))) {
return NULL;
}
MemberOffset data_offset(DataOffset().Int32Value() + i * sizeof(Object*));
@@ -1523,7 +1523,7 @@
// Given a method implemented by this class, but potentially from a
// super class or interface, return the specific implementation
// method for this class.
- Method* FindVirtualMethodForInterface(Method* method, bool can_throw);
+ Method* FindVirtualMethodForInterface(Method* method);
Method* FindInterfaceMethod(const StringPiece& name, const StringPiece& descriptor) const;
@@ -1532,7 +1532,7 @@
return method;
}
if (method->GetDeclaringClass()->IsInterface()) {
- return FindVirtualMethodForInterface(method, true);
+ return FindVirtualMethodForInterface(method);
}
return FindVirtualMethodForVirtual(method);
}
@@ -1941,10 +1941,10 @@
template<class T>
void ObjectArray<T>::Set(int32_t i, T* object) {
- if (IsValidIndex(i)) {
+ if (LIKELY(IsValidIndex(i))) {
if (object != NULL) {
Class* element_class = GetClass()->GetComponentType();
- if (!object->InstanceOf(element_class)) {
+ if (UNLIKELY(!object->InstanceOf(element_class))) {
ThrowArrayStoreException(object);
return;
}
@@ -2261,6 +2261,9 @@
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_),
new_detail_message, false);
}
+ String* GetDetailMessage() const {
+ return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), false);
+ }
std::string Dump() const;
// This is a runtime version of initCause, you shouldn't use it if initCause may have been
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 7c47a8f..1ac92fd 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -34,6 +34,71 @@
self->SetTopOfStack(sp, 0);
}
+static 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 void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self, Class* referrer,
+ Class* accessed, const Method* caller,
+ const Method* called,
+ bool is_interface, bool is_super) {
+ 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(),
+ (is_interface ? "interface" : (is_super ? "super class" : "virtual")),
+ PrettyMethod(called).c_str(),
+ PrettyMethod(caller).c_str());
+}
+
+static void ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
+ const Method* referrer,
+ const Method* interface_method,
+ Object* this_object) {
+ Thread::Current()->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 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 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 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 void ThrowNullPointerExceptionForMethodAccess(Thread* self, Method* caller,
+ uint32_t method_idx, bool is_interface,
+ bool is_super) {
+ const DexFile& dex_file =
+ Runtime::Current()->GetClassLinker()->FindDexFile(caller->GetDeclaringClass()->GetDexCache());
+ self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
+ "Attempt to invoke %s method '%s' from '%s' on a null object reference",
+ (is_interface ? "interface" : (is_super ? "super class" : "virtual")),
+ PrettyMethod(method_idx, dex_file, true).c_str(),
+ PrettyMethod(caller).c_str());
+}
+
/*
* Report location to debugger. Note: dalvikPC is the current offset within
* the method. However, because the offset alone cannot distinguish between
@@ -482,6 +547,7 @@
return resolved_field;
}
+
// 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, size_t expected_size) {
@@ -491,14 +557,10 @@
Class* fields_class = resolved_field->GetDeclaringClass();
Class* referring_class = referrer->GetDeclaringClass();
if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;","%s tried to access class %s",
- PrettyMethod(referrer).c_str(),
- PrettyDescriptor(fields_class).c_str());
+ ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
} else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
resolved_field->GetAccessFlags()))) {
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;","%s tried to access field %s",
- PrettyMethod(referrer).c_str(),
- PrettyField(resolved_field, false).c_str());
+ ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
return NULL; // failure
}
FieldHelper fh(resolved_field);
@@ -527,13 +589,6 @@
return NULL;
}
-static void ThrowNullPointerExceptionForFieldAccess(Thread* self, Field* field, bool is_read) {
- self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
- "Attempt to %s field '%s' of a null object",
- is_read ? "read from" : "write to",
- PrettyField(field, true).c_str());
-}
-
extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
Thread* self, Method** sp) {
Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int32_t));
@@ -766,10 +821,7 @@
}
Class* referrer = method->GetDeclaringClass();
if (UNLIKELY(!referrer->CanAccess(klass))) {
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
- "illegal class access: '%s' -> '%s'",
- PrettyDescriptor(referrer).c_str(),
- PrettyDescriptor(klass).c_str());
+ ThrowNewIllegalAccessErrorClass(self, referrer, klass);
return NULL; // Failure
}
}
@@ -815,10 +867,7 @@
if (access_check) {
Class* referrer = method->GetDeclaringClass();
if (UNLIKELY(!referrer->CanAccess(klass))) {
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
- "illegal class access: '%s' -> '%s'",
- PrettyDescriptor(referrer).c_str(),
- PrettyDescriptor(klass).c_str());
+ ThrowNewIllegalAccessErrorClass(self, referrer, klass);
return NULL; // Failure
}
}
@@ -868,10 +917,7 @@
if (access_check) {
Class* referrer = method->GetDeclaringClass();
if (UNLIKELY(!referrer->CanAccess(klass))) {
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
- "illegal class access: '%s' -> '%s'",
- PrettyDescriptor(referrer).c_str(),
- PrettyDescriptor(klass).c_str());
+ ThrowNewIllegalAccessErrorClass(self, referrer, klass);
return NULL; // Failure
}
}
@@ -945,11 +991,9 @@
return NULL; // Failure - Indicate to caller to deliver exception
}
// Perform access check if necessary.
- if (verify_access && !referrer->GetDeclaringClass()->CanAccess(klass)) {
- self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
- "Class %s is inaccessible to method %s",
- PrettyDescriptor(klass).c_str(),
- PrettyMethod(referrer, true).c_str());
+ 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>.
@@ -960,7 +1004,7 @@
//
// Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
// running.
- if (klass == referrer->GetDeclaringClass() && MethodHelper(referrer).IsClassInitializer()) {
+ if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) {
return klass;
}
if (!class_linker->EnsureInitialized(klass, true)) {
@@ -1086,46 +1130,191 @@
return 0; // Success
}
-// See comments in runtime_support_asm.S
-extern "C" uint64_t artFindInterfaceMethodInCacheFromCode(uint32_t method_idx,
- Object* this_object,
- Method* caller_method,
- Thread* thread, Method** sp) {
- Method* interface_method = caller_method->GetDexCacheResolvedMethods()->Get(method_idx);
- Method* found_method = NULL; // The found method
- if (LIKELY(interface_method != NULL && this_object != NULL)) {
- found_method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method, false);
+// Fast path method resolution that can't throw exceptions
+static Method* FindMethodFast(uint32_t method_idx, Object* this_object, const Method* referrer,
+ bool access_check, bool is_interface, bool is_super) {
+ if (UNLIKELY(this_object == NULL)) {
+ return NULL;
}
- if (UNLIKELY(found_method == NULL)) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
- if (this_object == NULL) {
- thread->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
- "null receiver during interface dispatch");
- return 0;
+ 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 (interface_method == NULL) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- interface_method = class_linker->ResolveMethod(method_idx, caller_method, false);
- if (interface_method == NULL) {
- // Could not resolve interface method. Throw error and unwind
- CHECK(thread->IsExceptionPending());
- return 0;
+ }
+ if (is_interface) {
+ return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+ } else if (is_super) {
+ return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
+ } else {
+ return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
+ }
+}
+
+// Slow path method resolution
+static Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
+ Thread* self, bool access_check, bool is_interface,
+ bool is_super) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, false);
+ if (LIKELY(resolved_method != NULL)) {
+ if (!access_check) {
+ if (is_interface) {
+ Method* interface_method =
+ this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+ if (UNLIKELY(interface_method == NULL)) {
+ ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
+ resolved_method,
+ this_object);
+ return NULL;
+ } else {
+ return interface_method;
+ }
+ } else {
+ ObjectArray<Method>* vtable;
+ uint16_t vtable_index = resolved_method->GetMethodIndex();
+ if (is_super) {
+ 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, is_interface,
+ is_super);
+ 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_interface) {
+ Method* interface_method =
+ this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+ if (UNLIKELY(interface_method == NULL)) {
+ ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
+ resolved_method,
+ this_object);
+ return NULL;
+ } else {
+ return interface_method;
+ }
+ } else {
+ ObjectArray<Method>* vtable;
+ uint16_t vtable_index = resolved_method->GetMethodIndex();
+ if (is_super) {
+ 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",
+ (is_super ? "super class" : "virtual"),
+ PrettyMethod(resolved_method).c_str(),
+ PrettyMethod(referrer).c_str());
+ return NULL;
+ }
}
}
- found_method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method, true);
- if (found_method == NULL) {
- CHECK(thread->IsExceptionPending());
- return 0;
+ }
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind
+ return NULL;
+}
+
+static uint64_t artInvokeCommon(uint32_t method_idx, Object* this_object, Method* caller_method,
+ Thread* self, Method** sp, bool access_check, bool is_interface,
+ bool is_super){
+ Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check,
+ is_interface, is_super);
+ if (UNLIKELY(method == NULL)) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
+ if (UNLIKELY(this_object == NULL)) {
+ ThrowNullPointerExceptionForMethodAccess(self, caller_method, method_idx, is_interface,
+ is_super);
+ return 0; // failure
+ }
+ method = FindMethodFromCode(method_idx, this_object, caller_method, self, access_check,
+ is_interface, is_super);
+ if (UNLIKELY(method == NULL)) {
+ CHECK(self->IsExceptionPending());
+ return 0; // failure
}
}
- const void* code = found_method->GetCode();
+ // TODO: DCHECK
+ CHECK(!self->IsExceptionPending());
+ const void* code = method->GetCode();
- uint32_t method_uint = reinterpret_cast<uint32_t>(found_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, true, false);
+}
+
+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, true, false);
+}
+
+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, false, true);
+}
+
+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, false, false);
+}
+
static void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) {
ScopedLocalRef<jclass> jlr_UTE_class(env,
env->FindClass("java/lang/reflect/UndeclaredThrowableException"));
diff --git a/src/runtime_support.h b/src/runtime_support.h
index b9c03e4..c8db48c 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -70,6 +70,9 @@
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_interface_trampoline(uint32_t, void*);
+ extern "C" void art_invoke_interface_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_object_init_from_code(void*);
extern "C" void art_test_suspend();
diff --git a/src/runtime_support_arm.S b/src/runtime_support_arm.S
index c45583a..8113b5b 100644
--- a/src/runtime_support_arm.S
+++ b/src/runtime_support_arm.S
@@ -171,7 +171,7 @@
b artThrowVerificationErrorFromCode @ artThrowVerificationErrorFromCode(kind, ref, Thread*, SP)
.global art_invoke_interface_trampoline
- .extern artFindInterfaceMethodInCacheFromCode
+ .extern artInvokeInterfaceTrampoline
/*
* All generated callsites for interface invokes will load arguments as usual - except instead
* of loading arg0/r0 with the target Method*, arg0/r0 will contain the method_idx. This
@@ -179,10 +179,10 @@
* artFindInterfaceMethodInCacheFromCode(idx, this, method);
* NOTE: "this" is first visable argument of the target, and so can be found in arg1/r1.
*
- * artFindInterfaceMethodInCacheFromCode will attempt to locate the target and return a 64-bit
+ * artInvokeInterfaceTrampoline 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, artFindInterfaceMethodInCacheFromCode will return NULL/NULL. There will be
+ * If unsuccessful, artInvokeInterfaceTrampoline will return NULL/NULL. There will be
* a 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
@@ -193,7 +193,49 @@
ldr r2, [sp, #48] @ pass caller Method*
mov r3, r9 @ pass Thread::Current
str sp, [sp, #0] @ pass SP
- bl artFindInterfaceMethodInCacheFromCode @ (method_idx, this, caller, Thread*, SP)
+ bl artInvokeInterfaceTrampoline @ (method_idx, this, caller, Thread*, SP)
+ mov r12, r1 @ save r0->code_
+ RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ cmp r0, #0 @ did we find the target?
+ bxne r12 @ tail call to target if so
+ DELIVER_PENDING_EXCEPTION
+
+ .global art_invoke_interface_trampoline_with_access_check
+ .extern artInvokeInterfaceTrampolineWithAccessCheck
+art_invoke_interface_trampoline_with_access_check:
+ SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC
+ ldr r2, [sp, #48] @ pass caller Method*
+ mov r3, r9 @ pass Thread::Current
+ str sp, [sp, #0] @ pass SP
+ bl artInvokeInterfaceTrampolineWithAccessCheck @ (method_idx, this, caller, Thread*, SP)
+ mov r12, r1 @ save r0->code_
+ RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ cmp r0, #0 @ did we find the target?
+ bxne r12 @ tail call to target if so
+ DELIVER_PENDING_EXCEPTION
+
+ .global art_invoke_super_trampoline_with_access_check
+ .extern artInvokeSuperTrampolineWithAccessCheck
+art_invoke_super_trampoline_with_access_check:
+ SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC
+ ldr r2, [sp, #48] @ pass caller Method*
+ mov r3, r9 @ pass Thread::Current
+ str sp, [sp, #0] @ pass SP
+ bl artInvokeSuperTrampolineWithAccessCheck @ (method_idx, this, caller, Thread*, SP)
+ mov r12, r1 @ save r0->code_
+ RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ cmp r0, #0 @ did we find the target?
+ bxne r12 @ tail call to target if so
+ DELIVER_PENDING_EXCEPTION
+
+ .global art_invoke_virtual_trampoline_with_access_check
+ .extern artInvokeVirtualTrampolineWithAccessCheck
+art_invoke_virtual_trampoline_with_access_check:
+ SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC
+ ldr r2, [sp, #48] @ pass caller Method*
+ mov r3, r9 @ pass Thread::Current
+ str sp, [sp, #0] @ pass SP
+ bl artInvokeVirtualTrampolineWithAccessCheck @ (method_idx, this, caller, Thread*, SP)
mov r12, r1 @ save r0->code_
RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
cmp r0, #0 @ did we find the target?
diff --git a/src/thread.cc b/src/thread.cc
index 582832d..8592bd3 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -116,6 +116,9 @@
pInitializeTypeFromCode = art_initialize_type_from_code;
pInitializeTypeAndVerifyAccessFromCode = art_initialize_type_and_verify_access_from_code;
pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
+ pInvokeInterfaceTrampolineWithAccessCheck = art_invoke_interface_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;
pObjectInit = art_object_init_from_code;
pResolveStringFromCode = art_resolve_string_from_code;
@@ -1451,7 +1454,10 @@
// resolution.
ClearException();
if (kDebugExceptionDelivery) {
- DumpStack(LOG(INFO) << "Delivering exception: " << PrettyTypeOf(exception) << std::endl);
+ String* msg = exception->GetDetailMessage();
+ std::string str_msg(msg != NULL ? msg->ToModifiedUtf8() : "");
+ DumpStack(LOG(INFO) << "Delivering exception: " << PrettyTypeOf(exception)
+ << ": " << str_msg << std::endl);
}
Context* long_jump_context = GetLongJumpContext();
diff --git a/src/thread.h b/src/thread.h
index b1b8a1e..b21af96 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -89,85 +89,6 @@
static const size_t kDefaultStackSize = 96 * KB;
- // 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)(long);
- double (*pL2d)(long);
- long long (*pF2l)(float);
- long long (*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);
- long long (*pLmul)(long long, long long);
- long long (*pLdivmod)(long long, long long);
- 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 (*pInvokeInterfaceTrampoline)(uint32_t, void*);
- void* (*pInitializeTypeFromCode)(uint32_t, void*);
- void* (*pInitializeTypeAndVerifyAccessFromCode)(uint32_t, void*);
- void (*pLockObjectFromCode)(void*);
- void (*pObjectInit)(void*);
- void* (*pResolveMethodFromCode)(void*, uint32_t, bool);
- 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*);
- void* (*pUnresolvedDirectMethodTrampolineFromCode)(int32_t, Method**, Thread*,
- Runtime::TrampolineType);
- void (*pUpdateDebuggerFromCode)(void*, void*, int32_t, void*);
-
class StackVisitor {
public:
virtual ~StackVisitor() {}
@@ -642,6 +563,90 @@
// A cached copy of the java.lang.Thread's name.
std::string* name_;
+ 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)(long);
+ double (*pL2d)(long);
+ long long (*pF2l)(float);
+ long long (*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);
+ long long (*pLmul)(long long, long long);
+ long long (*pLdivmod)(long long, long long);
+ 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 (*pInvokeInterfaceTrampoline)(uint32_t, void*);
+ void (*pInvokeInterfaceTrampolineWithAccessCheck)(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 (*pObjectInit)(void*);
+ void* (*pResolveMethodFromCode)(void*, uint32_t, bool);
+ 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*);
+ void* (*pUnresolvedDirectMethodTrampolineFromCode)(int32_t, Method**, Thread*,
+ Runtime::TrampolineType);
+ void (*pUpdateDebuggerFromCode)(void*, void*, int32_t, void*);
+
+ private:
DISALLOW_COPY_AND_ASSIGN(Thread);
};