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').