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/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(¤t_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(¤t_data_);
+ handler_.address_ = DecodeUnsignedLeb128(¤t_data_);
+ remaining_count_--;
+ return;
+ }
+
+ if (catch_all_) {
+ handler_.type_idx_ = kDexNoIndex;
+ handler_.address_ = DecodeUnsignedLeb128(¤t_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 {