Rename DexFile to DexCache

Change-Id: I93fa3e4f7cf87fbaac974f0d2577628a23f0d8c2
diff --git a/src/dex_file.h b/src/dex_file.h
index 6339317..e677b42 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -3,93 +3,521 @@
 #ifndef ART_SRC_DEX_FILE_H_
 #define ART_SRC_DEX_FILE_H_
 
+#include <map>
+
 #include "globals.h"
-#include "macros.h"
-#include "object.h"
+#include "leb128.h"
+#include "logging.h"
+#include "scoped_ptr.h"
+#include "stringpiece.h"
+#include "strutil.h"
 
 namespace art {
 
-class Class;
-class Field;
-class Method;
-class String;
 union JValue;
 
-class DexFile : public ObjectArray {
+// TODO: move all of the macro functionality into the DexCache class.
+class RawDexFile {
  public:
+  static const byte kDexMagic[];
+  static const byte kDexMagicVersion[];
+  static const size_t kSha1DigestSize = 20;
 
-  enum ArrayIndexes {
-    kStrings = 0,
-    kClasses = 1,
-    kMethods = 2,
-    kFields  = 3,
-    kMax     = 4,
+  static const byte kEncodedValueTypeMask = 0x1f;  // 0b11111
+  static const byte kEncodedValueArgShift = 5;
+
+  // The value of an invalid index.
+  static const uint32_t kDexNoIndex = 0xFFFFFFFF;
+
+  enum ValueType {
+    kByte = 0x00,
+    kShort = 0x02,
+    kChar = 0x03,
+    kInt = 0x04,
+    kLong = 0x06,
+    kFloat = 0x10,
+    kDouble = 0x11,
+    kString = 0x17,
+    kType = 0x18,
+    kField = 0x19,
+    kMethod = 0x1a,
+    kEnum = 0x1b,
+    kArray = 0x1c,
+    kAnnotation = 0x1d,
+    kNull = 0x1e,
+    kBoolean = 0x1f
   };
 
-  void Init(ObjectArray* strings, ObjectArray* classes,  ObjectArray* methods,  ObjectArray* fields);
+  // Raw header_item.
+  struct Header {
+    uint8_t magic_[8];
+    uint32_t checksum_;
+    uint8_t signature_[kSha1DigestSize];
+    uint32_t file_size_;  // length of entire file
+    uint32_t header_size_;  // offset to start of next section
+    uint32_t endian_tag_;
+    uint32_t link_size_;
+    uint32_t link_off_;
+    uint32_t map_off_;
+    uint32_t string_ids_size_;
+    uint32_t string_ids_off_;
+    uint32_t type_ids_size_;
+    uint32_t type_ids_off_;
+    uint32_t proto_ids_size_;
+    uint32_t proto_ids_off_;
+    uint32_t field_ids_size_;
+    uint32_t field_ids_off_;
+    uint32_t method_ids_size_;
+    uint32_t method_ids_off_;
+    uint32_t class_defs_size_;
+    uint32_t class_defs_off_;
+    uint32_t data_size_;
+    uint32_t data_off_;
+  };
 
-  size_t NumStrings() const {
-    return GetStrings()->GetLength();
+  // Raw string_id_item.
+  struct StringId {
+    uint32_t string_data_off_;  // offset in bytes from the base address
+  };
+
+  // Raw type_id_item.
+  struct TypeId {
+    uint32_t descriptor_idx_;  // index into string_ids
+  };
+
+  // Raw field_id_item.
+  struct FieldId {
+    uint16_t class_idx_;  // index into typeIds list for defining class
+    uint16_t type_idx_;  // index into typeIds for field type
+    uint32_t name_idx_;  // index into stringIds for field name
+  };
+
+  // Raw method_id_item.
+  struct MethodId {
+    uint16_t class_idx_;  // index into typeIds list for defining class
+    uint16_t proto_idx_;  // index into protoIds for method prototype
+    uint32_t name_idx_;  // index into stringIds for method name
+  };
+
+  // Raw proto_id_item.
+  struct ProtoId {
+    uint32_t shorty_idx_;  // index into string_ids for shorty descriptor
+    uint32_t return_type_idx_;  // index into type_ids list for return type
+    uint32_t parameters_off_;  // file offset to type_list for parameter types
+  };
+
+  // Raw class_def_item.
+  struct ClassDef {
+    uint32_t class_idx_;  // index into typeIds for this class
+    uint32_t access_flags_;
+    uint32_t superclass_idx_;  // index into typeIds for superclass
+    uint32_t interfaces_off_;  // file offset to TypeList
+    uint32_t source_file_idx_;  // index into stringIds for source file name
+    uint32_t annotations_off_;  // file offset to annotations_directory_item
+    uint32_t class_data_off_;  // file offset to class_data_item
+    uint32_t static_values_off_;  // file offset to EncodedArray
+  };
+
+  // Raw type_item.
+  struct TypeItem {
+    uint16_t type_idx_;  // index into type_ids section
+  };
+
+  // Raw type_list.
+  class TypeList {
+   public:
+    uint32_t Size() const {
+      return size_;
+    }
+
+    const TypeItem& GetTypeItem(uint32_t idx) const {
+      CHECK_LT(idx, this->size_);
+      return this->list_[idx];
+    }
+
+   private:
+    uint32_t size_;  // size of the list, in entries
+    TypeItem list_[1];  // elements of the list
+  };
+
+  class ParameterIterator {  // TODO: stream
+   public:
+    ParameterIterator(const RawDexFile& raw, const ProtoId& proto_id)
+        : raw_(raw), size_(0), pos_(0) {
+      type_list_ = raw_.GetProtoParameters(proto_id);
+      if (type_list_ != NULL) {
+        size_ = type_list_->Size();
+      }
+    }
+    bool HasNext() const { return pos_ != size_; }
+    void Next() { ++pos_; }
+    const char* GetDescriptor() {
+      uint32_t type_idx = type_list_->GetTypeItem(pos_).type_idx_;
+      return raw_.dexStringByTypeIdx(type_idx);
+    }
+   private:
+    const RawDexFile& raw_;
+    const TypeList* type_list_;
+    uint32_t size_;
+    uint32_t pos_;
+    DISALLOW_IMPLICIT_CONSTRUCTORS(ParameterIterator);
+  };
+
+  ParameterIterator* GetParameterIterator(const ProtoId& proto_id) const {
+    return new ParameterIterator(*this, proto_id);
   }
 
-  size_t NumClasses() const {
-    return GetClasses()->GetLength();
+  const char* GetReturnTypeDescriptor(const ProtoId& proto_id) const {
+    return dexStringByTypeIdx(proto_id.return_type_idx_);
   }
 
-  size_t NumMethods() const {
-    return GetMethods()->GetLength();
+  // Raw code_item.
+  struct CodeItem {
+    uint16_t registers_size_;
+    uint16_t ins_size_;
+    uint16_t outs_size_;
+    uint16_t tries_size_;
+    uint32_t debug_info_off_;  // file offset to debug info stream
+    uint32_t insns_size_;  // size of the insns array, in 2 byte code units
+    uint16_t insns_[1];
+  };
+
+  // Partially decoded form of class_data_item.
+  struct ClassDataHeader {
+    uint32_t static_fields_size_;  // the number of static fields
+    uint32_t instance_fields_size_;  // the number of instance fields
+    uint32_t direct_methods_size_;  // the number of direct methods
+    uint32_t virtual_methods_size_;  // the number of virtual methods
+  };
+
+  // Decoded form of encoded_field.
+  struct Field {
+    uint32_t field_idx_;  // index into the field_ids list for the identity of this field
+    uint32_t access_flags_;  // access flags for the field
+  };
+
+  // Decoded form of encoded_method.
+  struct Method {
+    uint32_t method_idx_;
+    uint32_t access_flags_;
+    uint32_t code_off_;
+  };
+
+  // Opens a .dex file from the file system.
+  static RawDexFile* OpenFile(const char* filename);
+
+  // Opens a .dex file from a new allocated pointer
+  static RawDexFile* OpenPtr(byte* ptr, size_t length);
+
+  // Closes a .dex file.
+  virtual ~RawDexFile();
+
+  const Header& GetHeader() {
+    CHECK(header_ != NULL);
+    return *header_;
   }
 
-  size_t NumFields() const {
-    return GetFields()->GetLength();
+  // Looks up a class definition by its class descriptor.
+  const ClassDef* FindClassDef(const StringPiece& descriptor) const;
+
+  // Returns the number of string identifiers in the .dex file.
+  size_t NumStringIds() const {
+    CHECK(header_ != NULL);
+    return header_->string_ids_size_;
   }
 
-  String* GetResolvedString(uint32_t string_idx) const {
-    return down_cast<String*>(GetStrings()->Get(string_idx));
+  // Returns the number of type identifiers in the .dex file.
+  size_t NumTypeIds() const {
+    CHECK(header_ != NULL);
+    return header_->type_ids_size_;
   }
 
-  void SetResolvedString(uint32_t string_idx, String* resolved) {
-    GetStrings()->Set(string_idx, resolved);
+  // Returns the number of prototype identifiers in the .dex file.
+  size_t NumProtoIds() const {
+    CHECK(header_ != NULL);
+    return header_->proto_ids_size_;
   }
 
-  Class* GetResolvedClass(uint32_t class_idx) const {
-    return down_cast<Class*>(GetClasses()->Get(class_idx));
+  // Returns the number of field identifiers in the .dex file.
+  size_t NumFieldIds() const {
+    CHECK(header_ != NULL);
+    return header_->field_ids_size_;
   }
 
-  void SetResolvedClass(uint32_t class_idx, Class* resolved) {
-    GetClasses()->Set(class_idx, resolved);
+  // Returns the number of method identifiers in the .dex file.
+  size_t NumMethodIds() const {
+    CHECK(header_ != NULL);
+    return header_->method_ids_size_;
   }
 
-  Method* GetResolvedMethod(uint32_t method_idx) const {
-    return down_cast<Method*>(GetMethods()->Get(method_idx));
+  // Returns the number of class definitions in the .dex file.
+  size_t NumClassDefs() const {
+    CHECK(header_ != NULL);
+    return header_->class_defs_size_;
   }
 
-  void SetResolvedMethod(uint32_t method_idx, Method* resolved) {
-    GetMethods()->Set(method_idx, resolved);
+  // Returns a pointer to the memory mapped class data.
+  // TODO: return a stream
+  const byte* GetClassData(const ClassDef& class_def) const {
+    if (class_def.class_data_off_ == 0) {
+      return NULL;
+    } else {
+      return base_ + class_def.class_data_off_;
+    }
   }
 
-  Field* GetResolvedField(uint32_t field_idx) const {
-    return down_cast<Field*>(GetFields()->Get(field_idx));
+  // Decodes the header section from the raw class data bytes.
+  ClassDataHeader ReadClassDataHeader(const byte** class_data) const {
+    CHECK(class_data != NULL);
+    ClassDataHeader header;
+    memset(&header, 0, sizeof(ClassDataHeader));
+    if (*class_data != NULL) {
+      header.static_fields_size_ = DecodeUnsignedLeb128(class_data);
+      header.instance_fields_size_ = DecodeUnsignedLeb128(class_data);
+      header.direct_methods_size_ = DecodeUnsignedLeb128(class_data);
+      header.virtual_methods_size_ = DecodeUnsignedLeb128(class_data);
+    }
+    return header;
   }
 
-  void SetResolvedfield(uint32_t field_idx, Field* resolved) {
-    GetFields()->Set(field_idx, resolved);
+  // Returns the class descriptor string of a class definition.
+  const char* GetClassDescriptor(const ClassDef& class_def) const {
+    return dexStringByTypeIdx(class_def.class_idx_);
+  }
+
+  // Returns the StringId at the specified index.
+  const StringId& GetStringId(uint32_t idx) const {
+    CHECK_LT(idx, NumStringIds());
+    return string_ids_[idx];
+  }
+
+  // Returns the TypeId at the specified index.
+  const TypeId& GetTypeId(uint32_t idx) const {
+    CHECK_LT(idx, NumTypeIds());
+    return type_ids_[idx];
+  }
+
+  // Returns the FieldId at the specified index.
+  const FieldId& GetFieldId(uint32_t idx) const {
+    CHECK_LT(idx, NumFieldIds());
+    return field_ids_[idx];
+  }
+
+  // Returns the MethodId at the specified index.
+  const MethodId& GetMethodId(uint32_t idx) const {
+    CHECK_LT(idx, NumMethodIds());
+    return method_ids_[idx];
+  }
+
+  // Returns the ProtoId at the specified index.
+  const ProtoId& GetProtoId(uint32_t idx) const {
+    CHECK_LT(idx, NumProtoIds());
+    return proto_ids_[idx];
+  }
+
+  // Returns the ClassDef at the specified index.
+  const ClassDef& GetClassDef(uint32_t idx) const {
+    CHECK_LT(idx, NumClassDefs());
+    return class_defs_[idx];
+  }
+
+  const TypeList* GetInterfacesList(const ClassDef& class_def) const {
+    if (class_def.interfaces_off_ == 0) {
+        return NULL;
+    } else {
+      const byte* addr = base_ + class_def.interfaces_off_;
+      return reinterpret_cast<const TypeList*>(addr);
+    }
+  }
+
+  const CodeItem* GetCodeItem(const Method& method) const {
+    if (method.code_off_ == 0) {
+      return NULL;  // native or abstract method
+    } else {
+      const byte* addr = base_ + method.code_off_;
+      return reinterpret_cast<const CodeItem*>(addr);
+    }
+  }
+
+  // Returns the short form method descriptor for the given prototype.
+  const char* GetShorty(uint32_t proto_idx) const {
+    const ProtoId& proto_id = GetProtoId(proto_idx);
+    return dexStringById(proto_id.shorty_idx_);
+  }
+
+  const TypeList* GetProtoParameters(const ProtoId& proto_id) const {
+    if (proto_id.parameters_off_ == 0) {
+      return NULL;
+    } else {
+      const byte* addr = base_ + proto_id.parameters_off_;
+      return reinterpret_cast<const TypeList*>(addr);
+    }
+  }
+
+  const byte* GetEncodedArray(const ClassDef& class_def) const {
+    if (class_def.static_values_off_ == 0) {
+      return 0;
+    } else {
+      return base_ + class_def.static_values_off_;
+    }
+  }
+
+  int32_t GetStringLength(const StringId& string_id) const {
+    const byte* ptr = base_ + string_id.string_data_off_;
+    return DecodeUnsignedLeb128(&ptr);
+  }
+
+  ValueType ReadEncodedValue(const byte** encoded_value, JValue* value) const;
+
+  // From libdex...
+
+  // Returns a pointer to the UTF-8 string data referred to by the
+  // given string_id.
+  const char* GetStringData(const StringId& string_id) const {
+    const byte* ptr = base_ + string_id.string_data_off_;
+    // Skip the uleb128 length.
+    while (*(ptr++) > 0x7f) /* empty */ ;
+    return (const char*) ptr;
+  }
+
+  // return the UTF-8 encoded string with the specified string_id index
+  const char* dexStringById(uint32_t idx) const {
+    const StringId& string_id = GetStringId(idx);
+    return GetStringData(string_id);
+  }
+
+  // Get the descriptor string associated with a given type index.
+  const char* dexStringByTypeIdx(uint32_t idx) const {
+    const TypeId& type_id = GetTypeId(idx);
+    return dexStringById(type_id.descriptor_idx_);
+  }
+
+  // TODO: encoded_field is actually a stream of bytes
+  void dexReadClassDataField(const byte** encoded_field,
+                             RawDexFile::Field* field,
+                             uint32_t* last_idx) const {
+    uint32_t idx = *last_idx + DecodeUnsignedLeb128(encoded_field);
+    field->access_flags_ = DecodeUnsignedLeb128(encoded_field);
+    field->field_idx_ = idx;
+    *last_idx = idx;
+  }
+
+  // TODO: encoded_method is actually a stream of bytes
+  void dexReadClassDataMethod(const byte** encoded_method,
+                              RawDexFile::Method* method,
+                              uint32_t* last_idx) const {
+    uint32_t idx = *last_idx + DecodeUnsignedLeb128(encoded_method);
+    method->access_flags_ = DecodeUnsignedLeb128(encoded_method);
+    method->code_off_ = DecodeUnsignedLeb128(encoded_method);
+    method->method_idx_ = idx;
+    *last_idx = idx;
+  }
+
+
+  // TODO: const reference
+  uint32_t dexGetIndexForClassDef(const ClassDef* class_def) const {
+    CHECK_GE(class_def, class_defs_);
+    CHECK_LT(class_def, class_defs_ + header_->class_defs_size_);
+    return class_def - class_defs_;
+  }
+
+  const char* dexGetSourceFile(const ClassDef& class_def) const {
+    if (class_def.source_file_idx_ == 0xffffffff) {
+      return NULL;
+    } else {
+      return dexStringById(class_def.source_file_idx_);
+    }
   }
 
  private:
-  ObjectArray* GetStrings() const {
-      return down_cast<ObjectArray*>(Get(kStrings));
-  }
-  ObjectArray* GetClasses() const {
-      return down_cast<ObjectArray*>(Get(kClasses));
-  }
-  ObjectArray* GetMethods() const {
-      return down_cast<ObjectArray*>(Get(kMethods));
-  }
-  ObjectArray* GetFields() const {
-      return down_cast<ObjectArray*>(Get(kFields));
-  }
-  DexFile();
+  // Helper class to deallocate underlying storage.
+  class Closer {
+   public:
+    virtual ~Closer();
+  };
+
+  // Helper class to deallocate mmap-backed .dex files.
+  class MmapCloser : public Closer {
+   public:
+    MmapCloser(void* addr, size_t length);
+    virtual ~MmapCloser();
+   private:
+    void* addr_;
+    size_t length_;
+  };
+
+  // Helper class for deallocating new/delete-backed .dex files.
+  class PtrCloser : public Closer {
+   public:
+    PtrCloser(byte* addr);
+    virtual ~PtrCloser();
+   private:
+    byte* addr_;
+  };
+
+  // Opens a .dex file at a the given address.
+  static RawDexFile* Open(const byte* dex_file, size_t length, Closer* closer);
+
+  RawDexFile(const byte* addr, size_t length, Closer* closer)
+      : base_(addr),
+        length_(length),
+        closer_(closer),
+        header_(0),
+        string_ids_(0),
+        type_ids_(0),
+        field_ids_(0),
+        method_ids_(0),
+        proto_ids_(0),
+        class_defs_(0) {}
+
+  // Top-level initializer that calls other Init methods.
+  bool Init();
+
+  // Caches pointers into to the various file sections.
+  void InitMembers();
+
+  // Builds the index of descriptors to class definitions.
+  void InitIndex();
+
+  // Returns true if the byte string equals the magic value.
+  bool CheckMagic(const byte* magic);
+
+  // Returns true if the header magic is of the expected value.
+  bool IsMagicValid();
+
+  // The index of descriptors to class definitions.
+  typedef std::map<const StringPiece, const RawDexFile::ClassDef*> Index;
+  Index index_;
+
+  // The base address of the memory mapping.
+  const byte* base_;
+
+  // The size of the underlying memory allocation in bytes.
+  size_t length_;
+
+  // Helper object to free the underlying allocation.
+  scoped_ptr<Closer> closer_;
+
+  // Points to the header section.
+  const Header* header_;
+
+  // Points to the base of the string identifier list.
+  const StringId* string_ids_;
+
+  // Points to the base of the type identifier list.
+  const TypeId* type_ids_;
+
+  // Points to the base of the field identifier list.
+  const FieldId* field_ids_;
+
+  // Points to the base of the method identifier list.
+  const MethodId* method_ids_;
+
+  // Points to the base of the prototype identifier list.
+  const ProtoId* proto_ids_;
+
+  // Points to the base of the class definition list.
+  const ClassDef* class_defs_;
 };
 
 }  // namespace art