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*);