Improved ClassLoader support

Change-Id: I587c0fa439c64a0c947641b01c072149f480bf85
diff --git a/src/object.h b/src/object.h
index 3a9888e..d0f4a63 100644
--- a/src/object.h
+++ b/src/object.h
@@ -262,10 +262,11 @@
   }
 
   char GetType() const {  // TODO: return type
-    return descriptor_[0];
+    return GetDescriptor()[0];
   }
 
   const StringPiece& GetDescriptor() const {
+    DCHECK_NE(0, descriptor_.size());
     return descriptor_;
   }
 
@@ -648,13 +649,72 @@
   ObjectArray();
 };
 
+// ClassLoader objects.
+class ClassLoader : public Object {
+ public:
+  std::vector<const DexFile*>& GetClassPath() {
+    return class_path_;
+  }
+  void SetClassPath(std::vector<const DexFile*>& class_path) {
+    DCHECK_EQ(0U, class_path_.size());
+    class_path_ = class_path;
+  }
+
+ private:
+  // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
+  Object* packages_;
+  ClassLoader* parent_;
+
+  // TODO remove once we can create a real PathClassLoader
+  std::vector<const DexFile*> class_path_;
+
+  ClassLoader();
+};
+
+class BaseDexClassLoader : public ClassLoader {
+ private:
+  // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
+  String* original_path_;
+  Object* path_list_;
+  BaseDexClassLoader();
+};
+
+class PathClassLoader : public BaseDexClassLoader {
+ private:
+  PathClassLoader();
+};
+
 // Class objects.
 class Class : public Object {
  public:
+
+  // Class Status
+  //
+  // kStatusNotReady: If a Class cannot be found in the class table by
+  // FindClass, it allocates an new one with AllocClass in the
+  // kStatusNotReady and calls LoadClass. Note if it does find a
+  // class, it may not be kStatusResolved and it will try to push it
+  // forward toward kStatusResolved.
+  //
+  // kStatusIdx: LoadClass populates with Class with information from
+  // the DexFile, moving the status to kStatusIdx, indicating that the
+  // Class values in super_class_ and interfaces_ have not been
+  // populated based on super_class_idx_ and interfaces_idx_. The new
+  // Class can then be inserted into the classes table.
+  //
+  // kStatusLoaded: After taking a lock on Class, the ClassLinker will
+  // attempt to move a kStatusIdx class forward to kStatusLoaded by
+  // using ResolveClass to initialize the super_class_ and interfaces_.
+  //
+  // kStatusResolved: Still holding the lock on Class, the ClassLinker
+  // will use LinkClass to link all members, creating Field and Method
+  // objects, setting up the vtable, etc. On success, the class is
+  // marked kStatusResolved.
+
   enum Status {
     kStatusError = -1,
     kStatusNotReady = 0,
-    kStatusIdx = 1,  // loaded, DEX idx in super or ifaces
+    kStatusIdx = 1,  // loaded, DEX idx in super_class_idx_ and interfaces_idx_
     kStatusLoaded = 2,  // DEX idx values resolved
     kStatusResolved = 3,  // part of linking
     kStatusVerifying = 4,  // in the process of being verified
@@ -679,7 +739,7 @@
     return super_class_ != NULL;
   }
 
-  Object* GetClassLoader() const {
+  ClassLoader* GetClassLoader() const {
     return class_loader_;
   }
 
@@ -688,11 +748,11 @@
   }
 
   Class* GetComponentType() const {
-    DCHECK(IsArray());
     return component_type_;
   }
 
   const StringPiece& GetDescriptor() const {
+    DCHECK_NE(0, descriptor_.size());
     return descriptor_;
   }
 
@@ -732,7 +792,7 @@
 
   // Returns true if this class represents an array class.
   bool IsArray() const {
-    return descriptor_[0] == '[';  // TODO: avoid parsing the descriptor
+    return GetDescriptor()[0] == '[';  // TODO: avoid parsing the descriptor
   }
 
   // Returns true if the class is an interface.
@@ -933,7 +993,7 @@
   uint32_t super_class_idx_;
 
   // defining class loader, or NULL for the "bootstrap" system loader
-  Object* class_loader_;  // TODO: make an instance field
+  ClassLoader* class_loader_;  // TODO: make an instance field
 
   // initiating class loader list
   // NOTE: for classes with low serialNumber, these are unused, and the
@@ -1136,23 +1196,52 @@
   static uint16_t GetUtf16FromUtf8(const char** utf8_data_in) {
     uint8_t one = *(*utf8_data_in)++;
     if ((one & 0x80) == 0) {
-      /* one-byte encoding */
+      // one-byte encoding
       return one;
     }
-    /* two- or three-byte encoding */
+    // two- or three-byte encoding
     uint8_t two = *(*utf8_data_in)++;
     if ((one & 0x20) == 0) {
-      /* two-byte encoding */
+      // two-byte encoding
       return ((one & 0x1f) << 6) |
               (two & 0x3f);
     }
-    /* three-byte encoding */
+    // three-byte encoding
     uint8_t three = *(*utf8_data_in)++;
     return ((one & 0x0f) << 12) |
             ((two & 0x3f) << 6) |
             (three & 0x3f);
   }
 
+  // Like "strlen", but for strings encoded with "modified" UTF-8.
+  //
+  // The value returned is the number of characters, which may or may not
+  // be the same as the number of bytes.
+  //
+  // (If this needs optimizing, try: mask against 0xa0, shift right 5,
+  // get increment {1-3} from table of 8 values.)
+  static size_t ModifiedUtf8Len(const char* utf8) {
+    size_t len = 0;
+    int ic;
+    while ((ic = *utf8++) != '\0') {
+      len++;
+      if ((ic & 0x80) == 0) {
+        // one-byte encoding
+        continue;
+      }
+      // two- or three-byte encoding
+      utf8++;
+      if ((ic & 0x20) == 0) {
+        // two-byte encoding
+        continue;
+      }
+      // three-byte encoding
+      utf8++;
+    }
+    return len;
+  }
+
+
   // The java/lang/String.computeHashCode() algorithm
   static int32_t ComputeUtf16Hash(const uint16_t* string_data, size_t string_length) {
     int32_t hash = 0;