Fix NPE message in LLVM.
Change-Id: Ie65060d065d747a6c9ad22c61d5fb29f6cf3c249
diff --git a/src/compiler_llvm/art_module.ll b/src/compiler_llvm/art_module.ll
index 874377e..434aa7b 100644
--- a/src/compiler_llvm/art_module.ll
+++ b/src/compiler_llvm/art_module.ll
@@ -57,7 +57,7 @@
declare void @art_throw_div_zero_from_code()
declare void @art_throw_array_bounds_from_code(i32, i32)
declare void @art_throw_no_such_method_from_code(i32)
-declare void @art_throw_null_pointer_exception_from_code()
+declare void @art_throw_null_pointer_exception_from_code(i32)
declare void @art_throw_stack_overflow_from_code()
declare void @art_throw_exception_from_code(%JavaObject*)
diff --git a/src/compiler_llvm/generated/art_module.cc b/src/compiler_llvm/generated/art_module.cc
index 2e46efc..52048eb 100644
--- a/src/compiler_llvm/generated/art_module.cc
+++ b/src/compiler_llvm/generated/art_module.cc
@@ -412,7 +412,7 @@
Function* func_art_throw_null_pointer_exception_from_code = mod->getFunction("art_throw_null_pointer_exception_from_code");
if (!func_art_throw_null_pointer_exception_from_code) {
func_art_throw_null_pointer_exception_from_code = Function::Create(
- /*Type=*/FuncTy_5,
+ /*Type=*/FuncTy_9,
/*Linkage=*/GlobalValue::ExternalLinkage,
/*Name=*/"art_throw_null_pointer_exception_from_code", mod); // (external, no body)
func_art_throw_null_pointer_exception_from_code->setCallingConv(CallingConv::C);
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index f4bc3c2..615e600 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -3776,7 +3776,7 @@
irb_.SetInsertPoint(block_exception);
EmitUpdateLineNumFromDexPC(dex_pc);
- irb_.CreateCall(irb_.GetRuntime(ThrowNullPointerException));
+ irb_.CreateCall(irb_.GetRuntime(ThrowNullPointerException), irb_.getInt32(dex_pc));
EmitBranchExceptionLandingPad(dex_pc);
irb_.SetInsertPoint(block_continue);
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 57fd507..36343f7 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -16,6 +16,7 @@
#include "class_linker.h"
#include "dex_verifier.h"
+#include "nth_caller_visitor.h"
#include "object.h"
#include "object_utils.h"
#include "runtime_support.h"
@@ -108,9 +109,12 @@
false).c_str());
}
-void art_throw_null_pointer_exception_from_code() {
+void art_throw_null_pointer_exception_from_code(uint32_t dex_pc) {
Thread* thread = Thread::Current();
- thread->ThrowNewException("Ljava/lang/NullPointerException;", NULL);
+ NthCallerVisitor visitor(0);
+ thread->WalkStack(&visitor);
+ Method* throw_method = visitor.caller;
+ ThrowNullPointerExceptionFromDexPC(thread, throw_method, dex_pc);
}
void art_throw_stack_overflow_from_code() {
diff --git a/src/compiler_llvm/runtime_support_llvm.h b/src/compiler_llvm/runtime_support_llvm.h
index 1040b90..1dbd71d 100644
--- a/src/compiler_llvm/runtime_support_llvm.h
+++ b/src/compiler_llvm/runtime_support_llvm.h
@@ -43,7 +43,7 @@
void art_throw_no_such_method_from_code(int32_t method_idx);
-void art_throw_null_pointer_exception_from_code();
+void art_throw_null_pointer_exception_from_code(uint32_t dex_pc);
void art_throw_stack_overflow_from_code();
diff --git a/src/dalvik_system_VMStack.cc b/src/dalvik_system_VMStack.cc
index 8401ec1..e0862c3 100644
--- a/src/dalvik_system_VMStack.cc
+++ b/src/dalvik_system_VMStack.cc
@@ -47,7 +47,7 @@
static jobject VMStack_getCallingClassLoader(JNIEnv* env, jclass) {
NthCallerVisitor visitor(2);
Thread::Current()->WalkStack(&visitor);
- return AddLocalReference<jobject>(env, visitor.class_loader);
+ return AddLocalReference<jobject>(env, visitor.caller->GetDeclaringClass()->GetClassLoader());
}
static jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass, jobject javaBootstrap, jobject javaSystem) {
@@ -79,7 +79,7 @@
static jclass VMStack_getStackClass2(JNIEnv* env, jclass) {
NthCallerVisitor visitor(3);
Thread::Current()->WalkStack(&visitor);
- return AddLocalReference<jclass>(env, visitor.declaring_class);
+ return AddLocalReference<jclass>(env, visitor.caller->GetDeclaringClass());
}
static jobjectArray VMStack_getThreadStackTrace(JNIEnv* env, jclass, jobject javaThread) {
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index c1d6eb0..2cd7090 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -426,7 +426,7 @@
NthCallerVisitor visitor(2);
Thread::Current()->WalkStack(&visitor);
- Class* caller_class = visitor.declaring_class;
+ Class* caller_class = visitor.caller->GetDeclaringClass();
ClassHelper caller_ch(caller_class);
if (!caller_class->CanAccess(c)) {
diff --git a/src/nth_caller_visitor.h b/src/nth_caller_visitor.h
index 6f82fa9..07b9e49 100644
--- a/src/nth_caller_visitor.h
+++ b/src/nth_caller_visitor.h
@@ -24,21 +24,18 @@
// Walks up the stack 'n' callers, when used with Thread::WalkStack.
struct NthCallerVisitor : public Thread::StackVisitor {
- NthCallerVisitor(size_t n) : n(n), count(0), declaring_class(NULL), class_loader(NULL) {}
+ NthCallerVisitor(size_t n) : n(n), count(0), caller(NULL) {}
bool VisitFrame(const Frame& f, uintptr_t) {
- DCHECK(class_loader == NULL);
+ DCHECK(caller == NULL);
if (count++ == n) {
- Method* m = f.GetMethod();
- declaring_class = m->GetDeclaringClass();
- class_loader = declaring_class->GetClassLoader();
+ caller = f.GetMethod();
return false;
}
return true;
}
size_t n;
size_t count;
- Class* declaring_class;
- Object* class_loader;
+ Method* caller;
};
} // namespace art
diff --git a/src/oat/runtime/support_throw.cc b/src/oat/runtime/support_throw.cc
index 45600fd..7d198c9 100644
--- a/src/oat/runtime/support_throw.cc
+++ b/src/oat/runtime/support_throw.cc
@@ -55,73 +55,7 @@
frame.Next();
Method* throw_method = frame.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;
- }
- }
+ ThrowNullPointerExceptionFromDexPC(self, throw_method, dex_pc);
self->DeliverException();
}
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 7b907ae..40b43c1 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -106,6 +106,76 @@
PrettyMethod(method_idx, dex_file, true).c_str());
}
+void ThrowNullPointerExceptionFromDexPC(Thread* self, Method* throw_method, uint32_t dex_pc) {
+ 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;
+ }
+ }
+}
+
std::string FieldNameFromIndex(const Method* method, uint32_t ref,
verifier::VerifyErrorRefType ref_type, bool access) {
CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_FIELD));
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 0229bc1..0cbfd59 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -54,6 +54,7 @@
void ThrowNullPointerExceptionForFieldAccess(Thread* self, Field* field, bool is_read);
void ThrowNullPointerExceptionForMethodAccess(Thread* self, Method* caller, uint32_t method_idx,
InvokeType type);
+void ThrowNullPointerExceptionFromDexPC(Thread* self, Method* caller, uint32_t dex_pc);
std::string FieldNameFromIndex(const Method* method, uint32_t ref,
verifier::VerifyErrorRefType ref_type, bool access);