summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ian Rogers <irogers@google.com> 2012-03-15 01:42:12 -0700
committer Ian Rogers <irogers@google.com> 2012-03-15 01:51:33 -0700
commit98d39884f64d13aada5e716bb38e2f069c7ad0a7 (patch)
treea4b110f88872719da560e8c3708bd5f597c3e6e0
parentf7d9ad39541dd09030e26d54d3b73a076f90cc74 (diff)
Add detail message to null pointer exceptions.
Remove redundant location of NPE in detail message of throw NPE for method access as the information is available via the stack. Change-Id: Iee3400c21a0348f6c4e7530b990bc546a80a513c
-rw-r--r--src/runtime_support.cc79
-rw-r--r--src/runtime_support_common.h5
-rw-r--r--test/034-call-null/expected.txt2
-rw-r--r--test/038-inner-null/expected.txt2
4 files changed, 79 insertions, 9 deletions
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index f5edebf12a..2ecb02e37b 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -108,10 +108,81 @@ extern "C" void artDeliverPendingExceptionFromCode(Thread* thread, Method** sp)
}
// Called by generated call to throw a NPE exception
-extern "C" void artThrowNullPointerExceptionFromCode(Thread* thread, Method** sp) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
- thread->ThrowNewException("Ljava/lang/NullPointerException;", NULL);
- thread->DeliverException();
+extern "C" void artThrowNullPointerExceptionFromCode(Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+ Frame fr = self->GetTopOfStack();
+ uintptr_t throw_native_pc = fr.GetReturnPC();
+ fr.Next();
+ Method* throw_method = fr.GetMethod();
+ uint32_t dex_pc = throw_method->ToDexPC(throw_native_pc - 2);
+ const DexFile::CodeItem* code = MethodHelper(throw_method).GetCodeItem();
+ CHECK_LT(dex_pc, code->insns_size_in_code_units_);
+ const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
+ DecodedInstruction dec_insn(instr);
+ switch (instr->Opcode()) {
+ case Instruction::INVOKE_DIRECT:
+ case Instruction::INVOKE_DIRECT_RANGE:
+ ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kDirect);
+ break;
+ case Instruction::INVOKE_VIRTUAL:
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kVirtual);
+ 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: {
+ Field* field =
+ Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
+ ThrowNullPointerExceptionForFieldAccess(self, field, true /* read */);
+ 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: {
+ Field* field =
+ Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
+ ThrowNullPointerExceptionForFieldAccess(self, field, false /* write */);
+ 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:
+ self->ThrowNewException("Ljava/lang/NullPointerException;",
+ "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:
+ self->ThrowNewException("Ljava/lang/NullPointerException;",
+ "Attempt to write to null array");
+ break;
+ default: {
+ const DexFile& dex_file = Runtime::Current()->GetClassLinker()
+ ->FindDexFile(throw_method->GetDeclaringClass()->GetDexCache());
+ std::string message("Null pointer exception during instruction '");
+ message += instr->DumpString(&dex_file);
+ message += "'";
+ self->ThrowNewException("Ljava/lang/NullPointerException;", message.c_str());
+ break;
+ }
+ }
+ self->DeliverException();
}
// Called by generated call to throw an arithmetic divide by zero exception
diff --git a/src/runtime_support_common.h b/src/runtime_support_common.h
index 8ef9d93657..c5121a99fe 100644
--- a/src/runtime_support_common.h
+++ b/src/runtime_support_common.h
@@ -104,10 +104,9 @@ static inline void ThrowNullPointerExceptionForMethodAccess(Thread* self,
std::ostringstream type_stream;
type_stream << type;
self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
- "Attempt to invoke %s method '%s' from '%s' on a null object reference",
+ "Attempt to invoke %s method '%s' on a null object reference",
type_stream.str().c_str(),
- PrettyMethod(method_idx, dex_file, true).c_str(),
- PrettyMethod(caller).c_str());
+ PrettyMethod(method_idx, dex_file, true).c_str());
}
// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
diff --git a/test/034-call-null/expected.txt b/test/034-call-null/expected.txt
index 582b35e10d..7ed221575a 100644
--- a/test/034-call-null/expected.txt
+++ b/test/034-call-null/expected.txt
@@ -1,2 +1,2 @@
-java.lang.NullPointerException
+java.lang.NullPointerException: Attempt to invoke direct method 'Main.doStuff()V' on a null object reference
at Main.main(Main.java:26)
diff --git a/test/038-inner-null/expected.txt b/test/038-inner-null/expected.txt
index d3aab89c7f..37f984c295 100644
--- a/test/038-inner-null/expected.txt
+++ b/test/038-inner-null/expected.txt
@@ -1,4 +1,4 @@
new Special()
-java.lang.NullPointerException
+java.lang.NullPointerException: Attempt to invoke virtual method 'Main$Blort.repaint()V' on a null object reference
at Main$Special.callInner(Main.java:31)
at Main.main(Main.java:20)