Class cast, fill array and interface exception support.
This change uses the deliver exception mechanism to implement support
for a number of runtime exceptions. It also tidies up code in the
compiler and allocates a singular callee save method in the image.
Also adds a fix for JNI internal test where we weren't passing
Thread::Current() and that this value is now being used in generated code.
Change-Id: I57eefd9afe40e92fa3a7e737f1a2ed7e1094b5c1
diff --git a/src/asm_support.h b/src/asm_support.h
index 097ab7a..17a29cf 100644
--- a/src/asm_support.h
+++ b/src/asm_support.h
@@ -8,9 +8,12 @@
#define rSELF r9
#define rLR r14
#define SUSPEND_CHECK_INTERVAL (1000)
-#endif
+// Offset of field Thread::top_of_managed_stack_ verified in InitCpu
+#define THREAD_TOP_OF_MANAGED_STACK_OFFSET 333
+// Offset of field Thread::top_of_managed_stack_pc_ verified in InitCpu
+#define THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET 337
-#if defined(__i386__)
+#elif defined(__i386__)
// Offset of field Thread::self_ verified in InitCpu
#define THREAD_SELF_OFFSET 0x165
#endif
diff --git a/src/class_linker.h b/src/class_linker.h
index 939fa55..78be84b 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -191,9 +191,6 @@
DexCache* AllocDexCache(const DexFile& dex_file);
Field* AllocField();
- // TODO: have no friends, we need this currently to create a special method
- // to describe callee save registers for throwing exceptions
- friend class Thread;
Method* AllocMethod();
CodeAndDirectMethods* AllocCodeAndDirectMethods(size_t length);
diff --git a/src/common_test.h b/src/common_test.h
index 127cad6..844fa00 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -113,9 +113,11 @@
#if defined(__i386__)
runtime_->SetJniStubArray(JniCompiler::CreateJniStub(kX86));
+ runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kX86));
compiler_.reset(new Compiler(kX86));
#elif defined(__arm__)
runtime_->SetJniStubArray(JniCompiler::CreateJniStub(kThumb2));
+ runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kThumb2));
compiler_.reset(new Compiler(kThumb2));
#endif
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 41053a2..58cd53b 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -37,7 +37,7 @@
loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
loadConstant(cUnit, r0, mir->dalvikInsn.vC); // arg0 <- type_id
loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
RegLocation rlResult = oatGetReturn(cUnit);
storeValue(cUnit, rlDest, rlResult);
@@ -60,7 +60,7 @@
loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
loadConstant(cUnit, r0, typeId); // arg0 <- type_id
loadConstant(cUnit, r2, elems); // arg2 <- count
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
/*
* NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
* return region. Because AllocFromCode placed the new array
@@ -181,7 +181,7 @@
loadConstant(cUnit, r0, mir->dalvikInsn.vB);
loadCurrMethodDirect(cUnit, r1);
loadValueDirect(cUnit, rlSrc, r2);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
} else {
// fast path
@@ -202,7 +202,7 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
loadConstant(cUnit, r0, typeIdx);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
skipTarget->defMask = ENCODE_ALL;
branchOver->generic.target = (LIR*)skipTarget;
@@ -234,7 +234,7 @@
loadConstant(cUnit, r0, mir->dalvikInsn.vB);
loadCurrMethodDirect(cUnit, r1);
loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
} else {
// fast path
@@ -255,7 +255,7 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
loadConstant(cUnit, r0, typeIdx);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
skipTarget->defMask = ENCODE_ALL;
branchOver->generic.target = (LIR*)skipTarget;
@@ -286,7 +286,7 @@
loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
loadConstant(cUnit, r0, mir->dalvikInsn.vB);
loadCurrMethodDirect(cUnit, r1);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
RegLocation rlResult = oatGetReturnWide(cUnit);
storeValueWide(cUnit, rlDest, rlResult);
} else {
@@ -308,7 +308,7 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
loadConstant(cUnit, r0, typeIdx);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
skipTarget->defMask = ENCODE_ALL;
branchOver->generic.target = (LIR*)skipTarget;
@@ -344,7 +344,7 @@
loadWordDisp(cUnit, rSELF, funcOffset, rLR);
loadConstant(cUnit, r0, mir->dalvikInsn.vB);
loadCurrMethodDirect(cUnit, r1);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
RegLocation rlResult = oatGetReturn(cUnit);
storeValue(cUnit, rlDest, rlResult);
} else {
@@ -366,7 +366,7 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
loadConstant(cUnit, r0, typeIdx);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
skipTarget->defMask = ENCODE_ALL;
branchOver->generic.target = (LIR*)skipTarget;
@@ -497,7 +497,7 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
loadConstant(cUnit, r1, dInsn->vB);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
genUnconditionalBranch(cUnit, rollback);
// Resume normal slow path
skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -664,7 +664,7 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
loadConstant(cUnit, r1, dInsn->vB);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
genUnconditionalBranch(cUnit, rollback);
// Resume normal slow path
skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -848,7 +848,7 @@
opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
loadConstant(cUnit, r2, (numArgs - 3) * 4);
- callNoUnwindHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
// Restore Method*
loadCurrMethodDirect(cUnit, r0);
} else {
@@ -1237,7 +1237,7 @@
OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
loadConstant(cUnit, r0, mir->dalvikInsn.vA);
loadConstant(cUnit, r1, mir->dalvikInsn.vB);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
break;
case OP_ARRAY_LENGTH:
@@ -2092,7 +2092,7 @@
LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
}
loadWordDisp(cUnit, rSELF, funcOffset, rLR);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
}
}
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 76d8b45..8f83cbb 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -55,19 +55,7 @@
}
#endif
-/*
- * If a helper routine might need to unwind, let it know the top
- * of the managed stack.
- */
-static ArmLIR* callUnwindableHelper(CompilationUnit* cUnit, int reg)
-{
- // Starting point for managed traceback if we throw
- storeWordDisp(cUnit, rSELF,
- art::Thread::TopOfManagedStackOffset().Int32Value(), rSP);
- return opReg(cUnit, kOpBlx, reg);
-}
-
-static ArmLIR* callNoUnwindHelper(CompilationUnit* cUnit, int reg)
+static ArmLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
{
return opReg(cUnit, kOpBlx, reg);
}
@@ -384,7 +372,7 @@
OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
// Materialize a pointer to the fill data image
newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
}
@@ -437,7 +425,7 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pFindInstanceFieldFromCode), rLR);
loadConstant(cUnit, r0, fieldIdx);
- callUnwindableHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
+ callRuntimeHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
target->defMask = ENCODE_ALL;
#ifndef EXERCISE_SLOWEST_FIELD_PATH
@@ -632,7 +620,7 @@
OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
genRegCopy(cUnit, r1, mReg);
loadConstant(cUnit, r0, mir->dalvikInsn.vB);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
RegLocation rlResult = oatGetReturn(cUnit);
storeValue(cUnit, rlDest, rlResult);
@@ -674,7 +662,7 @@
OFFSETOF_MEMBER(Thread, pAllocObjectFromCode), rLR);
loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
loadConstant(cUnit, r0, mir->dalvikInsn.vB); // arg0 <- type_id
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
RegLocation rlResult = oatGetReturn(cUnit);
storeValue(cUnit, rlDest, rlResult);
@@ -685,7 +673,7 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pDeliverException), rLR);
loadValueDirectFixed(cUnit, rlSrc, r0); // Get exception object
- callNoUnwindHelper(cUnit, rLR); // art_deliver_exception(exception);
+ callRuntimeHelper(cUnit, rLR); // art_deliver_exception(exception);
}
static void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
@@ -709,7 +697,7 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
loadConstant(cUnit, r0, mir->dalvikInsn.vC);
- callUnwindableHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
+ callRuntimeHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
genRegCopy(cUnit, r2, r0); // Align usage with fast path
// Rejoin code paths
ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -731,7 +719,7 @@
ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq);
genRegCopy(cUnit, r0, r3);
genRegCopy(cUnit, r1, r2);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
/* branch target here */
ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -762,7 +750,7 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
loadConstant(cUnit, r0, mir->dalvikInsn.vB);
- callUnwindableHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
+ callRuntimeHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
genRegCopy(cUnit, r2, r0); // Align usage with fast path
// Rejoin code paths
ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -783,7 +771,7 @@
ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq); /* If equal, trivial yes */
genRegCopy(cUnit, r0, r1);
genRegCopy(cUnit, r1, r2);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
/* branch target here */
ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -948,7 +936,7 @@
loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
rLR);
genRegCopy(cUnit, r0, rSELF);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
// Resume here
target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -996,7 +984,7 @@
loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
rLR);
genRegCopy(cUnit, r0, rSELF);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
// Resume here
target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -1084,7 +1072,7 @@
rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
}
- callNoUnwindHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
if (tgtSize == 1) {
RegLocation rlResult;
@@ -1139,7 +1127,7 @@
loadWordDisp(cUnit, rSELF, funcOffset, rLR);
loadValueDirectFixed(cUnit, rlSrc1, r0);
loadValueDirectFixed(cUnit, rlSrc2, r1);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
rlResult = oatGetReturn(cUnit);
storeValue(cUnit, rlDest, rlResult);
@@ -1185,7 +1173,7 @@
loadWordDisp(cUnit, rSELF, funcOffset, rLR);
loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
rlResult = oatGetReturnWide(cUnit);
storeValueWide(cUnit, rlDest, rlResult);
@@ -1265,7 +1253,7 @@
OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
/* Get the array's clazz */
loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), r1);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
// Now, redo loadValues in case they didn't survive the call
@@ -1455,7 +1443,7 @@
loadWordDisp(cUnit, rSELF, funcOffset, rLR);
loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
loadValueDirect(cUnit, rlShift, r2);
- callNoUnwindHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
RegLocation rlResult = oatGetReturnWide(cUnit);
storeValueWide(cUnit, rlDest, rlResult);
@@ -1550,7 +1538,7 @@
loadWordDisp(cUnit, rSELF, funcOffset, rLR);
loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
if (retReg == r0)
rlResult = oatGetReturnWide(cUnit);
@@ -1672,7 +1660,7 @@
if (checkZero) {
genImmedCheck(cUnit, kArmCondEq, r1, 0, mir, kArmThrowDivZero);
}
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
if (retReg == r0)
rlResult = oatGetReturn(cUnit);
@@ -1732,7 +1720,7 @@
callUnwindableHelper(cUnit, rLR); // CheckSuspendFromCode(self)
#else
ArmLIR* branch = opCondBranch(cUnit, kArmCondEq);
- callUnwindableHelper(cUnit, rLR); // CheckSuspendFromCode(self)
+ callRuntimeHelper(cUnit, rLR); // CheckSuspendFromCode(self)
ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
target->defMask = ENCODE_ALL;
branch->generic.target = (LIR*)target;
@@ -1960,7 +1948,7 @@
}
loadWordDisp(cUnit, rSELF, funcOffset, rLR);
loadConstant(cUnit, r1, lit);
- callUnwindableHelper(cUnit, rLR);
+ callRuntimeHelper(cUnit, rLR);
oatClobberCallRegs(cUnit);
if (isDiv)
rlResult = oatGetReturn(cUnit);
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 053575a..6c967ed 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -189,7 +189,10 @@
if (!runtime->HasJniStubArray()) {
runtime->SetJniStubArray(JniCompiler::CreateJniStub(kThumb2));
}
-
+ // similarly for the callee save method
+ if (!runtime->HasCalleeSaveMethod()) {
+ runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(kThumb2));
+ }
Compiler compiler(kThumb2);
if (method_names.empty()) {
compiler.CompileAll(class_loader);
diff --git a/src/image.h b/src/image.h
index e3fa35d..fdf6443 100644
--- a/src/image.h
+++ b/src/image.h
@@ -42,6 +42,7 @@
enum ImageRoot {
kJniStubArray,
+ kCalleeSaveMethod,
kImageRootsMax,
};
diff --git a/src/image_writer.cc b/src/image_writer.cc
index ae6c1c8..23bc6cf 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -107,6 +107,7 @@
ObjectArray<Object>* image_roots = ObjectArray<Object>::Alloc(object_array_class,
ImageHeader::kImageRootsMax);
image_roots->Set(ImageHeader::kJniStubArray, runtime->GetJniStubArray());
+ image_roots->Set(ImageHeader::kCalleeSaveMethod, runtime->GetCalleeSaveMethod());
return image_roots;
}
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index b3e5c79..725d9aa 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -836,7 +836,7 @@
Object* arg = NULL;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), NULL);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), NULL);
}
TEST_F(JniInternalTest, StaticNopMethod) {
@@ -851,7 +851,7 @@
Method::InvokeStub* stub = method->GetInvokeStub();
- (*stub)(method, NULL, NULL, NULL, NULL);
+ (*stub)(method, NULL, Thread::Current(), NULL, NULL);
}
TEST_F(JniInternalTest, StaticIdentityByteMethod) {
@@ -871,22 +871,22 @@
arg = 0;
result.b = -1;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(0, result.b);
arg = -1;
result.b = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(-1, result.b);
arg = SCHAR_MAX;
result.b = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(SCHAR_MAX, result.b);
arg = SCHAR_MIN;
result.b = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(SCHAR_MIN, result.b);
}
@@ -907,22 +907,22 @@
arg = 0;
result.i = -1;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(0, result.i);
arg = -1;
result.i = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(-1, result.i);
arg = INT_MAX;
result.i = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(INT_MAX, result.i);
arg = INT_MIN;
result.i = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(INT_MIN, result.i);
}
@@ -943,22 +943,22 @@
arg = 0.0;
result.d = -1.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(0.0, result.d);
arg = -1.0;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(-1.0, result.d);
arg = DBL_MAX;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(DBL_MAX, result.d);
arg = DBL_MIN;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
EXPECT_EQ(DBL_MIN, result.d);
}
@@ -980,31 +980,31 @@
args[0] = 0;
args[1] = 0;
result.i = -1;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(0, result.i);
args[0] = 1;
args[1] = 2;
result.i = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(3, result.i);
args[0] = -2;
args[1] = 5;
result.i = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(3, result.i);
args[0] = INT_MAX;
args[1] = INT_MIN;
result.i = 1234;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(-1, result.i);
args[0] = INT_MAX;
args[1] = INT_MAX;
result.i = INT_MIN;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(-2, result.i);
}
@@ -1027,35 +1027,35 @@
args[1] = 0;
args[2] = 0;
result.i = -1;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(0, result.i);
args[0] = 1;
args[1] = 2;
args[2] = 3;
result.i = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(6, result.i);
args[0] = -1;
args[1] = 2;
args[2] = -3;
result.i = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(-2, result.i);
args[0] = INT_MAX;
args[1] = INT_MIN;
args[2] = INT_MAX;
result.i = 1234;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(2147483646, result.i);
args[0] = INT_MAX;
args[1] = INT_MAX;
args[2] = INT_MAX;
result.i = INT_MIN;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(2147483645, result.i);
}
@@ -1079,7 +1079,7 @@
args[2] = 0;
args[3] = 0;
result.i = -1;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(0, result.i);
args[0] = 1;
@@ -1087,7 +1087,7 @@
args[2] = 3;
args[3] = 4;
result.i = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(10, result.i);
args[0] = -1;
@@ -1095,7 +1095,7 @@
args[2] = -3;
args[3] = 4;
result.i = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(2, result.i);
args[0] = INT_MAX;
@@ -1103,7 +1103,7 @@
args[2] = INT_MAX;
args[3] = INT_MIN;
result.i = 1234;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(-2, result.i);
args[0] = INT_MAX;
@@ -1111,7 +1111,7 @@
args[2] = INT_MAX;
args[3] = INT_MAX;
result.i = INT_MIN;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(-4, result.i);
}
@@ -1136,7 +1136,7 @@
args[3] = 0;
args[4] = 0;
result.i = -1.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(0, result.i);
args[0] = 1;
@@ -1145,7 +1145,7 @@
args[3] = 4;
args[4] = 5;
result.i = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(15, result.i);
args[0] = -1;
@@ -1154,7 +1154,7 @@
args[3] = 4;
args[4] = -5;
result.i = 0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(-3, result.i);
args[0] = INT_MAX;
@@ -1163,7 +1163,7 @@
args[3] = INT_MIN;
args[4] = INT_MAX;
result.i = 1234;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(2147483645, result.i);
args[0] = INT_MAX;
@@ -1172,7 +1172,7 @@
args[3] = INT_MAX;
args[4] = INT_MAX;
result.i = INT_MIN;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(2147483643, result.i);
}
@@ -1194,31 +1194,31 @@
args[0] = 0.0;
args[1] = 0.0;
result.d = -1.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(0.0, result.d);
args[0] = 1.0;
args[1] = 2.0;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(3.0, result.d);
args[0] = 1.0;
args[1] = -2.0;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(-1.0, result.d);
args[0] = DBL_MAX;
args[1] = DBL_MIN;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(1.7976931348623157e308, result.d);
args[0] = DBL_MAX;
args[1] = DBL_MAX;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(INFINITY, result.d);
}
@@ -1241,21 +1241,21 @@
args[1] = 0.0;
args[2] = 0.0;
result.d = -1.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(0.0, result.d);
args[0] = 1.0;
args[1] = 2.0;
args[2] = 3.0;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(6.0, result.d);
args[0] = 1.0;
args[1] = -2.0;
args[2] = 3.0;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(2.0, result.d);
}
@@ -1279,7 +1279,7 @@
args[2] = 0.0;
args[3] = 0.0;
result.d = -1.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(0.0, result.d);
args[0] = 1.0;
@@ -1287,7 +1287,7 @@
args[2] = 3.0;
args[3] = 4.0;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(10.0, result.d);
args[0] = 1.0;
@@ -1295,7 +1295,7 @@
args[2] = 3.0;
args[3] = -4.0;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(-2.0, result.d);
}
@@ -1320,7 +1320,7 @@
args[3] = 0.0;
args[4] = 0.0;
result.d = -1.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(0.0, result.d);
args[0] = 1.0;
@@ -1329,7 +1329,7 @@
args[3] = 4.0;
args[4] = 5.0;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(15.0, result.d);
args[0] = 1.0;
@@ -1338,7 +1338,7 @@
args[3] = -4.0;
args[4] = 5.0;
result.d = 0.0;
- (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+ (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
EXPECT_EQ(3.0, result.d);
}
#endif // __arm__
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 52cddb5..9d4b283 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -54,8 +54,9 @@
exit(EXIT_FAILURE);
}
-const char* image_roots_descriptions_[ImageHeader::kImageRootsMax] = {
+const char* image_roots_descriptions_[] = {
"kJniStubArray",
+ "kCalleeSaveMethod"
};
class OatDump {
@@ -66,6 +67,7 @@
os << image_header.GetMagic() << "\n\n";
os << "ROOTS:\n";
+ CHECK(sizeof(image_roots_descriptions_)/(sizeof(char*)) == ImageHeader::kImageRootsMax);
for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
os << StringPrintf("%s: %p\n",
@@ -82,7 +84,7 @@
private:
- OatDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space_), os_(os) {}
+ OatDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space), os_(os) {}
static void Callback(Object* obj, void* arg) {
DCHECK(obj != NULL);
@@ -118,9 +120,14 @@
if (obj->IsMethod()) {
Method* method = obj->AsMethod();
const ByteArray* code = method->GetCodeArray();
- StringAppendF(&summary, "\tCODE %p-%p\n", code->GetData(), code->GetData() + code->GetLength());
- const ByteArray* invoke = method->GetInvokeStubArray();
- StringAppendF(&summary, "\tJNI STUB %p-%p\n", invoke->GetData(), invoke->GetData() + invoke->GetLength());
+ if (method->IsPhony()) {
+ CHECK(code == NULL);
+ StringAppendF(&summary, "\tPHONY\n");
+ } else {
+ StringAppendF(&summary, "\tCODE %p-%p\n", code->GetData(), code->GetData() + code->GetLength());
+ const ByteArray* invoke = method->GetInvokeStubArray();
+ StringAppendF(&summary, "\tJNI STUB %p-%p\n", invoke->GetData(), invoke->GetData() + invoke->GetLength());
+ }
if (method->IsNative()) {
if (method->IsRegistered()) {
StringAppendF(&summary, "\tNATIVE REGISTERED %p\n", method->GetNativeMethod());
diff --git a/src/object.cc b/src/object.cc
index 40bc2e2..e92c8c7 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -62,8 +62,8 @@
Monitor::MonitorEnter(thread, this);
}
-void Object::MonitorExit(Thread* thread) {
- Monitor::MonitorExit(thread, this);
+bool Object::MonitorExit(Thread* thread) {
+ return Monitor::MonitorExit(thread, this);
}
void Object::Notify() {
@@ -604,15 +604,15 @@
// Set the low-order bit so a BLX will switch to Thumb mode
address |= 0x1;
}
- SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), reinterpret_cast<const void*>(address), false);
+ SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_),
+ reinterpret_cast<const void*>(address), false);
}
bool Method::IsWithinCode(uintptr_t pc) const {
- if (GetCode() == NULL) {
- return false;
- }
if (pc == 0) {
- // assume that this is some initial value that will always lie in code
+ // PC of 0 represents the beginning of a stack trace either a native or where we have a callee
+ // save method that has no code
+ DCHECK(IsNative() || IsPhony());
return true;
} else {
#if defined(__arm__)
diff --git a/src/object.h b/src/object.h
index e0a13ca..a562999 100644
--- a/src/object.h
+++ b/src/object.h
@@ -228,7 +228,7 @@
void MonitorEnter(Thread* thread);
- void MonitorExit(Thread* thread);
+ bool MonitorExit(Thread* thread);
void Notify();
@@ -927,8 +927,7 @@
// Is this a hand crafted method used for something like describing callee saves?
bool IsPhony() const {
- bool result =
- NULL == GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_), false);
+ bool result = this == Runtime::Current()->GetCalleeSaveMethod();
// Check that if we do think it is phony it looks like the callee save method
DCHECK(!result || GetCoreSpillMask() != 0);
return result;
@@ -951,6 +950,7 @@
}
static void SetClass(Class* java_lang_reflect_Method);
+ static Class* GetMethodClass() { return java_lang_reflect_Method_; }
static void ResetClass();
private:
diff --git a/src/runtime.cc b/src/runtime.cc
index 790a700..e9b7fdc 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -31,6 +31,7 @@
signal_catcher_(NULL),
java_vm_(NULL),
jni_stub_array_(NULL),
+ callee_save_method_(NULL),
started_(false),
vfprintf_(NULL),
exit_(NULL),
@@ -579,12 +580,50 @@
thread_list_->Unregister();
}
+Method* Runtime::CreateCalleeSaveMethod(InstructionSet insns) {
+ Class* method_class = Method::GetMethodClass();
+ Method* method = down_cast<Method*>(method_class->AllocObject());
+ method->SetDeclaringClass(method_class);
+ method->SetName(intern_table_->InternStrong("$$$callee_save_method$$$"));
+ method->SetSignature(intern_table_->InternStrong("()V"));
+ method->SetCode(NULL, insns, NULL);
+ if ((insns == kThumb2) || (insns == kArm)) {
+ method->SetFrameSizeInBytes(64);
+ method->SetReturnPcOffsetInBytes(60);
+ method->SetCoreSpillMask((1 << art::arm::R1) |
+ (1 << art::arm::R2) |
+ (1 << art::arm::R3) |
+ (1 << art::arm::R4) |
+ (1 << art::arm::R5) |
+ (1 << art::arm::R6) |
+ (1 << art::arm::R7) |
+ (1 << art::arm::R8) |
+ (1 << art::arm::R9) |
+ (1 << art::arm::R10) |
+ (1 << art::arm::R11) |
+ (1 << art::arm::LR));
+ method->SetFpSpillMask(0);
+ } else if (insns == kX86) {
+ method->SetFrameSizeInBytes(32);
+ method->SetReturnPcOffsetInBytes(28);
+ method->SetCoreSpillMask((1 << art::x86::EBX) |
+ (1 << art::x86::EBP) |
+ (1 << art::x86::ESI) |
+ (1 << art::x86::EDI));
+ method->SetFpSpillMask(0);
+ } else {
+ UNIMPLEMENTED(FATAL);
+ }
+ return method;
+}
+
void Runtime::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
class_linker_->VisitRoots(visitor, arg);
intern_table_->VisitRoots(visitor, arg);
java_vm_->VisitRoots(visitor, arg);
thread_list_->VisitRoots(visitor, arg);
visitor(jni_stub_array_, arg);
+ visitor(callee_save_method_, arg);
//(*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg);
//(*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg);
diff --git a/src/runtime.h b/src/runtime.h
index b3d3ebf..ee5f524 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -12,6 +12,7 @@
#include <jni.h>
+#include "constants.h"
#include "heap.h"
#include "globals.h"
#include "macros.h"
@@ -28,6 +29,7 @@
class Heap;
class InternTable;
class JavaVMExt;
+class Method;
class SignalCatcher;
class String;
class ThreadList;
@@ -154,6 +156,21 @@
jni_stub_array_ = jni_stub_array;
}
+ Method* CreateCalleeSaveMethod(InstructionSet insns);
+
+ bool HasCalleeSaveMethod() const {
+ return callee_save_method_ != NULL;
+ }
+
+ // Returns a special method that describes all callee saves being spilled to the stack.
+ Method* GetCalleeSaveMethod() const {
+ return callee_save_method_;
+ }
+
+ void SetCalleeSaveMethod(Method* method) {
+ callee_save_method_ = method;
+ }
+
int32_t GetStat(int kind);
RuntimeStats* GetStats();
@@ -198,6 +215,8 @@
ByteArray* jni_stub_array_;
+ Method* callee_save_method_;
+
bool started_;
// Hooks supported by JNI_CreateJavaVM
diff --git a/src/runtime_support.S b/src/runtime_support.S
index 6522243..5746059 100644
--- a/src/runtime_support.S
+++ b/src/runtime_support.S
@@ -4,92 +4,161 @@
.balign 4
- .global art_deliver_exception
- .extern artDeliverExceptionHelper
+ /* Deliver the given exception */
+ .extern artDeliverExceptionFromCode
+ /* Deliver an exception pending on a thread */
+ .extern artDeliverPendingException
+
+ .global art_deliver_exception_from_code
/*
- * Called by managed code, saves mosts registers (forms basis of long jump context).
- * artThrowExceptionHelper will place a mock Method* at the bottom of the thread.
- * r0 holds Throwable
+ * Called by managed code, saves mosts 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:
+art_deliver_exception_from_code:
stmdb sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
- sub sp, #16 @ 4 words of space, bottom word will hold Method*
- mov r1, r9 @ pass Thread::Current
- mov r2, sp @ pass SP
- b artDeliverExceptionHelper @ artDeliverExceptionHelper(Throwable*, Thread*, SP)
+ sub sp, #16 @ 4 words of space, bottom word will hold Method*
+ mov r1, r9 @ pass Thread::Current
+ mov r2, sp @ pass SP
+ b artDeliverExceptionFromCode @ artDeliverExceptionFromCode(Throwable*, Thread*, SP)
.global art_throw_null_pointer_exception_from_code
- .extern artThrowNullPointerExceptionFromCodeHelper
+ .extern artThrowNullPointerExceptionFromCode
/*
- * Create NPE and deliver
+ * Called by managed code to create and deliver a NullPointerException
*/
art_throw_null_pointer_exception_from_code:
stmdb sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
- sub sp, #16 @ 4 words of space, bottom word will hold Method*
- mov r0, r9 @ pass Thread::Current
- mov r1, sp @ pass SP
- b artThrowNullPointerExceptionFromCodeHelper @ artThrowNullPointerExceptionFromCodeHelper(Thread*, SP)
+ sub sp, #16 @ 4 words of space, bottom word will hold Method*
+ mov r0, r9 @ pass Thread::Current
+ mov r1, sp @ pass SP
+ b artThrowNullPointerExceptionFromCode @ artThrowNullPointerExceptionFromCode(Thread*, SP)
.global art_throw_div_zero_from_code
- .extern artThrowDivZeroFromCodeHelper
+ .extern artThrowDivZeroFromCode
/*
- * Create ArithmeticException and deliver
+ * Called by managed code to create and deliver an ArithmeticException
*/
art_throw_div_zero_from_code:
stmdb sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
- sub sp, #16 @ 4 words of space, bottom word will hold Method*
- mov r0, r9 @ pass Thread::Current
- mov r1, sp @ pass SP
- b artThrowDivZeroFromCodeHelper @ artThrowDivZeroFromCodeHelper(Thread*, SP)
+ sub sp, #16 @ 4 words of space, bottom word will hold Method*
+ mov r0, r9 @ pass Thread::Current
+ mov r1, sp @ pass SP
+ b artThrowDivZeroFromCode @ artThrowDivZeroFromCode(Thread*, SP)
.global art_throw_array_bounds_from_code
- .extern artThrowArrayBoundsFromCodeHelper
+ .extern artThrowArrayBoundsFromCode
/*
- * Create ArrayIndexOutOfBoundsException and deliver
+ * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException
*/
art_throw_array_bounds_from_code:
stmdb sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
- sub sp, #16 @ 4 words of space, bottom word will hold Method*
- mov r2, r9 @ pass Thread::Current
- mov r3, sp @ pass SP
- b artThrowArrayBoundsFromCodeHelper @ artThrowArrayBoundsFromCodeHelper(index, limit, Thread*, SP)
+ sub sp, #16 @ 4 words of space, bottom word will hold Method*
+ mov r2, r9 @ pass Thread::Current
+ mov r3, sp @ pass SP
+ b artThrowArrayBoundsFromCode @ artThrowArrayBoundsFromCode(index, limit, Thread*, SP)
.global art_invoke_interface_trampoline
- .extern artFindInterfaceMethodInCache
- .extern artFailedInvokeInterface
-art_invoke_interface_trampoline:
+ .extern artFindInterfaceMethodInCacheFromCode
/*
- * 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.
+ * 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
+ * artFindInterfaceMethodInCacheFromCode(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.
+ * artFindInterfaceMethodInCacheFromCode 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.
+ * If unsuccessful, artFindInterfaceMethodInCacheFromCode 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 pointing back to the original caller.
+ * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
+ * pointing back to the original caller.
*/
+art_invoke_interface_trampoline:
+ str sp, [R9, #THREAD_TOP_OF_MANAGED_STACK_OFFSET] @ record top of stack and pc in case of
+ str lr, [R9, #THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET] @ walking stack
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
+ ldr r2, [sp, #16] @ load caller's Method*
+ bl artFindInterfaceMethodInCacheFromCode @ (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
+ @ set up for throwing exception
+ stmdb sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
+ sub sp, #16 @ 4 words of space, bottom word will hold Method*
+ mov r0, r9 @ pass Thread::Current
+ mov r1, sp @ pass SP
+ b artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
+
+ .global art_handle_fill_data_from_code
+ .extern artHandleFillArrayDataFromCode
+ /*
+ * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
+ * failure.
+ */
+art_handle_fill_data_from_code:
+ str sp, [R9, #THREAD_TOP_OF_MANAGED_STACK_OFFSET] @ record top of stack and pc in case of
+ str lr, [R9, #THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET] @ walking stack
+ stmdb sp!, {lr} @ Save LR
+ sub sp, #12 @ Align stack
+ bl artHandleFillArrayDataFromCode @ (Array* array, const uint16_t* table)
+ add sp, #12
+ ldmia sp!, {lr} @ restore LR
+ cmp r0, #0 @ success?
+ moveq pc, lr @ return on success
+ @ set up for throwing exception
+ stmdb sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
+ sub sp, #16 @ 4 words of space, bottom word will hold Method*
+ mov r0, r9 @ pass Thread::Current
+ mov r1, sp @ pass SP
+ b artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
+
+ .global art_unlock_object_from_code
+ .extern artUnlockObjectFromCode
+ /*
+ * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
+ */
+art_unlock_object_from_code:
+ str sp, [R9, #THREAD_TOP_OF_MANAGED_STACK_OFFSET] @ record top of stack and pc in case of
+ str lr, [R9, #THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET] @ walking stack
+ stmdb sp!, {lr} @ Save LR
+ sub sp, #12 @ Align stack
+ bl artUnlockObjectFromCode @ (Thread* thread, Object* obj)
+ add sp, #12
+ ldmia sp!, {lr} @ restore LR
+ cmp r0, #0 @ success?
+ moveq pc, lr @ return on success
+ @ set up for throwing exception
+ stmdb sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
+ sub sp, #16 @ 4 words of space, bottom word will hold Method*
+ mov r0, r9 @ pass Thread::Current
+ mov r1, sp @ pass SP
+ b artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
+
+ .global art_check_cast_from_code
+ .extern artCheckCastFromCode
+ /*
+ * Entry from managed code that calls artCheckCastFromCode and delivers exception on failure.
+ */
+art_check_cast_from_code:
+ str sp, [R9, #THREAD_TOP_OF_MANAGED_STACK_OFFSET] @ record top of stack and pc in case of
+ str lr, [R9, #THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET] @ walking stack
+ stmdb sp!, {lr} @ Save LR
+ sub sp, #12 @ Align stack
+ bl artCheckCastFromCode @ (Class* a, Class* b)
+ add sp, #12
+ ldmia sp!, {lr} @ restore LR
+ cmp r0, #0 @ success?
+ moveq pc, lr @ return on success
+ @ set up for throwing exception
+ stmdb sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
+ sub sp, #16 @ 4 words of space, bottom word will hold Method*
+ mov r0, r9 @ pass Thread::Current
+ mov r1, sp @ pass SP
+ b artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
.global art_shl_long
art_shl_long:
@@ -180,14 +249,14 @@
#if defined(__i386__)
- .global art_deliver_exception
- .extern artDeliverExceptionHelper
+ .global art_deliver_exception_from_code
+ .extern artDeliverExceptionFromCode
/*
- * Called by managed code, saves callee saves and then calls artThrowExceptionHelper
+ * Called by managed code, saves callee saves and then calls artThrowException
* that will place a mock Method* at the bottom of the stack.
* EAX holds the exception.
*/
-art_deliver_exception:
+art_deliver_exception_from_code:
// Create frame
pushl %edi // Save callee saves
pushl %esi
@@ -198,11 +267,11 @@
pushl $0 // Will be clobbered to be Method*
mov %esp, %ecx
// Outgoing argument set up
- pushl $0 // Alignment padding
- pushl %ecx // pass SP
- pushl %fs:THREAD_SELF_OFFSET // pass fs:offsetof(Thread,self_)
- pushl %eax // pass Throwable*
- call artDeliverExceptionHelper // artDeliverExceptionHelper(Throwable*, Thread*, SP)
+ pushl $0 // Alignment padding
+ pushl %ecx // pass SP
+ pushl %fs:THREAD_SELF_OFFSET // pass fs:offsetof(Thread,self_)
+ pushl %eax // pass Throwable*
+ call artDeliverExceptionFromCode // artDeliverExceptionFromCode(Throwable*, Thread*, SP)
int3
#endif
diff --git a/src/runtime_support.h b/src/runtime_support.h
index ed047c9..e7aeb74 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -4,10 +4,17 @@
#define ART_SRC_RUNTIME_SUPPORT_H_
/* Helper for both JNI and regular compiled code */
-extern "C" void art_deliver_exception(void*);
+extern "C" void art_deliver_exception_from_code(void*);
#if defined(__arm__)
/* Compiler helpers */
+ extern "C" void art_check_cast_from_code(void*, void*);
+ extern "C" void art_handle_fill_data_from_code(void*, void*);
+ extern "C" void art_invoke_interface_trampoline(void*, void*, void*, 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_null_pointer_exception_from_code();
+ extern "C" void art_unlock_object_from_code(void*, void*);
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);
@@ -45,9 +52,9 @@
extern "C" int __aeabi_idivmod(int op1, int op2); // OP_REM_INT[_2ADDR|_LIT8|_LIT16]
extern "C" int __aeabi_idiv(int op1, int op2); // OP_DIV_INT[_2ADDR|_LIT8|_LIT16]
-/* Long long arithmetics - OP_REM_LONG[_2ADDR] & OP_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);
+ /* Long long arithmetics - OP_REM_LONG[_2ADDR] & OP_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);
#endif
diff --git a/src/space.cc b/src/space.cc
index 38c5720..57983d5 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -117,6 +117,9 @@
Object* jni_stub_array = image_header.GetImageRoot(ImageHeader::kJniStubArray);
Runtime::Current()->SetJniStubArray(down_cast<ByteArray*>(jni_stub_array));
+ Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
+ Runtime::Current()->SetCalleeSaveMethod(down_cast<Method*>(callee_save_method));
+
Init(map.release());
return true;
}
diff --git a/src/stub_arm.cc b/src/stub_arm.cc
index 986d2b0..79a581d 100644
--- a/src/stub_arm.cc
+++ b/src/stub_arm.cc
@@ -14,11 +14,15 @@
ByteArray* CreateAbstractMethodErrorStub() {
UniquePtr<ArmAssembler> assembler( static_cast<ArmAssembler*>(Assembler::Create(kArm)) );
- // R0 is the Method* already.
+ // Save callee saves and ready frame for exception delivery
+ RegList save = (1 << R1) | (1 << R2) | (1 << R3) | (1 << R4) | (1 << R5) | (1 << R6) | (1 << R7) |
+ (1 << R8) | (1 << R9) | (1 << R10) | (1 << R11) | (1 << LR);
+ __ PushList(save);
+ __ IncreaseFrameSize(16); // 4 words of space, bottom word will hold callee save Method*
- // Pass Thread::Current() in R1
- __ mov(R1, ShifterOperand(R9));
-
+ // R0 is the Method* already
+ __ 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));
// Leaf call to routine that never returns
diff --git a/src/thread.cc b/src/thread.cc
index 8ab10af..857d44d 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -63,12 +63,8 @@
LOG(INFO) << "Info: " << info;
}
-} // namespace art
-
// Called by generated call to throw an exception
-extern "C" void artDeliverExceptionHelper(art::Throwable* exception,
- art::Thread* thread,
- art::Method** sp) {
+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,
@@ -77,51 +73,94 @@
* exception_ in thread and delivering the exception.
*/
// Place a special frame at the TOS that will save all callee saves
- *sp = thread->CalleeSaveMethod();
+ *sp = Runtime::Current()->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
if (exception == NULL) {
thread->ThrowNewException("Ljava/lang/NullPointerException;", "throw with null exception");
- exception = thread->GetException();
+ } else {
+ thread->SetException(exception);
}
- thread->DeliverException(exception);
+ thread->DeliverException();
+}
+
+// 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) {
+ *sp = Runtime::Current()->GetCalleeSaveMethod();
+ thread->SetTopOfStack(sp, 0);
+ thread->DeliverException();
}
// Called by generated call to throw a NPE exception
-extern "C" void artThrowNullPointerExceptionFromCodeHelper(art::Thread* thread,
- art::Method** sp) {
+extern "C" void artThrowNullPointerExceptionFromCode(Thread* thread, Method** sp) {
// Place a special frame at the TOS that will save all callee saves
- *sp = thread->CalleeSaveMethod();
+ *sp = Runtime::Current()->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
thread->ThrowNewException("Ljava/lang/NullPointerException;", "unexpected null reference");
- art::Throwable* exception = thread->GetException();
- thread->DeliverException(exception);
+ thread->DeliverException();
}
// Called by generated call to throw an arithmetic divide by zero exception
-extern "C" void artThrowDivZeroFromCodeHelper(art::Thread* thread,
- art::Method** sp) {
+extern "C" void artThrowDivZeroFromCode(Thread* thread, Method** sp) {
// Place a special frame at the TOS that will save all callee saves
- *sp = thread->CalleeSaveMethod();
+ *sp = Runtime::Current()->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
thread->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
- art::Throwable* exception = thread->GetException();
- thread->DeliverException(exception);
+ thread->DeliverException();
}
// Called by generated call to throw an arithmetic divide by zero exception
-extern "C" void artThrowArrayBoundsFromCodeHelper(int index, int limit,
- art::Thread* thread,
- art::Method** sp) {
+extern "C" void artThrowArrayBoundsFromCode(int index, int limit, Thread* thread, Method** sp) {
// Place a special frame at the TOS that will save all callee saves
- *sp = thread->CalleeSaveMethod();
+ *sp = Runtime::Current()->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
thread->ThrowNewException("Ljava/lang/ArrayIndexOutOfBoundsException;",
"length=%d; index=%d", limit, index);
- art::Throwable* exception = thread->GetException();
- thread->DeliverException(exception);
+ thread->DeliverException();
}
-namespace art {
+// Called by the AbstractMethodError stub (not runtime support)
+void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp) {
+ *sp = Runtime::Current()->GetCalleeSaveMethod();
+ thread->SetTopOfStack(sp, 0);
+ thread->ThrowNewException("Ljava/lang/AbstractMethodError",
+ "abstract method \"%s\"",
+ PrettyMethod(method).c_str());
+ thread->DeliverException();
+}
+
+// TODO: placeholder
+void StackOverflowFromCode(Method* method) {
+ Thread::Current()->SetTopOfStackPC(reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
+ Thread::Current()->Dump(std::cerr);
+ //NOTE: to save code space, this handler needs to look up its own Thread*
+ UNIMPLEMENTED(FATAL) << "Stack overflow: " << PrettyMethod(method);
+}
+
+// TODO: placeholder
+void ThrowVerificationErrorFromCode(int32_t src1, int32_t ref) {
+ UNIMPLEMENTED(FATAL) << "Verification error, src1: " << src1 <<
+ " ref: " << ref;
+}
+
+// TODO: placeholder
+void ThrowNegArraySizeFromCode(int32_t index) {
+ UNIMPLEMENTED(FATAL) << "Negative array size: " << index;
+}
+
+// TODO: placeholder
+void ThrowInternalErrorFromCode(int32_t errnum) {
+ UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
+}
+
+// TODO: placeholder
+void ThrowRuntimeExceptionFromCode(int32_t errnum) {
+ UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
+}
+
+// TODO: placeholder
+void ThrowNoSuchMethodFromCode(int32_t method_idx) {
+ UNIMPLEMENTED(FATAL) << "No such method, idx: " << method_idx;
+}
// TODO: placeholder. Helper function to type
Class* InitializeTypeFromCode(uint32_t type_idx, Method* method) {
@@ -158,95 +197,39 @@
}
// TODO: placeholder (throw on failure)
-void CheckCastFromCode(const Class* a, const Class* b) {
+extern "C" int artCheckCastFromCode(const Class* a, const Class* b) {
DCHECK(a->IsClass());
DCHECK(b->IsClass());
if (b->IsAssignableFrom(a)) {
- return;
+ return 0; // Success
+ } else {
+ Thread::Current()->ThrowNewException("Ljava/lang/ClassCastException;",
+ "%s cannot be cast to %s",
+ PrettyClass(b).c_str(), PrettyClass(a).c_str());
+ return -1; // Failure
}
- UNIMPLEMENTED(FATAL);
}
-void UnlockObjectFromCode(Thread* thread, Object* obj) {
- // TODO: throw and unwind if lock not held
- // TODO: throw and unwind on NPE
- obj->MonitorExit(thread);
+extern "C" int artUnlockObjectFromCode(Thread* thread, Object* obj) {
+ DCHECK(obj != NULL); // Assumed to have been checked before entry
+ return obj->MonitorExit(thread) ? 0 /* Success */ : -1 /* Failure */;
}
void LockObjectFromCode(Thread* thread, Object* obj) {
+ DCHECK(obj != NULL); // Assumed to have been checked before entry
obj->MonitorEnter(thread);
- // TODO: throw and unwind on failure.
+ DCHECK(thread->HoldsLock(obj));
+ // Only possible exception is NPE and is handled before entry
+ DCHECK(thread->GetException() == NULL);
}
extern "C" void artCheckSuspendFromCode(Thread* thread) {
Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
}
-// TODO: placeholder
-void StackOverflowFromCode(Method* method) {
- Thread::Current()->SetTopOfStackPC(reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
- Thread::Current()->Dump(std::cerr);
- //NOTE: to save code space, this handler needs to look up its own Thread*
- UNIMPLEMENTED(FATAL) << "Stack overflow: " << PrettyMethod(method);
-}
-
-// TODO: placeholder
-void ThrowNullPointerFromCode() {
- Thread::Current()->SetTopOfStackPC(reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
- Thread::Current()->Dump(std::cerr);
- //NOTE: to save code space, this handler must look up caller's Method*
- UNIMPLEMENTED(FATAL) << "Null pointer exception";
-}
-
-// TODO: placeholder
-void ThrowDivZeroFromCode() {
- UNIMPLEMENTED(FATAL) << "Divide by zero";
-}
-
-// TODO: placeholder
-void ThrowArrayBoundsFromCode(int32_t index, int32_t limit) {
- UNIMPLEMENTED(FATAL) << "Bound check exception, idx: " << index << ", limit: " << limit;
-}
-
-// TODO: placeholder
-void ThrowVerificationErrorFromCode(int32_t src1, int32_t ref) {
- UNIMPLEMENTED(FATAL) << "Verification error, src1: " << src1 <<
- " ref: " << ref;
-}
-
-// TODO: placeholder
-void ThrowNegArraySizeFromCode(int32_t index) {
- UNIMPLEMENTED(FATAL) << "Negative array size: " << index;
-}
-
-// TODO: placeholder
-void ThrowInternalErrorFromCode(int32_t errnum) {
- UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
-}
-
-// TODO: placeholder
-void ThrowRuntimeExceptionFromCode(int32_t errnum) {
- UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
-}
-
-// TODO: placeholder
-void ThrowNoSuchMethodFromCode(int32_t method_idx) {
- UNIMPLEMENTED(FATAL) << "No such method, idx: " << method_idx;
-}
-
-void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread) {
- thread->ThrowNewException("Ljava/lang/AbstractMethodError",
- "abstract method \"%s\"",
- PrettyMethod(method).c_str());
- thread->DeliverException(thread->GetException());
-}
-
-
/*
- * Temporary placeholder. Should include run-time checks for size
- * of fill data <= size of array. If not, throw arrayOutOfBoundsException.
- * As with other new "FromCode" routines, this should return to the caller
- * only if no exception has been thrown.
+ * 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
@@ -259,38 +242,43 @@
* ubyte data[size*width] table of data values (may contain a single-byte
* padding at the end)
*/
-void HandleFillArrayDataFromCode(Array* array, const uint16_t* table) {
- uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
- uint32_t size_in_bytes = size * table[1];
- if (static_cast<int32_t>(size) > array->GetLength()) {
- ThrowArrayBoundsFromCode(array->GetLength(), size);
- }
- memcpy((char*)array + art::Array::DataOffset().Int32Value(),
- (char*)&table[4], size_in_bytes);
-}
-
-/*
- * 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
- * runtime_support.S
- */
-extern "C" void artFailedInvokeInterface() {
- UNIMPLEMENTED(FATAL) << "Unimplemented exception throw";
+extern "C" int artHandleFillArrayDataFromCode(Array* array, const uint16_t* table) {
+ DCHECK_EQ(table[0], 0x0300);
+ if (array == NULL) {
+ Thread::Current()->ThrowNewException("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 (static_cast<int32_t>(size) > array->GetLength()) {
+ Thread::Current()->ThrowNewException("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().Int32Value(), (char*)&table[4], size_in_bytes);
+ return 0; // Success
}
// See comments in runtime_support.S
-extern "C" uint64_t artFindInterfaceMethodInCache(uint32_t method_idx,
- Object* this_object , Method* caller_method)
-{
+extern "C" uint64_t artFindInterfaceMethodInCacheFromCode(uint32_t method_idx,
+ Object* this_object ,
+ Method* caller_method) {
+ Thread* thread = Thread::Current();
if (this_object == NULL) {
- ThrowNullPointerFromCode();
+ thread->ThrowNewException("Ljava/lang/NullPointerException;",
+ "null receiver during interface dispatch");
+ return 0;
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Method* interface_method = class_linker->ResolveMethod(method_idx, caller_method, false);
if (interface_method == NULL) {
- UNIMPLEMENTED(FATAL) << "Could not resolve interface method. Throw error and unwind";
+ // Could not resolve interface method. Throw error and unwind
+ CHECK(thread->GetException() != NULL);
+ return 0;
}
Method* method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
const void* code = method->GetCode();
@@ -363,20 +351,22 @@
pFmod = fmod;
pLdivmod = __aeabi_ldivmod;
pLmul = __aeabi_lmul;
- pThrowNullPointerFromCode = art_throw_null_pointer_exception_from_code;
- pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code;
- pThrowDivZeroFromCode = art_throw_div_zero_from_code;
+ pCheckCastFromCode = art_check_cast_from_code;
+ pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
pTestSuspendFromCode = art_test_suspend;
+ pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code;
+ pThrowDivZeroFromCode = art_throw_div_zero_from_code;
+ pThrowNullPointerFromCode = art_throw_null_pointer_exception_from_code;
+ pUnlockObjectFromCode = art_unlock_object_from_code;
#endif
- pDeliverException = art_deliver_exception;
+ pDeliverException = art_deliver_exception_from_code;
pF2l = F2L;
pD2l = D2L;
pAllocFromCode = Array::AllocFromCode;
pCheckAndAllocFromCode = CheckAndAllocFromCode;
pAllocObjectFromCode = Class::AllocObjectFromCode;
pMemcpy = memcpy;
- pHandleFillArrayDataFromCode = HandleFillArrayDataFromCode;
pGet32Static = Field::Get32StaticFromCode;
pSet32Static = Field::Set32StaticFromCode;
pGet64Static = Field::Get64StaticFromCode;
@@ -388,9 +378,7 @@
pResolveMethodFromCode = ResolveMethodFromCode;
pInitializeStaticStorage = ClassLinker::InitializeStaticStorageFromCode;
pInstanceofNonTrivialFromCode = Object::InstanceOf;
- pCheckCastFromCode = CheckCastFromCode;
pLockObjectFromCode = LockObjectFromCode;
- pUnlockObjectFromCode = UnlockObjectFromCode;
pFindInstanceFieldFromCode = Field::FindInstanceFieldFromCode;
pCheckSuspendFromCode = artCheckSuspendFromCode;
pStackOverflowFromCode = StackOverflowFromCode;
@@ -409,11 +397,11 @@
size_t frame_size = GetMethod()->GetFrameSizeInBytes();
DCHECK_NE(frame_size, 0u);
DCHECK_LT(frame_size, 1024u);
- byte* next_sp = reinterpret_cast<byte*>(sp_) +
- frame_size;
+ byte* next_sp = reinterpret_cast<byte*>(sp_) + frame_size;
sp_ = reinterpret_cast<Method**>(next_sp);
- DCHECK(*sp_ == NULL ||
- (*sp_)->GetClass()->GetDescriptor()->Equals("Ljava/lang/reflect/Method;"));
+ if(*sp_ != NULL) {
+ DCHECK_EQ((*sp_)->GetClass(), Method::GetMethodClass());
+ }
}
bool Frame::HasMethod() const {
@@ -421,8 +409,7 @@
}
uintptr_t Frame::GetReturnPC() const {
- byte* pc_addr = reinterpret_cast<byte*>(sp_) +
- GetMethod()->GetReturnPcOffsetInBytes();
+ byte* pc_addr = reinterpret_cast<byte*>(sp_) + GetMethod()->GetReturnPcOffsetInBytes();
return *reinterpret_cast<uintptr_t*>(pc_addr);
}
@@ -431,8 +418,7 @@
Method* method = GetMethod();
DCHECK(method != NULL);
size_t frame_size = method->GetFrameSizeInBytes();
- byte* save_addr = reinterpret_cast<byte*>(sp_) + frame_size -
- ((num + 1) * kPointerSize);
+ byte* save_addr = reinterpret_cast<byte*>(sp_) + frame_size - ((num + 1) * kPointerSize);
#if defined(__i386__)
save_addr -= kPointerSize; // account for return address
#endif
@@ -1187,7 +1173,7 @@
break;
}
// last_tos should return Frame instead of sp?
- frame.SetSP(reinterpret_cast<art::Method**>(record->last_top_of_managed_stack_));
+ frame.SetSP(reinterpret_cast<Method**>(record->last_top_of_managed_stack_));
pc = record->last_top_of_managed_stack_pc_;
record = record->link_;
}
@@ -1312,41 +1298,6 @@
UNIMPLEMENTED(FATAL);
}
-Method* Thread::CalleeSaveMethod() const {
- // TODO: we should only allocate this once
- Method* method = Runtime::Current()->GetClassLinker()->AllocMethod();
-#if defined(__arm__)
- method->SetCode(NULL, art::kThumb2, NULL);
- method->SetFrameSizeInBytes(64);
- method->SetReturnPcOffsetInBytes(60);
- method->SetCoreSpillMask((1 << art::arm::R1) |
- (1 << art::arm::R2) |
- (1 << art::arm::R3) |
- (1 << art::arm::R4) |
- (1 << art::arm::R5) |
- (1 << art::arm::R6) |
- (1 << art::arm::R7) |
- (1 << art::arm::R8) |
- (1 << art::arm::R9) |
- (1 << art::arm::R10) |
- (1 << art::arm::R11) |
- (1 << art::arm::LR));
- method->SetFpSpillMask(0);
-#elif defined(__i386__)
- method->SetCode(NULL, art::kX86, NULL);
- method->SetFrameSizeInBytes(32);
- method->SetReturnPcOffsetInBytes(28);
- method->SetCoreSpillMask((1 << art::x86::EBX) |
- (1 << art::x86::EBP) |
- (1 << art::x86::ESI) |
- (1 << art::x86::EDI));
- method->SetFpSpillMask(0);
-#else
- UNIMPLEMENTED(FATAL);
-#endif
- return method;
-}
-
class CatchBlockStackVisitor : public Thread::StackVisitor {
public:
CatchBlockStackVisitor(Class* to_find, Context* ljc)
@@ -1409,8 +1360,9 @@
uint32_t native_method_count_;
};
-void Thread::DeliverException(Throwable* exception) {
- SetException(exception); // Set exception on thread
+void Thread::DeliverException() {
+ Throwable *exception = GetException(); // Set exception on thread
+ CHECK(exception != NULL);
Context* long_jump_context = GetLongJumpContext();
CatchBlockStackVisitor catch_finder(exception->GetClass(), long_jump_context);
diff --git a/src/thread.h b/src/thread.h
index 212abdc..e198d9a 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -212,12 +212,12 @@
void (*pSetObjStatic)(uint32_t, const Method*, Object*);
void (*pCanPutArrayElementFromCode)(const Object*, const Class*);
bool (*pInstanceofNonTrivialFromCode) (const Object*, const Class*);
- void (*pCheckCastFromCode) (const Class*, const Class*);
+ void (*pCheckCastFromCode) (void*, void*);
Method* (*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
- void (*pUnlockObjectFromCode)(Thread*, Object*);
+ void (*pUnlockObjectFromCode)(void*, void*);
void (*pLockObjectFromCode)(Thread*, Object*);
void (*pDeliverException)(void*);
- void (*pHandleFillArrayDataFromCode)(Array*, const uint16_t*);
+ void (*pHandleFillArrayDataFromCode)(void*, void*);
Class* (*pInitializeTypeFromCode)(uint32_t, Method*);
void (*pResolveMethodFromCode)(Method*, uint32_t);
void (*pInvokeInterfaceTrampoline)(void*, void*, void*, void*);
@@ -234,7 +234,7 @@
void (*pThrowRuntimeExceptionFromCode)(int32_t);
void (*pThrowInternalErrorFromCode)(int32_t);
void (*pThrowNoSuchMethodFromCode)(int32_t);
- void (*pThrowAbstractMethodErrorFromCode)(Method* method, Thread* thread);
+ void (*pThrowAbstractMethodErrorFromCode)(Method* method, Thread* thread, Method** sp);
void* (*pFindNativeMethod)(Thread* thread);
Object* (*pDecodeJObjectInThread)(Thread* thread, jobject obj);
@@ -339,7 +339,7 @@
}
// Find catch block and perform long jump to appropriate exception handle
- void DeliverException(Throwable* exception);
+ void DeliverException();
Context* GetLongJumpContext();
@@ -358,10 +358,6 @@
top_of_managed_stack_pc_ = pc;
}
- // Returns a special method that describes all callee saves being spilt to the
- // stack.
- Method* CalleeSaveMethod() const;
-
void ThrowNewException(const char* exception_class_descriptor, const char* fmt, ...)
__attribute__ ((format(printf, 3, 4)));
diff --git a/src/thread_arm.cc b/src/thread_arm.cc
index 8b0d9a4..52f1b20 100644
--- a/src/thread_arm.cc
+++ b/src/thread_arm.cc
@@ -1,11 +1,16 @@
// Copyright 2011 Google Inc. All Rights Reserved.
-#include "macros.h"
#include "thread.h"
+#include "asm_support.h"
+#include "macros.h"
+
namespace art {
void Thread::InitCpu() {
+ CHECK_EQ(THREAD_TOP_OF_MANAGED_STACK_OFFSET, OFFSETOF_MEMBER(Thread, top_of_managed_stack_));
+ CHECK_EQ(THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET,
+ OFFSETOF_MEMBER(Thread, top_of_managed_stack_pc_));
}
} // namespace art
diff --git a/test/IntMath/IntMath.java b/test/IntMath/IntMath.java
index a38525e..c43d09e 100644
--- a/test/IntMath/IntMath.java
+++ b/test/IntMath/IntMath.java
@@ -767,6 +767,25 @@
return foo.getFoo();
}
+ static int throwClassCast(Object o) {
+ return ((Integer)o).intValue();
+ }
+
+ static int testClassCast() {
+ int res = 0;
+ try {
+ res += throwClassCast(Integer.valueOf(123));
+ } catch(ClassCastException e) {
+ res += 456;
+ }
+ try {
+ res += throwClassCast(new Short((short)321));
+ } catch(ClassCastException e) {
+ res += 765;
+ }
+ return res;
+ }
+
public static void main(String[] args) {
boolean failure = false;
int res;
@@ -920,6 +939,14 @@
failure = true;
}
+ res = testClassCast();
+ if (res == 888) {
+ System.out.println("testClassCast PASSED");
+ } else {
+ System.out.println("testClassCast FAILED: " + res);
+ failure = true;
+ }
+
res = manyArgs(0, 1L, 2, 3L, 4, 5L, 6, 7, 8.0, 9.0f, 10.0,
(short)11, 12, (char)13, 14, 15, (byte)-16, true, 18,
19, 20L, 21L, 22, 23, 24, 25, 26);