Complete support for loading classes from a DEX file.

Change-Id: I1b9aa105fc78df170e83b259d8d04317c296a1b5
diff --git a/src/dex_file.cc b/src/dex_file.cc
index a89baaf..1951af5 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -52,8 +52,7 @@
 
 Class* DexFile::LoadClass(const RawDexFile::ClassDef& class_def) {
   const byte* class_data = raw_->GetClassData(class_def);
-  RawDexFile::ClassDataHeader header;
-  raw_->DecodeClassDataHeader(&header, class_data);
+  RawDexFile::ClassDataHeader header = raw_->ReadClassDataHeader(&class_data);
 
   const char* descriptor = raw_->GetClassDescriptor(class_def);
   CHECK(descriptor != NULL);
@@ -61,9 +60,9 @@
   // Allocate storage for the new class object.
   size_t size = Class::Size(header.static_fields_size_);
   Class* klass = Heap::AllocClass(size);
-  CHECK(klass != NULL);
+  CHECK(klass != NULL);  // TODO: throw an OOME
 
-  //klass->klass_ = NULL;  // TODO
+  klass->klass_ = NULL;  // TODO
   klass->descriptor_ = descriptor;
   klass->access_flags_ = class_def.access_flags_;
   klass->class_loader_ = NULL;  // TODO
@@ -73,32 +72,70 @@
 
   klass->super_ = reinterpret_cast<Class*>(class_def.superclass_idx_);
 
+  klass->num_sfields_ = header.static_fields_size_;
+  klass->num_ifields_ = header.instance_fields_size_;
+  klass->num_dmethods_ = header.direct_methods_size_;
+  klass->num_vmethods_ = header.virtual_methods_size_;
+
+  klass->source_file_ = raw_->dexGetSourceFile(class_def);
+
   // Load class interfaces.
-  LoadClassInterfaces(class_def, klass);
+  LoadInterfaces(class_def, klass);
 
   // Load static fields.
-  if (header.static_fields_size_ != 0) {
-    for (size_t i = 0; i < header.static_fields_size_; ++i) {
-      // TODO
+  if (klass->num_sfields_ != 0) {
+    uint32_t last_idx = 0;
+    for (size_t i = 0; i < klass->num_sfields_; ++i) {
+      RawDexFile::Field raw_field;
+      raw_->dexReadClassDataField(&class_data, &raw_field, &last_idx);
+      LoadField(klass, raw_field, &klass->sfields_[i]);
     }
   }
 
   // Load instance fields.
-  if (header.instance_fields_size_ != 0) {
-    for (size_t i = 0; i < header.instance_fields_size_; ++i) {
-      // TODO
+  if (klass->num_ifields_ != 0) {
+    // TODO: append instance fields to class object
+    klass->ifields_ = new IField[klass->num_ifields_];
+    uint32_t last_idx = 0;
+    for (size_t i = 0; i < klass->num_ifields_; ++i) {
+      RawDexFile::Field raw_field;
+      raw_->dexReadClassDataField(&class_data, &raw_field, &last_idx);
+      LoadField(klass, raw_field, &klass->ifields_[i]);
     }
   }
 
   // Load direct methods.
+  if (klass->num_dmethods_ != 0) {
+    // TODO: append direct methods to class object
+    klass->dmethods_ = new Method[klass->num_dmethods_];
+    uint32_t last_idx = 0;
+    for (size_t i = 0; i < klass->num_dmethods_; ++i) {
+      RawDexFile::Method raw_method;
+      raw_->dexReadClassDataMethod(&class_data, &raw_method, &last_idx);
+      LoadMethod(klass, raw_method, &klass->dmethods_[i]);
+      // TODO: register maps
+    }
+  }
 
   // Load virtual methods.
+  if (klass->num_vmethods_ != 0) {
+    // TODO: append virtual methods to class object
+    klass->vmethods_ = new Method[klass->num_vmethods_];
+    memset(klass->vmethods_, 0xff, sizeof(Method));
+    uint32_t last_idx = 0;
+    for (size_t i = 0; i < klass->num_vmethods_; ++i) {
+      RawDexFile::Method raw_method;
+      raw_->dexReadClassDataMethod(&class_data, &raw_method, &last_idx);
+      LoadMethod(klass, raw_method, &klass->vmethods_[i]);
+      // TODO: register maps
+    }
+  }
 
   return klass;
 }
 
-void DexFile::LoadClassInterfaces(const RawDexFile::ClassDef& class_def,
-                                  Class* klass) {
+void DexFile::LoadInterfaces(const RawDexFile::ClassDef& class_def,
+                             Class* klass) {
   const RawDexFile::TypeList* list = raw_->GetInterfacesList(class_def);
   if (list != NULL) {
     klass->interface_count_ = list->Size();
@@ -110,19 +147,41 @@
   }
 }
 
-void DexFile::LoadSFields(Class* klass, const RawDexFile::Field* src,
-                            Field* dst) {
-
+void DexFile::LoadField(Class* klass, const RawDexFile::Field& src,
+                        Field* dst) {
+  const RawDexFile::FieldId& field_id = raw_->GetFieldId(src.field_idx_);
+  dst->klass_ = klass;
+  dst->name_ = raw_->dexStringById(field_id.name_idx_);
+  dst->signature_ = raw_->dexStringByTypeIdx(field_id.type_idx_);
+  dst->access_flags_ = src.access_flags_;
 }
 
-void DexFile::LoadIFields(Class* klass, const RawDexFile::Field* src,
-                          Field* dst) {
-}
-
-void DexFile::LoadMethod(Class* klass, const RawDexFile::Method* src,
+void DexFile::LoadMethod(Class* klass, const RawDexFile::Method& src,
                          Method* dst) {
+  const RawDexFile::MethodId& method_id = raw_->GetMethodId(src.method_idx_);
+  dst->klass_ = klass;
+  dst->name_ = raw_->dexStringById(method_id.name_idx_);
+  dst->dex_file_ = this;
+  dst->proto_idx_ = method_id.proto_idx_;
+  dst->shorty_ = raw_->GetShorty(method_id.proto_idx_);
+  dst->access_flags_ = src.access_flags_;
+
+  // TODO: check for finalize method
+
+  const RawDexFile::Code* code_item = raw_->GetCode(src);
+  if (code_item != NULL) {
+    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()) {
+      ++num_args;
+    }
+    dst->num_registers_ = dst->num_ins_ + num_args;
+    // TODO: native methods
+  }
 }
 
-
-
 }  // namespace art
diff --git a/src/dex_file.h b/src/dex_file.h
index 3cd1a57..94ba33d 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -35,17 +35,11 @@
 
   void Init();
 
-  void LoadClassInterfaces(const RawDexFile::ClassDef& class_def,
-                             Class *klass);
+  void LoadInterfaces(const RawDexFile::ClassDef& class_def, Class *klass);
 
-  void LoadSFields(Class* klass, const RawDexFile::Field* src,
-                   Field* dst);
+  void LoadField(Class* klass, const RawDexFile::Field& src, Field* dst);
 
-  void LoadIFields(Class* klass, const RawDexFile::Field* src,
-                   Field* dst);
-
-  void LoadMethod(Class* klass, const RawDexFile::Method* src,
-                  Method* dst);
+  void LoadMethod(Class* klass, const RawDexFile::Method& src, Method* dst);
 
   // Table of contents for interned String objects.
   String** strings_;
diff --git a/src/dex_file_test.cc b/src/dex_file_test.cc
index ff80e46..74adca3 100644
--- a/src/dex_file_test.cc
+++ b/src/dex_file_test.cc
@@ -30,6 +30,12 @@
 
   Class* klass = dex->LoadClass("LNested;");
   ASSERT_TRUE(klass != NULL);
+
+  uint32_t vmeth = klass->NumVirtualMethods();
+  EXPECT_EQ(vmeth, 0U);
+
+  uint32_t dmeth = klass->NumDirectMethods();
+  EXPECT_EQ(dmeth, 1U);
 }
 
 }  // namespace art
diff --git a/src/object.cc b/src/object.cc
new file mode 100644
index 0000000..a4f41b7
--- /dev/null
+++ b/src/object.cc
@@ -0,0 +1,23 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "src/globals.h"
+#include "src/object.h"
+#include "src/logging.h"
+
+namespace art {
+
+uint32_t Method::NumArgRegisters() {
+  CHECK(shorty_ != NULL);
+  uint32_t num_registers = 0;
+  for (size_t i = 1; shorty_[0] != '\0'; ++i) {
+    char ch = shorty_[i];
+    if (ch == 'D' || ch == 'J') {
+      num_registers += 2;
+    } else {
+      num_registers += 1;
+    }
+  }
+  return num_registers;
+}
+
+}  // namespace art
diff --git a/src/object.h b/src/object.h
index b7d3a50..e8d1ee1 100644
--- a/src/object.h
+++ b/src/object.h
@@ -4,6 +4,7 @@
 #define ART_SRC_OBJECT_H_
 
 #include "src/globals.h"
+#include "src/macros.h"
 
 namespace art {
 
@@ -14,29 +15,75 @@
 class InterfaceEntry;
 class Monitor;
 class Method;
+class Object;
 class SField;
 
+union JValue {
+  uint8_t z;
+  int8_t b;
+  uint16_t c;
+  int16_t s;
+  int32_t i;
+  int64_t j;
+  float f;
+  double d;
+  Object* l;
+};
+
+static const uint32_t kAccPublic = 0x0001; // class, field, method, ic
+static const uint32_t kAccPrivate = 0x0002; // field, method, ic
+static const uint32_t kAccProtected = 0x0004; // field, method, ic
+static const uint32_t kAccStatic = 0x0008; // field, method, ic
+static const uint32_t kAccFinal = 0x0010; // class, field, method, ic
+static const uint32_t kAccSynchronized = 0x0020; // method (only allowed on natives)
+static const uint32_t kAccSuper = 0x0020; // class (not used in Dalvik)
+static const uint32_t kAccVolatile = 0x0040; // field
+static const uint32_t kAccBridge = 0x0040; // method (1.5)
+static const uint32_t kAccTransient = 0x0080; // field
+static const uint32_t kAccVarargs = 0x0080; // method (1.5)
+static const uint32_t kAccNative = 0x0100; // method
+static const uint32_t kAccInterface = 0x0200; // class, ic
+static const uint32_t kAccAbstract = 0x0400; // class, method, ic
+static const uint32_t kAccStrict = 0x0800; // method
+static const uint32_t kAccSynthetic = 0x1000; // field, method, ic
+static const uint32_t kAccAnnotation = 0x2000; // class, ic (1.5)
+static const uint32_t kAccEnum = 0x4000; // class, field, ic (1.5)
+
+static const uint32_t kAccConstructor = 0x00010000; // method (Dalvik only)
+static const uint32_t kAccDeclaredSynchronized = 0x00020000; // method (Dalvik only)
+
+
 class Object {
+ public:
   Class* klass_;
   Monitor* lock_;
 };
 
 class Field {
+ public:
+  // The class in which this field is declared.
   Class* klass_;
+
+  const char* name_;
+
+  // e.g. "I", "[C", "Landroid/os/Debug;"
+  const char* signature_;
+
+  uint32_t access_flags_;
 };
 
 // Instance fields.
-class IField : Field {
-  // TODO
+class IField : public Field {
+  uint32_t offset_;
 };
 
 // Static fields.
-class SField : Field {
-  // TODO
+class SField : public Field {
+  JValue value_;
 };
 
 // Class objects.
-class Class : Object {
+class Class : public Object {
  public:
   enum ClassStatus {
     kClassError = -1,
@@ -60,6 +107,15 @@
     return OFFSETOF_MEMBER(Class, sfields_) + sizeof(SField) * num_sfields;
   }
 
+  uint32_t NumDirectMethods() {
+    return num_dmethods_;
+  }
+
+  uint32_t NumVirtualMethods() {
+    return num_vmethods_;
+  }
+
+
  public: // TODO: private
   // leave space for instance data; we could access fields directly if
   // we freeze the definition of java/lang/Class
@@ -76,7 +132,7 @@
   char* descriptor_alloc_;
 
   // access flags; low 16 bits are defined by VM spec
-  uint32_t access_flags_;
+  uint32_t access_flags_;  // TODO: make an instance field?
 
   // VM-unique class serial number, nonzero, set very early
   //uint32_t serial_number_;
@@ -101,7 +157,7 @@
   // For array classes, the class object for base element, for
   // instanceof/checkcast (for String[][][], this will be String).
   // Otherwise, NULL.
-  Class* array_element_class_;
+  Class* array_element_class_;  // TODO: make an instance field
 
   // For array classes, the number of array dimensions, e.g. int[][]
   // is 2.  Otherwise 0.
@@ -112,10 +168,10 @@
 
   // The superclass, or NULL if this is java.lang.Object or a
   // primitive type.
-  Class* super_;
+  Class* super_;  // TODO: make an instance field
 
   // defining class loader, or NULL for the "bootstrap" system loader
-  Object* class_loader_;
+  Object* class_loader_;  // TODO: make an instance field
 
   // initiating class loader list
   // NOTE: for classes with low serialNumber, these are unused, and the
@@ -127,12 +183,12 @@
   Class** interfaces_;
 
   // static, private, and <init> methods
-  int direct_method_count_;
-  Method* direct_methods_;
+  uint32_t num_dmethods_;
+  Method* dmethods_;
 
   // virtual methods defined in this class; invoked through vtable
-  int virtual_method_count_;
-  Method* virtual_methods_;
+  uint32_t num_vmethods_;
+  Method* vmethods_;
 
   // Virtual method table (vtable), for use by "invoke-virtual".  The
   // vtable from the superclass is copied in, and virtual methods from
@@ -172,8 +228,10 @@
   // All instance fields that refer to objects are guaranteed to be at
   // the beginning of the field list.  ifieldRefCount specifies the
   // number of reference fields.
-  int ifield_count_;
-  int ifield_ref_count_; // number of fields that are object refs
+  uint32_t num_ifields_;
+
+  // number of fields that are object refs
+  uint32_t num_reference_ifields_;
   IField* ifields_;
 
   // bitmap of offsets of ifields
@@ -183,7 +241,7 @@
   const char* source_file_;
 
   // Static fields
-  uint16_t num_sfields_;
+  uint32_t num_sfields_;
   SField sfields_[];  // MUST be last item
 };
 
@@ -206,7 +264,90 @@
 
 class Method {
  public:
-  Class* klass;
+  // Returns true if the method is declared public.
+  bool IsPublic() {
+    return (access_flags_ & kAccPublic) != 0;
+  }
+
+  // Returns true if the method is declared private.
+  bool IsPrivate() {
+    return (access_flags_ & kAccPrivate) != 0;
+  }
+
+  // Returns true if the method is declared static.
+  bool IsStatic() {
+    return (access_flags_ & kAccStatic) != 0;
+  }
+
+  // Returns true if the method is declared native and synchronized.
+  bool IsSynchronized() {
+    return (access_flags_ & kAccSynchronized) != 0;
+  }
+
+  // Returns true if the method is not native and declared synchronized.
+  bool IsDeclaredSynchronized() {
+    return (access_flags_ & kAccDeclaredSynchronized) != 0;
+  }
+
+  // Returns true if the method is declared final.
+  bool IsFinal() {
+    return (access_flags_ & kAccFinal) != 0;
+  }
+
+  // Returns true if the method is declared native.
+  bool IsNative() {
+    return (access_flags_ & kAccNative) != 0;
+  }
+
+  // Returns true if the method is declared abstract.
+  bool IsAbstract() {
+    return (access_flags_ & kAccAbstract) != 0;
+  }
+
+  bool IsSynthetic() {
+    return (access_flags_ & kAccSynthetic) != 0;
+  }
+
+  // Number of argument registers required by the prototype.
+  uint32_t NumArgRegisters();
+
+ public:  // TODO: private
+  // the class we are a part of
+  Class* klass_;
+
+  // access flags; low 16 bits are defined by spec (could be uint16_t?)
+  uint32_t access_flags_;
+
+  // For concrete virtual methods, this is the offset of the method
+  // in "vtable".
+  //
+  // For abstract methods in an interface class, this is the offset
+  // of the method in "iftable[n]->methodIndexArray".
+  uint16_t method_index_;
+
+  // Method bounds; not needed for an abstract method.
+  //
+  // For a native method, we compute the size of the argument list, and
+  // set "insSize" and "registerSize" equal to it.
+  uint16_t num_registers_;  // ins + locals
+  uint16_t num_outs_;
+  uint16_t num_ins_;
+
+  // method name, e.g. "<init>" or "eatLunch"
+  const char* name_;
+
+  // A pointer to the DEX file this class was loaded from or NULL for
+  // proxy objects.
+  DexFile* dex_file_;
+
+  // Method prototype descriptor string (return and argument types).
+  uint32_t proto_idx_;
+
+  // The short-form method descriptor string.
+  const char* shorty_;
+
+  // A pointer to the memory-mapped DEX code.
+  const uint16_t* insns_;
 };
 
 }  // namespace art
diff --git a/src/raw_dex_file.h b/src/raw_dex_file.h
index 3cd7c88..ca01486 100644
--- a/src/raw_dex_file.h
+++ b/src/raw_dex_file.h
@@ -57,15 +57,15 @@
 
   // Raw field_id_item.
   struct FieldId {
-    uint32_t class_idx_;  // index into typeIds list for defining class
-    uint32_t type_idx_;  // index into typeIds for field type
+    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 {
-    uint32_t class_idx_;  // index into typeIds list for defining class
-    uint32_t proto_idx_;  // index into protoIds for method prototype
+    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
   };
 
@@ -148,6 +148,11 @@
   // Closes a .dex file.
   ~RawDexFile();
 
+  const Header& GetHeader() {
+    CHECK(header_ != NULL);
+    return *header_;
+  }
+
   // Looks up a class definition by its class descriptor.
   const ClassDef* FindClassDef(const char* descriptor);
 
@@ -197,15 +202,13 @@
   }
 
   // Decodes the header section from the raw class data bytes.
-  void DecodeClassDataHeader(ClassDataHeader* header, const byte* class_data) {
-    CHECK(header != NULL);
-    memset(header, 0, sizeof(ClassDataHeader));
-    if (header != 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);
-    }
+  ClassDataHeader ReadClassDataHeader(const byte** class_data) {
+    ClassDataHeader header;
+    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;
   }
 
   // Returns the class descriptor string of a class definition.
@@ -258,6 +261,21 @@
     }
   }
 
+  const Code* GetCode(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 Code*>(addr);
+    }
+  }
+
+  // Returns the short form method descriptor for the given prototype.
+  const char* GetShorty(uint32_t proto_idx) {
+    const ProtoId& proto_id = GetProtoId(proto_idx);
+    return dexStringById(proto_id.shorty_idx_);
+  }
+
   // From libdex...
 
   // Returns a pointer to the UTF-8 string data referred to by the
@@ -281,6 +299,41 @@
     return dexStringById(type_id.descriptor_idx_);
   }
 
+  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;
+  }
+
+  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:
   RawDexFile(const byte* addr, size_t length)
       : base_(addr),