Implement artThrowVerificationErrorFromCode.
Change-Id: Ib7f2ad06f20bd0a83fbab573bb16a9d2f872826a
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index ca1fdea0..57f216d 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -16,6 +16,8 @@
#include "runtime_support.h"
+#include "dex_verifier.h"
+
namespace art {
// Temporary debugging hook for compiler.
@@ -128,15 +130,136 @@
thread->DeliverException();
}
-extern "C" void artThrowVerificationErrorFromCode(int32_t src1, int32_t ref, Thread* thread, Method** sp) {
+std::string ClassNameFromIndex(Method* method, uint32_t ref, DexVerifier::VerifyErrorRefType ref_type, bool access) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
+
+ uint16_t type_idx = 0;
+ if (ref_type == DexVerifier::VERIFY_ERROR_REF_FIELD) {
+ const DexFile::FieldId& id = dex_file.GetFieldId(ref);
+ type_idx = id.class_idx_;
+ } else if (ref_type == DexVerifier::VERIFY_ERROR_REF_METHOD) {
+ const DexFile::MethodId& id = dex_file.GetMethodId(ref);
+ type_idx = id.class_idx_;
+ } else if (ref_type == DexVerifier::VERIFY_ERROR_REF_CLASS) {
+ type_idx = ref;
+ } else {
+ CHECK(false) << static_cast<int>(ref_type);
+ }
+
+ std::string class_name(PrettyDescriptor(dex_file.dexStringByTypeIdx(type_idx)));
+ if (!access) {
+ return class_name;
+ }
+
+ std::string result;
+ result += "tried to access class ";
+ result += class_name;
+ result += " from class ";
+ result += PrettyDescriptor(method->GetDeclaringClass()->GetDescriptor());
+ return result;
+}
+
+std::string FieldNameFromIndex(const Method* method, uint32_t ref, DexVerifier::VerifyErrorRefType ref_type, bool access) {
+ CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(DexVerifier::VERIFY_ERROR_REF_FIELD));
+
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
+
+ const DexFile::FieldId& id = dex_file.GetFieldId(ref);
+ std::string class_name(PrettyDescriptor(dex_file.dexStringByTypeIdx(id.class_idx_)));
+ const char* field_name = dex_file.dexStringById(id.name_idx_);
+ if (!access) {
+ return class_name + "." + field_name;
+ }
+
+ std::string result;
+ result += "tried to access field ";
+ result += class_name + "." + field_name;
+ result += " from class ";
+ result += PrettyDescriptor(method->GetDeclaringClass()->GetDescriptor());
+ return result;
+}
+
+std::string MethodNameFromIndex(const Method* method, uint32_t ref, DexVerifier::VerifyErrorRefType ref_type, bool access) {
+ CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(DexVerifier::VERIFY_ERROR_REF_METHOD));
+
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
+
+ const DexFile::MethodId& id = dex_file.GetMethodId(ref);
+ std::string class_name(PrettyDescriptor(dex_file.dexStringByTypeIdx(id.class_idx_)));
+ const char* method_name = dex_file.dexStringById(id.name_idx_);
+ if (!access) {
+ return class_name + "." + method_name;
+ }
+
+ std::string result;
+ result += "tried to access method ";
+ result += class_name + "." + method_name + ":" + dex_file.CreateMethodDescriptor(id.proto_idx_, NULL);
+ result += " from class ";
+ result += PrettyDescriptor(method->GetDeclaringClass()->GetDescriptor());
+ return result;
+}
+
+extern "C" void artThrowVerificationErrorFromCode(int32_t kind, int32_t ref, Thread* self, Method** sp) {
// Place a special frame at the TOS that will save all callee saves
Runtime* runtime = Runtime::Current();
*sp = runtime->GetCalleeSaveMethod();
- thread->SetTopOfStack(sp, 0);
- LOG(WARNING) << "TODO: verifcation error detail message. src1=" << src1 << " ref=" << ref;
- thread->ThrowNewExceptionF("Ljava/lang/VerifyError;",
- "TODO: verification error detail message. src1=%d; ref=%d", src1, ref);
- thread->DeliverException();
+ self->SetTopOfStack(sp, 0);
+
+ Frame frame = self->GetTopOfStack();
+ frame.Next();
+ Method* method = frame.GetMethod();
+
+ DexVerifier::VerifyErrorRefType ref_type = static_cast<DexVerifier::VerifyErrorRefType>(kind >> kVerifyErrorRefTypeShift);
+
+ const char* exception_class = "Ljava/lang/VerifyError;";
+ std::string msg;
+
+ switch (static_cast<DexVerifier::VerifyError>(kind & ~(0xff << kVerifyErrorRefTypeShift))) {
+ case DexVerifier::VERIFY_ERROR_NO_CLASS:
+ exception_class = "Ljava/lang/NoClassDefFoundError;";
+ msg = ClassNameFromIndex(method, ref, ref_type, false);
+ break;
+ case DexVerifier::VERIFY_ERROR_NO_FIELD:
+ exception_class = "Ljava/lang/NoSuchFieldError;";
+ msg = FieldNameFromIndex(method, ref, ref_type, false);
+ break;
+ case DexVerifier::VERIFY_ERROR_NO_METHOD:
+ exception_class = "Ljava/lang/NoSuchMethodError;";
+ msg = MethodNameFromIndex(method, ref, ref_type, false);
+ break;
+ case DexVerifier::VERIFY_ERROR_ACCESS_CLASS:
+ exception_class = "Ljava/lang/IllegalAccessError;";
+ msg = ClassNameFromIndex(method, ref, ref_type, true);
+ break;
+ case DexVerifier::VERIFY_ERROR_ACCESS_FIELD:
+ exception_class = "Ljava/lang/IllegalAccessError;";
+ msg = FieldNameFromIndex(method, ref, ref_type, true);
+ break;
+ case DexVerifier::VERIFY_ERROR_ACCESS_METHOD:
+ exception_class = "Ljava/lang/IllegalAccessError;";
+ msg = MethodNameFromIndex(method, ref, ref_type, true);
+ break;
+ case DexVerifier::VERIFY_ERROR_CLASS_CHANGE:
+ exception_class = "Ljava/lang/IncompatibleClassChangeError;";
+ msg = ClassNameFromIndex(method, ref, ref_type, false);
+ break;
+ case DexVerifier::VERIFY_ERROR_INSTANTIATION:
+ exception_class = "Ljava/lang/InstantiationError;";
+ msg = ClassNameFromIndex(method, ref, ref_type, false);
+ break;
+ case DexVerifier::VERIFY_ERROR_GENERIC:
+ // Generic VerifyError; use default exception, no message.
+ break;
+ case DexVerifier::VERIFY_ERROR_NONE:
+ CHECK(false);
+ break;
+ }
+
+ self->ThrowNewException(exception_class, msg.c_str());
+ self->DeliverException();
}
extern "C" void artThrowInternalErrorFromCode(int32_t errnum, Thread* thread, Method** sp) {
diff --git a/src/runtime_support_asm.S b/src/runtime_support_asm.S
index dee8cc4..25a6872 100644
--- a/src/runtime_support_asm.S
+++ b/src/runtime_support_asm.S
@@ -107,7 +107,7 @@
SETUP_CALLEE_SAVE_FRAME
mov r2, r9 @ pass Thread::Current
mov r3, sp @ pass SP
- b artThrowVerificationErrorFromCode @ artThrowVerificationErrorFromCode(src1, ref, Thread*, SP)
+ b artThrowVerificationErrorFromCode @ artThrowVerificationErrorFromCode(kind, ref, Thread*, SP)
.global art_invoke_interface_trampoline
.extern artFindInterfaceMethodInCacheFromCode
diff --git a/src/utils.cc b/src/utils.cc
index b5063ffeb..03a4811 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -51,8 +51,10 @@
if (java_descriptor == NULL) {
return "null";
}
- std::string descriptor(java_descriptor->ToModifiedUtf8());
+ return PrettyDescriptor(java_descriptor->ToModifiedUtf8());
+}
+std::string PrettyDescriptor(const std::string& descriptor) {
// Count the number of '['s to get the dimensionality.
const char* c = descriptor.c_str();
size_t dim = 0;
diff --git a/src/utils.h b/src/utils.h
index 97bf2c8..5470f7f 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -149,6 +149,7 @@
// "[[I" would be "int[][]", "[Ljava/lang/String;" would be
// "java.lang.String[]", and so forth.
std::string PrettyDescriptor(const String* descriptor);
+std::string PrettyDescriptor(const std::string& descriptor);
// Returns a human-readable signature for 'f'. Something like "a.b.C.f" or
// "int a.b.C.f" (depending on the value of 'with_type').