summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/Frontend.cc6
-rw-r--r--src/compiler/codegen/arm/MethodCodegenDriver.cc234
-rw-r--r--src/compiler_test.cc16
-rw-r--r--src/object.h4
-rw-r--r--src/runtime_support.S38
-rw-r--r--src/runtime_support.h1
-rw-r--r--src/thread.cc42
-rw-r--r--src/thread.h2
-rw-r--r--test/IntMath/IntMath.java33
9 files changed, 293 insertions, 83 deletions
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index d6f891b497..e9f8a3a299 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -705,6 +705,9 @@ bool oatCompileMethod(Method* method, art::InstructionSet insnSet)
if (PrettyMethod(method).find("virtualCall") != std::string::npos) {
compiling = true;
}
+ if (PrettyMethod(method).find("tryThing") != std::string::npos) {
+ compiling = true;
+ }
if (PrettyMethod(method).find("getFoo") != std::string::npos) {
compiling = true;
}
@@ -714,6 +717,9 @@ bool oatCompileMethod(Method* method, art::InstructionSet insnSet)
if (PrettyMethod(method).find("IntMath.<init>") != std::string::npos) {
compiling = true;
}
+ if (PrettyMethod(method).find("IntMathBase.<init>") != std::string::npos) {
+ compiling = true;
+ }
if (PrettyMethod(method).find("java.lang.Object.<init>") != std::string::npos) {
compiling = true;
}
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index d95b870001..eb9296bb05 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -478,7 +478,7 @@ static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
skipTarget->defMask = ENCODE_ALL;
skipBranch->generic.target = (LIR*)skipTarget;
- // Get base_method->method_index [usr rLR, set r12]
+ // Get base_method->method_index [usr rLR, set r0]
loadBaseDisp(cUnit, mir, rLR,
Method::GetMethodIndexOffset().Int32Value(), r0,
kUnsignedHalf, INVALID_SREG);
@@ -528,62 +528,25 @@ static int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
return callState;
}
-/*
- * Interleave launch code for INVOKE_INTERFACE. The target is
- * identified using artFindInterfaceMethodInCache(class, ref, method, dex)
- * Note that we'll have to reload "this" following the helper call.
- *
- * FIXME: do we need to have artFindInterfaceMethodInCache return
- * a NULL if not found so we can throw exception here? Otherwise,
- * may need to pass some additional info to allow the helper function
- * to throw on its own.
- */
+// Interleave launch code for INVOKE_INTERFACE.
static int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
DecodedInstruction* dInsn, int state,
ArmLIR* rollback)
{
- UNIMPLEMENTED(FATAL) << "Need findInterfaceMethodInCache";
-#if 0
- RegLocation rlArg;
switch(state) {
- case 0:
- // Load "this" [set r12]
- rlArg = oatGetSrc(cUnit, mir, 0);
- loadValueDirectFixed(cUnit, rlArg, r12);
- // Get the current Method* [set arg2]
- loadCurrMethodDirect(cUnit, r2);
- // Is "this" null? [use r12]
- genNullCheck(cUnit, oatSSASrc(mir,0), r12,
- mir->offset, NULL);
- // Get curMethod->clazz [set arg3]
- loadBaseDisp(cUnit, mir, r2, OFFSETOF_MEMBER(Method, clazz),
- r3, kWord, INVALID_SREG);
- // Load this->class [usr r12, set arg0]
- loadBaseDisp(cUnit, mir, r12, OFFSETOF_MEMBER(Class, clazz),
- r3, kWord, INVALID_SREG);
- // Load address of helper function
- loadBaseDisp(cUnit, mir, rSELF,
- OFFSETOF_MEMBER(Thread, pArtFindInterfaceMethodInCache),
- rLR, kWord, INVALID_SREG);
- // Get dvmDex
- loadBaseDisp(cUnit, mir, r3, OFFSETOF_MEMBER(Class, pDvmDex),
- r3, kWord, INVALID_SREG);
- // Load ref [set arg1]
- loadConstant(cUnit, r1, dInsn->vB);
- // Call out to helper, target Method returned in ret0
- newLIR1(cUnit, kThumbBlxR, rLR);
+ case 0: // Load trampoline target
+ loadWordDisp(cUnit, rSELF,
+ OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
+ rLR);
+ // Load r0 with method index
+ loadConstant(cUnit, r0, dInsn->vB);
break;
- case 1: // Get the target compiled code address [use r0, set rLR]
- loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, compiledInsns),
- rLR, kWord, INVALID_SREG);
default:
return -1;
}
-#endif
return state + 1;
}
-
/*
* Interleave launch code for INVOKE_SUPER. See comments
* for nextVCallIns.
@@ -592,49 +555,132 @@ static int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
DecodedInstruction* dInsn, int state,
ArmLIR* rollback)
{
- UNIMPLEMENTED(FATAL) << "Need INVOKE_SUPER implementation";
-#if 0
+ 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.
+ */
+ Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
+ Get(dInsn->vB);
+ CHECK(baseMethod != NULL);
+ Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
+ 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);
switch(state) {
- case 0:
- // Get the current Method* [set r0]
+ case 0: // Get current Method* [set r0]
loadCurrMethodDirect(cUnit, r0);
// Load "this" [set r1]
rlArg = oatGetSrc(cUnit, mir, 0);
loadValueDirectFixed(cUnit, rlArg, r1);
- // Get method->clazz [use r0, set r12]
- loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, clazz),
- r12, kWord, INVALID_SREG);
- // Get pResmethods [use r0, set rLR]
- loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, pResMethods),
- rLR, kWord, INVALID_SREG);
- // Get clazz->super [use r12, set r12]
- loadBaseDisp(cUnit, mir, r12, OFFSETOF_MEMBER(Class, super),
- r12, kWord, INVALID_SREG);
- // Get base method [use rLR, set r0]
- loadBaseDisp(cUnit, mir, rLR, dInsn->vB * 4, r0,
- kWord, INVALID_SREG);
+ // Get method->declaring_class_ [use r0, set rLR]
+ loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
+ rLR);
// Is "this" null? [use r1]
genNullCheck(cUnit, oatSSASrc(mir,0), r1,
mir->offset, NULL);
- // Get methodIndex [use r0, set rLR]
- loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, methodIndex),
- rLR, kUnsignedHalf, INVALID_SREG);
- // Get vtableCount [use r12, set r0]
- loadBaseDisp(cUnit, mir, r12,
- OFFSETOF_MEMBER(Class, vtableCount),
- r0, kWord, INVALID_SREG);
- // Compare method index w/ vtable count [use r12, use rLR]
- genRegRegCheck(cUnit, kArmCondGe, rLR, r0, mir->offset, NULL);
- // get target Method* [use rLR, use r12, set r0]
- loadBaseIndexed(cUnit, r0, r12, rLR, 2, kWord);
- case 1: // Get the target compiled code address [use r0, set rLR]
- loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, compiledInsns),
- rLR, kWord, INVALID_SREG);
+ break;
+ case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
+ loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
+ rLR);
+ break;
+ case 2: // Get ...->super_class_->vtable [u/s rLR]
+ loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
+ break;
+ case 3: // Get target method [use rLR, set r0]
+ loadWordDisp(cUnit, rLR, (target_idx * 4) +
+ art::Array::DataOffset().Int32Value(), r0);
+ break;
+ case 4: // Get the target compiled code address [uses r0, sets rLR]
+ loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
+ break;
+ default:
+ return -1;
+ }
+ return state + 1;
+}
+
+/* Slow-path version of nextSuperCallInsn */
+static int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+ DecodedInstruction* dInsn, int state,
+ ArmLIR* rollback)
+{
+ DCHECK(rollback != NULL);
+ 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.
+ */
+ switch(state) {
+ case 0: // Get the current Method* [sets r0]
+ loadCurrMethodDirect(cUnit, r0);
+ break;
+ case 1: // Get method->dex_cache_resolved_methods_ [usr 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) +
+ art::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);
+ newLIR1(cUnit, kThumbBlxR, 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);
+ case 4: // Get method->declaring_class_->super_class [usr r0, set r0]
+ loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
+ break;
+ case 5: // Get ...->super_class_->vtable [u/s r0]
+ loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
+ // In load shadow fold vtable_ object header size into method_index_
+ opRegImm(cUnit, kOpAdd, rLR,
+ art::Array::DataOffset().Int32Value() / 4);
+ if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+ // Range check, throw NSM on failure
+ tReg = oatAllocTemp(cUnit);
+ loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
+ tReg);
+ genBoundsCheck(cUnit, tReg, rLR, mir->offset, NULL);
+ oatFreeTemp(cUnit, tReg);
+ }
+ // Get target Method*
+ loadBaseIndexed(cUnit, r0, r0, rLR, 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;
}
-#endif
return state + 1;
}
@@ -822,6 +868,10 @@ static void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
newLIR1(cUnit, kThumbBlxR, rLR);
}
+/*
+ * 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)
{
DecodedInstruction* dInsn = &mir->dalvikInsn;
@@ -847,13 +897,41 @@ static void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
DecodedInstruction* dInsn = &mir->dalvikInsn;
int callState = 0;
ArmLIR* nullCk;
+ ArmLIR* rollback;
+ Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
+ Get(dInsn->vB);
+ NextCallInsn nextCallInsn;
+ bool fastPath = true;
+ if (baseMethod == NULL) {
+ fastPath = false;
+ } else {
+ Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
+ 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;
+ }
// TODO - redundantly loading arg0/r1 ("this")
if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
- false, nextSuperCallInsn, NULL);
+ false, nextCallInsn, rollback);
else
callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
- nextSuperCallInsn, NULL);
+ nextCallInsn, rollback);
// Finish up any of the call sequence not interleaved in arg loading
while (callState >= 0) {
callState = nextSuperCallInsn(cUnit, mir, dInsn, callState, NULL);
diff --git a/src/compiler_test.cc b/src/compiler_test.cc
index c144f7ccd1..656c7d4780 100644
--- a/src/compiler_test.cc
+++ b/src/compiler_test.cc
@@ -103,6 +103,19 @@ TEST_F(CompilerTest, BasicCodegen) {
10);
}
+// TODO: Need invoke-interface test
+
+TEST_F(CompilerTest, SuperTest) {
+ CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
+ const ClassLoader* class_loader = LoadDex("IntMath");
+ CompileDirectMethod(class_loader, "IntMathBase", "<init>", "()V");
+ CompileVirtualMethod(class_loader, "IntMathBase", "tryThing", "()I");
+ CompileDirectMethod(class_loader, "IntMath", "<init>", "()V");
+ CompileVirtualMethod(class_loader, "IntMath", "tryThing", "()I");
+ AssertStaticIntMethod(class_loader, "IntMath", "superTest", "(I)I", 4175,
+ 4141);
+}
+
TEST_F(CompilerTest, ConstStringTest) {
AssertStaticIntMethod(LoadDex("IntMath"), "IntMath", "constStringTest",
"(I)I", 2468, 1234);
@@ -231,6 +244,7 @@ TEST_F(CompilerTest, ManyArgs) {
TEST_F(CompilerTest, VirtualCall) {
CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
const ClassLoader* class_loader = LoadDex("IntMath");
+ CompileDirectMethod(class_loader, "IntMathBase", "<init>", "()V");
CompileDirectMethod(class_loader, "IntMath", "<init>", "()V");
CompileVirtualMethod(class_loader, "IntMath", "virtualCall", "(I)I");
AssertStaticIntMethod(class_loader, "IntMath", "staticCall", "(I)I", 6,
@@ -240,6 +254,7 @@ TEST_F(CompilerTest, VirtualCall) {
TEST_F(CompilerTest, TestIGetPut) {
CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
const ClassLoader* class_loader = LoadDex("IntMath");
+ CompileDirectMethod(class_loader, "IntMathBase", "<init>", "()V");
CompileDirectMethod(class_loader, "IntMath", "<init>", "(I)V");
CompileDirectMethod(class_loader, "IntMath", "<init>", "()V");
CompileVirtualMethod(class_loader, "IntMath", "getFoo", "()I");
@@ -248,4 +263,5 @@ TEST_F(CompilerTest, TestIGetPut) {
111);
}
+
} // namespace art
diff --git a/src/object.h b/src/object.h
index 5857571140..a0f3e38416 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1512,6 +1512,10 @@ class Class : public Object, public StaticStorageBase {
OFFSET_OF_OBJECT_MEMBER(Class, super_class_), false);
}
+ static MemberOffset SuperClassOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(Class, super_class_));
+ }
+
void SetSuperClass(Class *new_super_class) {
// super class is assigned once, except during class linker initialization
Class* old_super_class = GetFieldObject<Class*>(
diff --git a/src/runtime_support.S b/src/runtime_support.S
index 46c2dd39b3..fe40cf2da9 100644
--- a/src/runtime_support.S
+++ b/src/runtime_support.S
@@ -1,6 +1,44 @@
#if defined(__arm__)
.balign 4
+
+ .global art_invoke_interface_trampoline
+ .extern artFindInterfaceMethodInCache
+ .extern artFailedInvokeInterface
+art_invoke_interface_trampoline:
+ /*
+ * 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 wrapper will
+ * save arg1-arg3, load the caller's Method*, align the stack and
+ * call the helper artFindInterfaceMethodInCache(idx, this, method);
+ * NOTE: "this" is first visable argument of the target, and so can be
+ * found in arg1/r1.
+ *
+ * artFindInterfaceMethodInCache 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, artFindInterfaceMethodInCache will return
+ * NULL/NULL. This is somewhat different than the usual
+ * mechanism of helper routines performing the unwind & throw.
+ * The reason is that this trampoline is not unwindable. In the
+ * event artFindInterfaceMethodInCache fails to resolve, the wrapper
+ * will prepare an unwindable environment and jump to another helper
+ * to do unwind/throw.
+ *
+ * On success this wrapper will restore arguments and *jump* to the
+ * target, leaving the lr pointing back to the original caller.
+ */
+ stmdb sp!, {r1, r2, r3, lr}
+ ldr r2, [sp, #16] @ load caller's Method*
+ bl artFindInterfaceMethodInCache @ (method_idx, this, callerMethod)
+ mov r12, r1 @ save r0->code_
+ ldmia sp!, {r1, r2, r3, lr} @ restore arguments
+ cmp r0, #0 @ did we find the target?
+ bxne r12 @ tail call to target if so
+ b artFailedInvokeInterface @ Will appear as if called directly
+
.global art_shl_long
art_shl_long:
/*
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 8d65aaaacf..23126d79ae 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -8,6 +8,7 @@
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);
+ extern "C" void art_invoke_interface_trampoline(void*, void*, void*, void*);
/* Conversions */
extern "C" float __aeabi_i2f(int op1); // OP_INT_TO_FLOAT
diff --git a/src/thread.cc b/src/thread.cc
index aa24bec755..31786c9970 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -34,6 +34,42 @@ pid_t gettid() { return syscall(__NR_gettid);}
pthread_key_t Thread::pthread_key_self_;
+// Temporary debugging hook for compiler.
+static void DebugMe(Method* method, uint32_t info) {
+ LOG(INFO) << "DebugMe";
+ if (method != NULL)
+ LOG(INFO) << PrettyMethod(method);
+ LOG(INFO) << "Info: " << info;
+}
+
+/*
+ * TODO: placeholder for a method that can be called by the
+ * invoke-interface trampoline to unwind and handle exception. The
+ * trampoline will arrange it so that the caller appears to be the
+ * callsite of the failed invoke-interface. See comments in
+ * compiler/runtime_support.S
+ */
+extern "C" void artFailedInvokeInterface()
+{
+ UNIMPLEMENTED(FATAL) << "Unimplemented exception throw";
+}
+
+// TODO: placeholder. See comments in compiler/runtime_support.S
+extern "C" uint64_t artFindInterfaceMethodInCache(uint32_t method_idx,
+ Object* this_object , Method* caller_method)
+{
+ /*
+ * Note: this_object has not yet been null-checked. To match
+ * the old-world state, nullcheck this_object and load
+ * Class* this_class = this_object->GetClass().
+ * See comments and possible thrown exceptions in old-world
+ * Interp.cpp:dvmInterpFindInterfaceMethod, and complete with
+ * new-world FindVirtualMethodForInterface.
+ */
+ UNIMPLEMENTED(FATAL) << "Unimplemented invoke interface";
+ return 0LL;
+}
+
// TODO: placeholder. This is what generated code will call to throw
static void ThrowException(Thread* thread, Throwable* exception) {
/*
@@ -98,6 +134,7 @@ void Thread::InitFunctionPointers() {
pD2l = D2L;
pLdivmod = __aeabi_ldivmod;
pLmul = __aeabi_lmul;
+ pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
#endif
pAllocFromCode = Array::AllocFromCode;
pAllocObjectFromCode = Class::AllocObjectFromCode;
@@ -113,15 +150,12 @@ void Thread::InitFunctionPointers() {
pThrowException = ThrowException;
pInitializeTypeFromCode = InitializeTypeFromCode;
pResolveMethodFromCode = ResolveMethodFromCode;
+ pDebugMe = DebugMe;
#if 0
bool (Thread::*pUnlockObject)(Thread*, Object*);
int (Thread::*pInstanceofNonTrivialFromCode)(const Class*, const Class*);
-Method* (Thread::*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, DvmDex*);
bool (Thread::*pUnlockObjectFromCode)(Thread*, Object*);
void (Thread::*pLockObjectFromCode)(Thread*, Object*);
-Object* (Thread::*pAllocObjectFromCode)(Class*, int);
-void (Thread::*pThrowException)(Thread*, Object*);
-bool (Thread::*pHandleFillArrayDataFromCode)(Array*, const uint16_t*);
#endif
}
diff --git a/src/thread.h b/src/thread.h
index 8a297d6b88..fc523a3d97 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -174,6 +174,7 @@ class Thread {
static const size_t kDefaultStackSize = 64 * 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);
@@ -219,6 +220,7 @@ class Thread {
void (*pHandleFillArrayDataFromCode)(Array*, const uint16_t*);
Class* (*pInitializeTypeFromCode)(uint32_t, Method*);
void (*pResolveMethodFromCode)(Method*, uint32_t);
+ void (*pInvokeInterfaceTrampoline)(void*, void*, void*, void*);
class StackVisitor {
public:
diff --git a/test/IntMath/IntMath.java b/test/IntMath/IntMath.java
index 05cecce0b2..ba7d575927 100644
--- a/test/IntMath/IntMath.java
+++ b/test/IntMath/IntMath.java
@@ -1,6 +1,6 @@
// Copyright 2011 Google Inc. All Rights Reserved.
-class IntMath {
+class IntMath extends IntMathBase {
public static boolean mBoolean1, mBoolean2;
public static byte mByte1, mByte2;
@@ -16,13 +16,28 @@ class IntMath {
private int foo_;
public IntMath(int stuff) {
+ super();
foo_ = stuff;
}
public IntMath() {
+ super();
foo_ = 123;
}
+ int tryThing() {
+ int val = super.tryThing();
+ return val + 10;
+ }
+
+ static int superTest(int x) {
+ IntMath instance = new IntMath();
+ IntMath base = instance;
+ int val1 = instance.tryThing();
+ int val2 = base.tryThing();
+ return val1 + val2 + x;
+ }
+
static int constClassTest(int x) {
Class c = String.class;
if (c != null) {
@@ -837,5 +852,21 @@ class IntMath {
} else {
System.out.printf("catchBlock FAILED: %d\n", res);
}
+
+ res = superTest(4141);
+ if (res == 4175) {
+ System.out.printf("superTest PASSED\n");
+ } else {
+ System.out.printf("superTest FAILED: %d\n", res);
+ }
+ }
+}
+
+class IntMathBase {
+ IntMathBase() {
+ }
+
+ int tryThing() {
+ return 7;
}
}