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) {