Add compiler allocation paths Class::NewInstanceFromCode and Array::AllocFromCode

Change-Id: I604377656f182f29692cda757dc7fdb4acc938b9
diff --git a/src/class_linker.cc b/src/class_linker.cc
index e0b55ca..4738926 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -89,9 +89,11 @@
   // Object[] is for DexCache and int[] is for various Class members.
   Class* object_array_class = AllocClass(java_lang_Class, sizeof(Class));
   CHECK(object_array_class != NULL);
+  object_array_class->array_rank_ = 1;
   object_array_class->component_type_ = java_lang_Object;
   Class* int_array_class = AllocClass(java_lang_Class, sizeof(Class));
   CHECK(int_array_class != NULL);
+  int_array_class->array_rank_ = 1;
   IntArray::SetArrayClass(int_array_class);
 
   // String and char[] are necessary so that FindClass can assign names to members
@@ -102,6 +104,7 @@
   String::SetClass(java_lang_String);
   Class* char_array_class = AllocClass(java_lang_Class, sizeof(Class));
   CHECK(char_array_class != NULL);
+  char_array_class->array_rank_ = 1;
   CharArray::SetArrayClass(char_array_class);
   // Now String::Alloc* can be used
 
@@ -258,7 +261,7 @@
     ClassRoot class_root = static_cast<ClassRoot>(i);
     Class* klass = GetClassRoot(class_root);
     CHECK(klass != NULL);
-    DCHECK(klass->IsArray() || klass->IsPrimitive() || klass->dex_cache_ != NULL);
+    DCHECK(klass->IsArrayClass() || klass->IsPrimitive() || klass->dex_cache_ != NULL);
     // note SetClassRoot does additional validation.
     // if possible add new checks there to catch errors early
   }
@@ -373,7 +376,7 @@
   if (dex_cache != NULL) {
     state->dex_caches.insert(dex_cache);
   } else {
-    DCHECK(klass->IsArray() || klass->IsPrimitive());
+    DCHECK(klass->IsArrayClass() || klass->IsPrimitive());
   }
 
   // check if this is a root, if so, register it
@@ -1865,7 +1868,7 @@
     resolved = FindClass(descriptor, class_loader);
   }
   if (resolved != NULL) {
-    Class* check = resolved->IsArray() ? resolved->component_type_ : resolved;
+    Class* check = resolved->IsArrayClass() ? resolved->component_type_ : resolved;
     if (dex_cache != check->GetDexCache()) {
       if (check->GetClassLoader() != NULL) {
         LG << "Class resolved by unexpected DEX";  // TODO: IllegalAccessError
diff --git a/src/class_linker.h b/src/class_linker.h
index eb40d28..306613f 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -40,13 +40,13 @@
 
   size_t NumLoadedClasses() const;
 
-  // Resolve a String with the given ID from the DexFile, storing the
+  // Resolve a String with the given index from the DexFile, storing the
   // result in the DexCache.
   String* ResolveString(const DexFile& dex_file,
                         uint32_t string_idx,
                         DexCache* dex_cache);
 
-  // Resolve a Type with the given ID from the DexFile, storing the
+  // Resolve a Type with the given index from the DexFile, storing the
   // result in the DexCache. The referrer is used to identity the
   // target DexCache and ClassLoader to use for resolution.
   Class* ResolveType(const DexFile& dex_file,
@@ -58,6 +58,17 @@
                        referrer->GetClassLoader());
   }
 
+  // Resolve a Type with the given index from the DexFile, storing the
+  // result in the DexCache. The referrer is used to identity the
+  // target DexCache and ClassLoader to use for resolution.
+  Class* ResolveType(uint32_t type_idx, Method* referrer) {
+    Class* declaring_class = referrer->GetDeclaringClass();
+    DexCache* dex_cache = declaring_class->GetDexCache();
+    const ClassLoader* class_loader = declaring_class->GetClassLoader();
+    const DexFile& dex_file = FindDexFile(dex_cache);
+    return ResolveType(dex_file, type_idx, dex_cache, class_loader);
+  }
+
   // Resolve a type with the given ID from the DexFile, storing the
   // result in DexCache. The ClassLoader is used to search for the
   // type, since it may be referenced from but not contained within
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index c1ef7b7..71bf523 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -40,7 +40,8 @@
     EXPECT_FALSE(primitive->IsErroneous());
     EXPECT_TRUE(primitive->IsVerified());
     EXPECT_TRUE(primitive->IsLinked());
-    EXPECT_FALSE(primitive->IsArray());
+    EXPECT_FALSE(primitive->IsArrayInstance());
+    EXPECT_FALSE(primitive->IsArrayClass());
     EXPECT_EQ(0, primitive->array_rank_);
     EXPECT_FALSE(primitive->IsInterface());
     EXPECT_TRUE(primitive->IsPublic());
@@ -80,7 +81,8 @@
     EXPECT_FALSE(array->IsErroneous());
     EXPECT_TRUE(array->IsVerified());
     EXPECT_TRUE(array->IsLinked());
-    EXPECT_TRUE(array->IsArray());
+    EXPECT_FALSE(array->IsArrayInstance());
+    EXPECT_TRUE(array->IsArrayClass());
     EXPECT_LE(1, array->array_rank_);
     EXPECT_FALSE(array->IsInterface());
     EXPECT_EQ(array->GetComponentType()->IsPublic(), array->IsPublic());
@@ -225,7 +227,7 @@
     EXPECT_EQ(class_loader, klass->GetClassLoader());
     if (klass->IsPrimitive()) {
       AssertPrimitiveClass(descriptor, klass);
-    } else if (klass->IsArray()) {
+    } else if (klass->IsArrayClass()) {
       AssertArrayClass(descriptor, klass);
     } else {
       AssertClass(descriptor, klass);
@@ -302,7 +304,8 @@
   EXPECT_FALSE(JavaLangObject->IsErroneous());
   EXPECT_FALSE(JavaLangObject->IsVerified());
   EXPECT_TRUE(JavaLangObject->IsLinked());
-  EXPECT_FALSE(JavaLangObject->IsArray());
+  EXPECT_FALSE(JavaLangObject->IsArrayInstance());
+  EXPECT_FALSE(JavaLangObject->IsArrayClass());
   EXPECT_EQ(0, JavaLangObject->array_rank_);
   EXPECT_FALSE(JavaLangObject->IsInterface());
   EXPECT_TRUE(JavaLangObject->IsPublic());
@@ -332,7 +335,8 @@
   EXPECT_FALSE(MyClass->IsErroneous());
   EXPECT_FALSE(MyClass->IsVerified());
   EXPECT_TRUE(MyClass->IsLinked());
-  EXPECT_FALSE(MyClass->IsArray());
+  EXPECT_FALSE(MyClass->IsArrayInstance());
+  EXPECT_FALSE(MyClass->IsArrayClass());
   EXPECT_EQ(0, JavaLangObject->array_rank_);
   EXPECT_FALSE(MyClass->IsInterface());
   EXPECT_FALSE(MyClass->IsPublic());
diff --git a/src/heap.cc b/src/heap.cc
index 026fbe0..42e42bd 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -104,7 +104,7 @@
   DCHECK(klass == NULL
          || klass->descriptor_ == NULL
          || (klass->IsClassClass() && num_bytes >= sizeof(Class))
-         || (klass->object_size_ == (klass->IsArray() ? 0 : num_bytes)));
+         || (klass->object_size_ == (klass->IsArrayClass() ? 0 : num_bytes)));
   Object* obj = Allocate(num_bytes);
   if (obj != NULL) {
     obj->klass_ = klass;
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 0d7b256..57090ac 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -1910,7 +1910,7 @@
   static jsize GetArrayLength(JNIEnv* env, jarray java_array) {
     ScopedJniThreadState ts(env);
     Object* obj = Decode<Object*>(ts, java_array);
-    CHECK(obj->IsArray()); // TODO: ReportJniError
+    CHECK(obj->IsArrayInstance()); // TODO: ReportJniError
     Array* array = obj->AsArray();
     return array->GetLength();
   }
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc
index 179d954..eb81cf6 100644
--- a/src/mark_sweep.cc
+++ b/src/mark_sweep.cc
@@ -190,7 +190,7 @@
   DCHECK(obj->IsClass());
   const Class* klass = obj->AsClass();
   MarkObject(klass->GetClass());
-  if (klass->IsArray()) {
+  if (klass->IsArrayClass()) {
     MarkObject(klass->GetComponentType());
   }
   if (klass->IsLoaded()) {
@@ -299,7 +299,7 @@
   DCHECK(IsMarked(obj));
   if (obj->IsClass()) {
     ScanClass(obj);
-  } else if (obj->IsArray()) {
+  } else if (obj->IsArrayInstance()) {
     ScanArray(obj);
   } else {
     ScanOther(obj);
diff --git a/src/object.cc b/src/object.cc
index 175e687..7328dbe 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -14,10 +14,46 @@
 
 namespace art {
 
-Array* Array::Alloc(Class* array_class, size_t component_count) {
+Array* Array::Alloc(Class* array_class, int32_t component_count, size_t component_size) {
+  DCHECK_GE(component_count, 0);
+  DCHECK(array_class->IsArrayClass());
+  size_t size = SizeOf(component_count, component_size);
+  Array* array = down_cast<Array*>(Heap::AllocObject(array_class, size));
+  if (array != NULL) {
+    DCHECK(array->IsArrayInstance());
+    array->SetLength(component_count);
+  }
+  return array;
+}
+
+Array* Array::Alloc(Class* array_class, int32_t component_count) {
   return Alloc(array_class, component_count, array_class->GetComponentSize());
 }
 
+Array* Array::AllocFromCode(uint32_t type_idx, Method* method, int32_t component_count) {
+  Class* klass = method->dex_cache_types_->Get(type_idx);
+  if (klass == NULL) {
+    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
+    if (klass == NULL || !klass->IsArrayClass()) {
+      UNIMPLEMENTED(FATAL) << "throw an error";
+      return NULL;
+    }
+  }
+  return Array::Alloc(klass, component_count);
+}
+
+Object* Class::NewInstanceFromCode(uint32_t type_idx, Method* method) {
+  Class* klass = method->dex_cache_types_->Get(type_idx);
+  if (klass == NULL) {
+    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
+    if (klass == NULL) {
+      UNIMPLEMENTED(FATAL) << "throw an error";
+      return NULL;
+    }
+  }
+  return klass->NewInstance();
+}
+
 bool Class::Implements(const Class* klass) const {
   DCHECK(klass != NULL);
   DCHECK(klass->IsInterface());
@@ -52,8 +88,8 @@
 //   int[] instanceof Object[]     --> false
 //
 bool Class::IsArrayAssignableFromArray(const Class* klass) const {
-  DCHECK(IsArray());
-  DCHECK(klass->IsArray());
+  DCHECK(IsArrayClass());
+  DCHECK(klass->IsArrayClass());
   DCHECK_GT(array_rank_, 0);
   DCHECK_GT(klass->array_rank_, 0);
   DCHECK(component_type_ != NULL);
@@ -87,8 +123,8 @@
 
 bool Class::IsAssignableFromArray(const Class* klass) const {
   DCHECK(!IsInterface());  // handled first in IsAssignableFrom
-  DCHECK(klass->IsArray());
-  if (!IsArray()) {
+  DCHECK(klass->IsArrayClass());
+  if (!IsArrayClass()) {
     // If "this" is not also an array, it must be Object.
     // klass's super should be java_lang_Object, since it is an array.
     Class* java_lang_Object = klass->GetSuperClass();
@@ -101,7 +137,7 @@
 
 bool Class::IsSubClass(const Class* klass) const {
   DCHECK(!IsInterface());
-  DCHECK(!klass->IsArray());
+  DCHECK(!klass->IsArrayClass());
   const Class* current = this;
   do {
     if (current == klass) {
@@ -151,10 +187,10 @@
     return false;
   }
   // Arrays are in the same package when their element classes are.
-  if (klass1->IsArray()) {
+  if (klass1->IsArrayClass()) {
     klass1 = klass1->GetComponentType();
   }
-  if (klass2->IsArray()) {
+  if (klass2->IsArrayClass()) {
     klass2 = klass2->GetComponentType();
   }
   // Compare the package part of the descriptor string.
diff --git a/src/object.h b/src/object.h
index 9db0704..2cdfae2 100644
--- a/src/object.h
+++ b/src/object.h
@@ -244,15 +244,15 @@
     return true;
   }
 
-  bool IsArray() const;
+  bool IsArrayInstance() const;
 
   Array* AsArray() {
-    DCHECK(IsArray());
+    DCHECK(IsArrayInstance());
     return down_cast<Array*>(this);
   }
 
   const Array* AsArray() const {
-    DCHECK(IsArray());
+    DCHECK(IsArrayInstance());
     return down_cast<const Array*>(this);
   }
 
@@ -751,20 +751,16 @@
     return sizeof(Array) + component_count * component_size;
   }
 
+  // Given the context of a calling Method, use its DexCache to
+  // resolve a type to an array Class. If it cannot be resolved, throw
+  // an error. If it can, use it to create an array.
+  static Array* AllocFromCode(uint32_t type_idx, Method* method, int32_t component_count);
+
   // A convenience for code that doesn't know the component size,
   // and doesn't want to have to work it out itself.
-  static Array* Alloc(Class* array_class, size_t component_count);
+  static Array* Alloc(Class* array_class, int32_t component_count);
 
-  static Array* Alloc(Class* array_class,
-                      size_t component_count,
-                      size_t component_size) {
-    size_t size = SizeOf(component_count, component_size);
-    Array* array = down_cast<Array*>(Heap::AllocObject(array_class, size));
-    if (array != NULL) {
-      array->SetLength(component_count);
-    }
-    return array;
-  }
+  static Array* Alloc(Class* array_class, int32_t component_count, size_t component_size);
 
   size_t SizeOf() const;
 
@@ -810,7 +806,7 @@
 class ObjectArray : public Array {
  public:
   static ObjectArray<T>* Alloc(Class* object_array_class,
-                               size_t length) {
+                               int32_t length) {
     return Array::Alloc(object_array_class, length, sizeof(uint32_t))->AsObjectArray<T>();
   }
 
@@ -941,6 +937,11 @@
     kPrimNot = -1
   };
 
+  // Given the context of a calling Method, use its DexCache to
+  // resolve a type to a Class. If it cannot be resolved, throw an
+  // error. If it can, use it to create an instance.
+  static Object* NewInstanceFromCode(uint32_t type_idx, Method* method);
+
   Object* NewInstance() {
     DCHECK(!IsAbstract());
     return Heap::AllocObject(this, this->object_size_);
@@ -966,7 +967,7 @@
     if (IsInterface()) {
       return klass->Implements(this);
     }
-    if (klass->IsArray()) {
+    if (klass->IsArrayClass()) {
       return IsAssignableFromArray(klass);
     }
     return klass->IsSubClass(this);
@@ -1041,7 +1042,7 @@
                               const String* descriptor2);
 
   // Returns true if this class represents an array class.
-  bool IsArray() const;
+  bool IsArrayClass() const;
 
   // Returns true if the class is an interface.
   bool IsInterface() const {
@@ -1391,11 +1392,11 @@
 }
 
 inline bool Object::IsObjectArray() const {
-  return IsArray() && !klass_->component_type_->IsPrimitive();
+  return IsArrayInstance() && !klass_->component_type_->IsPrimitive();
 }
 
-inline bool Object::IsArray() const {
-  return klass_->IsArray();
+inline bool Object::IsArrayInstance() const {
+  return klass_->IsArrayClass();
 }
 
 inline bool Object::IsField() const {
@@ -1411,7 +1412,7 @@
 }
 
 inline size_t Object::SizeOf() const {
-  if (IsArray()) {
+  if (IsArrayInstance()) {
     return AsArray()->SizeOf();
   }
   if (IsClass()) {
@@ -1757,8 +1758,8 @@
   }
 }
 
-inline bool Class::IsArray() const {
-  return GetDescriptor()->CharAt(0) == '[';  // TODO: avoid parsing the descriptor
+inline bool Class::IsArrayClass() const {
+  return array_rank_ != 0;
 }
 
 class InterfaceEntry {
diff --git a/src/object_test.cc b/src/object_test.cc
index fc58778..c7ddde9 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -37,6 +37,18 @@
     }
     EXPECT_EQ(hash_expected, string->GetHashCode());
   }
+
+  uint32_t FindTypeIdxByDescriptor(const DexFile& dex_file, const StringPiece& descriptor) {
+    for (size_t i = 0; i < dex_file.NumTypeIds(); i++) {
+      const DexFile::TypeId& type_id = dex_file.GetTypeId(i);
+      if (descriptor == dex_file.GetTypeDescriptor(type_id)) {
+        return i;
+      }
+    }
+    CHECK(false) << "Could not find type index for " << descriptor;
+    return 0;
+  }
+
 };
 
 TEST_F(ObjectTest, IsInSamePackage) {
@@ -154,6 +166,27 @@
   TestPrimitiveArray<ShortArray>(class_linker_);
 }
 
+TEST_F(ObjectTest, AllocObjectFromCode) {
+  // pretend we are trying to call 'new String' from Object.toString
+  Class* java_lang_Object = class_linker_->FindSystemClass("Ljava/lang/Object;");
+  Method* toString = java_lang_Object->FindVirtualMethod("toString", "()Ljava/lang/String;");
+  uint32_t type_idx = FindTypeIdxByDescriptor(*java_lang_dex_file_.get(), "Ljava/lang/String;");
+  Object* string = Class::NewInstanceFromCode(type_idx, toString);
+  EXPECT_TRUE(string->IsString());
+}
+
+TEST_F(ObjectTest, AllocArrayFromCode) {
+  // pretend we are trying to call 'new char[3]' from String.toCharArray
+  Class* java_lang_String = class_linker_->FindSystemClass("Ljava/lang/String;");
+  Method* toCharArray = java_lang_String->FindVirtualMethod("toCharArray", "()[C");
+  uint32_t type_idx = FindTypeIdxByDescriptor(*java_lang_dex_file_.get(), "[C");
+  Object* array = Array::AllocFromCode(type_idx, toCharArray, 3);
+  EXPECT_TRUE(array->IsArrayInstance());
+  EXPECT_EQ(3, array->AsArray()->GetLength());
+  EXPECT_TRUE(array->GetClass()->IsArrayClass());
+  EXPECT_TRUE(array->GetClass()->GetComponentType()->IsPrimitive());
+}
+
 TEST_F(ObjectTest, String) {
   // Test the empty string.
   AssertString(0, "",     "", 0);
diff --git a/src/reference_table.cc b/src/reference_table.cc
index ebdb7bc..a006b65 100644
--- a/src/reference_table.cc
+++ b/src/reference_table.cc
@@ -54,7 +54,7 @@
 // If "obj" is an array, return the number of elements in the array.
 // Otherwise, return zero.
 size_t GetElementCount(const Object* obj) {
-  if (obj == NULL || obj == kClearedJniWeakGlobal || !obj->IsArray()) {
+  if (obj == NULL || obj == kClearedJniWeakGlobal || !obj->IsArrayInstance()) {
     return 0;
   }
   return obj->AsArray()->GetLength();
diff --git a/src/thread.h b/src/thread.h
index b7f639e..215da71 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -204,7 +204,7 @@
   int (*pArtInstanceofNonTrivialNoThrow) (const struct ClassObject*,
                 const struct ClassObject*);
   int (*pArtInstanceofNonTrivial) (const struct ClassObject*, const struct ClassObject*);
-  Array* (*pArtAllocArrayByClass)(Class*, size_t);
+  Array* (*pArtAllocArrayByClass)(Class*, int32_t);
   struct Method* (*pArtFindInterfaceMethodInCache)(ClassObject*, uint32_t,
                            const struct Method*, struct DvmDex*);
   bool (*pArtUnlockObjectNoThrow)(struct Thread*, struct Object*);