Fix DexFile's line number and test EH and StackTraceElement in 3 ways.

Testing exception handling: 1. Walking stack 10 levels and then check
depth == 10. 2. Check if correct stack trace is being generated. 3. For
native frame, lineno should be -2 to indicate it is native. Note that
"line number == -2" is how libcore tells from StackTraceElement.

Change-Id: If38c16a59624f259985bcfcebc337b73b0582460
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 231b4be..f782fe9 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -540,6 +540,12 @@
 }
 
 int32_t DexFile::GetLineNumFromPC(const art::Method* method, uint32_t rel_pc) const {
+  // For native method, lineno should be -2 to indicate it is native. Note that
+  // "line number == -2" is how libcore tells from StackTraceElement.
+  if (method->code_off_ == 0) {
+    return -2;
+  }
+
   const CodeItem* code_item = GetCodeItem(method->code_off_);
   DCHECK(code_item != NULL);
 
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 259c0a4..cc5e3e0 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -157,17 +157,14 @@
                trace_array->Get(0)->GetDeclaringClass()->ToModifiedUtf8().c_str());
   EXPECT_STREQ("MyClass.java", trace_array->Get(0)->GetFileName()->ToModifiedUtf8().c_str());
   EXPECT_STREQ("g", trace_array->Get(0)->GetMethodName()->ToModifiedUtf8().c_str());
-  EXPECT_EQ(22u, trace_array->Get(0)->GetLineNumber());
+  EXPECT_EQ(22, trace_array->Get(0)->GetLineNumber());
 
   ASSERT_TRUE(trace_array->Get(1) != NULL);
   EXPECT_STREQ("java.lang.MyClass",
                trace_array->Get(1)->GetDeclaringClass()->ToModifiedUtf8().c_str());
   EXPECT_STREQ("MyClass.java", trace_array->Get(1)->GetFileName()->ToModifiedUtf8().c_str());
   EXPECT_STREQ("f", trace_array->Get(1)->GetMethodName()->ToModifiedUtf8().c_str());
-  EXPECT_EQ(7u, trace_array->Get(1)->GetLineNumber());
+  EXPECT_EQ(7, trace_array->Get(1)->GetLineNumber());
 }
 
-// TODO: Test with native frame: For native frame, lineno should be -2 to
-// indicate it is native. That is how libcore tells from the StackTraceElement.
-
 }  // namespace art
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index ce0bb51..9129162 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -376,4 +376,34 @@
   EXPECT_EQ(1, gExceptionHandler_calls);
 }
 
+jint Java_MyClass_nativeUpCall(JNIEnv* env, jobject thisObj, jint i) {
+  if (i <= 0) {
+    ObjectArray<StackTraceElement>* trace_array = Thread::Current()->AllocStackTrace();
+    EXPECT_TRUE(trace_array != NULL);
+    EXPECT_EQ(11, trace_array->GetLength());
+
+    for (int32_t i = 0; i < trace_array->GetLength(); ++i) {
+      EXPECT_EQ(-2, trace_array->Get(i)->GetLineNumber());
+      EXPECT_STREQ("MyClassNatives.java", trace_array->Get(i)->GetFileName()->ToModifiedUtf8().c_str());
+      EXPECT_STREQ("MyClass", trace_array->Get(i)->GetDeclaringClass()->ToModifiedUtf8().c_str());
+      EXPECT_STREQ("fooI", trace_array->Get(i)->GetMethodName()->ToModifiedUtf8().c_str());
+    }
+    return 0;
+  } else {
+    jclass jklass = env->FindClass("MyClass");
+    EXPECT_TRUE(jklass != NULL);
+    jmethodID jmethod = env->GetMethodID(jklass, "fooI", "(I)I");
+    EXPECT_TRUE(jmethod != NULL);
+
+    jint result = env->CallNonvirtualIntMethod(thisObj, jklass, jmethod, i - 1);
+    return i + result;
+  }
+}
+
+TEST_F(JniCompilerTest, NativeStackTraceElement) {
+  SetupForTest(false, "fooI", "(I)I", reinterpret_cast<void*>(&Java_MyClass_nativeUpCall));
+  jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 10);
+  EXPECT_EQ(55, result);
+}
+
 }  // namespace art
diff --git a/src/object.h b/src/object.h
index 8a186e1..1df10ad 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1724,12 +1724,12 @@
     return file_name_;
   }
 
-  uint32_t GetLineNumber() const {
+  int32_t GetLineNumber() const {
     return line_number_;
   }
 
   static StackTraceElement* Alloc(const String* declaring_class, const String* method_name,
-                                  const String* file_name, uint32_t line_number) {
+                                  const String* file_name, int32_t line_number) {
     StackTraceElement* trace = down_cast<StackTraceElement*>(GetStackTraceElement()->NewInstance());
     trace->declaring_class_ = declaring_class;
     trace->method_name_ = method_name;
@@ -1746,7 +1746,7 @@
   const String* declaring_class_;
   const String* method_name_;
   const String* file_name_;
-  uint32_t line_number_;
+  int32_t line_number_;
 
   static Class* GetStackTraceElement() {
     DCHECK(java_lang_StackTraceElement_ != NULL);