Stack Trace Element with its unit test added too.

The unit test passes.

Change-Id: I6f6af771cae1387c60c3b511148a347fe3237345
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 3907d07..3c72dad 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -30,6 +30,7 @@
   "Ljava/lang/ClassLoader;",
   "Ldalvik/system/BaseDexClassLoader;",
   "Ldalvik/system/PathClassLoader;",
+  "Ljava/lang/StackTraceElement;",
   "Z",
   "B",
   "C",
@@ -47,6 +48,7 @@
   "[I",
   "[J",
   "[S",
+  "[Ljava/lang/StackTraceElement;",
 };
 
 ClassLinker* ClassLinker::Create(const std::vector<const DexFile*>& boot_class_path, Space* space) {
@@ -237,12 +239,15 @@
   SetClassRoot(kFloatArrayClass, FindSystemClass("[F"));
   SetClassRoot(kLongArrayClass, FindSystemClass("[J"));
   SetClassRoot(kShortArrayClass, FindSystemClass("[S"));
+  SetClassRoot(kJavaLangStackTraceElement, FindSystemClass("Ljava/lang/StackTraceElement;"));
+  SetClassRoot(kJavaLangStackTraceElementArrayClass, FindSystemClass("[Ljava/lang/StackTraceElement;"));
   BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
   ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
   DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
   FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
   LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
   ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
+  StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
 
   FinishInit();
 }
@@ -342,6 +347,7 @@
   LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
   ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
   PathClassLoader::SetClass(GetClassRoot(kDalvikSystemPathClassLoader));
+  StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
 
   FinishInit();
 }
@@ -415,6 +421,7 @@
   LongArray::ResetArrayClass();
   ShortArray::ResetArrayClass();
   PathClassLoader::ResetClass();
+  StackTraceElement::ResetClass();
 }
 
 DexCache* ClassLinker::AllocDexCache(const DexFile& dex_file) {
@@ -446,6 +453,12 @@
   return down_cast<Method*>(GetClassRoot(kJavaLangReflectMethod)->NewInstance());
 }
 
+ObjectArray<StackTraceElement>* ClassLinker::AllocStackTraceElementArray(size_t length) {
+  return ObjectArray<StackTraceElement>::Alloc(
+      GetClassRoot(kJavaLangStackTraceElementArrayClass),
+      length);
+}
+
 Class* ClassLinker::FindClass(const StringPiece& descriptor,
                               const ClassLoader* class_loader) {
   // TODO: remove this contrived parent class loader check when we have a real ClassLoader.
diff --git a/src/class_linker.h b/src/class_linker.h
index c848825..88e1a67 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -104,6 +104,8 @@
   const DexFile& FindDexFile(const DexCache* dex_cache) const;
   DexCache* FindDexCache(const DexFile& dex_file) const;
 
+  ObjectArray<StackTraceElement>* AllocStackTraceElementArray(size_t length);
+
  private:
   ClassLinker();
 
@@ -239,6 +241,7 @@
     kJavaLangClassLoader,
     kDalvikSystemBaseDexClassLoader,
     kDalvikSystemPathClassLoader,
+    kJavaLangStackTraceElement,
     kPrimitiveBoolean,
     kPrimitiveByte,
     kPrimitiveChar,
@@ -256,6 +259,7 @@
     kIntArrayClass,
     kLongArrayClass,
     kShortArrayClass,
+    kJavaLangStackTraceElementArrayClass,
     kClassRootsMax,
   };
   ObjectArray<Class>* class_roots_;
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 3489086..01eb099 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -532,7 +532,10 @@
   return static_cast<ValueType>(type);
 }
 
-String* DexFile::dexArtStringById(uint32_t idx) const {
+String* DexFile::dexArtStringById(int32_t idx) const {
+  if (idx == -1) {
+    return NULL;
+  }
   return String::AllocFromModifiedUtf8(dexStringById(idx));
 }
 
diff --git a/src/dex_file.h b/src/dex_file.h
index 2dcb3b2..db7a54b 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -535,7 +535,7 @@
     return dexStringById(idx, &unicode_length);
   }
 
-  String* dexArtStringById(uint32_t idx) const;
+  String* dexArtStringById(int32_t idx) const;
 
   // Get the descriptor string associated with a given type index.
   const char* dexStringByTypeIdx(uint32_t idx, int32_t* unicode_length) const {
@@ -548,7 +548,7 @@
     return dexStringById(type_id.descriptor_idx_);
   }
 
-  String* dexArtStringByTypeIdx(uint32_t idx) const {
+  String* dexArtStringByTypeIdx(int32_t idx) const {
     const TypeId& type_id = GetTypeId(idx);
     return dexArtStringById(type_id.descriptor_idx_);
   }
diff --git a/src/exception.h b/src/exception.h
deleted file mode 100644
index 5b31e86..0000000
--- a/src/exception.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2011 Google Inc. All Rights Reserved.
-
-#ifndef ART_SRC_EXCEPTION_H_
-#define ART_SRC_EXCEPTION_H_
-
-#include "class_linker.h"
-#include "dex_file.h"
-#include "object.h"
-#include "thread.h"
-
-namespace art {
-
-struct InternalStackTrace {
-  const Method* method;
-  const uint16_t* pc;
-};
-
-extern InternalStackTrace *GetStackTrace(uint16_t stack_depth);
-
-}
-
-#endif  // ART_SRC_EXCEPTION_H_
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 99fd954..4337d7a 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -73,8 +73,12 @@
     ASSERT_TRUE(my_klass_ != NULL);
     method_f_ = my_klass_->FindVirtualMethod("f", "()I");
     ASSERT_TRUE(method_f_ != NULL);
+    method_f_->SetFrameSizeInBytes(8);
+    method_f_->SetReturnPcOffsetInBytes(4);
     method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
     ASSERT_TRUE(method_g_ != NULL);
+    method_g_->SetFrameSizeInBytes(8);
+    method_g_->SetReturnPcOffsetInBytes(4);
   }
 
   DexFile::CatchHandlerItem FindCatchHandlerItem(Method* method,
@@ -132,4 +136,36 @@
   ASSERT_EQ(true, iter.HasNext());
 }
 
+TEST_F(ExceptionTest, StackTraceElement) {
+  enum {STACK_SIZE = 1000};
+  uint32_t top_of_stack = 0;
+  uintptr_t fake_stack[STACK_SIZE];
+  fake_stack[top_of_stack++] = reinterpret_cast<uintptr_t>(method_g_);
+  fake_stack[top_of_stack++] = 3;
+  fake_stack[top_of_stack++] = reinterpret_cast<uintptr_t>(method_f_);
+  fake_stack[top_of_stack++] = 3;
+
+  Thread* thread = Thread::Current();
+  thread->SetTopOfStack(fake_stack);
+
+  Thread::InternalStackTrace* traces = thread->GetStackTrace(2);
+  ObjectArray<StackTraceElement>* trace_array = thread->GetStackTraceElement(2, traces);
+  delete[] traces;
+
+  ASSERT_TRUE(trace_array->Get(0) != NULL);
+  EXPECT_STREQ("java.lang.MyClass", 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());
+
+  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());
+}
+
+// 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/object.cc b/src/object.cc
index 5d64466..175e687 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -602,6 +602,19 @@
   dalvik_system_PathClassLoader_ = NULL;
 }
 
+Class* StackTraceElement::java_lang_StackTraceElement_ = NULL;
+
+void StackTraceElement::SetClass(Class* java_lang_StackTraceElement) {
+  CHECK(java_lang_StackTraceElement_ == NULL);
+  CHECK(java_lang_StackTraceElement != NULL);
+  java_lang_StackTraceElement_ = java_lang_StackTraceElement;
+}
+
+void StackTraceElement::ResetClass() {
+  CHECK(java_lang_StackTraceElement_ != NULL);
+  java_lang_StackTraceElement_ = NULL;
+}
+
 static const char* kClassStatusNames[] = {
   "Error",
   "NotReady",
diff --git a/src/object.h b/src/object.h
index 6c8fd6b..e306d74 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1681,6 +1681,53 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(Throwable);
 };
 
+class StackTraceElement : public Object {
+ public:
+  const String* GetDeclaringClass() const {
+    return declaring_class_;
+  }
+
+  const String* GetMethodName() const {
+    return method_name_;
+  }
+
+  const String* GetFileName() const {
+    return file_name_;
+  }
+
+  uint32_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) {
+    StackTraceElement* trace = down_cast<StackTraceElement*>(GetStackTraceElement()->NewInstance());
+    trace->declaring_class_ = declaring_class;
+    trace->method_name_ = method_name;
+    trace->file_name_ = file_name;
+    trace->line_number_ = line_number;
+    return trace;
+  }
+
+  static void SetClass(Class* java_lang_StackTraceElement);
+
+  static void ResetClass();
+
+ private:
+  const String* declaring_class_;
+  const String* method_name_;
+  const String* file_name_;
+  uint32_t line_number_;
+
+  static Class* GetStackTraceElement() {
+    DCHECK(java_lang_StackTraceElement_ != NULL);
+    return java_lang_StackTraceElement_;
+  }
+
+  static Class* java_lang_StackTraceElement_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StackTraceElement);
+};
+
 inline bool Object::IsString() const {
   // TODO use "klass_ == String::GetJavaLangString()" instead?
   return klass_ == klass_->descriptor_->klass_;
diff --git a/src/thread.cc b/src/thread.cc
index 2f43e23..047c89d 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -119,10 +119,10 @@
   sp_ = reinterpret_cast<const Method**>(next_sp);
 }
 
-void* Frame::GetPC() const {
+uintptr_t Frame::GetPC() const {
   byte* pc_addr = reinterpret_cast<byte*>(sp_) +
       GetMethod()->GetReturnPcOffsetInBytes();
-  return reinterpret_cast<void*>(pc_addr);
+  return *reinterpret_cast<uintptr_t*>(pc_addr);
 }
 
 const Method* Frame::NextMethod() const {
@@ -309,6 +309,38 @@
   return result;
 }
 
+// TODO: Replaces trace.method and trace.pc with IntArray nad
+// ObjectArray<Method>.
+Thread::InternalStackTrace* Thread::GetStackTrace(uint16_t length) {
+  Frame frame = Thread::Current()->GetTopOfStack();
+  InternalStackTrace *traces = new InternalStackTrace[length];
+  for (uint16_t i = 0; i < length && frame.HasNext(); ++i, frame.Next()) {
+    traces[i].method = frame.GetMethod();
+    traces[i].pc = frame.GetPC();
+  }
+  return traces;
+}
+
+ObjectArray<StackTraceElement>* Thread::GetStackTraceElement(uint16_t length, InternalStackTrace *raw_trace) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  ObjectArray<StackTraceElement>* java_traces = class_linker->AllocStackTraceElementArray(length);
+
+  for (uint16_t i = 0; i < length; ++i) {
+    // Prepare parameter for StackTraceElement(String cls, String method, String file, int line)
+    const Method* method = raw_trace[i].method;
+    const Class* klass = method->GetDeclaringClass();
+    const DexFile& dex_file = class_linker->FindDexFile(klass->GetDexCache());
+    String* readable_descriptor = String::AllocFromModifiedUtf8(PrettyDescriptor(klass->GetDescriptor()).c_str());
+
+    StackTraceElement* obj =
+        StackTraceElement::Alloc(readable_descriptor,
+                                 method->GetName(), String::AllocFromModifiedUtf8(klass->source_file_),
+                                 dex_file.GetLineNumFromPC(method, method->ToDexPC(raw_trace[i].pc)));
+    java_traces->Set(i, obj);
+  }
+  return java_traces;
+}
+
 void Thread::ThrowNewException(const char* exception_class_descriptor, const char* fmt, ...) {
   std::string msg;
   va_list args;
diff --git a/src/thread.h b/src/thread.h
index e8ca156..8a3a49b 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -27,6 +27,8 @@
 class Thread;
 class ThreadList;
 class Throwable;
+class StackTraceElement;
+template<class T> class ObjectArray;
 
 class Mutex {
  public:
@@ -131,7 +133,7 @@
 
   void Next();
 
-  void* GetPC() const;
+  uintptr_t GetPC() const;
 
   const Method** GetSP() const {
     return sp_;
@@ -388,6 +390,16 @@
     class_loader_override_ = class_loader_override;
   }
 
+  struct InternalStackTrace {
+    const Method* method;
+    uintptr_t pc;
+  };
+
+  // Get the top length frames information
+  InternalStackTrace* GetStackTrace(uint16_t length);
+
+  ObjectArray<StackTraceElement>* GetStackTraceElement(uint16_t length, InternalStackTrace *raw_trace);
+
  private:
   Thread()
       : id_(1234),