Exception Handling: libdex integration. Also added unit test on exception.

Runtime processing of TryItem and CatchHandler. Added iterator.

Next step: Exception Handling: RT integration. Implement throw and
unwind.

Change-Id: Idf88ce83e37b004016f1eca2c621e5a86948fe91
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 9053d57..2aed455 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -489,6 +489,7 @@
     dst->descriptor_ = String::AllocFromModifiedUtf8(utf16_length, utf8.get());
   }
   dst->proto_idx_ = method_id.proto_idx_;
+  dst->code_off_ = src.code_off_;
   dst->shorty_ = dex_file.GetShorty(method_id.proto_idx_);
   dst->access_flags_ = src.access_flags_;
 
@@ -499,7 +500,6 @@
     dst->num_registers_ = code_item->registers_size_;
     dst->num_ins_ = code_item->ins_size_;
     dst->num_outs_ = code_item->outs_size_;
-    dst->insns_ = code_item->insns_;
   } else {
     uint16_t num_args = dst->NumArgRegisters();
     if (!dst->IsStatic()) {
@@ -1340,7 +1340,9 @@
   for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
     Method* method = klass->GetVirtualMethod(i);
     if (method->IsAbstract()) {
-      method->insns_ = reinterpret_cast<uint16_t*>(0xFFFFFFFF);  // TODO: AbstractMethodError
+      LG << "AbstractMethodError";
+      method->code_off_ = 0xFFFFFFFF;
+      // TODO: throw AbstractMethodError
     }
   }
 }
diff --git a/src/class_linker.h b/src/class_linker.h
index edd48eb..fa50537 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -201,6 +201,7 @@
   FRIEND_TEST(DexCacheTest, Open);
   friend class ObjectTest;
   FRIEND_TEST(ObjectTest, AllocObjectArray);
+  FRIEND_TEST(ExceptionTest, MyClass_F_G);
   DISALLOW_COPY_AND_ASSIGN(ClassLinker);
 };
 
diff --git a/src/dex_file.h b/src/dex_file.h
index 014bd6e..373ec51 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -12,6 +12,7 @@
 #include "scoped_ptr.h"
 #include "stringpiece.h"
 #include "strutil.h"
+#include "utils.h"
 
 namespace art {
 
@@ -183,6 +184,11 @@
     uint16_t insns_[1];
   };
 
+  struct CatchHandlerItem {
+    uint32_t type_idx_;    // type index of the caught exception type
+    uint32_t address_;     // handler address
+  };
+
   // Raw try_item.
   struct TryItem {
     uint32_t start_addr_;
@@ -190,6 +196,64 @@
     uint16_t handler_off_;
   };
 
+  class CatchHandlerIterator {
+    public:
+      CatchHandlerIterator() {
+        remaining_count_ = -1;
+        catch_all_ = false;
+      }
+
+      CatchHandlerIterator(const byte* handler_data) {
+        current_data_ = handler_data;
+        remaining_count_ = DecodeUnsignedLeb128(&current_data_);
+
+        // If remaining_count_ is non-positive, then it is the negative of
+        // the number of catch types, and the catches are followed by a
+        // catch-all handler.
+        if (remaining_count_ <= 0) {
+          catch_all_ = true;
+          remaining_count_ = -remaining_count_;
+        } else {
+          catch_all_ = false;
+        }
+        Next();
+      }
+
+      CatchHandlerItem& Get() {
+        return handler_;
+      }
+
+      void Next() {
+        if (remaining_count_ > 0) {
+          handler_.type_idx_ = DecodeUnsignedLeb128(&current_data_);
+          handler_.address_  = DecodeUnsignedLeb128(&current_data_);
+          remaining_count_--;
+          return;
+        }
+
+        if (catch_all_) {
+          handler_.type_idx_ = kDexNoIndex;
+          handler_.address_  = DecodeUnsignedLeb128(&current_data_);
+          catch_all_ = false;
+          return;
+        }
+
+        // no more handler
+        remaining_count_ = -1;
+      }
+
+      bool End() const {
+        return remaining_count_ < 0 && catch_all_ == false;
+      }
+
+    private:
+      CatchHandlerItem handler_;
+      const byte *current_data_;  // the current handlder in dex file.
+      int32_t remaining_count_;   // number of handler not read.
+      bool catch_all_;            // is there a handler that will catch all exceptions in case
+                                  // that all typed handler does not match.
+  };
+
   // Partially decoded form of class_data_item.
   struct ClassDataHeader {
     uint32_t static_fields_size_;  // the number of static fields
@@ -349,10 +413,14 @@
   }
 
   const CodeItem* GetCodeItem(const Method& method) const {
-    if (method.code_off_ == 0) {
+    return GetCodeItem(method.code_off_);
+  }
+
+  const CodeItem* GetCodeItem(const uint32_t code_off_) const {
+    if (code_off_ == 0) {
       return NULL;  // native or abstract method
     } else {
-      const byte* addr = base_ + method.code_off_;
+      const byte* addr = base_ + code_off_;
       return reinterpret_cast<const CodeItem*>(addr);
     }
   }
@@ -449,6 +517,86 @@
     *last_idx = idx;
   }
 
+  const TryItem* dexGetTryItems(const CodeItem& code_item, uint32_t offset) const {
+    const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_];
+    return reinterpret_cast<const TryItem*>
+        (RoundUp(reinterpret_cast<uint32_t>(insns_end_), 4)) + offset;
+  }
+
+  // Get the base of the encoded data for the given DexCode.
+  const byte* dexGetCatchHandlerData(const CodeItem& code_item, uint32_t offset) const {
+    const byte* handler_data = reinterpret_cast<const byte*>
+        (dexGetTryItems(code_item, code_item.tries_size_));
+    return handler_data + offset;
+  }
+
+  // Find the handler associated with a given address, if any.
+  // Initializes the given iterator and returns true if a match is
+  // found. Returns end if there is no applicable handler.
+  CatchHandlerIterator dexFindCatchHandler(const CodeItem& code_item, uint32_t address) const {
+    CatchHandlerItem handler;
+    handler.address_ = -1;
+    int32_t offset = -1;
+
+    // Short-circuit the overwhelmingly common cases.
+    switch (code_item.tries_size_) {
+      case 0:
+        break;
+      case 1: {
+        const TryItem* tries = dexGetTryItems(code_item, 0);
+        uint32_t start = tries->start_addr_;
+        if (address < start)
+          break;
+
+        uint32_t end = start + tries->insn_count_;
+        if (address >= end)
+          break;
+
+        offset = tries->handler_off_;
+        break;
+      }
+      default:
+        offset = dexFindCatchHandlerOffset0(code_item, code_item.tries_size_, address);
+    }
+
+    if (offset >= 0) {
+      const byte* handler_data = dexGetCatchHandlerData(code_item, offset);
+      return CatchHandlerIterator(handler_data);
+    }
+    return CatchHandlerIterator();
+  }
+
+  int32_t dexFindCatchHandlerOffset0(const CodeItem &code_item,
+                                     int32_t tries_size,
+                                     uint32_t address) const {
+    // Note: Signed type is important for max and min.
+    int32_t min = 0;
+    int32_t max = tries_size - 1;
+
+    while (max >= min) {
+      int32_t guess = (min + max) >> 1;
+      const TryItem* pTry = dexGetTryItems(code_item, guess);
+      uint32_t start = pTry->start_addr_;
+
+      if (address < start) {
+        max = guess - 1;
+        continue;
+      }
+
+      uint32_t end = start + pTry->insn_count_;
+      if (address >= end) {
+        min = guess + 1;
+        continue;
+      }
+
+      // We have a winner!
+      return (int32_t) pTry->handler_off_;
+    }
+
+    // No match.
+    return -1;
+  }
+
 
   // TODO: const reference
   uint32_t dexGetIndexForClassDef(const ClassDef* class_def) const {
diff --git a/src/exception_test.cc b/src/exception_test.cc
new file mode 100644
index 0000000..ae1546f
--- /dev/null
+++ b/src/exception_test.cc
@@ -0,0 +1,105 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include <sys/mman.h>
+
+#include "assembler.h"
+#include "class_linker.h"
+#include "common_test.h"
+#include "dex_file.h"
+#include "jni_compiler.h"
+#include "runtime.h"
+#include "thread.h"
+#include "gtest/gtest.h"
+
+namespace art {
+
+// package java.lang;
+// import java.io.IOException;
+// class Object {};
+// public class MyClass {
+//   int f() throws Exception {
+//     try {
+//         g(1);
+//     } catch (IOException e) {
+//         return 1;
+//     } catch (Exception e) {
+//         return 2;
+//     }
+//     try {
+//         g(2);
+//     } catch (IOException e) {
+//         return 3;
+//     }
+//     return 0;
+//   }
+//   void g(int doThrow) throws Exception {
+//     if (doThrow == 1)
+//         throw new Exception();
+//     else if (doThrow == 2)
+//         throw new IOException();
+//   }
+// }
+
+static const char kMyClassExceptionHandleDex[] =
+  "ZGV4CjAzNQC/bXXtLZJLN1GzLr+ncrvPSl70n8t0yAjgAwAAcAAAAHhWNBIAAAAAAAAAACgDAAAN"
+  "AAAAcAAAAAcAAACkAAAAAwAAAMAAAAAAAAAAAAAAAAYAAADkAAAAAgAAABQBAACMAgAAVAEAAD4C"
+  "AABGAgAASQIAAGUCAAB8AgAAkwIAAKgCAAC8AgAAygIAAM0CAADRAgAA1AIAANcCAAABAAAAAgAA"
+  "AAMAAAAEAAAABQAAAAYAAAAIAAAAAQAAAAAAAAAAAAAACAAAAAYAAAAAAAAACQAAAAYAAAA4AgAA"
+  "AgABAAAAAAADAAEAAAAAAAQAAQAAAAAABAAAAAoAAAAEAAIACwAAAAUAAQAAAAAABQAAAAAAAAD/"
+  "////AAAAAAcAAAAAAAAACQMAAAAAAAAEAAAAAQAAAAUAAAAAAAAABwAAABgCAAATAwAAAAAAAAEA"
+  "AAABAwAAAQABAAAAAADeAgAAAQAAAA4AAAABAAEAAQAAAOMCAAAEAAAAcBAFAAAADgAEAAEAAgAC"
+  "AOgCAAAVAAAAEiISERIQbiAEAAMAEiBuIAQAAwASAA8ADQABECj9DQABICj6DQASMCj3AAADAAAA"
+  "AwABAAcAAAADAAYAAgICDAMPAQISAAAAAwACAAEAAAD3AgAAEwAAABIQMwIIACIAAwBwEAEAAAAn"
+  "ABIgMwIIACIAAgBwEAAAAAAnAA4AAAAAAAAAAAAAAAIAAAAAAAAAAwAAAFQBAAAEAAAAVAEAAAEA"
+  "AAAAAAY8aW5pdD4AAUkAGkxkYWx2aWsvYW5ub3RhdGlvbi9UaHJvd3M7ABVMamF2YS9pby9JT0V4"
+  "Y2VwdGlvbjsAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwATTGphdmEvbGFuZy9NeUNsYXNzOwASTGph"
+  "dmEvbGFuZy9PYmplY3Q7AAxNeUNsYXNzLmphdmEAAVYAAlZJAAFmAAFnAAV2YWx1ZQADAAcOAAQA"
+  "Bw4ABwAHLFFOAnYsLR4tIR4AFQEABw48aTxpAAIBAQwcARgDAAABAAWAgATcAgAAAQICgYAE8AID"
+  "AIgDAQDgAwAAAA8AAAAAAAAAAQAAAAAAAAABAAAADQAAAHAAAAACAAAABwAAAKQAAAADAAAAAwAA"
+  "AMAAAAAFAAAABgAAAOQAAAAGAAAAAgAAABQBAAADEAAAAQAAAFQBAAABIAAABAAAAFwBAAAGIAAA"
+  "AQAAABgCAAABEAAAAQAAADgCAAACIAAADQAAAD4CAAADIAAABAAAAN4CAAAEIAAAAQAAAAEDAAAA"
+  "IAAAAgAAAAkDAAAAEAAAAQAAACgDAAA=";
+
+class ExceptionTest : public RuntimeTest {
+};
+
+TEST_F(ExceptionTest, MyClass_F_G) {
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassExceptionHandleDex));
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+  Class* klass = class_linker_->FindClass("Ljava/lang/MyClass;", class_loader);
+  ASSERT_TRUE(klass != NULL);
+
+  Method* method_f = klass->FindVirtualMethod("f", "()I");
+  ASSERT_TRUE(method_f != NULL);
+
+  const DexFile& dex_file = class_linker_->FindDexFile(klass->GetDexCache());
+  const DexFile::CodeItem *code_item = dex_file.GetCodeItem(method_f->code_off_);
+
+  ASSERT_TRUE(code_item != NULL);
+
+  ASSERT_EQ(2u, code_item->tries_size_);
+  ASSERT_NE(0u, code_item->insns_size_);
+
+  const struct DexFile::TryItem *t0, *t1;
+  t0 = dex_file.dexGetTryItems(*code_item, 0);
+  t1 = dex_file.dexGetTryItems(*code_item, 1);
+  EXPECT_LE(t0->start_addr_, t1->start_addr_);
+
+  DexFile::CatchHandlerIterator iter =
+    dex_file.dexFindCatchHandler(*code_item, 4 /* Dex PC in the first try block */);
+  ASSERT_EQ(false, iter.End());
+  EXPECT_STREQ("Ljava/io/IOException;", dex_file.dexStringByTypeIdx(iter.Get().type_idx_));
+  iter.Next();
+  ASSERT_EQ(false, iter.End());
+  EXPECT_STREQ("Ljava/lang/Exception;", dex_file.dexStringByTypeIdx(iter.Get().type_idx_));
+  iter.Next();
+  ASSERT_EQ(true, iter.End());
+
+  iter = dex_file.dexFindCatchHandler(*code_item, 8 /* Dex PC in the second try block */);
+  ASSERT_EQ(false, iter.End());
+  EXPECT_STREQ("Ljava/io/IOException;", dex_file.dexStringByTypeIdx(iter.Get().type_idx_));
+  iter.Next();
+  ASSERT_EQ(true, iter.End());
+}
+
+}  // namespace art
diff --git a/src/object.h b/src/object.h
index e071b97..63f5b16 100644
--- a/src/object.h
+++ b/src/object.h
@@ -5,6 +5,7 @@
 
 #include "constants.h"
 #include "casts.h"
+#include "dex_file.h"
 #include "globals.h"
 #include "heap.h"
 #include "logging.h"
@@ -512,12 +513,12 @@
   // Method prototype descriptor string (return and argument types).
   uint32_t proto_idx_;
 
+  // Offset to the CodeItem.
+  uint32_t code_off_;
+
   // The short-form method descriptor string.
   StringPiece shorty_;
 
-  // A pointer to the memory-mapped DEX code.
-  const uint16_t* insns_;
-
  private:
   // Compiled code associated with this method
   const void* code_;