summaryrefslogtreecommitdiffstats
path: root/runtime/common_throws.cc
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2013-07-12 13:46:57 -0700
committerBrian Carlstrom <bdc@google.com>2013-07-12 17:49:01 -0700
commit7940e44f4517de5e2634a7e07d58d0fb26160513 (patch)
treeac90242d96229a6942f6e24ab137bc1f8f2e0025 /runtime/common_throws.cc
parent5cd9e3b122f276f610980cbaf0d2ad6ed4cd9088 (diff)
downloadandroid_art-7940e44f4517de5e2634a7e07d58d0fb26160513.tar.gz
android_art-7940e44f4517de5e2634a7e07d58d0fb26160513.tar.bz2
android_art-7940e44f4517de5e2634a7e07d58d0fb26160513.zip
Create separate Android.mk for main build targets
The runtime, compiler, dex2oat, and oatdump now are in seperate trees to prevent dependency creep. They can now be individually built without rebuilding the rest of the art projects. dalvikvm and jdwpspy were already this way. Builds in the art directory should behave as before, building everything including tests. Change-Id: Ic6b1151e5ed0f823c3dd301afd2b13eb2d8feb81
Diffstat (limited to 'runtime/common_throws.cc')
-rw-r--r--runtime/common_throws.cc485
1 files changed, 485 insertions, 0 deletions
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
new file mode 100644
index 0000000000..04979016e3
--- /dev/null
+++ b/runtime/common_throws.cc
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_throws.h"
+
+#include "base/logging.h"
+#include "class_linker-inl.h"
+#include "dex_file-inl.h"
+#include "dex_instruction-inl.h"
+#include "invoke_type.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
+#include "object_utils.h"
+#include "thread.h"
+#include "verifier/method_verifier.h"
+
+#include <sstream>
+
+namespace art {
+
+static void AddReferrerLocation(std::ostream& os, const mirror::Class* referrer)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (referrer != NULL) {
+ ClassHelper kh(referrer);
+ std::string location(kh.GetLocation());
+ if (!location.empty()) {
+ os << " (declaration of '" << PrettyDescriptor(referrer)
+ << "' appears in " << location << ")";
+ }
+ }
+}
+
+static void ThrowException(const ThrowLocation* throw_location, const char* exception_descriptor,
+ const mirror::Class* referrer, const char* fmt, va_list* args = NULL)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ std::ostringstream msg;
+ if (args != NULL) {
+ std::string vmsg;
+ StringAppendV(&vmsg, fmt, *args);
+ msg << vmsg;
+ } else {
+ msg << fmt;
+ }
+ AddReferrerLocation(msg, referrer);
+ Thread* self = Thread::Current();
+ if (throw_location == NULL) {
+ ThrowLocation computed_throw_location = self->GetCurrentLocationForThrow();
+ self->ThrowNewException(computed_throw_location, exception_descriptor, msg.str().c_str());
+ } else {
+ self->ThrowNewException(*throw_location, exception_descriptor, msg.str().c_str());
+ }
+}
+
+// AbstractMethodError
+
+void ThrowAbstractMethodError(const mirror::AbstractMethod* method) {
+ ThrowException(NULL, "Ljava/lang/AbstractMethodError;", NULL,
+ StringPrintf("abstract method \"%s\"",
+ PrettyMethod(method).c_str()).c_str());
+}
+
+// ArithmeticException
+
+void ThrowArithmeticExceptionDivideByZero() {
+ ThrowException(NULL, "Ljava/lang/ArithmeticException;", NULL, "divide by zero");
+}
+
+// ArrayIndexOutOfBoundsException
+
+void ThrowArrayIndexOutOfBoundsException(int index, int length) {
+ ThrowException(NULL, "Ljava/lang/ArrayIndexOutOfBoundsException;", NULL,
+ StringPrintf("length=%d; index=%d", length, index).c_str());
+}
+
+// ArrayStoreException
+
+void ThrowArrayStoreException(const mirror::Class* element_class,
+ const mirror::Class* array_class) {
+ ThrowException(NULL, "Ljava/lang/ArrayStoreException;", NULL,
+ StringPrintf("%s cannot be stored in an array of type %s",
+ PrettyDescriptor(element_class).c_str(),
+ PrettyDescriptor(array_class).c_str()).c_str());
+}
+
+// ClassCastException
+
+void ThrowClassCastException(const mirror::Class* dest_type, const mirror::Class* src_type) {
+ ThrowException(NULL, "Ljava/lang/ClassCastException;", NULL,
+ StringPrintf("%s cannot be cast to %s",
+ PrettyDescriptor(src_type).c_str(),
+ PrettyDescriptor(dest_type).c_str()).c_str());
+}
+
+void ThrowClassCastException(const ThrowLocation* throw_location, const char* msg) {
+ ThrowException(throw_location, "Ljava/lang/ClassCastException;", NULL, msg);
+}
+
+// ClassCircularityError
+
+void ThrowClassCircularityError(mirror::Class* c) {
+ std::ostringstream msg;
+ msg << PrettyDescriptor(c);
+ ThrowException(NULL, "Ljava/lang/ClassCircularityError;", c, msg.str().c_str());
+}
+
+// ClassFormatError
+
+void ThrowClassFormatError(const mirror::Class* referrer, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ ThrowException(NULL, "Ljava/lang/ClassFormatError;", referrer, fmt, &args);
+ va_end(args);}
+
+// IllegalAccessError
+
+void ThrowIllegalAccessErrorClass(mirror::Class* referrer, mirror::Class* accessed) {
+ std::ostringstream msg;
+ msg << "Illegal class access: '" << PrettyDescriptor(referrer) << "' attempting to access '"
+ << PrettyDescriptor(accessed) << "'";
+ ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str());
+}
+
+void ThrowIllegalAccessErrorClassForMethodDispatch(mirror::Class* referrer, mirror::Class* accessed,
+ const mirror::AbstractMethod* caller,
+ const mirror::AbstractMethod* called,
+ InvokeType type) {
+ std::ostringstream msg;
+ msg << "Illegal class access ('" << PrettyDescriptor(referrer) << "' attempting to access '"
+ << PrettyDescriptor(accessed) << "') in attempt to invoke " << type
+ << " method " << PrettyMethod(called).c_str();
+ ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str());
+}
+
+void ThrowIllegalAccessErrorMethod(mirror::Class* referrer, mirror::AbstractMethod* accessed) {
+ std::ostringstream msg;
+ msg << "Method '" << PrettyMethod(accessed) << "' is inaccessible to class '"
+ << PrettyDescriptor(referrer) << "'";
+ ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str());
+}
+
+void ThrowIllegalAccessErrorField(mirror::Class* referrer, mirror::Field* accessed) {
+ std::ostringstream msg;
+ msg << "Field '" << PrettyField(accessed, false) << "' is inaccessible to class '"
+ << PrettyDescriptor(referrer) << "'";
+ ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str());
+}
+
+void ThrowIllegalAccessErrorFinalField(const mirror::AbstractMethod* referrer,
+ mirror::Field* accessed) {
+ std::ostringstream msg;
+ msg << "Final field '" << PrettyField(accessed, false) << "' cannot be written to by method '"
+ << PrettyMethod(referrer) << "'";
+ ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer != NULL ? referrer->GetClass() : NULL,
+ msg.str().c_str());
+}
+
+void ThrowIllegalAccessError(mirror::Class* referrer, const char* fmt, ...){
+ va_list args;
+ va_start(args, fmt);
+ ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer, fmt, &args);
+ va_end(args);
+}
+
+// IllegalArgumentException
+
+void ThrowIllegalArgumentException(const ThrowLocation* throw_location, const char* msg) {
+ ThrowException(throw_location, "Ljava/lang/IllegalArgumentException;", NULL, msg);
+}
+
+
+// IncompatibleClassChangeError
+
+void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType found_type,
+ mirror::AbstractMethod* method,
+ const mirror::AbstractMethod* referrer) {
+ std::ostringstream msg;
+ msg << "The method '" << PrettyMethod(method) << "' was expected to be of type "
+ << expected_type << " but instead was found to be of type " << found_type;
+ ThrowException(NULL, "Ljava/lang/IncompatibleClassChangeError;",
+ referrer != NULL ? referrer->GetClass() : NULL,
+ msg.str().c_str());
+}
+
+void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(const mirror::AbstractMethod* interface_method,
+ mirror::Object* this_object,
+ const mirror::AbstractMethod* referrer) {
+ // Referrer is calling interface_method on this_object, however, the interface_method isn't
+ // implemented by this_object.
+ CHECK(this_object != NULL);
+ std::ostringstream msg;
+ msg << "Class '" << PrettyDescriptor(this_object->GetClass())
+ << "' does not implement interface '"
+ << PrettyDescriptor(interface_method->GetDeclaringClass())
+ << "' in call to '" << PrettyMethod(interface_method) << "'";
+ ThrowException(NULL, "Ljava/lang/IncompatibleClassChangeError;",
+ referrer != NULL ? referrer->GetClass() : NULL,
+ msg.str().c_str());
+}
+
+void ThrowIncompatibleClassChangeErrorField(const mirror::Field* resolved_field, bool is_static,
+ const mirror::AbstractMethod* referrer) {
+ std::ostringstream msg;
+ msg << "Expected '" << PrettyField(resolved_field) << "' to be a "
+ << (is_static ? "static" : "instance") << " field" << " rather than a "
+ << (is_static ? "instance" : "static") << " field";
+ ThrowException(NULL, "Ljava/lang/IncompatibleClassChangeError;", referrer->GetClass(),
+ msg.str().c_str());
+}
+
+void ThrowIncompatibleClassChangeError(const mirror::Class* referrer, const char* fmt, ...){
+ va_list args;
+ va_start(args, fmt);
+ ThrowException(NULL, "Ljava/lang/IncompatibleClassChangeError;", referrer, fmt, &args);
+ va_end(args);
+}
+
+// LinkageError
+
+void ThrowLinkageError(const mirror::Class* referrer, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ ThrowException(NULL, "Ljava/lang/LinkageError;", referrer, fmt, &args);
+ va_end(args);
+}
+
+// NegativeArraySizeException
+
+void ThrowNegativeArraySizeException(int size) {
+ ThrowException(NULL, "Ljava/lang/NegativeArraySizeException;", NULL, StringPrintf("%d", size).c_str());
+}
+
+void ThrowNegativeArraySizeException(const char* msg) {
+ ThrowException(NULL, "Ljava/lang/NegativeArraySizeException;", NULL, msg);
+}
+
+// NoSuchFieldError
+
+void ThrowNoSuchFieldError(const StringPiece& scope, mirror::Class* c,
+ const StringPiece& type, const StringPiece& name)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ClassHelper kh(c);
+ std::ostringstream msg;
+ msg << "No " << scope << "field " << name << " of type " << type
+ << " in class " << kh.GetDescriptor() << " or its superclasses";
+ ThrowException(NULL, "Ljava/lang/NoSuchFieldError;", c, msg.str().c_str());
+}
+
+// NoSuchMethodError
+
+void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name,
+ const StringPiece& signature) {
+ std::ostringstream msg;
+ ClassHelper kh(c);
+ msg << "No " << type << " method " << name << signature
+ << " in class " << kh.GetDescriptor() << " or its super classes";
+ ThrowException(NULL, "Ljava/lang/NoSuchMethodError;", c, msg.str().c_str());
+}
+
+void ThrowNoSuchMethodError(uint32_t method_idx) {
+ Thread* self = Thread::Current();
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ mirror::DexCache* dex_cache = throw_location.GetMethod()->GetDeclaringClass()->GetDexCache();
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ std::ostringstream msg;
+ msg << "No method '" << PrettyMethod(method_idx, dex_file, true) << "'";
+ ThrowException(&throw_location, "Ljava/lang/NoSuchMethodError;",
+ throw_location.GetMethod()->GetDeclaringClass(), msg.str().c_str());
+}
+
+// NullPointerException
+
+void ThrowNullPointerExceptionForFieldAccess(const ThrowLocation& throw_location,
+ mirror::Field* field, bool is_read) {
+ std::ostringstream msg;
+ msg << "Attempt to " << (is_read ? "read from" : "write to")
+ << " field '" << PrettyField(field, true) << "' on a null object reference";
+ ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL, msg.str().c_str());
+}
+
+static void ThrowNullPointerExceptionForMethodAccessImpl(const ThrowLocation& throw_location,
+ uint32_t method_idx,
+ const DexFile& dex_file,
+ InvokeType type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ std::ostringstream msg;
+ msg << "Attempt to invoke " << type << " method '"
+ << PrettyMethod(method_idx, dex_file, true) << "' on a null object reference";
+ ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL, msg.str().c_str());
+}
+
+void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location, uint32_t method_idx,
+ InvokeType type) {
+ mirror::DexCache* dex_cache = throw_location.GetMethod()->GetDeclaringClass()->GetDexCache();
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ ThrowNullPointerExceptionForMethodAccessImpl(throw_location, method_idx,
+ dex_file, type);
+}
+
+void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location,
+ mirror::AbstractMethod* method,
+ InvokeType type) {
+ mirror::DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ ThrowNullPointerExceptionForMethodAccessImpl(throw_location, method->GetDexMethodIndex(),
+ dex_file, type);
+}
+
+void ThrowNullPointerExceptionFromDexPC(const ThrowLocation& throw_location) {
+ const DexFile::CodeItem* code = MethodHelper(throw_location.GetMethod()).GetCodeItem();
+ uint32_t throw_dex_pc = throw_location.GetDexPc();
+ CHECK_LT(throw_dex_pc, code->insns_size_in_code_units_);
+ const Instruction* instr = Instruction::At(&code->insns_[throw_dex_pc]);
+ switch (instr->Opcode()) {
+ case Instruction::INVOKE_DIRECT:
+ ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_35c(), kDirect);
+ break;
+ case Instruction::INVOKE_DIRECT_RANGE:
+ ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_3rc(), kDirect);
+ break;
+ case Instruction::INVOKE_VIRTUAL:
+ ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_35c(), kVirtual);
+ break;
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_3rc(), kVirtual);
+ break;
+ case Instruction::INVOKE_INTERFACE:
+ ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_35c(), kInterface);
+ break;
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_3rc(), kInterface);
+ break;
+ case Instruction::INVOKE_VIRTUAL_QUICK:
+ case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
+ // Since we replaced the method index, we ask the verifier to tell us which
+ // method is invoked at this location.
+ mirror::AbstractMethod* method =
+ verifier::MethodVerifier::FindInvokedMethodAtDexPc(throw_location.GetMethod(),
+ throw_location.GetDexPc());
+ if (method != NULL) {
+ // NPE with precise message.
+ ThrowNullPointerExceptionForMethodAccess(throw_location, method, kVirtual);
+ } else {
+ // NPE with imprecise message.
+ ThrowNullPointerException(&throw_location,
+ "Attempt to invoke a virtual method on a null object reference");
+ }
+ break;
+ }
+ case Instruction::IGET:
+ case Instruction::IGET_WIDE:
+ case Instruction::IGET_OBJECT:
+ case Instruction::IGET_BOOLEAN:
+ case Instruction::IGET_BYTE:
+ case Instruction::IGET_CHAR:
+ case Instruction::IGET_SHORT: {
+ mirror::Field* field =
+ Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(),
+ throw_location.GetMethod(), false);
+ ThrowNullPointerExceptionForFieldAccess(throw_location, field, true /* read */);
+ break;
+ }
+ case Instruction::IGET_QUICK:
+ case Instruction::IGET_WIDE_QUICK:
+ case Instruction::IGET_OBJECT_QUICK: {
+ // Since we replaced the field index, we ask the verifier to tell us which
+ // field is accessed at this location.
+ mirror::Field* field =
+ verifier::MethodVerifier::FindAccessedFieldAtDexPc(throw_location.GetMethod(),
+ throw_location.GetDexPc());
+ if (field != NULL) {
+ // NPE with precise message.
+ ThrowNullPointerExceptionForFieldAccess(throw_location, field, true /* read */);
+ } else {
+ // NPE with imprecise message.
+ ThrowNullPointerException(&throw_location,
+ "Attempt to read from a field on a null object reference");
+ }
+ break;
+ }
+ case Instruction::IPUT:
+ case Instruction::IPUT_WIDE:
+ case Instruction::IPUT_OBJECT:
+ case Instruction::IPUT_BOOLEAN:
+ case Instruction::IPUT_BYTE:
+ case Instruction::IPUT_CHAR:
+ case Instruction::IPUT_SHORT: {
+ mirror::Field* field =
+ Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(),
+ throw_location.GetMethod(), false);
+ ThrowNullPointerExceptionForFieldAccess(throw_location, field, false /* write */);
+ break;
+ }
+ case Instruction::IPUT_QUICK:
+ case Instruction::IPUT_WIDE_QUICK:
+ case Instruction::IPUT_OBJECT_QUICK: {
+ // Since we replaced the field index, we ask the verifier to tell us which
+ // field is accessed at this location.
+ mirror::Field* field =
+ verifier::MethodVerifier::FindAccessedFieldAtDexPc(throw_location.GetMethod(),
+ throw_location.GetDexPc());
+ if (field != NULL) {
+ // NPE with precise message.
+ ThrowNullPointerExceptionForFieldAccess(throw_location, field, false /* write */);
+ } else {
+ // NPE with imprecise message.
+ ThrowNullPointerException(&throw_location,
+ "Attempt to write to a field on a null object reference");
+ }
+ break;
+ }
+ case Instruction::AGET:
+ case Instruction::AGET_WIDE:
+ case Instruction::AGET_OBJECT:
+ case Instruction::AGET_BOOLEAN:
+ case Instruction::AGET_BYTE:
+ case Instruction::AGET_CHAR:
+ case Instruction::AGET_SHORT:
+ ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL,
+ "Attempt to read from null array");
+ break;
+ case Instruction::APUT:
+ case Instruction::APUT_WIDE:
+ case Instruction::APUT_OBJECT:
+ case Instruction::APUT_BOOLEAN:
+ case Instruction::APUT_BYTE:
+ case Instruction::APUT_CHAR:
+ case Instruction::APUT_SHORT:
+ ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL,
+ "Attempt to write to null array");
+ break;
+ case Instruction::ARRAY_LENGTH:
+ ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL,
+ "Attempt to get length of null array");
+ break;
+ default: {
+ // TODO: We should have covered all the cases where we expect a NPE above, this
+ // message/logging is so we can improve any cases we've missed in the future.
+ const DexFile& dex_file =
+ *throw_location.GetMethod()->GetDeclaringClass()->GetDexCache()->GetDexFile();
+ ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL,
+ StringPrintf("Null pointer exception during instruction '%s'",
+ instr->DumpString(&dex_file).c_str()).c_str());
+ break;
+ }
+ }
+}
+
+void ThrowNullPointerException(const ThrowLocation* throw_location, const char* msg) {
+ ThrowException(throw_location, "Ljava/lang/NullPointerException;", NULL, msg);
+}
+
+// RuntimeException
+
+void ThrowRuntimeException(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ ThrowException(NULL, "Ljava/lang/RuntimeException;", NULL, fmt, &args);
+ va_end(args);
+}
+
+// VerifyError
+
+void ThrowVerifyError(const mirror::Class* referrer, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ ThrowException(NULL, "Ljava/lang/VerifyError;", referrer, fmt, &args);
+ va_end(args);
+}
+
+} // namespace art