Implement throw-verification-error opcode in LLVM-based compiler.

Change-Id: I3b902e593f380d7524c8a2d94800d0323364c613
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 40b43c1..0a1cf8f 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -221,6 +221,90 @@
   return result;
 }
 
+static inline std::string ClassNameFromIndex(const Method* method, uint32_t ref,
+                                             verifier::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 == verifier::VERIFY_ERROR_REF_FIELD) {
+    const DexFile::FieldId& id = dex_file.GetFieldId(ref);
+    type_idx = id.class_idx_;
+  } else if (ref_type == verifier::VERIFY_ERROR_REF_METHOD) {
+    const DexFile::MethodId& id = dex_file.GetMethodId(ref);
+    type_idx = id.class_idx_;
+  } else if (ref_type == verifier::VERIFY_ERROR_REF_CLASS) {
+    type_idx = ref;
+  } else {
+    CHECK(false) << static_cast<int>(ref_type);
+  }
+
+  std::string class_name(PrettyDescriptor(dex_file.StringByTypeIdx(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());
+  return result;
+}
+
+void ThrowVerificationError(Thread* self, const Method* method,
+                            int32_t kind, int32_t ref) {
+  verifier::VerifyErrorRefType ref_type =
+      static_cast<verifier::VerifyErrorRefType>(kind >> verifier::kVerifyErrorRefTypeShift);
+
+  const char* exception_class = "Ljava/lang/VerifyError;";
+  std::string msg;
+
+  switch (static_cast<verifier::VerifyError>(kind & ~(0xff << verifier::kVerifyErrorRefTypeShift))) {
+  case verifier::VERIFY_ERROR_NO_CLASS:
+    exception_class = "Ljava/lang/NoClassDefFoundError;";
+    msg = ClassNameFromIndex(method, ref, ref_type, false);
+    break;
+  case verifier::VERIFY_ERROR_NO_FIELD:
+    exception_class = "Ljava/lang/NoSuchFieldError;";
+    msg = FieldNameFromIndex(method, ref, ref_type, false);
+    break;
+  case verifier::VERIFY_ERROR_NO_METHOD:
+    exception_class = "Ljava/lang/NoSuchMethodError;";
+    msg = MethodNameFromIndex(method, ref, ref_type, false);
+    break;
+  case verifier::VERIFY_ERROR_ACCESS_CLASS:
+    exception_class = "Ljava/lang/IllegalAccessError;";
+    msg = ClassNameFromIndex(method, ref, ref_type, true);
+    break;
+  case verifier::VERIFY_ERROR_ACCESS_FIELD:
+    exception_class = "Ljava/lang/IllegalAccessError;";
+    msg = FieldNameFromIndex(method, ref, ref_type, true);
+    break;
+  case verifier::VERIFY_ERROR_ACCESS_METHOD:
+    exception_class = "Ljava/lang/IllegalAccessError;";
+    msg = MethodNameFromIndex(method, ref, ref_type, true);
+    break;
+  case verifier::VERIFY_ERROR_CLASS_CHANGE:
+    exception_class = "Ljava/lang/IncompatibleClassChangeError;";
+    msg = ClassNameFromIndex(method, ref, ref_type, false);
+    break;
+  case verifier::VERIFY_ERROR_INSTANTIATION:
+    exception_class = "Ljava/lang/InstantiationError;";
+    msg = ClassNameFromIndex(method, ref, ref_type, false);
+    break;
+  case verifier::VERIFY_ERROR_BAD_CLASS_SOFT:
+  case verifier::VERIFY_ERROR_BAD_CLASS_HARD:
+    // Generic VerifyError; use default exception, no message.
+    break;
+  case verifier::VERIFY_ERROR_NONE:
+    CHECK(false);
+    break;
+  }
+
+  self->ThrowNewException(exception_class, msg.c_str());
+}
+
 // Helper function to allocate array for FILLED_NEW_ARRAY.
 Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
                                   Thread* self, bool access_check) {