Use accessor methods for Object fields.
Ensure that Object fields are modified via accessors so that it's easy
to insert barriers (make all fields within Objects private). Add validity
checks to Field and Method accessors to ensure they are accessed when a
Class is in a suitable state. Add validity checks to all Object
accessors to check heap isn't corrupted. Remove hacked in strings from Field
and Method; make type fields used the dex cache that is lazily initialized.
Clean up various other TODOs and lint issues.
Change-Id: Iac0afc515c01f5419874d9cdcdb9a7b45443e3fb
diff --git a/src/assembler_arm.cc b/src/assembler_arm.cc
index 60b8f38..e613307 100644
--- a/src/assembler_arm.cc
+++ b/src/assembler_arm.cc
@@ -1419,7 +1419,7 @@
CHECK_EQ(R0, method_reg.AsCoreRegister());
AddConstant(SP, -frame_size);
RegList spill_list = 1 << R0 | 1 << LR;
- for(size_t i = 0; i < spill_regs.size(); i++) {
+ for (size_t i = 0; i < spill_regs.size(); i++) {
Register reg = spill_regs.at(i).AsCoreRegister();
// check assumption LR is the last register that gets spilled
CHECK_LT(reg, LR);
diff --git a/src/check_jni.cc b/src/check_jni.cc
index 3037eea..8a30279 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -360,34 +360,39 @@
ScopedJniThreadState ts(mEnv);
Field* f = DecodeField(ts, fid);
- if ((f->GetType() == 'L' || f->GetType() == '[') && java_object != NULL) {
- Object* obj = Decode<Object*>(ts, java_object);
- /*
- * If java_object is a weak global ref whose referent has been cleared,
- * obj will be NULL. Otherwise, obj should always be non-NULL
- * and valid.
- */
- if (obj != NULL && !Heap::IsHeapAddress(obj)) {
- LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
- JniAbort();
- return;
- } else {
-#if 0
- Class* field_class = dvmFindLoadedClass(f->signature);
- if (!obj->GetClass()->InstanceOf(field_class)) {
- LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << PrettyType(java_object);
+ Class* field_type = f->GetType();
+ if (!field_type->IsPrimitive()) {
+ if (java_object != NULL) {
+ Object* obj = Decode<Object*>(ts, java_object);
+ /*
+ * If java_object is a weak global ref whose referent has been cleared,
+ * obj will be NULL. Otherwise, obj should always be non-NULL
+ * and valid.
+ */
+ if (obj != NULL && !Heap::IsHeapAddress(obj)) {
+ LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object;
JniAbort();
return;
- }
+ } else {
+#if 0
+ Class* field_class = dvmFindLoadedClass(f->signature);
+ if (!obj->GetClass()->InstanceOf(field_class)) {
+ LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << PrettyType(java_object);
+ JniAbort();
+ return;
+ }
#else
- UNIMPLEMENTED(WARNING) << "need way to get Class* for a given Field*'s type";
+ UNIMPLEMENTED(WARNING) << "need way to get Class* for a given Field*'s type";
#endif
+ }
}
- } else if (f->GetType() != prim) {
+ } else if (field_type != Runtime::Current()->GetClassLinker()->FindPrimitiveClass(prim)) {
LOG(ERROR) << "JNI ERROR: attempt to set field " << PrettyField(f) << " with value of wrong type: " << prim;
JniAbort();
return;
- } else if (isStatic && !f->IsStatic()) {
+ }
+
+ if (isStatic && !f->IsStatic()) {
if (isStatic) {
LOG(ERROR) << "JNI ERROR: accessing non-static field " << PrettyField(f) << " as static";
} else {
@@ -414,8 +419,11 @@
}
Field* f = DecodeField(ts, fid);
+ Class* f_type = f->GetType();
+ // check invariant that all jfieldIDs have resovled types
+ DCHECK(f_type != NULL);
Class* c = o->GetClass();
- if (c->FindInstanceField(f->GetName()->ToModifiedUtf8(), f->GetDescriptor()) == NULL) {
+ if (c->FindInstanceField(f->GetName()->ToModifiedUtf8(), f_type) == NULL) {
LOG(ERROR) << "JNI ERROR: jfieldID " << PrettyField(f) << " not valid for an object of class " << PrettyType(o);
JniAbort();
}
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 36bf6a7..9a6470b 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2,6 +2,7 @@
#include "class_linker.h"
+#include <string>
#include <utility>
#include <vector>
@@ -69,6 +70,8 @@
ClassLinker::ClassLinker(InternTable* intern_table)
: classes_lock_(Mutex::Create("ClassLinker::Lock")),
class_roots_(NULL),
+ array_interfaces_(NULL),
+ array_iftable_(NULL),
init_done_(false),
intern_table_(intern_table) {
}
@@ -77,72 +80,84 @@
CHECK(!init_done_);
// java_lang_Class comes first, its needed for AllocClass
- Class* java_lang_Class = down_cast<Class*>(Heap::AllocObject(NULL, sizeof(ClassClass)));
+ Class* java_lang_Class = down_cast<Class*>(
+ Heap::AllocObject(NULL, sizeof(ClassClass)));
CHECK(java_lang_Class != NULL);
- java_lang_Class->class_size_ = sizeof(ClassClass);
- java_lang_Class->klass_ = java_lang_Class;
+ java_lang_Class->SetClass(java_lang_Class);
+ java_lang_Class->SetClassSize(sizeof(ClassClass));
// AllocClass(Class*) can now be used
// java_lang_Object comes next so that object_array_class can be created
Class* java_lang_Object = AllocClass(java_lang_Class, sizeof(Class));
CHECK(java_lang_Object != NULL);
// backfill Object as the super class of Class
- java_lang_Class->super_class_ = java_lang_Object;
- // mark as non-primitive for object_array_class
- java_lang_Object->primitive_type_ = Class::kPrimNot;
+ java_lang_Class->SetSuperClass(java_lang_Object);
+ java_lang_Object->SetStatus(Class::kStatusLoaded);
- // Object[] is for DexCache and int[] is for various Class members.
+ // Object[] next to hold class roots
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);
+ object_array_class->SetArrayRank(1);
+ object_array_class->SetComponentType(java_lang_Object);
- // String and char[] are necessary so that FindClass can assign names to members
- Class* java_lang_String = AllocClass(java_lang_Class, sizeof(StringClass));
- CHECK(java_lang_String != NULL);
- CHECK_LT(java_lang_String->object_size_, sizeof(String));
- java_lang_String->object_size_ = sizeof(String);
- String::SetClass(java_lang_String);
+
+ // Setup the char[] class to be used for String
Class* char_array_class = AllocClass(java_lang_Class, sizeof(Class));
- CHECK(char_array_class != NULL);
- char_array_class->array_rank_ = 1;
+ char_array_class->SetArrayRank(1);
CharArray::SetArrayClass(char_array_class);
- // Now String::Alloc* can be used
- // backfill Class descriptors missing until this point
- java_lang_Class->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/Class;");
- java_lang_Object->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/Object;");
- object_array_class->descriptor_ = String::AllocFromModifiedUtf8("[Ljava/lang/Object;");
- java_lang_String->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/String;");
- char_array_class->descriptor_ = String::AllocFromModifiedUtf8("[C");
- int_array_class->descriptor_ = String::AllocFromModifiedUtf8("[I");
+ // Setup String
+ Class* java_lang_String = AllocClass(java_lang_Class, sizeof(StringClass));
+ String::SetClass(java_lang_String);
+ java_lang_String->SetObjectSize(sizeof(String));
+ java_lang_String->SetStatus(Class::kStatusResolved);
- // Field and Method are necessary so that FindClass can link members
- Class* java_lang_reflect_Field = AllocClass(java_lang_Class, sizeof(FieldClass));
- CHECK(java_lang_reflect_Field != NULL);
- java_lang_reflect_Field->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/reflect/Field;");
- CHECK_LT(java_lang_reflect_Field->object_size_, sizeof(Field));
- java_lang_reflect_Field->object_size_ = sizeof(Field);
- Class* java_lang_reflect_Method = AllocClass(java_lang_Class, sizeof(MethodClass));
- java_lang_reflect_Method->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/reflect/Method;");
- CHECK(java_lang_reflect_Method != NULL);
- CHECK_LT(java_lang_reflect_Method->object_size_, sizeof(Method));
- java_lang_reflect_Method->object_size_ = sizeof(Method);
+ // Backfill Class descriptors missing until this point
+ // TODO: intern these strings
+ java_lang_Class->SetDescriptor(
+ String::AllocFromModifiedUtf8("Ljava/lang/Class;"));
+ java_lang_Object->SetDescriptor(
+ String::AllocFromModifiedUtf8("Ljava/lang/Object;"));
+ object_array_class->SetDescriptor(
+ String::AllocFromModifiedUtf8("[Ljava/lang/Object;"));
+ java_lang_String->SetDescriptor(
+ String::AllocFromModifiedUtf8("Ljava/lang/String;"));
+ char_array_class->SetDescriptor(String::AllocFromModifiedUtf8("[C"));
- // create storage for root classes, save away our work so far
+ // Create storage for root classes, save away our work so far (requires
+ // descriptors)
class_roots_ = ObjectArray<Class>::Alloc(object_array_class, kClassRootsMax);
SetClassRoot(kJavaLangClass, java_lang_Class);
SetClassRoot(kJavaLangObject, java_lang_Object);
SetClassRoot(kObjectArrayClass, object_array_class);
- SetClassRoot(kJavaLangString, java_lang_String);
SetClassRoot(kCharArrayClass, char_array_class);
+ SetClassRoot(kJavaLangString, java_lang_String);
+
+ // Setup the primitive type classes.
+ SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass("Z", Class::kPrimBoolean));
+ SetClassRoot(kPrimitiveByte, CreatePrimitiveClass("B", Class::kPrimByte));
+ SetClassRoot(kPrimitiveChar, CreatePrimitiveClass("C", Class::kPrimChar));
+ SetClassRoot(kPrimitiveShort, CreatePrimitiveClass("S", Class::kPrimShort));
+ SetClassRoot(kPrimitiveInt, CreatePrimitiveClass("I", Class::kPrimInt));
+ SetClassRoot(kPrimitiveLong, CreatePrimitiveClass("J", Class::kPrimLong));
+ SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass("F", Class::kPrimFloat));
+ SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass("D", Class::kPrimDouble));
+ SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass("V", Class::kPrimVoid));
+
+ // Backfill component type of char[]
+ char_array_class->SetComponentType(GetClassRoot(kPrimitiveChar));
+
+ // Create array interface entries to populate once we can load system classes
+ array_interfaces_ = AllocObjectArray<Class>(2);
+ array_iftable_ = new InterfaceEntry[2];
+
+ // Create int array type for AllocDexCache (done in AppendToBootClassPath)
+ Class* int_array_class = AllocClass(java_lang_Class, sizeof(Class));
+ int_array_class->SetArrayRank(1);
+ int_array_class->SetDescriptor(String::AllocFromModifiedUtf8("[I"));
+ int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt));
+ IntArray::SetArrayClass(int_array_class);
SetClassRoot(kIntArrayClass, int_array_class);
- SetClassRoot(kJavaLangReflectField, java_lang_reflect_Field);
- SetClassRoot(kJavaLangReflectMethod, java_lang_reflect_Method);
+
// now that these are registered, we can use AllocClass() and AllocObjectArray
// setup boot_class_path_ now that we can use AllocObjectArray to
@@ -152,137 +167,174 @@
CHECK(dex_file != NULL);
AppendToBootClassPath(*dex_file);
}
- // now we can use FindSystemClass, at least for non-arrays classes.
+
+ // Field and Method are necessary so that FindClass can link members
+ Class* java_lang_reflect_Field = AllocClass(java_lang_Class, sizeof(FieldClass));
+ CHECK(java_lang_reflect_Field != NULL);
+ java_lang_reflect_Field->SetDescriptor(String::AllocFromModifiedUtf8("Ljava/lang/reflect/Field;"));
+ java_lang_reflect_Field->SetObjectSize(sizeof(Field));
+ SetClassRoot(kJavaLangReflectField, java_lang_reflect_Field);
+ java_lang_reflect_Field->SetStatus(Class::kStatusResolved);
+ Field::SetClass(java_lang_reflect_Field);
+
+ Class* java_lang_reflect_Method = AllocClass(java_lang_Class, sizeof(MethodClass));
+ java_lang_reflect_Method->SetDescriptor(String::AllocFromModifiedUtf8("Ljava/lang/reflect/Method;"));
+ CHECK(java_lang_reflect_Method != NULL);
+ java_lang_reflect_Method->SetObjectSize(sizeof(Method));
+ SetClassRoot(kJavaLangReflectMethod, java_lang_reflect_Method);
+ java_lang_reflect_Method->SetStatus(Class::kStatusResolved);
+ Method::SetClass(java_lang_reflect_Method);
+
+ // now we can use FindSystemClass
+
+ // Object and String just need more minimal setup, since they do not have
+ // extra C++ fields.
+ java_lang_Object->SetStatus(Class::kStatusNotReady);
+ Class* Object_class = FindSystemClass("Ljava/lang/Object;");
+ CHECK_EQ(java_lang_Object, Object_class);
+ CHECK_EQ(java_lang_Object->GetObjectSize(), sizeof(Object));
+ java_lang_String->SetStatus(Class::kStatusNotReady);
+ Class* String_class = FindSystemClass("Ljava/lang/String;");
+ CHECK_EQ(java_lang_String, String_class);
+ CHECK_EQ(java_lang_String->GetObjectSize(), sizeof(String));
+
+ // Setup the primitive array type classes - can't be done until Object has
+ // a vtable
+ SetClassRoot(kBooleanArrayClass, FindSystemClass("[Z"));
+ BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
+
+ SetClassRoot(kByteArrayClass, FindSystemClass("[B"));
+ ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
+
+ Class* found_char_array_class = FindSystemClass("[C");
+ CHECK_EQ(char_array_class, found_char_array_class);
+
+ SetClassRoot(kShortArrayClass, FindSystemClass("[S"));
+ ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
+
+ Class* found_int_array_class = FindSystemClass("[I");
+ CHECK_EQ(int_array_class, found_int_array_class);
+
+ SetClassRoot(kLongArrayClass, FindSystemClass("[J"));
+ LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
+
+ SetClassRoot(kFloatArrayClass, FindSystemClass("[F"));
+ FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
+
+ SetClassRoot(kDoubleArrayClass, FindSystemClass("[D"));
+ DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
+
+ Class* found_object_array_class = FindSystemClass("[Ljava/lang/Object;");
+ CHECK_EQ(object_array_class, found_object_array_class);
+
+ // Setup the single, global copies of "interfaces" and "iftable"
+ Class* java_lang_Cloneable = FindSystemClass("Ljava/lang/Cloneable;");
+ CHECK(java_lang_Cloneable != NULL);
+ Class* java_io_Serializable = FindSystemClass("Ljava/io/Serializable;");
+ CHECK(java_io_Serializable != NULL);
+ CHECK(array_interfaces_ != NULL);
+ array_interfaces_->Set(0, java_lang_Cloneable);
+ array_interfaces_->Set(1, java_io_Serializable);
+ // We assume that Cloneable/Serializable don't have superinterfaces --
+ // normally we'd have to crawl up and explicitly list all of the
+ // supers as well. These interfaces don't have any methods, so we
+ // don't have to worry about the ifviPool either.
+ array_iftable_[0].SetInterface(array_interfaces_->Get(0));
+ array_iftable_[1].SetInterface(array_interfaces_->Get(1));
+
+ // Sanity check Object[]'s interfaces
+ CHECK_EQ(java_lang_Cloneable, object_array_class->GetInterface(0));
+ CHECK_EQ(java_io_Serializable, object_array_class->GetInterface(1));
// run Class, Field, and Method through FindSystemClass.
// this initializes their dex_cache_ fields and register them in classes_.
// we also override their object_size_ values to accommodate the extra C++ fields.
Class* Class_class = FindSystemClass("Ljava/lang/Class;");
CHECK_EQ(java_lang_Class, Class_class);
- CHECK_LT(java_lang_Class->object_size_, sizeof(Class));
- java_lang_Class->object_size_ = sizeof(Class);
+ // No sanity check on size as Class is variably sized
+
+ java_lang_reflect_Field->SetStatus(Class::kStatusNotReady);
Class* Field_class = FindSystemClass("Ljava/lang/reflect/Field;");
CHECK_EQ(java_lang_reflect_Field, Field_class);
- CHECK_LT(java_lang_reflect_Field->object_size_, sizeof(Field));
- java_lang_reflect_Field->object_size_ = sizeof(Field);
+ CHECK_LT(java_lang_reflect_Field->GetObjectSize(), sizeof(Field));
+ java_lang_reflect_Field->SetObjectSize(sizeof(Field));
+
+ java_lang_reflect_Method->SetStatus(Class::kStatusNotReady);
Class* Method_class = FindSystemClass("Ljava/lang/reflect/Method;");
CHECK_EQ(java_lang_reflect_Method, Method_class);
- CHECK_LT(java_lang_reflect_Method->object_size_, sizeof(Method));
- java_lang_reflect_Method->object_size_ = sizeof(Method);
-
- // Object and String just need more minimal setup, since they do not have extra C++ fields.
- Class* Object_class = FindSystemClass("Ljava/lang/Object;");
- CHECK_EQ(java_lang_Object, Object_class);
- CHECK_EQ(java_lang_Object->object_size_, sizeof(Object));
- Class* String_class = FindSystemClass("Ljava/lang/String;");
- CHECK_EQ(java_lang_String, String_class);
- CHECK_EQ(java_lang_String->object_size_, sizeof(String));
-
- // Setup the ClassLoaders, adjusting the object_size_ as necessary
- Class* java_lang_ClassLoader = FindSystemClass("Ljava/lang/ClassLoader;");
- CHECK(java_lang_ClassLoader != NULL);
- CHECK_LT(java_lang_ClassLoader->object_size_, sizeof(ClassLoader));
- java_lang_ClassLoader->object_size_ = sizeof(ClassLoader);
- SetClassRoot(kJavaLangClassLoader, java_lang_ClassLoader);
- Class* dalvik_system_BaseDexClassLoader = FindSystemClass("Ldalvik/system/BaseDexClassLoader;");
- CHECK(dalvik_system_BaseDexClassLoader != NULL);
- CHECK_EQ(dalvik_system_BaseDexClassLoader->object_size_, sizeof(BaseDexClassLoader));
- SetClassRoot(kDalvikSystemBaseDexClassLoader, dalvik_system_BaseDexClassLoader);
- Class* dalvik_system_PathClassLoader = FindSystemClass("Ldalvik/system/PathClassLoader;");
- CHECK(dalvik_system_PathClassLoader != NULL);
- CHECK_EQ(dalvik_system_PathClassLoader->object_size_, sizeof(PathClassLoader));
- SetClassRoot(kDalvikSystemPathClassLoader, dalvik_system_PathClassLoader);
- PathClassLoader::SetClass(dalvik_system_PathClassLoader);
-
- // Setup a single, global copy of "interfaces" and "iftable" for
- // reuse across array classes
- Class* java_lang_Cloneable = FindSystemClass("Ljava/lang/Cloneable;");
- CHECK(java_lang_Cloneable != NULL);
- Class* java_io_Serializable = FindSystemClass("Ljava/io/Serializable;");
- CHECK(java_io_Serializable != NULL);
-
- array_interfaces_ = AllocObjectArray<Class>(2);
- CHECK(array_interfaces_ != NULL);
- array_interfaces_->Set(0, java_lang_Cloneable);
- array_interfaces_->Set(1, java_io_Serializable);
-
- // We assume that Cloneable/Serializable don't have superinterfaces --
- // normally we'd have to crawl up and explicitly list all of the
- // supers as well. These interfaces don't have any methods, so we
- // don't have to worry about the ifviPool either.
- array_iftable_ = new InterfaceEntry[2];
- array_iftable_[0].SetInterface(array_interfaces_->Get(0));
- array_iftable_[1].SetInterface(array_interfaces_->Get(1));
- // now FindClass can be used for non-primitive array classes
-
- // run Object[] through FindClass to complete initialization
- Class* found_object_array_class = FindSystemClass("[Ljava/lang/Object;");
- CHECK_EQ(object_array_class, found_object_array_class);
- CHECK_EQ(java_lang_Cloneable, object_array_class->GetInterface(0));
- CHECK_EQ(java_io_Serializable, object_array_class->GetInterface(1));
-
- // Setup the primitive type classes.
- SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass("Z"));
- SetClassRoot(kPrimitiveByte, CreatePrimitiveClass("B"));
- SetClassRoot(kPrimitiveChar, CreatePrimitiveClass("C"));
- SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass("D"));
- SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass("F"));
- SetClassRoot(kPrimitiveInt, CreatePrimitiveClass("I"));
- SetClassRoot(kPrimitiveLong, CreatePrimitiveClass("J"));
- SetClassRoot(kPrimitiveShort, CreatePrimitiveClass("S"));
- SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass("V"));
- // now we can use FindSystemClass for anything, including for "[C"
-
- // run char[] and int[] through FindClass to complete initialization
- Class* found_char_array_class = FindSystemClass("[C");
- CHECK_EQ(char_array_class, found_char_array_class);
- Class* found_int_array_class = FindSystemClass("[I");
- CHECK_EQ(int_array_class, found_int_array_class);
-
- // Initialize all the other primitive array types for PrimitiveArray::Alloc.
- // These are easy because everything we need has already been set up.
- SetClassRoot(kBooleanArrayClass, FindSystemClass("[Z"));
- SetClassRoot(kByteArrayClass, FindSystemClass("[B"));
- SetClassRoot(kDoubleArrayClass, FindSystemClass("[D"));
- SetClassRoot(kFloatArrayClass, FindSystemClass("[F"));
- SetClassRoot(kLongArrayClass, FindSystemClass("[J"));
- SetClassRoot(kShortArrayClass, FindSystemClass("[S"));
- BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
- ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
- DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
- FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
- LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
- ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
+ CHECK_LT(java_lang_reflect_Method->GetObjectSize(), sizeof(Method));
+ java_lang_reflect_Method->SetObjectSize(sizeof(Method));
// java.lang.ref classes need to be specially flagged, but otherwise are normal classes
Class* java_lang_ref_FinalizerReference = FindSystemClass("Ljava/lang/ref/FinalizerReference;");
+ java_lang_ref_FinalizerReference->SetAccessFlags(
+ java_lang_ref_FinalizerReference->GetAccessFlags() |
+ kAccClassIsReference | kAccClassIsFinalizerReference);
Class* java_lang_ref_PhantomReference = FindSystemClass("Ljava/lang/ref/PhantomReference;");
+ java_lang_ref_PhantomReference->SetAccessFlags(
+ java_lang_ref_PhantomReference->GetAccessFlags() |
+ kAccClassIsReference | kAccClassIsPhantomReference);
Class* java_lang_ref_SoftReference = FindSystemClass("Ljava/lang/ref/SoftReference;");
+ java_lang_ref_SoftReference->SetAccessFlags(
+ java_lang_ref_SoftReference->GetAccessFlags() | kAccClassIsReference);
Class* java_lang_ref_WeakReference = FindSystemClass("Ljava/lang/ref/WeakReference;");
- java_lang_ref_FinalizerReference->access_flags_ |= kAccClassIsReference | kAccClassIsFinalizerReference;
- java_lang_ref_PhantomReference->access_flags_ |= kAccClassIsReference | kAccClassIsPhantomReference;
- java_lang_ref_SoftReference->access_flags_ |= kAccClassIsReference;
- java_lang_ref_WeakReference->access_flags_ |= kAccClassIsReference | kAccClassIsWeakReference;
+ java_lang_ref_WeakReference->SetAccessFlags(
+ java_lang_ref_WeakReference->GetAccessFlags() |
+ kAccClassIsReference | kAccClassIsWeakReference);
// Let the heap know some key offsets into java.lang.ref instances
+ // NB we hard code the field indexes here rather than using FindInstanceField
+ // as the types of the field can't be resolved prior to the runtime being
+ // fully initialized
Class* java_lang_ref_Reference = FindSystemClass("Ljava/lang/ref/Reference;");
- Field* referent = java_lang_ref_Reference->FindDeclaredInstanceField(
- "referent", "Ljava/lang/Object;");
- Field* queue = java_lang_ref_Reference->FindDeclaredInstanceField(
- "queue", "Ljava/lang/ref/ReferenceQueue;");
- Field* queueNext = java_lang_ref_Reference->FindDeclaredInstanceField(
- "queueNext", "Ljava/lang/ref/Reference;");
- Field* pendingNext = java_lang_ref_Reference->FindDeclaredInstanceField(
- "pendingNext", "Ljava/lang/ref/Reference;");
- Field* zombie = java_lang_ref_FinalizerReference->FindDeclaredInstanceField(
- "zombie", "Ljava/lang/Object;");
+
+ Field* pendingNext = java_lang_ref_Reference->GetInstanceField(0);
+ CHECK(pendingNext->GetName()->Equals("pendingNext"));
+ CHECK(ResolveType(pendingNext->GetTypeIdx(), pendingNext) ==
+ java_lang_ref_Reference);
+
+ Field* queue = java_lang_ref_Reference->GetInstanceField(1);
+ CHECK(queue->GetName()->Equals("queue"));
+ CHECK(ResolveType(queue->GetTypeIdx(), queue) ==
+ FindSystemClass("Ljava/lang/ref/ReferenceQueue;"));
+
+ Field* queueNext = java_lang_ref_Reference->GetInstanceField(2);
+ CHECK(queueNext->GetName()->Equals("queueNext"));
+ CHECK(ResolveType(queueNext->GetTypeIdx(), queueNext) ==
+ java_lang_ref_Reference);
+
+ Field* referent = java_lang_ref_Reference->GetInstanceField(3);
+ CHECK(referent->GetName()->Equals("referent"));
+ CHECK(ResolveType(referent->GetTypeIdx(), referent) ==
+ java_lang_Object);
+
+ Field* zombie = java_lang_ref_FinalizerReference->GetInstanceField(2);
+ CHECK(zombie->GetName()->Equals("zombie"));
+ CHECK(ResolveType(zombie->GetTypeIdx(), zombie) ==
+ java_lang_Object);
+
Heap::SetReferenceOffsets(referent->GetOffset(),
queue->GetOffset(),
queueNext->GetOffset(),
pendingNext->GetOffset(),
zombie->GetOffset());
- // Optimization for quick stack trace allocation
+ // Setup the ClassLoaders, adjusting the object_size_ as necessary
+ Class* java_lang_ClassLoader = FindSystemClass("Ljava/lang/ClassLoader;");
+ CHECK_LT(java_lang_ClassLoader->GetObjectSize(), sizeof(ClassLoader));
+ java_lang_ClassLoader->SetObjectSize(sizeof(ClassLoader));
+ SetClassRoot(kJavaLangClassLoader, java_lang_ClassLoader);
+
+ Class* dalvik_system_BaseDexClassLoader = FindSystemClass("Ldalvik/system/BaseDexClassLoader;");
+ CHECK_EQ(dalvik_system_BaseDexClassLoader->GetObjectSize(), sizeof(BaseDexClassLoader));
+ SetClassRoot(kDalvikSystemBaseDexClassLoader, dalvik_system_BaseDexClassLoader);
+
+ Class* dalvik_system_PathClassLoader = FindSystemClass("Ldalvik/system/PathClassLoader;");
+ CHECK_EQ(dalvik_system_PathClassLoader->GetObjectSize(), sizeof(PathClassLoader));
+ SetClassRoot(kDalvikSystemPathClassLoader, dalvik_system_PathClassLoader);
+ PathClassLoader::SetClass(dalvik_system_PathClassLoader);
+
+ // Set up java.lang.StackTraceElement as a convenience
SetClassRoot(kJavaLangStackTraceElement, FindSystemClass("Ljava/lang/StackTraceElement;"));
SetClassRoot(kJavaLangStackTraceElementArrayClass, FindSystemClass("[Ljava/lang/StackTraceElement;"));
StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
@@ -296,7 +348,7 @@
ClassRoot class_root = static_cast<ClassRoot>(i);
Class* klass = GetClassRoot(class_root);
CHECK(klass != NULL);
- DCHECK(klass->IsArrayClass() || klass->IsPrimitive() || klass->dex_cache_ != NULL);
+ DCHECK(klass->IsArrayClass() || klass->IsPrimitive() || klass->GetDexCache() != NULL);
// note SetClassRoot does additional validation.
// if possible add new checks there to catch errors early
}
@@ -316,7 +368,7 @@
struct DexCacheHash {
size_t operator()(art::DexCache* const& obj) const {
- return reinterpret_cast<size_t>(&obj);
+ return reinterpret_cast<size_t>(&obj);
}
};
typedef std::tr1::unordered_set<DexCache*, DexCacheHash> Set;
@@ -355,12 +407,12 @@
}
// reinit array_interfaces_ from any array class instance, they should all be ==
- array_interfaces_ = GetClassRoot(kObjectArrayClass)->interfaces_;
- DCHECK(array_interfaces_ == GetClassRoot(kBooleanArrayClass)->interfaces_);
+ array_interfaces_ = GetClassRoot(kObjectArrayClass)->GetInterfaces();
+ DCHECK(array_interfaces_ == GetClassRoot(kBooleanArrayClass)->GetInterfaces());
// build a map from location to DexCache to match up with DexFile::GetLocation
std::tr1::unordered_map<std::string, DexCache*> location_to_dex_cache;
- typedef InitCallbackState::Set::const_iterator It; // TODO: C++0x auto
+ typedef InitCallbackState::Set::const_iterator It; // TODO: C++0x auto
for (It it = state.dex_caches.begin(), end = state.dex_caches.end(); it != end; ++it) {
DexCache* dex_cache = *it;
std::string location = dex_cache->GetLocation()->ToModifiedUtf8();
@@ -374,8 +426,9 @@
DexCache* dex_cache = location_to_dex_cache[dex_file->GetLocation()];
AppendToBootClassPath(*dex_file, dex_cache);
}
-
String::SetClass(GetClassRoot(kJavaLangString));
+ Field::SetClass(GetClassRoot(kJavaLangReflectField));
+ Method::SetClass(GetClassRoot(kJavaLangReflectMethod));
BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
CharArray::SetArrayClass(GetClassRoot(kCharArrayClass));
@@ -399,7 +452,7 @@
return;
}
Class* klass = obj->AsClass();
- CHECK(klass->class_loader_ == NULL);
+ CHECK(klass->GetClassLoader() == NULL);
std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8();
@@ -415,7 +468,7 @@
}
// check if this is a root, if so, register it
- typedef InitCallbackState::Table::const_iterator It; // TODO: C++0x auto
+ typedef InitCallbackState::Table::const_iterator It; // TODO: C++0x auto
It it = state->descriptor_to_class_root.find(descriptor);
if (it != state->descriptor_to_class_root.end()) {
ClassRoot class_root = it->second;
@@ -435,7 +488,7 @@
{
MutexLock mu(classes_lock_);
- typedef Table::const_iterator It; // TODO: C++0x auto
+ typedef Table::const_iterator It; // TODO: C++0x auto
for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) {
visitor(it->second, arg);
}
@@ -447,6 +500,8 @@
ClassLinker::~ClassLinker() {
delete classes_lock_;
String::ResetClass();
+ Field::ResetClass();
+ Method::ResetClass();
BooleanArray::ResetArrayClass();
ByteArray::ResetArrayClass();
CharArray::ResetArrayClass();
@@ -478,7 +533,8 @@
Class* ClassLinker::AllocClass(Class* java_lang_Class, size_t class_size) {
DCHECK_GE(class_size, sizeof(Class));
Class* klass = Heap::AllocObject(java_lang_Class, class_size)->AsClass();
- klass->class_size_ = class_size;
+ klass->SetPrimitiveType(Class::kPrimNot); // default to not being primitive
+ klass->SetClassSize(class_size);
return klass;
}
@@ -553,27 +609,29 @@
} else {
klass = AllocClass(SizeOfClass(dex_file, dex_class_def));
}
- klass->dex_cache_ = dex_cache;
- LoadClass(dex_file, dex_class_def, klass, class_loader);
- // Check for a pending exception during load
- if (self->IsExceptionPending()) {
- // TODO: free native allocations in klass
- return NULL;
- }
- {
+ if (!klass->IsLinked()) {
+ klass->SetDexCache(dex_cache);
+ LoadClass(dex_file, dex_class_def, klass, class_loader);
+ // Check for a pending exception during load
+ if (self->IsExceptionPending()) {
+ // TODO: free native allocations in klass
+ return NULL;
+ }
ObjectLock lock(klass);
- klass->clinit_thread_id_ = self->GetId();
+ klass->SetClinitThreadId(self->GetId());
// Add the newly loaded class to the loaded classes table.
bool success = InsertClass(descriptor, klass); // TODO: just return collision
if (!success) {
// We may fail to insert if we raced with another thread.
- klass->clinit_thread_id_ = 0;
+ klass->SetClinitThreadId(0);
// TODO: free native allocations in klass
klass = LookupClass(descriptor, class_loader);
CHECK(klass != NULL);
+ return klass;
} else {
// Finish loading (if necessary) by finding parents
- if (!klass->IsLoaded() && !LoadSuperAndInterfaces(klass, dex_file)) {
+ CHECK(!klass->IsLoaded());
+ if (!LoadSuperAndInterfaces(klass, dex_file)) {
// Loading failed.
// TODO: CHECK(self->IsExceptionPending());
lock.NotifyAll();
@@ -581,7 +639,8 @@
}
CHECK(klass->IsLoaded());
// Link the class (if necessary)
- if (!klass->IsLinked() && !LinkClass(klass, dex_file)) {
+ CHECK(!klass->IsLinked());
+ if (!LinkClass(klass)) {
// Linking failed.
// TODO: CHECK(self->IsExceptionPending());
lock.NotifyAll();
@@ -595,7 +654,7 @@
if (!klass->IsLinked() && !klass->IsErroneous()) {
ObjectLock lock(klass);
// Check for circular dependencies between classes.
- if (!klass->IsLinked() && klass->clinit_thread_id_ == self->GetId()) {
+ if (!klass->IsLinked() && klass->GetClinitThreadId() == self->GetId()) {
self->ThrowNewException("Ljava/lang/ClassCircularityError;", NULL); // TODO: detail
return NULL;
}
@@ -666,43 +725,46 @@
Class* klass,
const ClassLoader* class_loader) {
CHECK(klass != NULL);
- CHECK(klass->dex_cache_ != NULL);
- CHECK_EQ(Class::kStatusNotReady, klass->status_);
+ CHECK(klass->GetDexCache() != NULL);
+ CHECK_EQ(Class::kStatusNotReady, klass->GetStatus());
const byte* class_data = dex_file.GetClassData(dex_class_def);
DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
CHECK(descriptor != NULL);
- klass->klass_ = GetClassRoot(kJavaLangClass);
- klass->descriptor_ = String::AllocFromModifiedUtf8(descriptor);
- klass->access_flags_ = dex_class_def.access_flags_;
- klass->class_loader_ = class_loader;
- klass->primitive_type_ = Class::kPrimNot;
- klass->status_ = Class::kStatusIdx;
+ klass->SetClass(GetClassRoot(kJavaLangClass));
+ if (klass->GetDescriptor() != NULL) {
+ DCHECK(klass->GetDescriptor()->Equals(descriptor));
+ } else {
+ klass->SetDescriptor(String::AllocFromModifiedUtf8(descriptor));
+ }
+ uint32_t access_flags = dex_class_def.access_flags_;
+ // Make sure there aren't any "bonus" flags set, since we use them for runtime
+ // state.
+ CHECK_EQ(access_flags & ~kAccClassFlagsMask, 0U);
+ klass->SetAccessFlags(access_flags);
+ klass->SetClassLoader(class_loader);
+ DCHECK(klass->GetPrimitiveType() == Class::kPrimNot);
+ klass->SetStatus(Class::kStatusIdx);
- // Make sure the aren't any "bonus" flags set, since we use them for runtime state.
- CHECK_EQ(klass->access_flags_ & ~kAccClassFlagsMask, 0U);
-
- klass->super_class_ = NULL;
- klass->super_class_type_idx_ = dex_class_def.superclass_idx_;
+ klass->SetSuperClassTypeIdx(dex_class_def.superclass_idx_);
size_t num_static_fields = header.static_fields_size_;
size_t num_instance_fields = header.instance_fields_size_;
size_t num_direct_methods = header.direct_methods_size_;
size_t num_virtual_methods = header.virtual_methods_size_;
- klass->source_file_ = dex_file.dexGetSourceFile(dex_class_def);
+ klass->SetSourceFile(dex_file.dexGetSourceFile(dex_class_def));
// Load class interfaces.
LoadInterfaces(dex_file, dex_class_def, klass);
// Load static fields.
- DCHECK(klass->sfields_ == NULL);
if (num_static_fields != 0) {
- klass->sfields_ = AllocObjectArray<Field>(num_static_fields);
+ klass->SetSFields(AllocObjectArray<Field>(num_static_fields));
uint32_t last_idx = 0;
- for (size_t i = 0; i < klass->NumStaticFields(); ++i) {
+ for (size_t i = 0; i < num_static_fields; ++i) {
DexFile::Field dex_field;
dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
Field* sfield = AllocField();
@@ -712,11 +774,10 @@
}
// Load instance fields.
- DCHECK(klass->ifields_ == NULL);
if (num_instance_fields != 0) {
- klass->ifields_ = AllocObjectArray<Field>(num_instance_fields);
+ klass->SetIFields(AllocObjectArray<Field>(num_instance_fields));
uint32_t last_idx = 0;
- for (size_t i = 0; i < klass->NumInstanceFields(); ++i) {
+ for (size_t i = 0; i < num_instance_fields; ++i) {
DexFile::Field dex_field;
dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
Field* ifield = AllocField();
@@ -726,12 +787,11 @@
}
// Load direct methods.
- DCHECK(klass->direct_methods_ == NULL);
if (num_direct_methods != 0) {
// TODO: append direct methods to class object
- klass->direct_methods_ = AllocObjectArray<Method>(num_direct_methods);
+ klass->SetDirectMethods(AllocObjectArray<Method>(num_direct_methods));
uint32_t last_idx = 0;
- for (size_t i = 0; i < klass->NumDirectMethods(); ++i) {
+ for (size_t i = 0; i < num_direct_methods; ++i) {
DexFile::Method dex_method;
dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
Method* meth = AllocMethod();
@@ -742,12 +802,11 @@
}
// Load virtual methods.
- DCHECK(klass->virtual_methods_ == NULL);
if (num_virtual_methods != 0) {
// TODO: append virtual methods to class object
- klass->virtual_methods_ = AllocObjectArray<Method>(num_virtual_methods);
+ klass->SetVirtualMethods(AllocObjectArray<Method>(num_virtual_methods));
uint32_t last_idx = 0;
- for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
+ for (size_t i = 0; i < num_virtual_methods; ++i) {
DexFile::Method dex_method;
dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
Method* meth = AllocMethod();
@@ -763,13 +822,12 @@
Class* klass) {
const DexFile::TypeList* list = dex_file.GetInterfacesList(dex_class_def);
if (list != NULL) {
- DCHECK(klass->interfaces_ == NULL);
- klass->interfaces_ = AllocObjectArray<Class>(list->Size());
- DCHECK(klass->interfaces_type_idx_ == NULL);
- klass->interfaces_type_idx_ = IntArray::Alloc(list->Size());
+ klass->SetInterfaces(AllocObjectArray<Class>(list->Size()));
+ IntArray* interfaces_idx = IntArray::Alloc(list->Size());
+ klass->SetInterfacesTypeIdx(interfaces_idx);
for (size_t i = 0; i < list->Size(); ++i) {
const DexFile::TypeItem& type_item = list->GetTypeItem(i);
- klass->interfaces_type_idx_->Set(i, type_item.type_idx_);
+ interfaces_idx->Set(i, type_item.type_idx_);
}
}
}
@@ -779,11 +837,19 @@
Class* klass,
Field* dst) {
const DexFile::FieldId& field_id = dex_file.GetFieldId(src.field_idx_);
- dst->declaring_class_ = klass;
- dst->name_ = ResolveString(dex_file, field_id.name_idx_, klass->GetDexCache());
- dst->descriptor_.set(dex_file.dexStringByTypeIdx(field_id.type_idx_));
- // TODO: Assign dst->type_.
- dst->access_flags_ = src.access_flags_;
+ dst->SetDeclaringClass(klass);
+ dst->SetName(ResolveString(dex_file, field_id.name_idx_, klass->GetDexCache()));
+ dst->SetTypeIdx(field_id.type_idx_);
+ dst->SetAccessFlags(src.access_flags_);
+
+ // In order to access primitive types using GetTypeDuringLinking we need to
+ // ensure they are resolved into the dex cache
+ const char* descriptor = dex_file.dexStringByTypeIdx(field_id.type_idx_);
+ if (descriptor[1] == '\0') {
+ // only the descriptors of primitive types should be 1 character long
+ Class* resolved = ResolveType(dex_file, field_id.type_idx_, klass);
+ DCHECK(resolved->IsPrimitive());
+ }
}
void ClassLinker::LoadMethod(const DexFile& dex_file,
@@ -791,38 +857,40 @@
Class* klass,
Method* dst) {
const DexFile::MethodId& method_id = dex_file.GetMethodId(src.method_idx_);
- dst->declaring_class_ = klass;
- dst->name_ = ResolveString(dex_file, method_id.name_idx_, klass->GetDexCache());
+ dst->SetDeclaringClass(klass);
+ dst->SetName(ResolveString(dex_file, method_id.name_idx_, klass->GetDexCache()));
{
int32_t utf16_length;
std::string utf8(dex_file.CreateMethodDescriptor(method_id.proto_idx_, &utf16_length));
- dst->signature_ = String::AllocFromModifiedUtf8(utf16_length, utf8.c_str());
+ dst->SetSignature(String::AllocFromModifiedUtf8(utf16_length, utf8.c_str()));
}
- dst->proto_idx_ = method_id.proto_idx_;
- dst->code_off_ = src.code_off_;
- dst->shorty_ = dex_file.GetShorty(method_id.proto_idx_);
- dst->access_flags_ = src.access_flags_;
+ dst->SetProtoIdx(method_id.proto_idx_);
+ dst->SetCodeItemOffset(src.code_off_);
+ const char* shorty = dex_file.GetShorty(method_id.proto_idx_);
+ dst->SetShorty(shorty);
+ dst->SetAccessFlags(src.access_flags_);
+ dst->SetReturnTypeIdx(dex_file.GetProtoId(method_id.proto_idx_).return_type_idx_);
- dst->dex_cache_strings_ = klass->dex_cache_->GetStrings();
- dst->dex_cache_resolved_types_ = klass->dex_cache_->GetResolvedTypes();
- dst->dex_cache_resolved_methods_ = klass->dex_cache_->GetResolvedMethods();
- dst->dex_cache_resolved_fields_ = klass->dex_cache_->GetResolvedFields();
- dst->dex_cache_code_and_direct_methods_ = klass->dex_cache_->GetCodeAndDirectMethods();
- dst->dex_cache_initialized_static_storage_ = klass->dex_cache_->GetInitializedStaticStorage();
+ dst->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
+ dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
+ dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
+ dst->SetDexCacheResolvedFields(klass->GetDexCache()->GetResolvedFields());
+ dst->SetDexCacheCodeAndDirectMethods(klass->GetDexCache()->GetCodeAndDirectMethods());
+ dst->SetDexCacheInitializedStaticStorage(klass->GetDexCache()->GetInitializedStaticStorage());
// TODO: check for finalize method
const DexFile::CodeItem* code_item = dex_file.GetCodeItem(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->SetNumRegisters(code_item->registers_size_);
+ dst->SetNumIns(code_item->ins_size_);
+ dst->SetNumOuts(code_item->outs_size_);
} else {
- uint16_t num_args = dst->NumArgRegisters();
- if (!dst->IsStatic()) {
+ uint16_t num_args = Method::NumArgRegisters(shorty);
+ if ((src.access_flags_ & kAccStatic) != 0) {
++num_args;
}
- dst->num_registers_ = dst->num_ins_ + num_args;
+ dst->SetNumRegisters(num_args);
// TODO: native methods
}
}
@@ -867,13 +935,15 @@
return NULL;
}
-Class* ClassLinker::CreatePrimitiveClass(const char* descriptor) {
+Class* ClassLinker::CreatePrimitiveClass(const char* descriptor,
+ Class::PrimitiveType type) {
+ // TODO: deduce one argument from the other
Class* klass = AllocClass(sizeof(Class));
CHECK(klass != NULL);
- klass->super_class_ = NULL;
- klass->access_flags_ = kAccPublic | kAccFinal | kAccAbstract;
- klass->descriptor_ = String::AllocFromModifiedUtf8(descriptor);
- klass->status_ = Class::kStatusInitialized;
+ klass->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
+ klass->SetDescriptor(String::AllocFromModifiedUtf8(descriptor));
+ klass->SetPrimitiveType(type);
+ klass->SetStatus(Class::kStatusInitialized);
bool success = InsertClass(descriptor, klass);
CHECK(success) << "CreatePrimitiveClass(" << descriptor << ") failed";
return klass;
@@ -893,36 +963,35 @@
//
// Returns NULL with an exception raised on failure.
Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor,
- const ClassLoader* class_loader)
-{
- CHECK(descriptor[0] == '[');
+ const ClassLoader* class_loader) {
+ CHECK_EQ('[', descriptor[0]);
// Identify the underlying element class and the array dimension depth.
- Class* component_type_ = NULL;
+ Class* component_type = NULL;
int array_rank;
if (descriptor[1] == '[') {
// array of arrays; keep descriptor and grab stuff from parent
Class* outer = FindClass(descriptor.substr(1), class_loader);
if (outer != NULL) {
- // want the base class, not "outer", in our component_type_
- component_type_ = outer->component_type_;
- array_rank = outer->array_rank_ + 1;
+ // want the base class, not "outer", in our component_type
+ component_type = outer->GetComponentType();
+ array_rank = outer->GetArrayRank() + 1;
} else {
- DCHECK(component_type_ == NULL); // make sure we fail
+ DCHECK(component_type == NULL); // make sure we fail
}
} else {
array_rank = 1;
if (descriptor[1] == 'L') {
// array of objects; strip off "[" and look up descriptor.
const StringPiece subDescriptor = descriptor.substr(1);
- component_type_ = FindClass(subDescriptor, class_loader);
+ component_type = FindClass(subDescriptor, class_loader);
} else {
// array of a primitive type
- component_type_ = FindPrimitiveClass(descriptor[1]);
+ component_type = FindPrimitiveClass(descriptor[1]);
}
}
- if (component_type_ == NULL) {
+ if (component_type == NULL) {
// failed
// DCHECK(Thread::Current()->IsExceptionPending()); // TODO
return NULL;
@@ -939,14 +1008,14 @@
// If we find it, the caller adds "loader" to the class' initiating
// loader list, which should prevent us from going through this again.
//
- // This call is unnecessary if "loader" and "component_type_->class_loader_"
+ // This call is unnecessary if "loader" and "component_type->GetClassLoader()"
// are the same, because our caller (FindClass) just did the
// lookup. (Even if we get this wrong we still have correct behavior,
// because we effectively do this lookup again when we add the new
// class to the hash table --- necessary because of possible races with
// other threads.)
- if (class_loader != component_type_->class_loader_) {
- Class* new_class = LookupClass(descriptor, component_type_->class_loader_);
+ if (class_loader != component_type->GetClassLoader()) {
+ Class* new_class = LookupClass(descriptor, component_type->GetClassLoader());
if (new_class != NULL) {
return new_class;
}
@@ -963,6 +1032,7 @@
Class* new_class = NULL;
if (!init_done_) {
+ // Classes that were hand created, ie not by FindSystemClass
if (descriptor == "[Ljava/lang/Object;") {
new_class = GetClassRoot(kObjectArrayClass);
} else if (descriptor == "[C") {
@@ -976,17 +1046,19 @@
if (new_class == NULL) {
return NULL;
}
+ new_class->SetArrayRank(array_rank);
+ new_class->SetComponentType(component_type);
}
- new_class->descriptor_ = String::AllocFromModifiedUtf8(descriptor.ToString().c_str());
+ DCHECK_LE(1, new_class->GetArrayRank());
+ DCHECK(new_class->GetComponentType() != NULL);
+ new_class->SetDescriptor(String::AllocFromModifiedUtf8(descriptor.ToString().c_str()));
Class* java_lang_Object = GetClassRoot(kJavaLangObject);
- new_class->super_class_ = java_lang_Object;
- new_class->vtable_ = java_lang_Object->vtable_;
- new_class->primitive_type_ = Class::kPrimNot;
- new_class->component_type_ = component_type_;
- new_class->class_loader_ = component_type_->class_loader_;
- new_class->array_rank_ = array_rank;
- new_class->status_ = Class::kStatusInitialized;
- // don't need to set new_class->object_size_
+ new_class->SetSuperClass(java_lang_Object);
+ new_class->SetVTable(java_lang_Object->GetVTable());
+ new_class->SetPrimitiveType(Class::kPrimNot);
+ new_class->SetClassLoader(component_type->GetClassLoader());
+ new_class->SetStatus(Class::kStatusInitialized);
+ // don't need to set new_class->SetObjectSize(..)
// because Object::SizeOf delegates to Array::SizeOf
@@ -1002,21 +1074,19 @@
// Use the single, global copies of "interfaces" and "iftable"
// (remember not to free them for arrays).
- DCHECK(array_interfaces_ != NULL);
- new_class->interfaces_ = array_interfaces_;
- new_class->iftable_count_ = 2;
- DCHECK(array_iftable_ != NULL);
- new_class->iftable_ = array_iftable_;
+ new_class->SetInterfaces(array_interfaces_);
+ new_class->SetIFTableCount(2);
+ new_class->SetIFTable(array_iftable_);
// Inherit access flags from the component type. Arrays can't be
// used as a superclass or interface, so we want to add "final"
// and remove "interface".
//
// Don't inherit any non-standard flags (e.g., kAccFinal)
- // from component_type_. We assume that the array class does not
+ // from component_type. We assume that the array class does not
// override finalize().
- new_class->access_flags_ = ((new_class->component_type_->access_flags_ &
- ~kAccInterface) | kAccFinal) & kAccJavaFlagsMask;
+ new_class->SetAccessFlags(((new_class->GetComponentType()->GetAccessFlags() &
+ ~kAccInterface) | kAccFinal) & kAccJavaFlagsMask);
if (InsertClass(descriptor, new_class)) {
return new_class;
@@ -1028,7 +1098,7 @@
// (Yes, this happens.)
// Grab the winning class.
- Class* other_class = LookupClass(descriptor, component_type_->class_loader_);
+ Class* other_class = LookupClass(descriptor, component_type->GetClassLoader());
DCHECK(other_class != NULL);
return other_class;
}
@@ -1070,10 +1140,10 @@
Class* ClassLinker::LookupClass(const StringPiece& descriptor, const ClassLoader* class_loader) {
size_t hash = StringPieceHash()(descriptor);
MutexLock mu(classes_lock_);
- typedef Table::const_iterator It; // TODO: C++0x auto
+ typedef Table::const_iterator It; // TODO: C++0x auto
for (It it = classes_.find(hash), end = classes_.end(); it != end; ++it) {
Class* klass = it->second;
- if (klass->descriptor_->Equals(descriptor) && klass->class_loader_ == class_loader) {
+ if (klass->GetDescriptor()->Equals(descriptor) && klass->GetClassLoader() == class_loader) {
return klass;
}
}
@@ -1097,7 +1167,7 @@
CHECK(klass->GetStatus() == Class::kStatusResolved);
- klass->status_ = Class::kStatusVerifying;
+ klass->SetStatus(Class::kStatusVerifying);
if (!DexVerify::VerifyClass(klass)) {
LG << "Verification failed"; // TODO: ThrowVerifyError
Object* exception = self->GetException();
@@ -1109,13 +1179,13 @@
klass->SetStatus(Class::kStatusVerified);
}
- if (klass->status_ == Class::kStatusInitialized) {
+ if (klass->GetStatus() == Class::kStatusInitialized) {
return true;
}
- while (klass->status_ == Class::kStatusInitializing) {
+ while (klass->GetStatus() == Class::kStatusInitializing) {
// we caught somebody else in the act; was it us?
- if (klass->clinit_thread_id_ == self->GetId()) {
+ if (klass->GetClinitThreadId() == self->GetId()) {
LG << "recursive <clinit>";
return true;
}
@@ -1161,10 +1231,10 @@
return false;
}
- DCHECK(klass->status_ < Class::kStatusInitializing);
+ DCHECK(klass->GetStatus() < Class::kStatusInitializing);
- klass->clinit_thread_id_ = self->GetId();
- klass->status_ = Class::kStatusInitializing;
+ klass->SetClinitThreadId(self->GetId());
+ klass->SetStatus(Class::kStatusInitializing);
}
if (!InitializeSuperClass(klass)) {
@@ -1211,12 +1281,12 @@
}
}
}
- for (size_t i = 0; i < klass->iftable_count_; ++i) {
- const InterfaceEntry* iftable = &klass->iftable_[i];
+ for (size_t i = 0; i < klass->GetIFTableCount(); ++i) {
+ const InterfaceEntry* iftable = &klass->GetIFTable()[i];
Class* interface = iftable->GetInterface();
if (klass->GetClassLoader() != interface->GetClassLoader()) {
for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
- uint32_t vtable_index = iftable->method_index_array_[j];
+ uint32_t vtable_index = iftable->GetMethodIndexArray()[j];
const Method* method = klass->GetVirtualMethod(vtable_index);
if (!HasSameMethodDescriptorClasses(method, interface,
method->GetClass())) {
@@ -1233,7 +1303,7 @@
const Class* klass1,
const Class* klass2) {
const DexFile& dex_file = FindDexFile(method->GetClass()->GetDexCache());
- const DexFile::ProtoId& proto_id = dex_file.GetProtoId(method->proto_idx_);
+ const DexFile::ProtoId& proto_id = dex_file.GetProtoId(method->GetProtoIdx());
DexFile::ParameterIterator *it;
for (it = dex_file.GetParameterIterator(proto_id); it->HasNext(); it->Next()) {
const char* descriptor = it->GetDescriptor();
@@ -1391,8 +1461,8 @@
}
}
-bool ClassLinker::LinkClass(Class* klass, const DexFile& dex_file) {
- CHECK_EQ(Class::kStatusLoaded, klass->status_);
+bool ClassLinker::LinkClass(Class* klass) {
+ CHECK_EQ(Class::kStatusLoaded, klass->GetStatus());
if (!LinkSuperClass(klass)) {
return false;
}
@@ -1407,44 +1477,43 @@
}
CreateReferenceInstanceOffsets(klass);
CreateReferenceStaticOffsets(klass);
- CHECK_EQ(Class::kStatusLoaded, klass->status_);
- klass->status_ = Class::kStatusResolved;
+ CHECK_EQ(Class::kStatusLoaded, klass->GetStatus());
+ klass->SetStatus(Class::kStatusResolved);
return true;
}
bool ClassLinker::LoadSuperAndInterfaces(Class* klass, const DexFile& dex_file) {
- CHECK_EQ(Class::kStatusIdx, klass->status_);
- if (klass->super_class_type_idx_ != DexFile::kDexNoIndex) {
- Class* super_class = ResolveType(dex_file, klass->super_class_type_idx_, klass);
+ CHECK_EQ(Class::kStatusIdx, klass->GetStatus());
+ if (klass->GetSuperClassTypeIdx() != DexFile::kDexNoIndex) {
+ Class* super_class = ResolveType(dex_file, klass->GetSuperClassTypeIdx(), klass);
if (super_class == NULL) {
LG << "Failed to resolve superclass";
return false;
}
- klass->super_class_ = super_class; // TODO: write barrier
+ klass->SetSuperClass(super_class);
}
- if (klass->NumInterfaces() > 0) {
- for (size_t i = 0; i < klass->NumInterfaces(); ++i) {
- uint32_t type_idx = klass->interfaces_type_idx_->Get(i);
- klass->SetInterface(i, ResolveType(dex_file, type_idx, klass));
- if (klass->GetInterface(i) == NULL) {
- LG << "Failed to resolve interface";
- return false;
- }
- // Verify
- if (!klass->CanAccess(klass->GetInterface(i))) {
- LG << "Inaccessible interface";
- return false;
- }
+ for (size_t i = 0; i < klass->NumInterfaces(); ++i) {
+ uint32_t idx = klass->GetInterfacesTypeIdx()->Get(i);
+ Class *interface = ResolveType(dex_file, idx, klass);
+ klass->SetInterface(i, interface);
+ if (interface == NULL) {
+ LG << "Failed to resolve interface";
+ return false;
+ }
+ // Verify
+ if (!klass->CanAccess(interface)) {
+ LG << "Inaccessible interface";
+ return false;
}
}
// Mark the class as loaded.
- klass->status_ = Class::kStatusLoaded;
+ klass->SetStatus(Class::kStatusLoaded);
return true;
}
bool ClassLinker::LinkSuperClass(Class* klass) {
CHECK(!klass->IsPrimitive());
- const Class* super = klass->GetSuperClass();
+ Class* super = klass->GetSuperClass();
if (klass->GetDescriptor()->Equals("Ljava/lang/Object;")) {
if (super != NULL) {
LG << "Superclass must not be defined"; // TODO: ClassFormatError
@@ -1459,21 +1528,28 @@
}
// Verify
if (super->IsFinal()) {
- LG << "Superclass " << super->descriptor_->ToModifiedUtf8() << " is declared final"; // TODO: IncompatibleClassChangeError
+ LG << "Superclass " << super->GetDescriptor()->ToModifiedUtf8() << " is declared final"; // TODO: IncompatibleClassChangeError
return false;
}
if (super->IsInterface()) {
- LG << "Superclass " << super->descriptor_->ToModifiedUtf8() << " is an interface"; // TODO: IncompatibleClassChangeError
+ LG << "Superclass " << super->GetDescriptor()->ToModifiedUtf8() << " is an interface"; // TODO: IncompatibleClassChangeError
return false;
}
if (!klass->CanAccess(super)) {
- LG << "Superclass " << super->descriptor_->ToModifiedUtf8() << " is inaccessible"; // TODO: IllegalAccessError
+ LG << "Superclass " << super->GetDescriptor()->ToModifiedUtf8() << " is inaccessible"; // TODO: IllegalAccessError
return false;
}
+#ifndef NDEBUG
+ // Ensure super classes are fully resolved prior to resolving fields..
+ while (super != NULL) {
+ CHECK(super->IsLinked());
+ super = super->GetSuperClass();
+ }
+#endif
return true;
}
-// Populate the class vtable and itable.
+// Populate the class vtable and itable. Compute return type indices.
bool ClassLinker::LinkMethods(Class* klass) {
if (klass->IsInterface()) {
// No vtable.
@@ -1483,7 +1559,7 @@
return false;
}
for (size_t i = 0; i < count; ++i) {
- klass->GetVirtualMethod(i)->method_index_ = i;
+ klass->GetVirtualMethodDuringLinking(i)->SetMethodIndex(i);
}
} else {
// Link virtual method tables
@@ -1500,32 +1576,32 @@
bool ClassLinker::LinkVirtualMethods(Class* klass) {
if (klass->HasSuperClass()) {
- uint32_t max_count = klass->NumVirtualMethods() + klass->GetSuperClass()->vtable_->GetLength();
- size_t actual_count = klass->GetSuperClass()->vtable_->GetLength();
+ uint32_t max_count = klass->NumVirtualMethods() + klass->GetSuperClass()->GetVTable()->GetLength();
+ size_t actual_count = klass->GetSuperClass()->GetVTable()->GetLength();
CHECK_LE(actual_count, max_count);
// TODO: do not assign to the vtable field until it is fully constructed.
- klass->vtable_ = klass->GetSuperClass()->vtable_->CopyOf(max_count);
+ ObjectArray<Method>* vtable = klass->GetSuperClass()->GetVTable()->CopyOf(max_count);
// See if any of our virtual methods override the superclass.
for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
- Method* local_method = klass->GetVirtualMethod(i);
+ Method* local_method = klass->GetVirtualMethodDuringLinking(i);
size_t j = 0;
for (; j < actual_count; ++j) {
- Method* super_method = klass->vtable_->Get(j);
+ Method* super_method = vtable->Get(j);
if (local_method->HasSameNameAndDescriptor(super_method)) {
// Verify
if (super_method->IsFinal()) {
LG << "Method overrides final method"; // TODO: VirtualMachineError
return false;
}
- klass->vtable_->Set(j, local_method);
- local_method->method_index_ = j;
+ vtable->Set(j, local_method);
+ local_method->SetMethodIndex(j);
break;
}
}
if (j == actual_count) {
// Not overriding, append.
- klass->vtable_->Set(actual_count, local_method);
- local_method->method_index_ = actual_count;
+ vtable->Set(actual_count, local_method);
+ local_method->SetMethodIndex(actual_count);
actual_count += 1;
}
}
@@ -1533,11 +1609,12 @@
LG << "Too many methods defined on class"; // TODO: VirtualMachineError
return false;
}
+ // Shrink vtable if possible
CHECK_LE(actual_count, max_count);
if (actual_count < max_count) {
- // TODO: do not assign to the vtable field until it is fully constructed.
- klass->vtable_ = klass->vtable_->CopyOf(actual_count);
+ vtable = vtable->CopyOf(actual_count);
}
+ klass->SetVTable(vtable);
} else {
CHECK(klass->GetDescriptor()->Equals("Ljava/lang/Object;"));
uint32_t num_virtual_methods = klass->NumVirtualMethods();
@@ -1545,12 +1622,13 @@
LG << "Too many methods"; // TODO: VirtualMachineError
return false;
}
- // TODO: do not assign to the vtable field until it is fully constructed.
- klass->vtable_ = AllocObjectArray<Method>(num_virtual_methods);
+ ObjectArray<Method>* vtable = AllocObjectArray<Method>(num_virtual_methods);
for (size_t i = 0; i < num_virtual_methods; ++i) {
- klass->vtable_->Set(i, klass->GetVirtualMethod(i));
- klass->GetVirtualMethod(i)->method_index_ = i & 0xFFFF;
+ Method* virtual_method = klass->GetVirtualMethodDuringLinking(i);
+ vtable->Set(i, virtual_method);
+ virtual_method->SetMethodIndex(i & 0xFFFF);
}
+ klass->SetVTable(vtable);
}
return true;
}
@@ -1562,24 +1640,25 @@
int miranda_alloc = 0;
size_t super_ifcount;
if (klass->HasSuperClass()) {
- super_ifcount = klass->GetSuperClass()->iftable_count_;
+ super_ifcount = klass->GetSuperClass()->GetIFTableCount();
} else {
super_ifcount = 0;
}
size_t ifcount = super_ifcount;
ifcount += klass->NumInterfaces();
for (size_t i = 0; i < klass->NumInterfaces(); i++) {
- ifcount += klass->GetInterface(i)->iftable_count_;
+ ifcount += klass->GetInterface(i)->GetIFTableCount();
}
if (ifcount == 0) {
- DCHECK(klass->iftable_count_ == 0);
- DCHECK(klass->iftable_ == NULL);
+ // TODO: enable these asserts with klass status validation
+ // DCHECK(klass->GetIFTableCount() == 0);
+ // DCHECK(klass->GetIFTable() == NULL);
return true;
}
- klass->iftable_ = new InterfaceEntry[ifcount * sizeof(InterfaceEntry)];
- memset(klass->iftable_, 0x00, sizeof(InterfaceEntry) * ifcount);
+ InterfaceEntry* iftable = new InterfaceEntry[ifcount];
+ memset(iftable, 0x00, sizeof(InterfaceEntry) * ifcount);
if (super_ifcount != 0) {
- memcpy(klass->iftable_, klass->GetSuperClass()->iftable_,
+ memcpy(iftable, klass->GetSuperClass()->GetIFTable(),
sizeof(InterfaceEntry) * super_ifcount);
}
// Flatten the interface inheritance hierarchy.
@@ -1591,40 +1670,43 @@
LG << "Class implements non-interface class"; // TODO: IncompatibleClassChangeError
return false;
}
- klass->iftable_[idx++].SetInterface(interf);
- for (size_t j = 0; j < interf->iftable_count_; j++) {
- klass->iftable_[idx++].SetInterface(interf->iftable_[j].GetInterface());
+ iftable[idx++].SetInterface(interf);
+ for (size_t j = 0; j < interf->GetIFTableCount(); j++) {
+ iftable[idx++].SetInterface(interf->GetIFTable()[j].GetInterface());
}
}
+ klass->SetIFTable(iftable);
CHECK_EQ(idx, ifcount);
- klass->iftable_count_ = ifcount;
+ klass->SetIFTableCount(ifcount);
if (klass->IsInterface() || super_ifcount == ifcount) {
return true;
}
for (size_t i = super_ifcount; i < ifcount; i++) {
- pool_size += klass->iftable_[i].GetInterface()->NumVirtualMethods();
+ pool_size += iftable[i].GetInterface()->NumVirtualMethods();
}
if (pool_size == 0) {
return true;
}
- klass->ifvi_pool_count_ = pool_size;
- klass->ifvi_pool_ = new uint32_t[pool_size];
+ klass->SetIfviPoolCount(pool_size);
+ uint32_t* ifvi_pool = new uint32_t[pool_size];
+ klass->SetIfviPool(ifvi_pool);
std::vector<Method*> miranda_list;
for (size_t i = super_ifcount; i < ifcount; ++i) {
- klass->iftable_[i].method_index_array_ = klass->ifvi_pool_ + pool_offset;
- Class* interface = klass->iftable_[i].GetInterface();
+ iftable[i].SetMethodIndexArray(ifvi_pool + pool_offset);
+ Class* interface = iftable[i].GetInterface();
pool_offset += interface->NumVirtualMethods(); // end here
+ ObjectArray<Method>* vtable = klass->GetVTableDuringLinking();
for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
Method* interface_method = interface->GetVirtualMethod(j);
int k; // must be signed
- for (k = klass->vtable_->GetLength() - 1; k >= 0; --k) {
- Method* vtable_method = klass->vtable_->Get(k);
+ for (k = vtable->GetLength() - 1; k >= 0; --k) {
+ Method* vtable_method = vtable->Get(k);
if (interface_method->HasSameNameAndDescriptor(vtable_method)) {
if (!vtable_method->IsPublic()) {
LG << "Implementation not public";
return false;
}
- klass->iftable_[i].method_index_array_[j] = k;
+ iftable[i].GetMethodIndexArray()[j] = k;
break;
}
}
@@ -1645,7 +1727,8 @@
}
}
// point the interface table at a phantom slot index
- klass->iftable_[i].method_index_array_[j] = klass->vtable_->GetLength() + mir;
+ iftable[i].GetMethodIndexArray()[j] =
+ vtable->GetLength() + mir;
if (mir == miranda_count) {
miranda_list[miranda_count++] = interface_method;
}
@@ -1655,30 +1738,33 @@
if (miranda_count != 0) {
int old_method_count = klass->NumVirtualMethods();
int new_method_count = old_method_count + miranda_count;
- klass->virtual_methods_ = klass->virtual_methods_->CopyOf(new_method_count);
+ klass->SetVirtualMethods(
+ klass->GetVirtualMethods()->CopyOf(new_method_count));
- CHECK(klass->vtable_ != NULL);
- int old_vtable_count = klass->vtable_->GetLength();
+ ObjectArray<Method>* vtable = klass->GetVTableDuringLinking();
+ CHECK(vtable != NULL);
+ int old_vtable_count = vtable->GetLength();
int new_vtable_count = old_vtable_count + miranda_count;
- // TODO: do not assign to the vtable field until it is fully constructed.
- klass->vtable_ = klass->vtable_->CopyOf(new_vtable_count);
-
+ vtable = vtable->CopyOf(new_vtable_count);
for (int i = 0; i < miranda_count; i++) {
Method* meth = AllocMethod();
+ // TODO: this shouldn't be a memcpy
memcpy(meth, miranda_list[i], sizeof(Method));
- meth->klass_ = klass;
- meth->access_flags_ |= kAccMiranda;
- meth->method_index_ = 0xFFFF & (old_vtable_count + i);
+ meth->SetDeclaringClass(klass);
+ meth->SetAccessFlags(meth->GetAccessFlags() | kAccMiranda);
+ meth->SetMethodIndex(0xFFFF & (old_vtable_count + i));
klass->SetVirtualMethod(old_method_count + i, meth);
- klass->vtable_->Set(old_vtable_count + i, meth);
+ vtable->Set(old_vtable_count + i, meth);
}
+ // TODO: do not assign to the vtable field until it is fully constructed.
+ klass->SetVTable(vtable);
}
return true;
}
void ClassLinker::LinkAbstractMethods(Class* klass) {
for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
- Method* method = klass->GetVirtualMethod(i);
+ Method* method = klass->GetVirtualMethodDuringLinking(i);
if (method->IsAbstract()) {
LG << "AbstractMethodError";
// TODO: throw AbstractMethodError
@@ -1688,53 +1774,64 @@
bool ClassLinker::LinkInstanceFields(Class* klass) {
CHECK(klass != NULL);
- size_t field_offset;
- if (klass->GetSuperClass() != NULL) {
- field_offset = klass->GetSuperClass()->object_size_;
- } else {
- field_offset = OFFSETOF_MEMBER(DataObject, fields_);
- }
- return LinkFields(field_offset,
- klass->num_reference_instance_fields_,
- klass->NumInstanceFields(),
- klass->ifields_,
- klass->object_size_);
+ return LinkFields(klass, true);
}
bool ClassLinker::LinkStaticFields(Class* klass) {
CHECK(klass != NULL);
- size_t allocated_class_size = klass->class_size_;
- size_t field_offset = OFFSETOF_MEMBER(Class, fields_);
- bool success = LinkFields(field_offset,
- klass->num_reference_static_fields_,
- klass->NumStaticFields(),
- klass->sfields_,
- klass->class_size_);
- CHECK_EQ(allocated_class_size, klass->class_size_);
+ size_t allocated_class_size = klass->GetClassSize();
+ bool success = LinkFields(klass, false);
+ CHECK_EQ(allocated_class_size, klass->GetClassSize());
return success;
}
-bool ClassLinker::LinkFields(size_t field_offset,
- size_t& num_reference_fields,
- size_t num_fields,
- ObjectArray<Field>* fields,
- size_t& size) {
+bool ClassLinker::LinkFields(Class *klass, bool instance) {
+ size_t num_fields =
+ instance ? klass->NumInstanceFields() : klass->NumStaticFields();
+
+ ObjectArray<Field>* fields =
+ instance ? klass->GetIFields() : klass->GetSFields();
+ // Fields updated at end of LinkFields
+ size_t num_reference_fields;
+ size_t size;
+
+ // Initialize size and field_offset
+ MemberOffset field_offset = Class::FieldsOffset();
+ if (instance) {
+ Class* super_class = klass->GetSuperClass();
+ if (super_class != NULL) {
+ CHECK(super_class->IsLinked());
+ field_offset = MemberOffset(super_class->GetObjectSize());
+ if (field_offset.Uint32Value() == 0u) {
+ field_offset = OFFSET_OF_OBJECT_MEMBER(DataObject, fields_);
+ }
+ } else {
+ field_offset = OFFSET_OF_OBJECT_MEMBER(DataObject, fields_);
+ }
+ size = field_offset.Uint32Value();
+ } else {
+ size = klass->GetClassSize();
+ }
+ DCHECK_LE(CLASS_SMALLEST_OFFSET, size);
+
CHECK((num_fields == 0) == (fields == NULL));
+
// Move references to the front.
- num_reference_fields = 0;
size_t i = 0;
- for ( ; i < num_fields; i++) {
- Field* pField = fields->Get(i);
- char c = pField->GetType();
- if (c != '[' && c != 'L') {
+ num_reference_fields = 0;
+ for (; i < num_fields; i++) {
+ Field* field = fields->Get(i);
+ const Class* field_type = field->GetTypeDuringLinking();
+ // if a field's type at this point is NULL it isn't primitive
+ if (field_type != NULL && field_type->IsPrimitive()) {
for (size_t j = num_fields - 1; j > i; j--) {
- Field* refField = fields->Get(j);
- char rc = refField->GetType();
- if (rc == '[' || rc == 'L') {
- fields->Set(i, refField);
- fields->Set(j, pField);
- pField = refField;
- c = rc;
+ Field* ref_field = fields->Get(j);
+ const Class* ref_field_type = ref_field->GetTypeDuringLinking();
+ if (ref_field_type == NULL || !ref_field_type->IsPrimitive()) {
+ fields->Set(i, ref_field);
+ fields->Set(j, field);
+ field = ref_field;
+ field_type = ref_field_type;
num_reference_fields++;
break;
}
@@ -1742,65 +1839,70 @@
} else {
num_reference_fields++;
}
- if (c != '[' && c != 'L') {
+ if (field_type != NULL && field_type->IsPrimitive()) {
break;
}
- pField->SetOffset(field_offset);
- field_offset += sizeof(uint32_t);
+ field->SetOffset(field_offset);
+ field_offset = MemberOffset(field_offset.Uint32Value() + sizeof(uint32_t));
}
// Now we want to pack all of the double-wide fields together. If
// we're not aligned, though, we want to shuffle one 32-bit field
// into place. If we can't find one, we'll have to pad it.
- if (i != num_fields && (field_offset & 0x04) != 0) {
- Field* pField = fields->Get(i);
- char c = pField->GetType();
-
- if (c != 'J' && c != 'D') {
+ if (i != num_fields && !IsAligned(field_offset.Uint32Value(), 8)) {
+ Field* field = fields->Get(i);
+ const Class* c = field->GetTypeDuringLinking();
+ CHECK(c != NULL); // should only be working on primitive types
+ if (!c->IsPrimitiveLong() && !c->IsPrimitiveDouble()) {
// The field that comes next is 32-bit, so just advance past it.
- DCHECK(c != '[');
- DCHECK(c != 'L');
- pField->SetOffset(field_offset);
- field_offset += sizeof(uint32_t);
+ DCHECK(c->IsPrimitive());
+ field->SetOffset(field_offset);
+ field_offset = MemberOffset(field_offset.Uint32Value() +
+ sizeof(uint32_t));
i++;
} else {
// Next field is 64-bit, so search for a 32-bit field we can
// swap into it.
bool found = false;
for (size_t j = num_fields - 1; j > i; j--) {
- Field* singleField = fields->Get(j);
- char rc = singleField->GetType();
- if (rc != 'J' && rc != 'D') {
- fields->Set(i, singleField);
- fields->Set(j, pField);
- pField = singleField;
- pField->SetOffset(field_offset);
- field_offset += sizeof(uint32_t);
+ Field* single_field = fields->Get(j);
+ const Class* rc = single_field->GetTypeDuringLinking();
+ CHECK(rc != NULL); // should only be working on primitive types
+ if (!rc->IsPrimitiveLong() && !rc->IsPrimitiveDouble()) {
+ fields->Set(i, single_field);
+ fields->Set(j, field);
+ field = single_field;
+ field->SetOffset(field_offset);
+ field_offset = MemberOffset(field_offset.Uint32Value() +
+ sizeof(uint32_t));
found = true;
i++;
break;
}
}
if (!found) {
- field_offset += sizeof(uint32_t);
+ field_offset = MemberOffset(field_offset.Uint32Value() +
+ sizeof(uint32_t));
}
}
}
// Alignment is good, shuffle any double-wide fields forward, and
// finish assigning field offsets to all fields.
- DCHECK(i == num_fields || (field_offset & 0x04) == 0);
+ DCHECK(i == num_fields || IsAligned(field_offset.Uint32Value(), 4));
for ( ; i < num_fields; i++) {
- Field* pField = fields->Get(i);
- char c = pField->GetType();
- if (c != 'D' && c != 'J') {
+ Field* field = fields->Get(i);
+ const Class* c = field->GetTypeDuringLinking();
+ CHECK(c != NULL); // should only be working on primitive types
+ if (!c->IsPrimitiveDouble() && !c->IsPrimitiveLong()) {
for (size_t j = num_fields - 1; j > i; j--) {
- Field* doubleField = fields->Get(j);
- char rc = doubleField->GetType();
- if (rc == 'D' || rc == 'J') {
- fields->Set(i, doubleField);
- fields->Set(j, pField);
- pField = doubleField;
+ Field* double_field = fields->Get(j);
+ const Class* rc = double_field->GetTypeDuringLinking();
+ CHECK(rc != NULL); // should only be working on primitive types
+ if (rc->IsPrimitiveDouble() || rc->IsPrimitiveLong()) {
+ fields->Set(i, double_field);
+ fields->Set(j, field);
+ field = double_field;
c = rc;
break;
}
@@ -1809,10 +1911,13 @@
// This is a double-wide field, leave it be.
}
- pField->SetOffset(field_offset);
- field_offset += sizeof(uint32_t);
- if (c == 'J' || c == 'D') {
- field_offset += sizeof(uint32_t);
+ field->SetOffset(field_offset);
+ if (c->IsPrimitiveLong() || c->IsPrimitiveDouble()) {
+ field_offset = MemberOffset(field_offset.Uint32Value() +
+ sizeof(uint64_t));
+ } else {
+ field_offset = MemberOffset(field_offset.Uint32Value() +
+ sizeof(uint32_t));
}
}
@@ -1821,14 +1926,9 @@
// non-reference fields, and all double-wide fields are aligned.
bool seen_non_ref = false;
for (i = 0; i < num_fields; i++) {
- Field *pField = fields->Get(i);
- char c = pField->GetType();
-
- if (c == 'D' || c == 'J') {
- DCHECK_EQ(0U, pField->GetOffset() & 0x07);
- }
-
- if (c != '[' && c != 'L') {
+ Field* field = fields->Get(i);
+ const Class* c = field->GetTypeDuringLinking();
+ if (c != NULL && c->IsPrimitive()) {
if (!seen_non_ref) {
seen_non_ref = true;
DCHECK_EQ(num_reference_fields, i);
@@ -1841,47 +1941,59 @@
DCHECK_EQ(num_fields, num_reference_fields);
}
#endif
- size = field_offset;
+ size = field_offset.Uint32Value();
+ DCHECK_LE(CLASS_SMALLEST_OFFSET, size);
+ // Update klass
+ if(instance) {
+ klass->SetNumReferenceInstanceFields(num_reference_fields);
+ if(!klass->IsVariableSize()) {
+ klass->SetObjectSize(size);
+ }
+ } else {
+ klass->SetNumReferenceStaticFields(num_reference_fields);
+ klass->SetClassSize(size);
+ }
return true;
}
// Set the bitmap of reference offsets, refOffsets, from the ifields
// list.
void ClassLinker::CreateReferenceInstanceOffsets(Class* klass) {
- klass->reference_instance_offsets_ = 0;
- if (klass->HasSuperClass()) {
- klass->reference_instance_offsets_ = klass->GetSuperClass()->GetReferenceInstanceOffsets();
+ uint32_t reference_offsets = 0;
+ Class* super_class = klass->GetSuperClass();
+ if (super_class != NULL) {
+ reference_offsets = super_class->GetReferenceInstanceOffsets();
// If our superclass overflowed, we don't stand a chance.
- if (klass->reference_instance_offsets_ == CLASS_WALK_SUPER) {
+ if (reference_offsets == CLASS_WALK_SUPER) {
+ klass->SetReferenceInstanceOffsets(reference_offsets);
return;
}
}
- CreateReferenceOffsets(klass->reference_instance_offsets_,
- klass->NumReferenceInstanceFields(),
- klass->ifields_);
+ CreateReferenceOffsets(klass, true, reference_offsets);
}
void ClassLinker::CreateReferenceStaticOffsets(Class* klass) {
- klass->reference_static_offsets_ = 0;
- CreateReferenceOffsets(klass->reference_static_offsets_,
- klass->NumReferenceStaticFields(),
- klass->sfields_);
+ CreateReferenceOffsets(klass, false, 0);
}
-void ClassLinker::CreateReferenceOffsets(uint32_t& reference_offsets,
- size_t num_reference_fields,
- const ObjectArray<Field>* fields) {
+void ClassLinker::CreateReferenceOffsets(Class* klass, bool instance,
+ uint32_t reference_offsets) {
+ size_t num_reference_fields =
+ instance ? klass->NumReferenceInstanceFieldsDuringLinking()
+ : klass->NumReferenceStaticFieldsDuringLinking();
+ const ObjectArray<Field>* fields =
+ instance ? klass->GetIFields() : klass->GetSFields();
// All of the fields that contain object references are guaranteed
// to be at the beginning of the fields list.
for (size_t i = 0; i < num_reference_fields; ++i) {
// Note that byte_offset is the offset from the beginning of
// object, not the offset into instance data
const Field* field = fields->Get(i);
- size_t byte_offset = field->GetOffset();
- CHECK_GE(byte_offset, CLASS_SMALLEST_OFFSET);
- CHECK_EQ(byte_offset & (CLASS_OFFSET_ALIGNMENT - 1), 0U);
- if (CLASS_CAN_ENCODE_OFFSET(byte_offset)) {
- uint32_t new_bit = CLASS_BIT_FROM_OFFSET(byte_offset);
+ MemberOffset byte_offset = field->GetOffsetDuringLinking();
+ CHECK_GE(byte_offset.Uint32Value(), CLASS_SMALLEST_OFFSET);
+ CHECK_EQ(byte_offset.Uint32Value() & (CLASS_OFFSET_ALIGNMENT - 1), 0U);
+ if (CLASS_CAN_ENCODE_OFFSET(byte_offset.Uint32Value())) {
+ uint32_t new_bit = CLASS_BIT_FROM_OFFSET(byte_offset.Uint32Value());
CHECK_NE(new_bit, 0U);
reference_offsets |= new_bit;
} else {
@@ -1889,18 +2001,25 @@
break;
}
}
+ // Update fields in klass
+ if (instance) {
+ klass->SetReferenceInstanceOffsets(reference_offsets);
+ } else {
+ klass->SetReferenceStaticOffsets(reference_offsets);
+ }
}
-const String* ClassLinker::ResolveString(const DexFile& dex_file,
+String* ClassLinker::ResolveString(const DexFile& dex_file,
uint32_t string_idx, DexCache* dex_cache) {
- const String* resolved = dex_cache->GetResolvedString(string_idx);
+ String* resolved = dex_cache->GetResolvedString(string_idx);
if (resolved != NULL) {
return resolved;
}
const DexFile::StringId& string_id = dex_file.GetStringId(string_idx);
int32_t utf16_length = dex_file.GetStringLength(string_id);
const char* utf8_data = dex_file.GetStringData(string_id);
- const String* string = intern_table_->InternStrong(utf16_length, utf8_data);
+ // TODO: remote the const_cast below
+ String* string = const_cast<String*>(intern_table_->InternStrong(utf16_length, utf8_data));
dex_cache->SetResolvedString(string_idx, string);
return string;
}
@@ -1910,26 +2029,28 @@
DexCache* dex_cache,
const ClassLoader* class_loader) {
Class* resolved = dex_cache->GetResolvedType(type_idx);
- if (resolved != NULL) {
- return resolved;
- }
- const char* descriptor = dex_file.dexStringByTypeIdx(type_idx);
- if (descriptor[0] != '\0' && descriptor[1] == '\0') {
- resolved = FindPrimitiveClass(descriptor[0]);
- } else {
- resolved = FindClass(descriptor, class_loader);
- }
- if (resolved != NULL) {
- 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
- return NULL;
+ if (resolved == NULL) {
+ const char* descriptor = dex_file.dexStringByTypeIdx(type_idx);
+ if (descriptor[1] == '\0') {
+ // only the descriptors of primitive types should be 1 character long
+ resolved = FindPrimitiveClass(descriptor[0]);
+ } else {
+ resolved = FindClass(descriptor, class_loader);
+ }
+ if (resolved != NULL) {
+ Class* check = resolved->IsArrayClass() ? resolved->GetComponentType() : resolved;
+ if (dex_cache != check->GetDexCache()) {
+ if (check->GetClassLoader() != NULL) {
+ LG << "Class resolved by unexpected DEX"; // TODO: IllegalAccessError
+ resolved = NULL;
+ }
}
}
- dex_cache->SetResolvedType(type_idx, resolved);
- } else {
- DCHECK(Thread::Current()->IsExceptionPending());
+ if (resolved != NULL) {
+ dex_cache->SetResolvedType(type_idx, resolved);
+ } else {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ }
}
return resolved;
}
@@ -1980,16 +2101,18 @@
}
const char* name = dex_file.dexStringById(field_id.name_idx_);
- const char* type = dex_file.dexStringByTypeIdx(field_id.type_idx_);
+ Class* field_type = ResolveType(dex_file, field_id.type_idx_, dex_cache, class_loader);
+ // TODO: LinkageError?
+ CHECK(field_type != NULL);
if (is_static) {
- resolved = klass->FindStaticField(name, type);
+ resolved = klass->FindStaticField(name, field_type);
} else {
- resolved = klass->FindInstanceField(name, type);
+ resolved = klass->FindInstanceField(name, field_type);
}
if (resolved != NULL) {
dex_cache->SetResolvedfield(field_idx, resolved);
} else {
- // DCHECK(Thread::Current()->IsExceptionPending());
+ // TODO: DCHECK(Thread::Current()->IsExceptionPending());
}
return resolved;
}
diff --git a/src/class_linker.h b/src/class_linker.h
index 3f95b8d..f63ab3c 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -45,7 +45,7 @@
// Resolve a String with the given index from the DexFile, storing the
// result in the DexCache.
- const String* ResolveString(const DexFile& dex_file, uint32_t string_idx, DexCache* dex_cache);
+ String* ResolveString(const DexFile& dex_file, uint32_t string_idx, DexCache* dex_cache);
// Resolve a Type with the given index from the DexFile, storing the
// result in the DexCache. The referrer is used to identity the
@@ -60,11 +60,21 @@
}
// Resolve a Type with the given index from the DexFile, storing the
- // result in the DexCache. The referrer is used to identity the
+ // result in the DexCache. The referrer is used to identify the
// target DexCache and ClassLoader to use for resolution.
Class* ResolveType(uint32_t type_idx, const Method* referrer) {
Class* declaring_class = referrer->GetDeclaringClass();
DexCache* dex_cache = declaring_class->GetDexCache();
+ // TODO: we could check for a dex cache hit here
+ const ClassLoader* class_loader = declaring_class->GetClassLoader();
+ const DexFile& dex_file = FindDexFile(dex_cache);
+ return ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ }
+
+ Class* ResolveType(uint32_t type_idx, const Field* referrer) {
+ Class* declaring_class = referrer->GetDeclaringClass();
+ DexCache* dex_cache = declaring_class->GetDexCache();
+ // TODO: we could check for a dex cache hit here
const ClassLoader* class_loader = declaring_class->GetClassLoader();
const DexFile& dex_file = FindDexFile(dex_cache);
return ResolveType(dex_file, type_idx, dex_cache, class_loader);
@@ -96,6 +106,7 @@
Field* ResolveField(uint32_t field_idx, const Method* referrer) {
Class* declaring_class = referrer->GetDeclaringClass();
DexCache* dex_cache = declaring_class->GetDexCache();
+ // TODO: we could check for a dex cache hit here
const ClassLoader* class_loader = declaring_class->GetClassLoader();
const DexFile& dex_file = FindDexFile(dex_cache);
return ResolveField(dex_file, field_idx, dex_cache, class_loader, true);
@@ -161,7 +172,8 @@
Method* AllocMethod();
CodeAndDirectMethods* AllocCodeAndDirectMethods(size_t length);
- Class* CreatePrimitiveClass(const char* descriptor);
+ Class* CreatePrimitiveClass(const char* descriptor,
+ Class::PrimitiveType type);
Class* CreateArrayClass(const StringPiece& descriptor,
const ClassLoader* class_loader);
@@ -211,7 +223,7 @@
const Class* klass1,
const Class* klass2);
- bool LinkClass(Class* klass, const DexFile& dex_file);
+ bool LinkClass(Class* klass);
bool LinkSuperClass(Class* klass);
@@ -227,17 +239,13 @@
bool LinkStaticFields(Class* klass);
bool LinkInstanceFields(Class* klass);
- bool LinkFields(size_t field_offset,
- size_t& num_reference_fields,
- size_t num_fields,
- ObjectArray<Field>* fields,
- size_t& size);
+ bool LinkFields(Class *klass, bool instance);
+
void CreateReferenceInstanceOffsets(Class* klass);
void CreateReferenceStaticOffsets(Class* klass);
- void CreateReferenceOffsets(uint32_t& reference_offsets,
- size_t num_reference_fields,
- const ObjectArray<Field>* fields);
+ void CreateReferenceOffsets(Class *klass, bool instance,
+ uint32_t reference_offsets);
std::vector<const DexFile*> boot_class_path_;
@@ -298,9 +306,9 @@
DCHECK(!init_done_);
DCHECK(klass != NULL);
- DCHECK(klass->class_loader_ == NULL);
- DCHECK(klass->descriptor_ != NULL);
- DCHECK(klass->descriptor_->Equals(GetClassRootDescriptor(class_root)));
+ DCHECK(klass->GetClassLoader() == NULL);
+ DCHECK(klass->GetDescriptor() != NULL);
+ DCHECK(klass->GetDescriptor()->Equals(GetClassRootDescriptor(class_root)));
DCHECK(class_roots_ != NULL);
DCHECK(class_roots_->Get(class_root) == NULL);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index a34f180..6f894e3 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -2,6 +2,8 @@
#include "class_linker.h"
+#include <string>
+
#include "UniquePtr.h"
#include "common_test.h"
#include "dex_cache.h"
@@ -35,14 +37,13 @@
EXPECT_TRUE(primitive->GetSuperClass() == NULL);
EXPECT_FALSE(primitive->HasSuperClass());
EXPECT_TRUE(primitive->GetClassLoader() == NULL);
- EXPECT_TRUE(primitive->GetComponentType() == NULL);
EXPECT_TRUE(primitive->GetStatus() == Class::kStatusInitialized);
EXPECT_FALSE(primitive->IsErroneous());
EXPECT_TRUE(primitive->IsVerified());
EXPECT_TRUE(primitive->IsLinked());
EXPECT_FALSE(primitive->IsArrayInstance());
EXPECT_FALSE(primitive->IsArrayClass());
- EXPECT_EQ(0, primitive->array_rank_);
+ EXPECT_EQ(0, primitive->GetArrayRank());
EXPECT_FALSE(primitive->IsInterface());
EXPECT_TRUE(primitive->IsPublic());
EXPECT_TRUE(primitive->IsFinal());
@@ -60,7 +61,7 @@
const StringPiece& component_type,
const ClassLoader* class_loader) {
Class* array = class_linker_->FindClass(array_descriptor, class_loader);
- EXPECT_EQ(array_rank, array->array_rank_);
+ EXPECT_EQ(array_rank, array->GetArrayRank());
EXPECT_TRUE(array->GetComponentType()->GetDescriptor()->Equals(component_type));
EXPECT_EQ(class_loader, array->GetClassLoader());
AssertArrayClass(array_descriptor, array);
@@ -83,7 +84,7 @@
EXPECT_TRUE(array->IsLinked());
EXPECT_FALSE(array->IsArrayInstance());
EXPECT_TRUE(array->IsArrayClass());
- EXPECT_LE(1, array->array_rank_);
+ EXPECT_LE(1, array->GetArrayRank());
EXPECT_FALSE(array->IsInterface());
EXPECT_EQ(array->GetComponentType()->IsPublic(), array->IsPublic());
EXPECT_TRUE(array->IsFinal());
@@ -101,49 +102,49 @@
EXPECT_TRUE(method->GetName() != NULL);
EXPECT_TRUE(method->GetSignature() != NULL);
- EXPECT_TRUE(method->dex_cache_strings_ != NULL);
- EXPECT_TRUE(method->dex_cache_resolved_types_ != NULL);
- EXPECT_TRUE(method->dex_cache_resolved_methods_ != NULL);
- EXPECT_TRUE(method->dex_cache_resolved_fields_ != NULL);
- EXPECT_TRUE(method->dex_cache_code_and_direct_methods_ != NULL);
- EXPECT_TRUE(method->dex_cache_initialized_static_storage_ != NULL);
- EXPECT_EQ(method->declaring_class_->dex_cache_->GetStrings(),
- method->dex_cache_strings_);
- EXPECT_EQ(method->declaring_class_->dex_cache_->GetResolvedTypes(),
- method->dex_cache_resolved_types_);
- EXPECT_EQ(method->declaring_class_->dex_cache_->GetResolvedMethods(),
- method->dex_cache_resolved_methods_);
- EXPECT_EQ(method->declaring_class_->dex_cache_->GetResolvedFields(),
- method->dex_cache_resolved_fields_);
- EXPECT_EQ(method->declaring_class_->dex_cache_->GetCodeAndDirectMethods(),
- method->dex_cache_code_and_direct_methods_);
- EXPECT_EQ(method->declaring_class_->dex_cache_->GetInitializedStaticStorage(),
- method->dex_cache_initialized_static_storage_);
+ EXPECT_TRUE(method->GetDexCacheStrings() != NULL);
+ EXPECT_TRUE(method->GetDexCacheResolvedTypes() != NULL);
+ EXPECT_TRUE(method->GetDexCacheResolvedMethods() != NULL);
+ EXPECT_TRUE(method->GetDexCacheResolvedFields() != NULL);
+ EXPECT_TRUE(method->GetDexCacheCodeAndDirectMethods() != NULL);
+ EXPECT_TRUE(method->GetDexCacheInitializedStaticStorage() != NULL);
+ EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetStrings(),
+ method->GetDexCacheStrings());
+ EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetResolvedTypes(),
+ method->GetDexCacheResolvedTypes());
+ EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetResolvedMethods(),
+ method->GetDexCacheResolvedMethods());
+ EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetResolvedFields(),
+ method->GetDexCacheResolvedFields());
+ EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetCodeAndDirectMethods(),
+ method->GetDexCacheCodeAndDirectMethods());
+ EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetInitializedStaticStorage(),
+ method->GetDexCacheInitializedStaticStorage());
}
void AssertField(Class* klass, Field* field) {
EXPECT_TRUE(field != NULL);
EXPECT_EQ(klass, field->GetDeclaringClass());
EXPECT_TRUE(field->GetName() != NULL);
- EXPECT_TRUE(field->GetDescriptor() != NULL);
+ EXPECT_TRUE(field->GetType() != NULL);
}
void AssertClass(const StringPiece& descriptor, Class* klass) {
EXPECT_TRUE(klass->GetDescriptor()->Equals(descriptor));
- if (klass->descriptor_->Equals(String::AllocFromModifiedUtf8("Ljava/lang/Object;"))) {
+ if (klass->GetDescriptor()->Equals(String::AllocFromModifiedUtf8("Ljava/lang/Object;"))) {
EXPECT_FALSE(klass->HasSuperClass());
} else {
EXPECT_TRUE(klass->HasSuperClass());
EXPECT_TRUE(klass->GetSuperClass() != NULL);
}
EXPECT_TRUE(klass->GetDexCache() != NULL);
- EXPECT_TRUE(klass->GetComponentType() == NULL);
- EXPECT_TRUE(klass->GetComponentType() == NULL);
EXPECT_EQ(Class::kStatusResolved, klass->GetStatus());
EXPECT_FALSE(klass->IsErroneous());
EXPECT_FALSE(klass->IsVerified());
EXPECT_TRUE(klass->IsLinked());
EXPECT_TRUE(klass->IsLoaded());
+ EXPECT_FALSE(klass->IsArrayClass());
+ EXPECT_EQ(0, klass->GetArrayRank());
EXPECT_TRUE(klass->IsInSamePackage(klass));
EXPECT_TRUE(Class::IsInSamePackage(klass->GetDescriptor(), klass->GetDescriptor()));
if (klass->IsInterface()) {
@@ -206,15 +207,13 @@
EXPECT_GE(klass->NumInstanceFields(), klass->NumReferenceInstanceFields());
for (size_t i = 0; i < klass->NumReferenceInstanceFields(); i++) {
Field* field = klass->GetInstanceField(i);
- Class* field_type = class_linker_->FindClass(field->GetDescriptor(),
- klass->GetClassLoader());
+ Class* field_type = field->GetType();
ASSERT_TRUE(field_type != NULL);
- EXPECT_FALSE(field_type->IsPrimitive());
+ ASSERT_TRUE(!field_type->IsPrimitive());
}
for (size_t i = klass->NumReferenceInstanceFields(); i < klass->NumInstanceFields(); i++) {
Field* field = klass->GetInstanceField(i);
- Class* field_type = class_linker_->FindClass(field->GetDescriptor(),
- klass->GetClassLoader());
+ Class* field_type = field->GetType();
ASSERT_TRUE(field_type != NULL);
EXPECT_TRUE(field_type->IsPrimitive());
}
@@ -310,13 +309,12 @@
EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
EXPECT_FALSE(JavaLangObject->HasSuperClass());
EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
- EXPECT_TRUE(JavaLangObject->GetComponentType() == NULL);
EXPECT_FALSE(JavaLangObject->IsErroneous());
EXPECT_FALSE(JavaLangObject->IsVerified());
EXPECT_TRUE(JavaLangObject->IsLinked());
EXPECT_FALSE(JavaLangObject->IsArrayInstance());
EXPECT_FALSE(JavaLangObject->IsArrayClass());
- EXPECT_EQ(0, JavaLangObject->array_rank_);
+ EXPECT_EQ(0, JavaLangObject->GetArrayRank());
EXPECT_FALSE(JavaLangObject->IsInterface());
EXPECT_TRUE(JavaLangObject->IsPublic());
EXPECT_FALSE(JavaLangObject->IsFinal());
@@ -340,14 +338,13 @@
EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
EXPECT_TRUE(MyClass->HasSuperClass());
EXPECT_EQ(class_loader, MyClass->GetClassLoader());
- EXPECT_TRUE(MyClass->GetComponentType() == NULL);
EXPECT_TRUE(MyClass->GetStatus() == Class::kStatusResolved);
EXPECT_FALSE(MyClass->IsErroneous());
EXPECT_FALSE(MyClass->IsVerified());
EXPECT_TRUE(MyClass->IsLinked());
EXPECT_FALSE(MyClass->IsArrayInstance());
EXPECT_FALSE(MyClass->IsArrayClass());
- EXPECT_EQ(0, JavaLangObject->array_rank_);
+ EXPECT_EQ(0, JavaLangObject->GetArrayRank());
EXPECT_FALSE(MyClass->IsInterface());
EXPECT_FALSE(MyClass->IsPublic());
EXPECT_FALSE(MyClass->IsFinal());
@@ -394,6 +391,13 @@
EXPECT_TRUE(throwable->GetInstanceField(3)->GetName()->Equals("stackTrace"));
EXPECT_TRUE(throwable->GetInstanceField(4)->GetName()->Equals("suppressedExceptions"));
+ Class* stack_trace_element = class_linker_->FindSystemClass( "Ljava/lang/StackTraceElement;");
+ ASSERT_EQ(4U, stack_trace_element->NumInstanceFields());
+ EXPECT_TRUE(stack_trace_element->GetInstanceField(0)->GetName()->Equals("declaringClass"));
+ EXPECT_TRUE(stack_trace_element->GetInstanceField(1)->GetName()->Equals("fileName"));
+ EXPECT_TRUE(stack_trace_element->GetInstanceField(2)->GetName()->Equals("methodName"));
+ EXPECT_TRUE(stack_trace_element->GetInstanceField(3)->GetName()->Equals("lineNumber"));
+
Class* accessible_object = class_linker_->FindSystemClass("Ljava/lang/reflect/AccessibleObject;");
ASSERT_EQ(1U, accessible_object->NumInstanceFields());
EXPECT_TRUE(accessible_object->GetInstanceField(0)->GetName()->Equals("flag"));
@@ -438,7 +442,8 @@
Class* array_class = class_linker_->FindSystemClass("[Ljava/lang/String;");
ObjectArray<String>* array = ObjectArray<String>::Alloc(array_class, 0);
uint32_t array_offset = reinterpret_cast<uint32_t>(array);
- uint32_t data_offset = reinterpret_cast<uint32_t>(array->GetData());
+ uint32_t data_offset =
+ array_offset + ObjectArray<String>::DataOffset().Uint32Value();
EXPECT_EQ(16U, data_offset - array_offset);
}
@@ -471,54 +476,54 @@
EXPECT_EQ(10U, statics->NumStaticFields());
- Field* s0 = statics->FindStaticField("s0", "Z");
- EXPECT_TRUE(s0->GetClass()->descriptor_->Equals("Ljava/lang/reflect/Field;"));
- EXPECT_EQ('Z', s0->GetType());
+ Field* s0 = statics->FindStaticField("s0", class_linker_->FindClass("Z", class_loader));
+ EXPECT_TRUE(s0->GetClass()->GetDescriptor()->Equals("Ljava/lang/reflect/Field;"));
+ EXPECT_TRUE(s0->GetType()->IsPrimitiveBoolean());
// EXPECT_EQ(true, s0->GetBoolean(NULL)); // TODO: needs clinit to be run?
s0->SetBoolean(NULL, false);
- Field* s1 = statics->FindStaticField("s1", "B");
- EXPECT_EQ('B', s1->GetType());
+ Field* s1 = statics->FindStaticField("s1", class_linker_->FindClass("B", class_loader));
+ EXPECT_TRUE(s1->GetType()->IsPrimitiveByte());
// EXPECT_EQ(5, s1->GetByte(NULL)); // TODO: needs clinit to be run?
s1->SetByte(NULL, 6);
- Field* s2 = statics->FindStaticField("s2", "C");
- EXPECT_EQ('C', s2->GetType());
+ Field* s2 = statics->FindStaticField("s2", class_linker_->FindClass("C", class_loader));
+ EXPECT_TRUE(s2->GetType()->IsPrimitiveChar());
// EXPECT_EQ('a', s2->GetChar(NULL)); // TODO: needs clinit to be run?
s2->SetChar(NULL, 'b');
- Field* s3 = statics->FindStaticField("s3", "S");
- EXPECT_EQ('S', s3->GetType());
+ Field* s3 = statics->FindStaticField("s3", class_linker_->FindClass("S", class_loader));
+ EXPECT_TRUE(s3->GetType()->IsPrimitiveShort());
// EXPECT_EQ(65000, s3->GetShort(NULL)); // TODO: needs clinit to be run?
s3->SetShort(NULL, 65001);
- Field* s4 = statics->FindStaticField("s4", "I");
- EXPECT_EQ('I', s4->GetType());
+ Field* s4 = statics->FindStaticField("s4", class_linker_->FindClass("I", class_loader));
+ EXPECT_TRUE(s4->GetType()->IsPrimitiveInt());
// EXPECT_EQ(2000000000, s4->GetInt(NULL)); // TODO: needs clinit to be run?
s4->SetInt(NULL, 2000000001);
- Field* s5 = statics->FindStaticField("s5", "J");
- EXPECT_EQ('J', s5->GetType());
+ Field* s5 = statics->FindStaticField("s5", class_linker_->FindClass("J", class_loader));
+ EXPECT_TRUE(s5->GetType()->IsPrimitiveLong());
// EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(NULL)); // TODO: needs clinit to be run?
s5->SetLong(NULL, 0x34567890abcdef12LL);
- Field* s6 = statics->FindStaticField("s6", "F");
- EXPECT_EQ('F', s6->GetType());
+ Field* s6 = statics->FindStaticField("s6", class_linker_->FindClass("F", class_loader));
+ EXPECT_TRUE(s6->GetType()->IsPrimitiveFloat());
// EXPECT_EQ(0.5, s6->GetFloat(NULL)); // TODO: needs clinit to be run?
s6->SetFloat(NULL, 0.75);
- Field* s7 = statics->FindStaticField("s7", "D");
- EXPECT_EQ('D', s7->GetType());
+ Field* s7 = statics->FindStaticField("s7", class_linker_->FindClass("D", class_loader));
+ EXPECT_TRUE(s7->GetType()->IsPrimitiveDouble());
// EXPECT_EQ(16777217, s7->GetDouble(NULL)); // TODO: needs clinit to be run?
s7->SetDouble(NULL, 16777219);
- Field* s8 = statics->FindStaticField("s8", "Ljava/lang/Object;");
- EXPECT_EQ('L', s8->GetType());
+ Field* s8 = statics->FindStaticField("s8", class_linker_->FindClass("Ljava/lang/Object;", class_loader));
+ EXPECT_FALSE(s8->GetType()->IsPrimitive());
// EXPECT_TRUE(s8->GetObject(NULL)->AsString()->Equals("android")); // TODO: needs clinit to be run?
s8->SetObject(NULL, String::AllocFromModifiedUtf8("robot"));
- Field* s9 = statics->FindStaticField("s9", "[Ljava/lang/Object;");
- EXPECT_EQ('[', s9->GetType());
+ Field* s9 = statics->FindStaticField("s9", class_linker_->FindClass("[Ljava/lang/Object;", class_loader));
+ EXPECT_TRUE(s9->GetType()->IsArrayClass());
// EXPECT_EQ(NULL, s9->GetObject(NULL)); // TODO: needs clinit to be run?
s9->SetObject(NULL, NULL);
diff --git a/src/class_loader.h b/src/class_loader.h
index da19539..3309a8a 100644
--- a/src/class_loader.h
+++ b/src/class_loader.h
@@ -10,13 +10,14 @@
namespace art {
-// ClassLoader objects.
+// C++ mirror of java.lang.ClassLoader
class ClassLoader : public Object {
public:
static const std::vector<const DexFile*>& GetClassPath(const ClassLoader* class_loader);
void SetClassPath(std::vector<const DexFile*>& class_path) {
DCHECK_EQ(0U, class_path_.size());
+ // TODO: use setter
class_path_ = class_path;
}
@@ -31,6 +32,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(ClassLoader);
};
+// C++ mirror of dalvik.system.BaseDexClassLoader
class BaseDexClassLoader : public ClassLoader {
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
@@ -39,6 +41,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(BaseDexClassLoader);
};
+// C++ mirror of dalvik.system.PathClassLoader
class PathClassLoader : public BaseDexClassLoader {
public:
static const PathClassLoader* Alloc(std::vector<const DexFile*> dex_files);
diff --git a/src/common_test.h b/src/common_test.h
index c79cea6..5318008 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -89,6 +89,8 @@
runtime_.reset(Runtime::Create(boot_class_path_));
ASSERT_TRUE(runtime_.get() != NULL);
class_linker_ = runtime_->GetClassLinker();
+
+ Heap::VerifyHeap(); // Check for heap corruption before the test
}
virtual void TearDown() {
@@ -127,6 +129,8 @@
CHECK(sym != NULL);
IcuCleanupFn icu_cleanup_fn = reinterpret_cast<IcuCleanupFn>(sym);
(*icu_cleanup_fn)();
+
+ Heap::VerifyHeap(); // Check for heap corruption after the test
}
std::string GetLibCoreDexFileName() {
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index 5cfddc0..4e3c9c4 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -2092,11 +2092,11 @@
* blocks.
*/
bb->dataFlowInfo->dalvikToSSAMap =
- (int *)oatNew(sizeof(int) * cUnit->method->num_registers_,
+ (int *)oatNew(sizeof(int) * cUnit->method->NumRegisters(),
false);
memcpy(bb->dataFlowInfo->dalvikToSSAMap, cUnit->dalvikToSSAMap,
- sizeof(int) * cUnit->method->num_registers_);
+ sizeof(int) * cUnit->method->NumRegisters());
return true;
}
@@ -2184,7 +2184,7 @@
void oatInitializeSSAConversion(CompilationUnit* cUnit)
{
int i;
- int numDalvikReg = cUnit->method->num_registers_;
+ int numDalvikReg = cUnit->method->NumRegisters();
cUnit->ssaToDalvikMap = (GrowableList *)oatNew(sizeof(GrowableList),
false);
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 9ef2b4f..dbd06ab 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -733,7 +733,7 @@
const art::DexFile& dex_file = class_linker->FindDexFile(
method->GetDeclaringClass()->GetDexCache());
const art::DexFile::CodeItem* code_item =
- dex_file.GetCodeItem(method->code_off_);
+ dex_file.GetCodeItem(method->GetCodeItemOffset());
const u2* codePtr = code_item->insns_;
const u2* codeEnd = code_item->insns_ + code_item->insns_size_;
int numBlocks = 0;
@@ -878,7 +878,7 @@
}
/* Adjust this value accordingly once inlining is performed */
- cUnit.numDalvikRegisters = cUnit.method->num_registers_;
+ cUnit.numDalvikRegisters = cUnit.method->NumRegisters();
/* Verify if all blocks are connected as claimed */
diff --git a/src/compiler/Ralloc.cc b/src/compiler/Ralloc.cc
index a4ab76f..6a4e663 100644
--- a/src/compiler/Ralloc.cc
+++ b/src/compiler/Ralloc.cc
@@ -119,9 +119,9 @@
}
/* Figure out the frame size */
- cUnit->numIns = cUnit->method->num_ins_;
- cUnit->numRegs = cUnit->method->num_registers_ - cUnit->numIns;
- cUnit->numOuts = cUnit->method->num_outs_;
+ cUnit->numIns = cUnit->method->NumIns();
+ cUnit->numRegs = cUnit->method->NumRegisters() - cUnit->numIns;
+ cUnit->numOuts = cUnit->method->NumOuts();
cUnit->numPadding = (STACK_ALIGN_WORDS -
(cUnit->numSpills + cUnit->numRegs +
cUnit->numOuts + 2)) & (STACK_ALIGN_WORDS-1);
diff --git a/src/compiler/SSATransformation.cc b/src/compiler/SSATransformation.cc
index 42e855d..95f6db5 100644
--- a/src/compiler/SSATransformation.cc
+++ b/src/compiler/SSATransformation.cc
@@ -107,8 +107,8 @@
* Also set the incoming parameters as defs in the entry block.
* Only need to handle the parameters for the outer method.
*/
- int inReg = cUnit->method->num_registers_ - cUnit->method->num_ins_;
- for (; inReg < cUnit->method->num_registers_; inReg++) {
+ int inReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
+ for (; inReg < cUnit->method->NumRegisters(); inReg++) {
oatSetBit(cUnit->defBlockMatrix[inReg],
cUnit->entryBlock->id);
}
diff --git a/src/compiler/codegen/arm/ArchUtility.cc b/src/compiler/codegen/arm/ArchUtility.cc
index d643a90..dc8bdec 100644
--- a/src/compiler/codegen/arm/ArchUtility.cc
+++ b/src/compiler/codegen/arm/ArchUtility.cc
@@ -407,7 +407,7 @@
" bytes, Dalvik size is " << insnsSize * 2;
LOG(INFO) << "expansion factor: " <<
(float)cUnit->totalSize / (float)(insnsSize * 2);
- for (int i = 0; i < method->num_registers_; i++) {
+ for (int i = 0; i < method->NumRegisters(); i++) {
RegLocation loc = cUnit->regLocation[i];
char buf[100];
if (loc.fpLocation == kLocPhysReg) {
diff --git a/src/compiler/codegen/arm/ArmRallocUtil.cc b/src/compiler/codegen/arm/ArmRallocUtil.cc
index 6223512..78d5267 100644
--- a/src/compiler/codegen/arm/ArmRallocUtil.cc
+++ b/src/compiler/codegen/arm/ArmRallocUtil.cc
@@ -94,7 +94,7 @@
for (i=0; i< ssaRep->numUses; i++) {
int origSreg = DECODE_REG(
oatConvertSSARegToDalvik(cUnit, ssaRep->uses[i]));
- assert(origSreg < cUnit->method->num_registers_);
+ assert(origSreg < cUnit->method->NumRegisters());
bool fpUse = ssaRep->fpUse ? ssaRep->fpUse[i] : false;
if (fp == fpUse) {
counts[origSreg].count++;
@@ -107,7 +107,7 @@
}
int origSreg = DECODE_REG(
oatConvertSSARegToDalvik(cUnit, ssaRep->defs[i]));
- assert(origSreg < cUnit->method->num_registers_);
+ assert(origSreg < cUnit->method->NumRegisters());
bool fpDef = ssaRep->fpDef ? ssaRep->fpDef[i] : false;
if (fp == fpDef) {
counts[origSreg].count++;
@@ -139,8 +139,8 @@
*/
extern void oatDoPromotion(CompilationUnit* cUnit)
{
- int numRegs = cUnit->method->num_registers_;
- int numIns = cUnit->method->num_ins_;
+ int numRegs = cUnit->method->NumRegisters();
+ int numIns = cUnit->method->NumIns();
/*
* Because ins don't have explicit definitions, we need to type
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index c69a27e..8caf0d1 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -404,12 +404,12 @@
break;
case 1: // Get the current Method->DeclaringClass() [sets r0]
loadBaseDisp(cUnit, mir, r0,
- OFFSETOF_MEMBER(art::Method, declaring_class_),
+ art::Method::DeclaringClassOffset().Int32Value(),
r0, kWord, INVALID_SREG);
break;
case 2: // Method->DeclaringClass()->GetDexCache() [sets r0]
loadBaseDisp(cUnit, mir, r0,
- OFFSETOF_MEMBER(art::Class, dex_cache_), r0, kWord,
+ art::Class::DexCacheOffset().Int32Value(), r0, kWord,
INVALID_SREG);
break;
case 3: // Method->DeclaringClass()->GetDexCache()->methodsObjectArr
@@ -425,7 +425,8 @@
kWord, INVALID_SREG);
break;
case 6: // Get the target compiled code address [uses r0, sets rLR]
- loadBaseDisp(cUnit, mir, r0, art::Method::GetCodeOffset(), rLR,
+ loadBaseDisp(cUnit, mir, r0,
+ art::Method::GetCodeOffset().Int32Value(), rLR,
kWord, INVALID_SREG);
break;
default:
@@ -502,18 +503,19 @@
break;
case 1: // Get the current Method->DeclaringClass() [uses/sets r0]
loadBaseDisp(cUnit, mir, r0,
- OFFSETOF_MEMBER(art::Method, declaring_class_),
+ art::Method::DeclaringClassOffset().Int32Value(),
r0, kWord, INVALID_SREG);
break;
case 2: // Method->DeclaringClass()->GetDexCache() [uses/sets r0]
loadBaseDisp(cUnit, mir, r0,
- OFFSETOF_MEMBER(art::Class, dex_cache_), r0, kWord,
+ art::Class::DexCacheOffset().Int32Value(),
+ r0, kWord,
INVALID_SREG);
break;
case 3: // ...()->GetDexCache()->methodsObjectArr [uses/sets r0]
loadBaseDisp(cUnit, mir, r0,
- art::DexCache::ResolvedMethodsOffset().Int32Value(), r0,
- kWord, INVALID_SREG);
+ art::DexCache::ResolvedMethodsOffset().Int32Value(),
+ r0, kWord, INVALID_SREG);
// Load "this" [set r1]
rlArg = oatGetSrc(cUnit, mir, 0);
loadValueDirectFixed(cUnit, rlArg, r1);
@@ -524,17 +526,18 @@
// Is "this" null? [use r1]
genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
// get this->clazz [use r1, set rLR]
- loadBaseDisp(cUnit, mir, r1, OFFSETOF_MEMBER(Object, klass_), rLR,
- kWord, INVALID_SREG);
+ loadBaseDisp(cUnit, mir, r1, Object::ClassOffset().Int32Value(),
+ rLR, kWord, INVALID_SREG);
// Get the base Method* [uses r0, sets r0]
loadBaseDisp(cUnit, mir, r0, dInsn->vB * 4, r0,
kWord, INVALID_SREG);
// get this->clazz->vtable [use rLR, set rLR]
loadBaseDisp(cUnit, mir, rLR,
- OFFSETOF_MEMBER(Class, vtable_), rLR, kWord,
+ Class::VTableOffset().Int32Value(), rLR, kWord,
INVALID_SREG);
// Get the method index [use r0, set r12]
- loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, method_index_),
+ loadBaseDisp(cUnit, mir, r0,
+ Method::MethodIndexOffset().Int32Value(),
r12, kUnsignedHalf, INVALID_SREG);
// Skip past the object header
opRegImm(cUnit, kOpAdd, rLR, art::Array::DataOffset().Int32Value());
@@ -542,7 +545,8 @@
loadBaseIndexed(cUnit, rLR, r12, r0, 2, kWord);
break;
case 5: // Get the target compiled code address [uses r0, sets rLR]
- loadBaseDisp(cUnit, mir, r0, art::Method::GetCodeOffset(), rLR,
+ loadBaseDisp(cUnit, mir, r0,
+ art::Method::GetCodeOffset().Int32Value(), rLR,
kWord, INVALID_SREG);
break;
default:
@@ -766,7 +770,7 @@
* Dalvik vRegs and the ins.
*/
int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
- int boundaryReg = cUnit->method->num_registers_ - cUnit->method->num_ins_;
+ int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
LOG(FATAL) << "Argument list spanned locals & args";
}
@@ -1628,11 +1632,13 @@
* home location */
static void flushIns(CompilationUnit* cUnit)
{
- if (cUnit->method->num_ins_ == 0)
+ if (cUnit->method->NumIns() == 0)
return;
- int inRegs = (cUnit->method->num_ins_ > 2) ? 3 : cUnit->method->num_ins_;
+ int inRegs = (cUnit->method->NumIns() > 2) ? 3
+ : cUnit->method->NumIns();
int startReg = r1;
- int startLoc = cUnit->method->num_registers_ - cUnit->method->num_ins_;
+ int startLoc = cUnit->method->NumRegisters() -
+ cUnit->method->NumIns();
for (int i = 0; i < inRegs; i++) {
RegLocation loc = cUnit->regLocation[startLoc + i];
//TUNING: be smarter about flushing ins to frame
@@ -1654,7 +1660,7 @@
}
// Now, do initial assignment of all promoted arguments passed in frame
- for (int i = inRegs; i < cUnit->method->num_ins_;) {
+ for (int i = inRegs; i < cUnit->method->NumIns();) {
RegLocation loc = cUnit->regLocation[startLoc + i];
if (loc.fpLocation == kLocPhysReg) {
loc.location = kLocPhysReg;
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 11146f7..c4a1fed 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -389,7 +389,7 @@
#else
bool isVolatile = false;
#endif
- int fieldOffset = fieldPtr->GetOffset();
+ int fieldOffset = fieldPtr->GetOffset().Int32Value();
RegLocation rlResult;
RegisterClass regClass = oatRegClassBySize(size);
rlObj = loadValue(cUnit, rlObj, kCoreReg);
@@ -418,7 +418,7 @@
#else
bool isVolatile = false;
#endif
- int fieldOffset = fieldPtr->GetOffset();
+ int fieldOffset = fieldPtr->GetOffset().Int32Value();
RegisterClass regClass = oatRegClassBySize(size);
rlObj = loadValue(cUnit, rlObj, kCoreReg);
rlSrc = loadValue(cUnit, rlSrc, regClass);
@@ -448,7 +448,7 @@
#else
bool isVolatile = false;
#endif
- int fieldOffset = fieldPtr->GetOffset();
+ int fieldOffset = fieldPtr->GetOffset().Int32Value();
RegLocation rlResult;
rlObj = loadValue(cUnit, rlObj, kCoreReg);
int regPtr = oatAllocTemp(cUnit);
@@ -483,7 +483,7 @@
#else
bool isVolatile = false;
#endif
- int fieldOffset = fieldPtr->GetOffset();
+ int fieldOffset = fieldPtr->GetOffset().Int32Value();
rlObj = loadValue(cUnit, rlObj, kCoreReg);
int regPtr;
@@ -504,12 +504,12 @@
static void genConstClass(CompilationUnit* cUnit, MIR* mir,
RegLocation rlDest, RegLocation rlSrc)
{
- art::Class* classPtr = cUnit->method->dex_cache_resolved_types_->
+ art::Class* classPtr = cUnit->method->GetDexCacheResolvedTypes()->
Get(mir->dalvikInsn.vB);
int mReg = loadCurrMethod(cUnit);
int resReg = oatAllocTemp(cUnit);
RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
- loadWordDisp(cUnit, mReg, OFFSETOF_MEMBER(Method, dex_cache_strings_),
+ loadWordDisp(cUnit, mReg, Method::DexCacheStringsOffset().Int32Value(),
resReg);
loadWordDisp(cUnit, resReg, Array::DataOffset().Int32Value() +
(sizeof(String*) * mir->dalvikInsn.vB), rlResult.lowReg);
@@ -547,14 +547,14 @@
RegLocation rlDest, RegLocation rlSrc)
{
/* All strings should be available at compile time */
- const art::String* str = cUnit->method->dex_cache_strings_->
+ const art::String* str = cUnit->method->GetDexCacheStrings()->
Get(mir->dalvikInsn.vB);
DCHECK(str != NULL);
int mReg = loadCurrMethod(cUnit);
int resReg = oatAllocTemp(cUnit);
RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
- loadWordDisp(cUnit, mReg, OFFSETOF_MEMBER(Method, dex_cache_strings_),
+ loadWordDisp(cUnit, mReg, Method::DexCacheStringsOffset().Int32Value(),
resReg);
loadWordDisp(cUnit, resReg, Array::DataOffset().Int32Value() +
(sizeof(String*) * mir->dalvikInsn.vB), rlResult.lowReg);
@@ -605,8 +605,8 @@
/* When taken r0 has NULL which can be used for store directly */
ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
/* r1 now contains object->clazz */
- assert(OFFSETOF_MEMBER(Object, klass_) == 0);
- loadWordDisp(cUnit, r0, OFFSETOF_MEMBER(Object, klass_), r1);
+ assert(Object::ClassOffset().Int32Value() == 0);
+ loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
/* r1 now contains object->clazz */
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
@@ -647,7 +647,7 @@
* with clazz.
*/
/* r0 now contains object->clazz */
- loadWordDisp(cUnit, rlSrc.lowReg, OFFSETOF_MEMBER(Object, klass_), r0);
+ loadWordDisp(cUnit, rlSrc.lowReg, Object::ClassOffset().Int32Value(), r0);
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
opRegReg(cUnit, kOpCmp, r0, r1);
@@ -799,7 +799,7 @@
genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
loadWordDisp(cUnit, rSELF, Thread::IdOffset().Int32Value(), r3);
newLIR3(cUnit, kThumb2Ldrex, r2, r1,
- OFFSETOF_MEMBER(Object, monitor_) >> 2); // Get object->lock
+ Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
// Align owner
opRegImm(cUnit, kOpLsl, r3, art::Monitor::kLwLockOwnerShift);
// Is lock unheld on lock or held by us (==threadId) on unlock?
@@ -809,7 +809,7 @@
art::Monitor::kLwLockOwnerShift - 1);
hopBranch = newLIR2(cUnit, kThumb2Cbnz, r2, 0);
newLIR4(cUnit, kThumb2Strex, r2, r3, r1,
- OFFSETOF_MEMBER(Object, monitor_) >> 2);
+ Object::MonitorOffset().Int32Value() >> 2);
oatGenMemBarrier(cUnit, kSY);
branch = newLIR2(cUnit, kThumb2Cbz, r2, 0);
@@ -848,7 +848,7 @@
loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj
oatLockCallTemps(cUnit); // Prepare for explicit register usage
genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
- loadWordDisp(cUnit, r1, OFFSETOF_MEMBER(Object, monitor_), r2); // Get lock
+ loadWordDisp(cUnit, r1, Object::MonitorOffset().Int32Value(), r2); // Get lock
loadWordDisp(cUnit, rSELF, Thread::IdOffset().Int32Value(), r3);
// Is lock unheld on lock or held by us (==threadId) on unlock?
opRegRegImm(cUnit, kOpAnd, r12, r2, (art::Monitor::kLwHashStateMask <<
@@ -860,7 +860,7 @@
opRegReg(cUnit, kOpSub, r2, r3);
hopBranch = opCondBranch(cUnit, kArmCondNe);
oatGenMemBarrier(cUnit, kSY);
- storeWordDisp(cUnit, r1, OFFSETOF_MEMBER(Object, monitor_), r12);
+ storeWordDisp(cUnit, r1, Object::MonitorOffset().Int32Value(), r12);
branch = opNone(cUnit, kOpUncondBr);
hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -1152,9 +1152,9 @@
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
/* Get the array's clazz */
- loadWordDisp(cUnit, r1, OFFSETOF_MEMBER(Object, klass_), r1);
+ loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), r1);
/* Get the object's clazz */
- loadWordDisp(cUnit, r0, OFFSETOF_MEMBER(Object, klass_), r0);
+ loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r0);
opReg(cUnit, kOpBlx, rLR);
oatClobberCallRegs(cUnit);
diff --git a/src/dex_cache.h b/src/dex_cache.h
index f2cfcc7..137f267 100644
--- a/src/dex_cache.h
+++ b/src/dex_cache.h
@@ -109,11 +109,11 @@
return GetInitializedStaticStorage()->GetLength();
}
- const String* GetResolvedString(uint32_t string_idx) const {
+ String* GetResolvedString(uint32_t string_idx) const {
return GetStrings()->Get(string_idx);
}
- void SetResolvedString(uint32_t string_idx, const String* resolved) {
+ void SetResolvedString(uint32_t string_idx, String* resolved) {
GetStrings()->Set(string_idx, resolved);
}
@@ -141,8 +141,8 @@
GetResolvedFields()->Set(field_idx, resolved);
}
- ObjectArray<const String>* GetStrings() const {
- return static_cast<ObjectArray<const String>*>(GetNonNull(kStrings));
+ ObjectArray<String>* GetStrings() const {
+ return static_cast<ObjectArray<String>*>(GetNonNull(kStrings));
}
ObjectArray<Class>* GetResolvedTypes() const {
return static_cast<ObjectArray<Class>*>(GetNonNull(kResolvedTypes));
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 3d66909..c8e7c70 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -543,11 +543,11 @@
int32_t DexFile::GetLineNumFromPC(const art::Method* method, uint32_t rel_pc) const {
// For native method, lineno should be -2 to indicate it is native. Note that
// "line number == -2" is how libcore tells from StackTraceElement.
- if (method->code_off_ == 0) {
+ if (method->GetCodeItemOffset() == 0) {
return -2;
}
- const CodeItem* code_item = GetCodeItem(method->code_off_);
+ const CodeItem* code_item = GetCodeItem(method->GetCodeItemOffset());
DCHECK(code_item != NULL);
// A method with no line number info should return -1
@@ -573,7 +573,7 @@
arg_reg++;
}
- ParameterIterator *it = GetParameterIterator(GetProtoId(method->proto_idx_));
+ ParameterIterator *it = GetParameterIterator(GetProtoId(method->GetProtoIdx()));
for (uint32_t i = 0; i < parameters_size && it->HasNext(); ++i, it->Next()) {
if (arg_reg >= code_item->registers_size_) {
LOG(FATAL) << "invalid stream";
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 0e62b25..f257e78 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -655,7 +655,7 @@
const DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
- const DexFile::CodeItem *code_item = dex_file.GetCodeItem(method->code_off_);
+ const DexFile::CodeItem *code_item = dex_file.GetCodeItem(method->GetCodeItemOffset());
/*
* If there aren't any instructions, make sure that's expected, then
@@ -682,29 +682,26 @@
/*
* Allocate and initialize an array to hold instruction data.
*/
- uint32_t* insn_flags = new uint32_t[code_item->insns_size_]();
+ UniquePtr<uint32_t[]> insn_flags(new uint32_t[code_item->insns_size_]());
/*
* Run through the instructions and see if the width checks out.
*/
- if (!CheckInsnWidth(code_item->insns_, code_item->insns_size_, insn_flags)) {
- delete insn_flags;
+ if (!CheckInsnWidth(code_item->insns_, code_item->insns_size_, insn_flags.get())) {
return false;
}
/*
* Flag instructions guarded by a "try" block and check exception handlers.
*/
- if (!ScanTryCatchBlocks(code_item, insn_flags)) {
- delete insn_flags;
+ if (!ScanTryCatchBlocks(code_item, insn_flags.get())) {
return false;
}
/*
* Perform static instruction verification.
*/
- if (!VerifyInstructions(&dex_file, code_item, insn_flags)) {
- delete insn_flags;
+ if (!VerifyInstructions(&dex_file, code_item, insn_flags.get())) {
return false;
}
@@ -712,7 +709,6 @@
* TODO: Code flow analysis
*/
- delete insn_flags;
return true;
}
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 3611b67..439e7ed 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -74,18 +74,18 @@
ASSERT_TRUE(my_klass_ != NULL);
method_f_ = my_klass_->FindVirtualMethod("f", "()I");
ASSERT_TRUE(method_f_ != NULL);
- method_f_->SetFrameSizeInBytes(8);
+ method_f_->SetFrameSizeInBytes(kStackAlignment);
method_f_->SetReturnPcOffsetInBytes(4);
method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
ASSERT_TRUE(method_g_ != NULL);
- method_g_->SetFrameSizeInBytes(8);
+ method_g_->SetFrameSizeInBytes(kStackAlignment);
method_g_->SetReturnPcOffsetInBytes(4);
}
DexFile::CatchHandlerItem FindCatchHandlerItem(Method* method,
const char exception_type[],
uint32_t addr) {
- const DexFile::CodeItem* code_item = dex_->GetCodeItem(method->code_off_);
+ const DexFile::CodeItem* code_item = dex_->GetCodeItem(method->GetCodeItemOffset());
for (DexFile::CatchHandlerIterator iter = dex_->dexFindCatchHandler(*code_item, addr);
!iter.HasNext(); iter.Next()) {
if (strcmp(exception_type, dex_->dexStringByTypeIdx(iter.Get().type_idx_)) == 0) {
@@ -105,7 +105,7 @@
};
TEST_F(ExceptionTest, FindCatchHandler) {
- const DexFile::CodeItem *code_item = dex_->GetCodeItem(method_f_->code_off_);
+ const DexFile::CodeItem *code_item = dex_->GetCodeItem(method_f_->GetCodeItemOffset());
ASSERT_TRUE(code_item != NULL);
@@ -141,12 +141,23 @@
enum {STACK_SIZE = 1000};
uint32_t top_of_stack = 0;
uintptr_t fake_stack[STACK_SIZE];
+ ASSERT_EQ(kStackAlignment, 16);
+ ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t));
+
+ // Create/push fake 16byte stack frame for method g
fake_stack[top_of_stack++] = reinterpret_cast<uintptr_t>(method_g_);
fake_stack[top_of_stack++] = 3;
+ fake_stack[top_of_stack++] = 0;
+ fake_stack[top_of_stack++] = 0;
+
+ // Create/push fake 16byte stack frame for method f
fake_stack[top_of_stack++] = reinterpret_cast<uintptr_t>(method_f_);
fake_stack[top_of_stack++] = 3;
- fake_stack[top_of_stack++] = NULL;
fake_stack[top_of_stack++] = 0;
+ fake_stack[top_of_stack++] = 0;
+
+ // Pull Method* of NULL to terminate the trace
+ fake_stack[top_of_stack++] = NULL;
Thread* thread = Thread::Current();
thread->SetTopOfStack(fake_stack);
diff --git a/src/heap.cc b/src/heap.cc
index 1682cc5..cb5e0dc 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -31,11 +31,11 @@
HeapBitmap* Heap::live_bitmap_ = NULL;
-size_t Heap::reference_referent_offset_ = 0; // TODO
-size_t Heap::reference_queue_offset_ = 0; // TODO
-size_t Heap::reference_queueNext_offset_ = 0; // TODO
-size_t Heap::reference_pendingNext_offset_ = 0; // TODO
-size_t Heap::finalizer_reference_zombie_offset_ = 0; // TODO
+MemberOffset Heap::reference_referent_offset_ = MemberOffset(0);
+MemberOffset Heap::reference_queue_offset_ = MemberOffset(0);
+MemberOffset Heap::reference_queueNext_offset_ = MemberOffset(0);
+MemberOffset Heap::reference_pendingNext_offset_ = MemberOffset(0);
+MemberOffset Heap::finalizer_reference_zombie_offset_ = MemberOffset(0);
bool Heap::Init(size_t initial_size, size_t maximum_size, const char* boot_image_file_name) {
Space* boot_space;
@@ -83,6 +83,9 @@
live_bitmap_ = live_bitmap.release();
mark_bitmap_ = mark_bitmap.release();
+ num_bytes_allocated_ = 0;
+ num_objects_allocated_ = 0;
+
// TODO: allocate the card table
// Make objects in boot_space live (after live_bitmap_ is set)
@@ -108,28 +111,17 @@
Object* Heap::AllocObject(Class* klass, size_t num_bytes) {
DCHECK(klass == NULL
- || klass->descriptor_ == NULL
+ || klass->GetDescriptor() == NULL
|| (klass->IsClassClass() && num_bytes >= sizeof(Class))
- || (klass->object_size_ == (klass->IsArrayClass() ? 0 : num_bytes)));
+ || (klass->IsVariableSize() || klass->GetObjectSize() == num_bytes));
+ DCHECK(num_bytes >= sizeof(Object));
Object* obj = Allocate(num_bytes);
if (obj != NULL) {
- obj->klass_ = klass;
+ obj->SetClass(klass);
}
return obj;
}
-void Heap::VerifyObject(const Object* obj) {
- if (!IsAligned(obj, kObjectAlignment)) {
- LOG(FATAL) << "Object isn't aligned: " << obj;
- } else if (!live_bitmap_->Test(obj)) {
- // TODO: we don't hold a lock here as it is assumed the live bit map
- // isn't changing if the mutator is running.
- LOG(FATAL) << "Object is dead: " << obj;
- } else if(obj->GetClass() == NULL) {
- LOG(FATAL) << "Object has no class: " << obj;
- }
-}
-
bool Heap::IsHeapAddress(const Object* obj) {
if (!IsAligned(obj, kObjectAlignment)) {
return false;
@@ -138,6 +130,52 @@
return true;
}
+bool Heap::verify_object_disabled_;
+
+void Heap::VerifyObject(const Object* obj) {
+ if (obj != NULL && !verify_object_disabled_) {
+ if (!IsAligned(obj, kObjectAlignment)) {
+ LOG(FATAL) << "Object isn't aligned: " << obj;
+ } else if (!live_bitmap_->Test(obj)) {
+ // TODO: we don't hold a lock here as it is assumed the live bit map
+ // isn't changing if the mutator is running.
+ LOG(FATAL) << "Object is dead: " << obj;
+ }
+ // Ignore early dawn of the universe verifications
+ if(num_objects_allocated_ > 10) {
+ const byte* raw_addr = reinterpret_cast<const byte*>(obj) +
+ Object::ClassOffset().Int32Value();
+ const Class* c = *reinterpret_cast<Class* const *>(raw_addr);
+ if (c == NULL) {
+ LOG(FATAL) << "Null class" << " in object: " << obj;
+ } else if (!IsAligned(c, kObjectAlignment)) {
+ LOG(FATAL) << "Class isn't aligned: " << c << " in object: " << obj;
+ } else if (!live_bitmap_->Test(c)) {
+ LOG(FATAL) << "Class of object is dead: " << c << " in object: " << obj;
+ }
+ // Check obj.getClass().getClass() == obj.getClass().getClass().getClass()
+ // NB we don't use the accessors here as they have internal sanity checks
+ // that we don't want to run
+ raw_addr = reinterpret_cast<const byte*>(c) +
+ Object::ClassOffset().Int32Value();
+ const Class* c_c = *reinterpret_cast<Class* const *>(raw_addr);
+ raw_addr = reinterpret_cast<const byte*>(c_c) +
+ Object::ClassOffset().Int32Value();
+ const Class* c_c_c = *reinterpret_cast<Class* const *>(raw_addr);
+ CHECK_EQ(c_c, c_c_c);
+ }
+ }
+}
+
+static void HeapVerifyCallback(Object* obj, void *arg) {
+ DCHECK(obj != NULL);
+ Heap::VerifyObject(obj);
+}
+
+void Heap::VerifyHeap() {
+ live_bitmap_->Walk(HeapVerifyCallback, NULL);
+}
+
void Heap::RecordAllocation(Space* space, const Object* obj) {
size_t size = space->AllocationSize(obj);
DCHECK_NE(size, 0u);
@@ -163,12 +201,12 @@
void Heap::RecordImageAllocations(Space* space) {
CHECK(space != NULL);
CHECK(live_bitmap_ != NULL);
- byte* current = space->GetBase() + RoundUp(sizeof(ImageHeader), 8);
+ byte* current = space->GetBase() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
while (current < space->GetLimit()) {
- DCHECK(IsAligned(current, 8));
+ DCHECK(IsAligned(current, kObjectAlignment));
const Object* obj = reinterpret_cast<const Object*>(current);
live_bitmap_->Set(obj);
- current += RoundUp(obj->SizeOf(), 8);
+ current += RoundUp(obj->SizeOf(), kObjectAlignment);
}
}
diff --git a/src/heap.h b/src/heap.h
index 6420a2a..bc06289 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -7,6 +7,7 @@
#include "globals.h"
#include "object_bitmap.h"
+#include "offsets.h"
namespace art {
@@ -36,6 +37,9 @@
// Check sanity of given reference. Requires the heap lock.
static void VerifyObject(const Object *obj);
+ // Check sanity of all live references. Requires the heap lock.
+ static void VerifyHeap();
+
// A weaker test than VerifyObject that doesn't require the heap lock,
// and doesn't abort on error, allowing the caller to report more
// meaningful diagnostics.
@@ -74,16 +78,16 @@
return mark_bitmap_;
}
- static void SetReferenceOffsets(size_t reference_referent_offset,
- size_t reference_queue_offset,
- size_t reference_queueNext_offset,
- size_t reference_pendingNext_offset,
- size_t finalizer_reference_zombie_offset) {
- CHECK_NE(reference_referent_offset, 0U);
- CHECK_NE(reference_queue_offset, 0U);
- CHECK_NE(reference_queueNext_offset, 0U);
- CHECK_NE(reference_pendingNext_offset, 0U);
- CHECK_NE(finalizer_reference_zombie_offset, 0U);
+ static void SetReferenceOffsets(MemberOffset reference_referent_offset,
+ MemberOffset reference_queue_offset,
+ MemberOffset reference_queueNext_offset,
+ MemberOffset reference_pendingNext_offset,
+ MemberOffset finalizer_reference_zombie_offset) {
+ CHECK_NE(reference_referent_offset.Uint32Value(), 0U);
+ CHECK_NE(reference_queue_offset.Uint32Value(), 0U);
+ CHECK_NE(reference_queueNext_offset.Uint32Value(), 0U);
+ CHECK_NE(reference_pendingNext_offset.Uint32Value(), 0U);
+ CHECK_NE(finalizer_reference_zombie_offset.Uint32Value(), 0U);
reference_referent_offset_ = reference_referent_offset;
reference_queue_offset_ = reference_queue_offset;
reference_queueNext_offset_ = reference_queueNext_offset;
@@ -91,31 +95,36 @@
finalizer_reference_zombie_offset_ = finalizer_reference_zombie_offset;
}
- static size_t GetReferenceReferentOffset() {
- DCHECK_NE(reference_referent_offset_, 0U);
+ static MemberOffset GetReferenceReferentOffset() {
+ DCHECK_NE(reference_referent_offset_.Uint32Value(), 0U);
return reference_referent_offset_;
}
- static size_t GetReferenceQueueOffset() {
- DCHECK_NE(reference_queue_offset_, 0U);
+ static MemberOffset GetReferenceQueueOffset() {
+ DCHECK_NE(reference_queue_offset_.Uint32Value(), 0U);
return reference_queue_offset_;
}
- static size_t GetReferenceQueueNextOffset() {
- DCHECK_NE(reference_queueNext_offset_, 0U);
+ static MemberOffset GetReferenceQueueNextOffset() {
+ DCHECK_NE(reference_queueNext_offset_.Uint32Value(), 0U);
return reference_queueNext_offset_;
}
- static size_t GetReferencePendingNextOffset() {
- DCHECK_NE(reference_pendingNext_offset_, 0U);
+ static MemberOffset GetReferencePendingNextOffset() {
+ DCHECK_NE(reference_pendingNext_offset_.Uint32Value(), 0U);
return reference_pendingNext_offset_;
}
- static size_t GetFinalizerReferenceZombieOffset() {
- DCHECK_NE(finalizer_reference_zombie_offset_, 0U);
+ static MemberOffset GetFinalizerReferenceZombieOffset() {
+ DCHECK_NE(finalizer_reference_zombie_offset_.Uint32Value(), 0U);
return finalizer_reference_zombie_offset_;
}
+ static void DisableObjectValidation() {
+ // TODO: remove this hack necessary for image writing
+ verify_object_disabled_ = true;
+ }
+
private:
// Allocates uninitialized storage.
static Object* Allocate(size_t num_bytes);
@@ -158,19 +167,21 @@
static size_t num_objects_allocated_;
// offset of java.lang.ref.Reference.referent
- static size_t reference_referent_offset_;
+ static MemberOffset reference_referent_offset_;
// offset of java.lang.ref.Reference.queue
- static size_t reference_queue_offset_;
+ static MemberOffset reference_queue_offset_;
// offset of java.lang.ref.Reference.queueNext
- static size_t reference_queueNext_offset_;
+ static MemberOffset reference_queueNext_offset_;
// offset of java.lang.ref.Reference.pendingNext
- static size_t reference_pendingNext_offset_;
+ static MemberOffset reference_pendingNext_offset_;
// offset of java.lang.ref.FinalizerReference.zombie
- static size_t finalizer_reference_zombie_offset_;
+ static MemberOffset finalizer_reference_zombie_offset_;
+
+ static bool verify_object_disabled_;
DISALLOW_IMPLICIT_CONSTRUCTORS(Heap);
};
diff --git a/src/heap_test.cc b/src/heap_test.cc
index 568ddd2..53489e4 100644
--- a/src/heap_test.cc
+++ b/src/heap_test.cc
@@ -6,9 +6,9 @@
class HeapTest : public CommonTest {};
-TEST_F(HeapTest, GarbageCollectClassLinkerInit) {
+TEST_F(HeapTest, DISABLED_GarbageCollectClassLinkerInit) {
// garbage is created during ClassLinker::Init
Heap::CollectGarbage();
}
-} // namespace art
+} // namespace art
diff --git a/src/image_test.cc b/src/image_test.cc
index b03cbe3..fd88b20 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -1,5 +1,8 @@
// Copyright 2011 Google Inc. All Rights Reserved.
+#include <string>
+#include <vector>
+
#include "common_test.h"
#include "file.h"
#include "image.h"
@@ -12,7 +15,6 @@
class ImageTest : public CommonTest {};
TEST_F(ImageTest, WriteRead) {
-
// TODO: move the touching of classes and GC to the ImageWriter proper
for (size_t i = 0; i < java_lang_dex_file_->NumClassDefs(); i++) {
const DexFile::ClassDef& class_def = java_lang_dex_file_->GetClassDef(i);
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 887be66..e0e77c7 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -118,6 +118,8 @@
void ImageWriter::CopyAndFixupObjects() {
HeapBitmap* heap_bitmap = Heap::GetLiveBits();
DCHECK(heap_bitmap != NULL);
+ // TODO: heap validation can't handle this fix up pass
+ Heap::DisableObjectValidation();
heap_bitmap->Walk(CopyAndFixupObjectsCallback, this);
}
@@ -140,7 +142,7 @@
void ImageWriter::FixupObject(const Object* orig, Object* copy) {
DCHECK(orig != NULL);
DCHECK(copy != NULL);
- copy->klass_ = down_cast<Class*>(GetImageAddress(orig->klass_));
+ copy->SetClass(down_cast<Class*>(GetImageAddress(orig->GetClass())));
// TODO: special case init of pointers to malloc data (or removal of these pointers)
if (orig->IsClass()) {
FixupClass(orig->AsClass(), down_cast<Class*>(copy));
@@ -182,6 +184,13 @@
// TODO: remove need for this by adding "signature" to java.lang.reflect.Method
copy->signature_ = down_cast<String*>(GetImageAddress(orig->signature_));
DCHECK(copy->signature_ != NULL);
+ copy->dex_cache_strings_ = down_cast<ObjectArray<String>*>(GetImageAddress(orig->dex_cache_strings_));
+ copy->dex_cache_resolved_types_ = down_cast<ObjectArray<Class>*>(GetImageAddress(orig->dex_cache_resolved_types_));
+ copy->dex_cache_resolved_methods_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->dex_cache_resolved_methods_));
+ copy->dex_cache_resolved_fields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->dex_cache_resolved_fields_));
+ copy->dex_cache_code_and_direct_methods_ = down_cast<CodeAndDirectMethods*>(GetImageAddress(orig->dex_cache_code_and_direct_methods_));
+ copy->dex_cache_initialized_static_storage_ = down_cast<ObjectArray<StaticStorageBase>*>(GetImageAddress(orig->dex_cache_initialized_static_storage_));
+
// TODO: convert shorty_ to heap allocated storage
}
@@ -193,7 +202,7 @@
void ImageWriter::FixupObjectArray(const ObjectArray<Object>* orig, ObjectArray<Object>* copy) {
for (int32_t i = 0; i < orig->GetLength(); ++i) {
const Object* element = orig->Get(i);
- copy->Set(i, GetImageAddress(element));
+ copy->SetWithoutChecks(i, GetImageAddress(element));
}
}
@@ -225,9 +234,9 @@
// Found a reference offset bitmap. Fixup the specified offsets.
while (ref_offsets != 0) {
size_t right_shift = CLZ(ref_offsets);
- size_t byte_offset = CLASS_OFFSET_FROM_CLZ(right_shift);
- const Object* ref = orig->GetFieldObject(byte_offset);
- copy->SetFieldObject(byte_offset, GetImageAddress(ref));
+ MemberOffset byte_offset = CLASS_OFFSET_FROM_CLZ(right_shift);
+ const Object* ref = orig->GetFieldObject<const Object*>(byte_offset, false);
+ copy->SetFieldObject(byte_offset, GetImageAddress(ref), false);
ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
}
} else {
@@ -245,9 +254,9 @@
Field* field = (is_static
? klass->GetStaticField(i)
: klass->GetInstanceField(i));
- size_t field_offset = field->GetOffset();
- const Object* ref = orig->GetFieldObject(field_offset);
- copy->SetFieldObject(field_offset, GetImageAddress(ref));
+ MemberOffset field_offset = field->GetOffset();
+ const Object* ref = orig->GetFieldObject<const Object*>(field_offset, false);
+ copy->SetFieldObject(field_offset, GetImageAddress(ref), false);
}
}
}
diff --git a/src/image_writer.h b/src/image_writer.h
index 80012bc..b63effe 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -30,13 +30,13 @@
// we use the lock word to store the offset of the object in the image
void SetImageOffset(Object* object, size_t offset) {
DCHECK(object != NULL);
- DCHECK(object->monitor_ == NULL); // should be no lock
+ DCHECK(object->GetMonitor() == NULL); // should be no lock
DCHECK_NE(0U, offset);
- object->monitor_ = reinterpret_cast<Monitor*>(offset);
+ object->SetMonitor(reinterpret_cast<Monitor*>(offset));
}
size_t GetImageOffset(const Object* object) {
DCHECK(object != NULL);
- size_t offset = reinterpret_cast<size_t>(object->monitor_);
+ size_t offset = reinterpret_cast<size_t>(object->GetMonitor());
DCHECK_NE(0U, offset);
return offset;
}
diff --git a/src/java_lang_System.cc b/src/java_lang_System.cc
index 43335ac..e45519e 100644
--- a/src/java_lang_System.cc
+++ b/src/java_lang_System.cc
@@ -183,7 +183,7 @@
// Neither class is primitive. Are the types trivially compatible?
const int width = sizeof(Object*);
- bool sameDimensions = srcArray->GetClass()->array_rank_ == dstArray->GetClass()->array_rank_;
+ bool sameDimensions = srcArray->GetClass()->GetArrayRank() == dstArray->GetClass()->GetArrayRank();
if (sameDimensions && srcComponentType->InstanceOf(dstComponentType)) {
// Yes. Bulk copy.
move32(dstBytes + dstPos * width, srcBytes + srcPos * width, length * width);
@@ -207,7 +207,7 @@
// race by modifying the source array after we check but before we copy,
// and cause us to copy incompatible elements.
- Object** srcObj = reinterpret_cast<ObjectArray<Object>*>(srcArray)->GetData() + srcPos;
+ Object* const * srcObj = reinterpret_cast<Object* const *>(srcBytes + srcPos * width);
Class* dstClass = dstArray->GetClass();
Class* initialElementClass = NULL;
diff --git a/src/jni_compiler.cc b/src/jni_compiler.cc
index adc87da..238b9ef 100644
--- a/src/jni_compiler.cc
+++ b/src/jni_compiler.cc
@@ -4,6 +4,7 @@
#include "jni_compiler.h"
#include <sys/mman.h>
+#include <vector>
#include "assembler.h"
#include "calling_convention.h"
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 3ffc184..254fbdf 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -349,9 +349,12 @@
int gSuspendCounterHandler_calls;
void SuspendCountHandler(Method** frame) {
+ EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+ Thread::Current()->SetState(Thread::kRunnable);
EXPECT_TRUE((*frame)->GetName()->Equals("fooI"));
gSuspendCounterHandler_calls++;
Thread::Current()->DecrementSuspendCount();
+ Thread::Current()->SetState(Thread::kNative);
}
TEST_F(JniCompilerTest, SuspendCountAcknowledgement) {
@@ -377,9 +380,12 @@
int gExceptionHandler_calls;
void ExceptionHandler(Method** frame) {
+ EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+ Thread::Current()->SetState(Thread::kRunnable);
EXPECT_TRUE((*frame)->GetName()->Equals("throwException"));
gExceptionHandler_calls++;
Thread::Current()->ClearException();
+ Thread::Current()->SetState(Thread::kNative);
}
void Java_MyClass_throwException(JNIEnv* env, jobject) {
@@ -410,6 +416,8 @@
jint Java_MyClass_nativeUpCall(JNIEnv* env, jobject thisObj, jint i) {
if (i <= 0) {
+ EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+ Thread::Current()->SetState(Thread::kRunnable);
ObjectArray<StackTraceElement>* trace_array = Thread::Current()->AllocStackTrace();
EXPECT_TRUE(trace_array != NULL);
EXPECT_EQ(11, trace_array->GetLength());
@@ -420,6 +428,7 @@
EXPECT_STREQ("MyClass", trace_array->Get(i)->GetDeclaringClass()->ToModifiedUtf8().c_str());
EXPECT_STREQ("fooI", trace_array->Get(i)->GetMethodName()->ToModifiedUtf8().c_str());
}
+ Thread::Current()->SetState(Thread::kNative);
return 0;
} else {
jclass jklass = env->FindClass("MyClass");
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 36787d8..125401e 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -346,12 +346,26 @@
}
Field* field = NULL;
- if (is_static) {
- field = c->FindStaticField(name, sig);
+ Class* field_type;
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ if (sig[1] != '\0') {
+ // TODO: need to get the appropriate ClassLoader.
+ const ClassLoader* cl = ts.Self()->GetClassLoaderOverride();
+ field_type = class_linker->FindClass(sig, cl);
} else {
- field = c->FindInstanceField(name, sig);
+ field_type = class_linker->FindPrimitiveClass(*sig);
}
-
+ if (field_type == NULL) {
+ // Failed to find type from the signature of the field.
+ // TODO: Linkage or NoSuchFieldError?
+ CHECK(ts.Self()->IsExceptionPending());
+ return NULL;
+ }
+ if (is_static) {
+ field = c->FindStaticField(name, field_type);
+ } else {
+ field = c->FindInstanceField(name, field_type);
+ }
if (field == NULL) {
Thread* self = Thread::Current();
std::string class_descriptor(c->GetDescriptor()->ToModifiedUtf8());
@@ -360,7 +374,9 @@
name, class_descriptor.c_str());
return NULL;
}
-
+ // Check invariant that all jfieldIDs have resolved types (how else would
+ // the type equality in Find...Field hold?)
+ DCHECK(field->GetType() != NULL);
jweak fid = AddWeakGlobalReference(ts, field);
return reinterpret_cast<jfieldID>(fid);
}
diff --git a/src/jni_internal_arm.cc b/src/jni_internal_arm.cc
index 0d19c1c..6b4162b 100644
--- a/src/jni_internal_arm.cc
+++ b/src/jni_internal_arm.cc
@@ -49,7 +49,7 @@
size_t reg_bytes = (method->IsStatic() ? 3 : 2) * kPointerSize;
// Bytes passed by stack
size_t stack_bytes;
- if( method->NumArgArrayBytes() > reg_bytes){
+ if (method->NumArgArrayBytes() > reg_bytes) {
stack_bytes = method->NumArgArrayBytes() - reg_bytes;
} else {
stack_bytes = 0;
@@ -61,7 +61,7 @@
__ StoreToOffset(kStoreWord, IP, SP, 0);
// Copy values by stack
- for(size_t off = 0; off < stack_bytes; off += kPointerSize) {
+ for (size_t off = 0; off < stack_bytes; off += kPointerSize) {
// we're displaced off of r3 by bytes that'll go in registers
int r3_offset = reg_bytes + off;
__ LoadFromOffset(kLoadWord, IP, R3, r3_offset);
@@ -93,7 +93,7 @@
}
// Load the code pointer we are about to call.
- __ LoadFromOffset(kLoadWord, IP, R0, method->GetCodeOffset());
+ __ LoadFromOffset(kLoadWord, IP, R0, method->GetCodeOffset().Int32Value());
// Do the call.
__ blx(IP);
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 3e3e381..e82b734 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -2,9 +2,10 @@
#include "jni_internal.h"
-#include <cmath>
#include <sys/mman.h>
+#include <cmath>
+
#include "common_test.h"
namespace art {
@@ -1560,4 +1561,4 @@
ASSERT_TRUE(env_->GetDirectBufferCapacity(buffer) == sizeof(bytes));
}
-}
+} // namespace art
diff --git a/src/jni_internal_x86.cc b/src/jni_internal_x86.cc
index ad30acc..782ff66 100644
--- a/src/jni_internal_x86.cc
+++ b/src/jni_internal_x86.cc
@@ -60,7 +60,7 @@
if (ch != 'V') {
// Load the result JValue pointer.
__ movl(EDI, Address(ESP, 24));
- switch(ch) {
+ switch (ch) {
case 'D':
__ fstpl(Address(EDI, 0));
break;
@@ -76,7 +76,7 @@
break;
}
}
- __ popl(EDI); // restore EDI
+ __ popl(EDI); // restore EDI
__ ret();
}
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc
index af7f1a5..ac9a7cd 100644
--- a/src/mark_sweep.cc
+++ b/src/mark_sweep.cc
@@ -191,8 +191,8 @@
// Found a reference offset bitmap. Mark the specified offsets.
while (ref_offsets != 0) {
size_t right_shift = CLZ(ref_offsets);
- size_t byte_offset = CLASS_OFFSET_FROM_CLZ(right_shift);
- const Object* ref = obj->GetFieldObject(byte_offset);
+ MemberOffset byte_offset = CLASS_OFFSET_FROM_CLZ(right_shift);
+ const Object* ref = obj->GetFieldObject<const Object*>(byte_offset, false);
MarkObject(ref);
ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
}
@@ -211,8 +211,8 @@
Field* field = (is_static
? klass->GetStaticField(i)
: klass->GetInstanceField(i));
- size_t field_offset = field->GetOffset();
- const Object* ref = obj->GetFieldObject(field_offset);
+ MemberOffset field_offset = field->GetOffset();
+ const Object* ref = obj->GetFieldObject<const Object*>(field_offset, false);
MarkObject(ref);
}
}
@@ -267,32 +267,33 @@
void MarkSweep::EnqueuePendingReference(Object* ref, Object** list) {
DCHECK(ref != NULL);
DCHECK(list != NULL);
- size_t offset = Heap::GetReferencePendingNextOffset();
+
+ MemberOffset offset = Heap::GetReferencePendingNextOffset();
if (*list == NULL) {
- ref->SetFieldObject(offset, ref);
+ ref->SetFieldObject(offset, ref, false);
*list = ref;
} else {
- Object* head = (*list)->GetFieldObject(offset);
- ref->SetFieldObject(offset, head);
- (*list)->SetFieldObject(offset, ref);
+ Object* head = (*list)->GetFieldObject<Object*>(offset, false);
+ ref->SetFieldObject(offset, head, false);
+ (*list)->SetFieldObject(offset, ref, false);
}
}
Object* MarkSweep::DequeuePendingReference(Object** list) {
DCHECK(list != NULL);
DCHECK(*list != NULL);
- size_t offset = Heap::GetReferencePendingNextOffset();
- Object* head = (*list)->GetFieldObject(offset);
+ MemberOffset offset = Heap::GetReferencePendingNextOffset();
+ Object* head = (*list)->GetFieldObject<Object*>(offset, false);
Object* ref;
if (*list == head) {
ref = *list;
*list = NULL;
} else {
- Object* next = head->GetFieldObject(offset);
- (*list)->SetFieldObject(offset, next);
+ Object* next = head->GetFieldObject<Object*>(offset, false);
+ (*list)->SetFieldObject(offset, next, false);
ref = head;
}
- ref->SetFieldObject(offset, NULL);
+ ref->SetFieldObject(offset, NULL, false);
return ref;
}
@@ -303,18 +304,18 @@
DCHECK(obj != NULL);
Class* klass = obj->GetClass();
DCHECK(klass != NULL);
- DCHECK(klass->IsReference());
- Object* pending = obj->GetFieldObject(Heap::GetReferencePendingNextOffset());
- Object* referent = obj->GetFieldObject(Heap::GetReferenceReferentOffset());
+ DCHECK(klass->IsReferenceClass());
+ Object* pending = obj->GetFieldObject<Object*>(Heap::GetReferencePendingNextOffset(), false);
+ Object* referent = obj->GetFieldObject<Object*>(Heap::GetReferenceReferentOffset(), false);
if (pending == NULL && referent != NULL && !IsMarked(referent)) {
Object** list = NULL;
- if (klass->IsSoftReference()) {
+ if (klass->IsSoftReferenceClass()) {
list = &soft_reference_list_;
- } else if (klass->IsWeakReference()) {
+ } else if (klass->IsWeakReferenceClass()) {
list = &weak_reference_list_;
- } else if (klass->IsFinalizerReference()) {
+ } else if (klass->IsFinalizerReferenceClass()) {
list = &finalizer_reference_list_;
- } else if (klass->IsPhantomReference()) {
+ } else if (klass->IsPhantomReferenceClass()) {
list = &phantom_reference_list_;
}
DCHECK(list != NULL);
@@ -331,7 +332,7 @@
DCHECK(klass != NULL);
MarkObject(klass);
ScanInstanceFields(obj);
- if (klass->IsReference()) {
+ if (klass->IsReferenceClass()) {
DelayReferenceReferent(const_cast<Object*>(obj));
}
}
@@ -366,20 +367,22 @@
void MarkSweep::ClearReference(Object* ref) {
DCHECK(ref != NULL);
- ref->SetFieldObject(Heap::GetReferenceReferentOffset(), NULL);
+ ref->SetFieldObject(Heap::GetReferenceReferentOffset(), NULL, false);
}
bool MarkSweep::IsEnqueuable(const Object* ref) {
DCHECK(ref != NULL);
- const Object* queue = ref->GetFieldObject(Heap::GetReferenceQueueOffset());
- const Object* queue_next = ref->GetFieldObject(Heap::GetReferenceQueueNextOffset());
+ const Object* queue =
+ ref->GetFieldObject<Object*>(Heap::GetReferenceQueueOffset(), false);
+ const Object* queue_next =
+ ref->GetFieldObject<Object*>(Heap::GetReferenceQueueNextOffset(), false);
return (queue != NULL) && (queue_next == NULL);
}
void MarkSweep::EnqueueReference(Object* ref) {
DCHECK(ref != NULL);
- CHECK(ref->GetFieldObject(Heap::GetReferenceQueueOffset()) != NULL);
- CHECK(ref->GetFieldObject(Heap::GetReferenceQueueNextOffset()) == NULL);
+ CHECK(ref->GetFieldObject<Object*>(Heap::GetReferenceQueueOffset(), false) != NULL);
+ CHECK(ref->GetFieldObject<Object*>(Heap::GetReferenceQueueNextOffset(), false) == NULL);
EnqueuePendingReference(ref, &cleared_reference_list_);
}
@@ -393,7 +396,7 @@
size_t counter = 0;
while (*list != NULL) {
Object* ref = DequeuePendingReference(list);
- Object* referent = ref->GetFieldObject(Heap::GetReferenceReferentOffset());
+ Object* referent = ref->GetFieldObject<Object*>(Heap::GetReferenceReferentOffset(), false);
if (referent == NULL) {
// Referent was cleared by the user during marking.
continue;
@@ -420,10 +423,10 @@
// scheduled for appending by the heap worker thread.
void MarkSweep::ClearWhiteReferences(Object** list) {
DCHECK(list != NULL);
- size_t offset = Heap::GetReferenceReferentOffset();
+ MemberOffset offset = Heap::GetReferenceReferentOffset();
while (*list != NULL) {
Object* ref = DequeuePendingReference(list);
- Object* referent = ref->GetFieldObject(offset);
+ Object* referent = ref->GetFieldObject<Object*>(offset, false);
if (referent != NULL && !IsMarked(referent)) {
// Referent is white, clear it.
ClearReference(ref);
@@ -440,17 +443,17 @@
// referent field is cleared.
void MarkSweep::EnqueueFinalizerReferences(Object** list) {
DCHECK(list != NULL);
- size_t referent_offset = Heap::GetReferenceReferentOffset();
- size_t zombie_offset = Heap::GetFinalizerReferenceZombieOffset();
+ MemberOffset referent_offset = Heap::GetReferenceReferentOffset();
+ MemberOffset zombie_offset = Heap::GetFinalizerReferenceZombieOffset();
bool has_enqueued = false;
while (*list != NULL) {
Object* ref = DequeuePendingReference(list);
- Object* referent = ref->GetFieldObject(referent_offset);
+ Object* referent = ref->GetFieldObject<Object*>(referent_offset, false);
if (referent != NULL && !IsMarked(referent)) {
MarkObject(referent);
// If the referent is non-null the reference must queuable.
DCHECK(IsEnqueuable(ref));
- ref->SetFieldObject(zombie_offset, referent);
+ ref->SetFieldObject(zombie_offset, referent, false);
ClearReference(ref);
EnqueueReference(ref);
has_enqueued = true;
diff --git a/src/mark_sweep.h b/src/mark_sweep.h
index f20cc41..841d819 100644
--- a/src/mark_sweep.h
+++ b/src/mark_sweep.h
@@ -6,6 +6,7 @@
#include "macros.h"
#include "mark_stack.h"
#include "object_bitmap.h"
+#include "offsets.h"
namespace art {
diff --git a/src/object.cc b/src/object.cc
index cdc0e69..39d3c25 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -3,7 +3,10 @@
#include "object.h"
#include <string.h>
+
#include <algorithm>
+#include <string>
+#include <utility>
#include "class_linker.h"
#include "class_loader.h"
@@ -17,37 +20,503 @@
namespace art {
-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);
+bool Object::IsString() const {
+ // TODO use "klass_ == String::GetJavaLangString()" instead?
+ return GetClass() == GetClass()->GetDescriptor()->GetClass();
+}
+
+// TODO: get global references for these
+Class* Field::java_lang_reflect_Field_ = NULL;
+
+void Field::SetClass(Class* java_lang_reflect_Field) {
+ CHECK(java_lang_reflect_Field_ == NULL);
+ CHECK(java_lang_reflect_Field != NULL);
+ java_lang_reflect_Field_ = java_lang_reflect_Field;
+}
+
+void Field::ResetClass() {
+ CHECK(java_lang_reflect_Field_ != NULL);
+ java_lang_reflect_Field_ = NULL;
+}
+
+void Field::SetTypeIdx(uint32_t type_idx) {
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Field, type_idx_), type_idx, false);
+}
+
+Class* Field::GetTypeDuringLinking() const {
+ // We are assured that the necessary primitive types are in the dex cache
+ // early during class linking
+ return GetDeclaringClass()->GetDexCache()->GetResolvedType(GetTypeIdx());
+}
+
+Class* Field::GetType() const {
+ DCHECK(Runtime::Current() != NULL)
+ << "Can't call GetType without an initialized runtime";
+ // Do full linkage (which sets dex cache value to speed next call)
+ return Runtime::Current()->GetClassLinker()->ResolveType(GetTypeIdx(), this);
+}
+
+uint32_t Field::Get32StaticFromCode(uint32_t field_idx, const Method* referrer) {
+ Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+ if (field == NULL) {
+ UNIMPLEMENTED(FATAL) << "throw an error";
+ return 0;
}
- return array;
+ DCHECK(field->GetType()->PrimitiveSize() == sizeof(int32_t));
+ return field->Get32(NULL);
+}
+void Field::Set32StaticFromCode(uint32_t field_idx, const Method* referrer, uint32_t new_value) {
+ Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+ if (field == NULL) {
+ UNIMPLEMENTED(FATAL) << "throw an error";
+ return;
+ }
+ DCHECK(field->GetType()->PrimitiveSize() == sizeof(int32_t));
+ field->Set32(NULL, new_value);
+}
+uint64_t Field::Get64StaticFromCode(uint32_t field_idx, const Method* referrer) {
+ Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+ if (field == NULL) {
+ UNIMPLEMENTED(FATAL) << "throw an error";
+ return 0;
+ }
+ DCHECK(field->GetType()->PrimitiveSize() == sizeof(int64_t));
+ return field->Get64(NULL);
+}
+void Field::Set64StaticFromCode(uint32_t field_idx, const Method* referrer, uint64_t new_value) {
+ Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+ if (field == NULL) {
+ UNIMPLEMENTED(FATAL) << "throw an error";
+ return;
+ }
+ DCHECK(field->GetType()->PrimitiveSize() == sizeof(int64_t));
+ field->Set64(NULL, new_value);
+}
+Object* Field::GetObjStaticFromCode(uint32_t field_idx, const Method* referrer) {
+ Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+ if (field == NULL) {
+ UNIMPLEMENTED(FATAL) << "throw an error";
+ return 0;
+ }
+ DCHECK(!field->GetType()->IsPrimitive());
+ return field->GetObj(NULL);
+}
+void Field::SetObjStaticFromCode(uint32_t field_idx, const Method* referrer, Object* new_value) {
+ Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+ if (field == NULL) {
+ UNIMPLEMENTED(FATAL) << "throw an error";
+ return;
+ }
+ DCHECK(!field->GetType()->IsPrimitive());
+ field->SetObj(NULL, new_value);
}
-Array* Array::Alloc(Class* array_class, int32_t component_count) {
- return Alloc(array_class, component_count, array_class->GetComponentSize());
+uint32_t Field::Get32(const Object* object) const {
+ CHECK((object == NULL) == IsStatic());
+ if (IsStatic()) {
+ object = declaring_class_;
+ }
+ return object->GetField32(GetOffset(), IsVolatile());
}
-Array* Array::AllocFromCode(uint32_t type_idx, Method* method, int32_t component_count) {
- // TODO: throw on negative component_count
- Class* klass = method->dex_cache_resolved_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;
+void Field::Set32(Object* object, uint32_t new_value) const {
+ CHECK((object == NULL) == IsStatic());
+ if (IsStatic()) {
+ object = declaring_class_;
+ }
+ object->SetField32(GetOffset(), new_value, IsVolatile());
+}
+
+uint64_t Field::Get64(const Object* object) const {
+ CHECK((object == NULL) == IsStatic());
+ if (IsStatic()) {
+ object = declaring_class_;
+ }
+ return object->GetField64(GetOffset(), IsVolatile());
+}
+
+void Field::Set64(Object* object, uint64_t new_value) const {
+ CHECK((object == NULL) == IsStatic());
+ if (IsStatic()) {
+ object = declaring_class_;
+ }
+ object->SetField64(GetOffset(), new_value, IsVolatile());
+}
+
+Object* Field::GetObj(const Object* object) const {
+ CHECK((object == NULL) == IsStatic());
+ if (IsStatic()) {
+ object = declaring_class_;
+ }
+ return object->GetFieldObject<Object*>(GetOffset(), IsVolatile());
+}
+
+void Field::SetObj(Object* object, const Object* new_value) const {
+ CHECK((object == NULL) == IsStatic());
+ if (IsStatic()) {
+ object = declaring_class_;
+ }
+ object->SetFieldObject(GetOffset(), new_value, IsVolatile());
+}
+
+bool Field::GetBoolean(const Object* object) const {
+ DCHECK(GetType()->IsPrimitiveBoolean());
+ return Get32(object);
+}
+
+void Field::SetBoolean(Object* object, bool z) const {
+ DCHECK(GetType()->IsPrimitiveBoolean());
+ Set32(object, z);
+}
+
+int8_t Field::GetByte(const Object* object) const {
+ DCHECK(GetType()->IsPrimitiveByte());
+ return Get32(object);
+}
+
+void Field::SetByte(Object* object, int8_t b) const {
+ DCHECK(GetType()->IsPrimitiveByte());
+ Set32(object, b);
+}
+
+uint16_t Field::GetChar(const Object* object) const {
+ DCHECK(GetType()->IsPrimitiveChar());
+ return Get32(object);
+}
+
+void Field::SetChar(Object* object, uint16_t c) const {
+ DCHECK(GetType()->IsPrimitiveChar());
+ Set32(object, c);
+}
+
+uint16_t Field::GetShort(const Object* object) const {
+ DCHECK(GetType()->IsPrimitiveShort());
+ return Get32(object);
+}
+
+void Field::SetShort(Object* object, uint16_t s) const {
+ DCHECK(GetType()->IsPrimitiveShort());
+ Set32(object, s);
+}
+
+int32_t Field::GetInt(const Object* object) const {
+ DCHECK(GetType()->IsPrimitiveInt());
+ return Get32(object);
+}
+
+void Field::SetInt(Object* object, int32_t i) const {
+ DCHECK(GetType()->IsPrimitiveInt());
+ Set32(object, i);
+}
+
+int64_t Field::GetLong(const Object* object) const {
+ DCHECK(GetType()->IsPrimitiveLong());
+ return Get64(object);
+}
+
+void Field::SetLong(Object* object, int64_t j) const {
+ DCHECK(GetType()->IsPrimitiveLong());
+ Set64(object, j);
+}
+
+float Field::GetFloat(const Object* object) const {
+ DCHECK(GetType()->IsPrimitiveFloat());
+ JValue float_bits;
+ float_bits.i = Get32(object);
+ return float_bits.f;
+}
+
+void Field::SetFloat(Object* object, float f) const {
+ DCHECK(GetType()->IsPrimitiveFloat());
+ JValue float_bits;
+ float_bits.f = f;
+ Set32(object, float_bits.i);
+}
+
+double Field::GetDouble(const Object* object) const {
+ DCHECK(GetType()->IsPrimitiveDouble());
+ JValue double_bits;
+ double_bits.j = Get64(object);
+ return double_bits.d;
+}
+
+void Field::SetDouble(Object* object, double d) const {
+ DCHECK(GetType()->IsPrimitiveDouble());
+ JValue double_bits;
+ double_bits.d = d;
+ Set64(object, double_bits.j);
+}
+
+Object* Field::GetObject(const Object* object) const {
+ CHECK(!GetType()->IsPrimitive());
+ return GetObj(object);
+}
+
+void Field::SetObject(Object* object, const Object* l) const {
+ CHECK(!GetType()->IsPrimitive());
+ SetObj(object, l);
+}
+
+// TODO: get global references for these
+Class* Method::java_lang_reflect_Method_ = NULL;
+
+void Method::SetClass(Class* java_lang_reflect_Method) {
+ CHECK(java_lang_reflect_Method_ == NULL);
+ CHECK(java_lang_reflect_Method != NULL);
+ java_lang_reflect_Method_ = java_lang_reflect_Method;
+}
+
+void Method::ResetClass() {
+ CHECK(java_lang_reflect_Method_ != NULL);
+ java_lang_reflect_Method_ = NULL;
+}
+
+ObjectArray<String>* Method::GetDexCacheStrings() const {
+ return GetFieldObject<ObjectArray<String>*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_strings_), false);
+}
+
+void Method::SetReturnTypeIdx(uint32_t new_return_type_idx) {
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, java_return_type_idx_),
+ new_return_type_idx, false);
+}
+
+Class* Method::GetReturnType() const {
+ DCHECK(GetDeclaringClass()->IsLinked());
+ // Short-cut
+ Class* result = GetDexCacheResolvedTypes()->Get(GetReturnTypeIdx());
+ if (result == NULL) {
+ // Do full linkage and set cache value for next call
+ result = Runtime::Current()->GetClassLinker()->ResolveType(GetReturnTypeIdx(), this);
+ }
+ CHECK(result != NULL);
+ return result;
+}
+
+void Method::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_strings_),
+ new_dex_cache_strings, false);
+}
+
+ObjectArray<Class>* Method::GetDexCacheResolvedTypes() const {
+ return GetFieldObject<ObjectArray<Class>*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_types_), false);
+}
+
+void Method::SetDexCacheResolvedTypes(ObjectArray<Class>* new_dex_cache_classes) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_types_),
+ new_dex_cache_classes, false);
+}
+
+ObjectArray<Method>* Method::GetDexCacheResolvedMethods() const {
+ return GetFieldObject<ObjectArray<Method>*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_methods_), false);
+}
+
+void Method::SetDexCacheResolvedMethods(ObjectArray<Method>* new_dex_cache_methods) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_methods_),
+ new_dex_cache_methods, false);
+}
+
+ObjectArray<Field>* Method::GetDexCacheResolvedFields() const {
+ return GetFieldObject<ObjectArray<Field>*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_fields_), false);
+}
+
+void Method::SetDexCacheResolvedFields(ObjectArray<Field>* new_dex_cache_fields) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_fields_),
+ new_dex_cache_fields, false);
+}
+
+CodeAndDirectMethods* Method::GetDexCacheCodeAndDirectMethods() const {
+ return GetFieldPtr<CodeAndDirectMethods*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_code_and_direct_methods_),
+ false);
+}
+
+void Method::SetDexCacheCodeAndDirectMethods(CodeAndDirectMethods* new_value) {
+ SetFieldPtr<CodeAndDirectMethods*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_code_and_direct_methods_),
+ new_value, false);
+}
+
+ObjectArray<StaticStorageBase>* Method::GetDexCacheInitializedStaticStorage() const {
+ return GetFieldObject<ObjectArray<StaticStorageBase>*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_initialized_static_storage_),
+ false);
+}
+
+void Method::SetDexCacheInitializedStaticStorage(ObjectArray<StaticStorageBase>* new_value) {
+ SetFieldObject(
+ OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_initialized_static_storage_),
+ new_value, false);
+
+}
+
+size_t Method::NumArgRegisters(const StringPiece& shorty) {
+ CHECK_LE(1, shorty.length());
+ uint32_t num_registers = 0;
+ for (int i = 1; i < shorty.length(); ++i) {
+ char ch = shorty[i];
+ if (ch == 'D' || ch == 'J') {
+ num_registers += 2;
+ } else {
+ num_registers += 1;
}
}
- return Array::Alloc(klass, component_count);
+ return num_registers;
+}
+
+size_t Method::NumArgArrayBytes() const {
+ const StringPiece& shorty = GetShorty();
+ size_t num_bytes = 0;
+ for (int i = 1; i < shorty.length(); ++i) {
+ char ch = shorty[i];
+ if (ch == 'D' || ch == 'J') {
+ num_bytes += 8;
+ } else if (ch == 'L') {
+ // Argument is a reference or an array. The shorty descriptor
+ // does not distinguish between these types.
+ num_bytes += sizeof(Object*);
+ } else {
+ num_bytes += 4;
+ }
+ }
+ return num_bytes;
+}
+
+// The number of reference arguments to this method including implicit this
+// pointer
+size_t Method::NumReferenceArgs() const {
+ const StringPiece& shorty = GetShorty();
+ size_t result = IsStatic() ? 0 : 1; // The implicit this pointer.
+ for (int i = 1; i < shorty.length(); i++) {
+ if ((shorty[i] == 'L') || (shorty[i] == '[')) {
+ result++;
+ }
+ }
+ return result;
+}
+
+// The number of long or double arguments
+size_t Method::NumLongOrDoubleArgs() const {
+ const StringPiece& shorty = GetShorty();
+ size_t result = 0;
+ for (int i = 1; i < shorty.length(); i++) {
+ if ((shorty[i] == 'D') || (shorty[i] == 'J')) {
+ result++;
+ }
+ }
+ return result;
+}
+
+// The number of reference arguments to this method before the given parameter
+// index
+size_t Method::NumReferenceArgsBefore(unsigned int param) const {
+ const StringPiece& shorty = GetShorty();
+ CHECK_LT(param, NumArgs());
+ unsigned int result = IsStatic() ? 0 : 1;
+ for (unsigned int i = 1; (i < (unsigned int)shorty.length()) &&
+ (i < (param + 1)); i++) {
+ if (shorty[i] == 'L') {
+ result++;
+ }
+ }
+ return result;
+}
+
+// Is the given method parameter a reference?
+bool Method::IsParamAReference(unsigned int param) const {
+ CHECK_LT(param, NumArgs());
+ if (IsStatic()) {
+ param++; // 0th argument must skip return value at start of the shorty
+ } else if (param == 0) {
+ return true; // this argument
+ }
+ return GetShorty()[param] == 'L';
+}
+
+// Is the given method parameter a long or double?
+bool Method::IsParamALongOrDouble(unsigned int param) const {
+ CHECK_LT(param, NumArgs());
+ if (IsStatic()) {
+ param++; // 0th argument must skip return value at start of the shorty
+ } else if (param == 0) {
+ return false; // this argument
+ }
+ return (GetShorty()[param] == 'J') || (GetShorty()[param] == 'D');
+}
+
+static size_t ShortyCharToSize(char x) {
+ switch (x) {
+ case 'V': return 0;
+ case '[': return kPointerSize;
+ case 'L': return kPointerSize;
+ case 'D': return 8;
+ case 'J': return 8;
+ default: return 4;
+ }
+}
+
+size_t Method::ParamSize(unsigned int param) const {
+ CHECK_LT(param, NumArgs());
+ if (IsStatic()) {
+ param++; // 0th argument must skip return value at start of the shorty
+ } else if (param == 0) {
+ return kPointerSize; // this argument
+ }
+ return ShortyCharToSize(GetShorty()[param]);
+}
+
+size_t Method::ReturnSize() const {
+ return ShortyCharToSize(GetShorty()[0]);
+}
+
+bool Method::HasSameNameAndDescriptor(const Method* that) const {
+ return (this->GetName()->Equals(that->GetName()) &&
+ this->GetSignature()->Equals(that->GetSignature()));
+}
+
+void Method::SetCode(const byte* compiled_code,
+ size_t byte_count,
+ InstructionSet set) {
+ // Copy the code into an executable region.
+ code_instruction_set_ = set;
+ code_area_.reset(MemMap::Map(byte_count,
+ PROT_READ | PROT_WRITE | PROT_EXEC));
+ CHECK(code_area_.get());
+ byte* code = code_area_->GetAddress();
+ memcpy(code, compiled_code, byte_count);
+ __builtin___clear_cache(code, code + byte_count);
+
+ uintptr_t address = reinterpret_cast<uintptr_t>(code);
+ if (code_instruction_set_ == kThumb2) {
+ // Set the low-order bit so a BLX will switch to Thumb mode
+ address |= 0x1;
+ }
+ SetFieldPtr<uintptr_t>(OFFSET_OF_OBJECT_MEMBER(Method, code_), address, false);
+}
+
+void Class::SetStatus(Status new_status) {
+ CHECK(new_status > GetStatus() || new_status == kStatusError ||
+ Runtime::Current() == NULL); // no runtime implies we're not initialized
+ CHECK(sizeof(Status) == sizeof(uint32_t));
+ return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_),
+ new_status, false);
+}
+
+DexCache* Class::GetDexCache() const {
+ return GetFieldObject<DexCache*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_), false);
+}
+
+void Class::SetDexCache(DexCache* new_dex_cache) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_),
+ new_dex_cache, false);
}
Object* Class::AllocObjectFromCode(uint32_t type_idx, Method* method) {
- Class* klass = method->dex_cache_resolved_types_->Get(type_idx);
+ Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
if (klass == NULL) {
klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
if (klass == NULL) {
@@ -63,9 +532,67 @@
return Heap::AllocObject(this, this->object_size_);
}
-bool Class::CanPutArrayElementFromCode(const Class* elementClass, const Class* arrayClass) {
- UNIMPLEMENTED(FATAL);
- return false;
+void Class::SetReferenceInstanceOffsets(uint32_t new_reference_offsets) {
+ if (new_reference_offsets != CLASS_WALK_SUPER) {
+ // Sanity check that the number of bits set in the reference offset bitmap
+ // agrees with the number of references
+ Class* cur = this;
+ size_t cnt = 0;
+ while (cur) {
+ cnt += cur->NumReferenceInstanceFieldsDuringLinking();
+ cur = cur->GetSuperClass();
+ }
+ CHECK_EQ((size_t)__builtin_popcount(new_reference_offsets), cnt);
+ }
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_),
+ new_reference_offsets, false);
+}
+
+void Class::SetReferenceStaticOffsets(uint32_t new_reference_offsets) {
+ if (new_reference_offsets != CLASS_WALK_SUPER) {
+ // Sanity check that the number of bits set in the reference offset bitmap
+ // agrees with the number of references
+ CHECK_EQ((size_t)__builtin_popcount(new_reference_offsets),
+ NumReferenceStaticFieldsDuringLinking());
+ }
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, reference_static_offsets_),
+ new_reference_offsets, false);
+}
+
+size_t Class::PrimitiveSize() const {
+ switch (GetPrimitiveType()) {
+ case kPrimBoolean:
+ case kPrimByte:
+ case kPrimChar:
+ case kPrimShort:
+ case kPrimInt:
+ case kPrimFloat:
+ return sizeof(int32_t);
+ case kPrimLong:
+ case kPrimDouble:
+ return sizeof(int64_t);
+ default:
+ LOG(FATAL) << "Primitive type size calculation on invalid type " << this;
+ return 0;
+ }
+}
+
+size_t Class::GetTypeSize(const String* descriptor) {
+ switch (descriptor->CharAt(0)) {
+ case 'B': return 1; // byte
+ case 'C': return 2; // char
+ case 'D': return 8; // double
+ case 'F': return 4; // float
+ case 'I': return 4; // int
+ case 'J': return 8; // long
+ case 'S': return 2; // short
+ case 'Z': return 1; // boolean
+ case 'L': return sizeof(Object*);
+ case '[': return sizeof(Array*);
+ default:
+ LOG(ERROR) << "Unknown type " << descriptor;
+ return 0;
+ }
}
bool Class::Implements(const Class* klass) const {
@@ -82,6 +609,11 @@
return false;
}
+bool Class::CanPutArrayElementFromCode(const Class* elementClass, const Class* arrayClass) {
+ UNIMPLEMENTED(FATAL);
+ return false;
+}
+
// Determine whether "this" is assignable from "klazz", where both of these
// are array classes.
//
@@ -104,35 +636,30 @@
bool Class::IsArrayAssignableFromArray(const Class* klass) const {
DCHECK(IsArrayClass());
DCHECK(klass->IsArrayClass());
- DCHECK_GT(array_rank_, 0);
- DCHECK_GT(klass->array_rank_, 0);
- DCHECK(component_type_ != NULL);
- DCHECK(klass->component_type_ != NULL);
- if (array_rank_ > klass->array_rank_) {
+ DCHECK_GT(GetArrayRank(), 0);
+ DCHECK_GT(klass->GetArrayRank(), 0);
+ DCHECK(GetComponentType() != NULL);
+ DCHECK(klass->GetComponentType() != NULL);
+ if (GetArrayRank() > klass->GetArrayRank()) {
// Too many []s.
return false;
}
- if (array_rank_ == klass->array_rank_) {
- return component_type_->IsAssignableFrom(klass->component_type_);
+ if (GetArrayRank() == klass->GetArrayRank()) {
+ return GetComponentType()->IsAssignableFrom(klass->GetComponentType());
}
- DCHECK_LT(array_rank_, klass->array_rank_);
+ DCHECK_LT(GetArrayRank(), klass->GetArrayRank());
// The thing we might be assignable from has more dimensions. We
// must be an Object or array of Object, or a standard array
// interface or array of standard array interfaces (the standard
// interfaces being java/lang/Cloneable and java/io/Serializable).
- if (component_type_->IsInterface()) {
+ if (GetComponentType()->IsInterface()) {
// See if we implement our component type. We know the
// base element is an interface; if the array class implements
// it, we know it's a standard array interface.
- return Implements(component_type_);
+ return Implements(GetComponentType());
}
- // See if this is an array of Object, Object[], etc. We know
- // that the superclass of an array is always Object, so we
- // just compare the element type to that.
- Class* java_lang_Object = GetSuperClass();
- DCHECK(java_lang_Object != NULL);
- DCHECK(java_lang_Object->GetSuperClass() == NULL);
- return (component_type_ == java_lang_Object);
+ // See if this is an array of Object, Object[], etc.
+ return GetComponentType()->IsObjectClass();
}
bool Class::IsAssignableFromArray(const Class* klass) const {
@@ -211,326 +738,15 @@
return IsInSamePackage(klass1->descriptor_, klass2->descriptor_);
}
-uint32_t Field::Get32StaticFromCode(uint32_t field_idx, const Method* referrer) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return 0;
- }
- return field->Get32(NULL);
-}
-void Field::Set32StaticFromCode(uint32_t field_idx, const Method* referrer, uint32_t new_value) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return;
- }
- field->Set32(NULL, new_value);
-}
-uint64_t Field::Get64StaticFromCode(uint32_t field_idx, const Method* referrer) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return 0;
- }
- return field->Get64(NULL);
-}
-void Field::Set64StaticFromCode(uint32_t field_idx, const Method* referrer, uint64_t new_value) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return;
- }
- field->Set64(NULL, new_value);
-}
-Object* Field::GetObjStaticFromCode(uint32_t field_idx, const Method* referrer) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return 0;
- }
- return field->GetObj(NULL);
-}
-void Field::SetObjStaticFromCode(uint32_t field_idx, const Method* referrer, Object* new_value) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return;
- }
- field->SetObj(NULL, new_value);
+const ClassLoader* Class::GetClassLoader() const {
+ return GetFieldObject<const ClassLoader*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), false);
}
-uint32_t Field::Get32(const Object* object) const {
- CHECK((object == NULL) == IsStatic());
- if (IsStatic()) {
- object = declaring_class_;
- }
- // TODO: volatile
- return object->GetField32(GetOffset());
-}
-
-void Field::Set32(Object* object, uint32_t new_value) const {
- CHECK((object == NULL) == IsStatic());
- if (IsStatic()) {
- object = declaring_class_;
- }
- // TODO: volatile
- object->SetField32(GetOffset(), new_value);
-}
-
-uint64_t Field::Get64(const Object* object) const {
- CHECK((object == NULL) == IsStatic());
- if (IsStatic()) {
- object = declaring_class_;
- }
- // TODO: volatile
- return object->GetField64(GetOffset());
-}
-
-void Field::Set64(Object* object, uint64_t new_value) const {
- CHECK((object == NULL) == IsStatic());
- if (IsStatic()) {
- object = declaring_class_;
- }
- // TODO: volatile
- object->SetField64(GetOffset(), new_value);
-}
-
-Object* Field::GetObj(const Object* object) const {
- CHECK((object == NULL) == IsStatic());
- if (IsStatic()) {
- object = declaring_class_;
- }
- // TODO: volatile
- return object->GetFieldObject(GetOffset());
-}
-
-void Field::SetObj(Object* object, const Object* new_value) const {
- CHECK((object == NULL) == IsStatic());
- if (IsStatic()) {
- object = declaring_class_;
- }
- // TODO: volatile
- object->SetFieldObject(GetOffset(), new_value);
-}
-
-bool Field::GetBoolean(const Object* object) const {
- CHECK_EQ(GetType(), 'Z');
- return Get32(object);
-}
-
-void Field::SetBoolean(Object* object, bool z) const {
- CHECK_EQ(GetType(), 'Z');
- Set32(object, z);
-}
-
-int8_t Field::GetByte(const Object* object) const {
- CHECK_EQ(GetType(), 'B');
- return Get32(object);
-}
-
-void Field::SetByte(Object* object, int8_t b) const {
- CHECK_EQ(GetType(), 'B');
- Set32(object, b);
-}
-
-uint16_t Field::GetChar(const Object* object) const {
- CHECK_EQ(GetType(), 'C');
- return Get32(object);
-}
-
-void Field::SetChar(Object* object, uint16_t c) const {
- CHECK_EQ(GetType(), 'C');
- Set32(object, c);
-}
-
-uint16_t Field::GetShort(const Object* object) const {
- CHECK_EQ(GetType(), 'S');
- return Get32(object);
-}
-
-void Field::SetShort(Object* object, uint16_t s) const {
- CHECK_EQ(GetType(), 'S');
- Set32(object, s);
-}
-
-int32_t Field::GetInt(const Object* object) const {
- CHECK_EQ(GetType(), 'I');
- return Get32(object);
-}
-
-void Field::SetInt(Object* object, int32_t i) const {
- CHECK_EQ(GetType(), 'I');
- Set32(object, i);
-}
-
-int64_t Field::GetLong(const Object* object) const {
- CHECK_EQ(GetType(), 'J');
- return Get64(object);
-}
-
-void Field::SetLong(Object* object, int64_t j) const {
- CHECK_EQ(GetType(), 'J');
- Set64(object, j);
-}
-
-float Field::GetFloat(const Object* object) const {
- CHECK_EQ(GetType(), 'F');
- JValue float_bits;
- float_bits.i = Get32(object);
- return float_bits.f;
-}
-
-void Field::SetFloat(Object* object, float f) const {
- CHECK_EQ(GetType(), 'F');
- JValue float_bits;
- float_bits.f = f;
- Set32(object, float_bits.i);
-}
-
-double Field::GetDouble(const Object* object) const {
- CHECK_EQ(GetType(), 'D');
- JValue double_bits;
- double_bits.j = Get64(object);
- return double_bits.d;
-}
-
-void Field::SetDouble(Object* object, double d) const {
- CHECK_EQ(GetType(), 'D');
- JValue double_bits;
- double_bits.d = d;
- Set64(object, double_bits.j);
-}
-
-Object* Field::GetObject(const Object* object) const {
- CHECK(GetType() == 'L' || GetType() == '[');
- return GetObj(object);
-}
-
-void Field::SetObject(Object* object, const Object* l) const {
- CHECK(GetType() == 'L' || GetType() == '[');
- SetObj(object, l);
-}
-
-uint32_t Method::NumArgRegisters() const {
- CHECK(shorty_ != NULL);
- uint32_t num_registers = 0;
- for (int i = 1; i < shorty_.length(); ++i) {
- char ch = shorty_[i];
- if (ch == 'D' || ch == 'J') {
- num_registers += 2;
- } else {
- num_registers += 1;
- }
- }
- return num_registers;
-}
-
-size_t Method::NumArgArrayBytes() const {
- const StringPiece& shorty = GetShorty();
- size_t num_bytes = 0;
- for (int i = 1; i < shorty.size(); ++i) {
- char ch = shorty[i];
- if (ch == 'D' || ch == 'J') {
- num_bytes += 8;
- } else if (ch == 'L') {
- // Argument is a reference or an array. The shorty descriptor
- // does not distinguish between these types.
- num_bytes += sizeof(Object*);
- } else {
- num_bytes += 4;
- }
- }
- return num_bytes;
-}
-
-// The number of reference arguments to this method including implicit this
-// pointer
-size_t Method::NumReferenceArgs() const {
- size_t result = IsStatic() ? 0 : 1; // The implicit this pointer.
- for (int i = 1; i < shorty_.length(); i++) {
- if ((shorty_[i] == 'L') || (shorty_[i] == '[')) {
- result++;
- }
- }
- return result;
-}
-
-// The number of long or double arguments
-size_t Method::NumLongOrDoubleArgs() const {
- size_t result = 0;
- for (int i = 1; i < shorty_.length(); i++) {
- if ((shorty_[i] == 'D') || (shorty_[i] == 'J')) {
- result++;
- }
- }
- return result;
-}
-
-// The number of reference arguments to this method before the given parameter
-// index
-size_t Method::NumReferenceArgsBefore(unsigned int param) const {
- CHECK_LT(param, NumArgs());
- unsigned int result = IsStatic() ? 0 : 1;
- for (unsigned int i = 1; (i < (unsigned int)shorty_.length()) &&
- (i < (param + 1)); i++) {
- if ((shorty_[i] == 'L') || (shorty_[i] == '[')) {
- result++;
- }
- }
- return result;
-}
-
-// Is the given method parameter a reference?
-bool Method::IsParamAReference(unsigned int param) const {
- CHECK_LT(param, NumArgs());
- if (IsStatic()) {
- param++; // 0th argument must skip return value at start of the shorty
- } else if (param == 0) {
- return true; // this argument
- }
- return ((shorty_[param] == 'L') || (shorty_[param] == '['));
-}
-
-// Is the given method parameter a long or double?
-bool Method::IsParamALongOrDouble(unsigned int param) const {
- CHECK_LT(param, NumArgs());
- if (IsStatic()) {
- param++; // 0th argument must skip return value at start of the shorty
- } else if (param == 0) {
- return false; // this argument
- }
- return (shorty_[param] == 'J') || (shorty_[param] == 'D');
-}
-
-static size_t ShortyCharToSize(char x) {
- switch (x) {
- case 'V': return 0;
- case '[': return kPointerSize;
- case 'L': return kPointerSize;
- case 'D': return 8;
- case 'J': return 8;
- default: return 4;
- }
-}
-
-size_t Method::ParamSize(unsigned int param) const {
- CHECK_LT(param, NumArgs());
- if (IsStatic()) {
- param++; // 0th argument must skip return value at start of the shorty
- } else if (param == 0) {
- return kPointerSize; // this argument
- }
- return ShortyCharToSize(shorty_[param]);
-}
-
-size_t Method::ReturnSize() const {
- return ShortyCharToSize(shorty_[0]);
-}
-
-bool Method::HasSameNameAndDescriptor(const Method* that) const {
- return (this->GetName()->Equals(that->GetName()) &&
- this->GetSignature()->Equals(that->GetSignature()));
+void Class::SetClassLoader(const ClassLoader* new_cl) {
+ ClassLoader* new_class_loader = const_cast<ClassLoader*>(new_cl);
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_),
+ new_class_loader, false);
}
Method* Class::FindVirtualMethodForInterface(Method* method) {
@@ -540,7 +756,8 @@
for (size_t i = 0; i < iftable_count_; i++) {
InterfaceEntry& interface_entry = iftable_[i];
if (interface_entry.GetInterface() == declaring_class) {
- return vtable_->Get(interface_entry.method_index_array_[method->method_index_]);
+ return GetVTable()->Get(
+ interface_entry.GetMethodIndexArray()[method->GetMethodIndex()]);
}
}
UNIMPLEMENTED(FATAL) << "Need to throw an error of some kind";
@@ -593,23 +810,23 @@
return NULL;
}
-Field* Class::FindDeclaredInstanceField(const StringPiece& name, const StringPiece& descriptor) {
+Field* Class::FindDeclaredInstanceField(const StringPiece& name, Class* type) {
// Is the field in this class?
// Interfaces are not relevant because they can't contain instance fields.
for (size_t i = 0; i < NumInstanceFields(); ++i) {
Field* f = GetInstanceField(i);
- if (f->GetName()->Equals(name) && f->GetDescriptor() == descriptor) {
+ if (f->GetName()->Equals(name) && type == f->GetType()) {
return f;
}
}
return NULL;
}
-Field* Class::FindInstanceField(const StringPiece& name, const StringPiece& descriptor) {
+Field* Class::FindInstanceField(const StringPiece& name, Class* type) {
// Is the field in this class, or any of its superclasses?
// Interfaces are not relevant because they can't contain instance fields.
for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
- Field* f = c->FindDeclaredInstanceField(name, descriptor);
+ Field* f = c->FindDeclaredInstanceField(name, type);
if (f != NULL) {
return f;
}
@@ -617,22 +834,23 @@
return NULL;
}
-Field* Class::FindDeclaredStaticField(const StringPiece& name, const StringPiece& descriptor) {
+Field* Class::FindDeclaredStaticField(const StringPiece& name, Class* type) {
+ DCHECK(type != NULL);
for (size_t i = 0; i < NumStaticFields(); ++i) {
Field* f = GetStaticField(i);
- if (f->GetName()->Equals(name) && f->GetDescriptor() == descriptor) {
+ if (f->GetName()->Equals(name) && f->GetType() == type) {
return f;
}
}
return NULL;
}
-Field* Class::FindStaticField(const StringPiece& name, const StringPiece& descriptor) {
+Field* Class::FindStaticField(const StringPiece& name, Class* type) {
// Is the field in this class (or its interfaces), or any of its
// superclasses (or their interfaces)?
for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
// Is the field in this class?
- Field* f = c->FindDeclaredStaticField(name, descriptor);
+ Field* f = c->FindDeclaredStaticField(name, type);
if (f != NULL) {
return f;
}
@@ -640,7 +858,7 @@
// Is this field in any of this class' interfaces?
for (size_t i = 0; i < c->NumInterfaces(); ++i) {
Class* interface = c->GetInterface(i);
- f = interface->FindDeclaredStaticField(name, descriptor);
+ f = interface->FindDeclaredStaticField(name, type);
if (f != NULL) {
return f;
}
@@ -649,6 +867,35 @@
return NULL;
}
+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) {
+ // TODO: throw on negative component_count
+ Class* klass = method->GetDexCacheResolvedTypes()->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);
+}
+
template<typename T>
PrimitiveArray<T>* PrimitiveArray<T>::Alloc(size_t length) {
DCHECK(array_class_ != NULL);
@@ -676,6 +923,7 @@
CHECK(java_lang_String != NULL);
java_lang_String_ = java_lang_String;
}
+
void String::ResetClass() {
CHECK(java_lang_String_ != NULL);
java_lang_String_ = NULL;
@@ -685,6 +933,135 @@
return Runtime::Current()->GetInternTable()->InternWeak(this);
}
+int32_t String::GetHashCode() const {
+ int32_t result = GetField32(
+ OFFSET_OF_OBJECT_MEMBER(String, hash_code_), false);
+ DCHECK(result != 0 ||
+ ComputeUtf16Hash(GetCharArray(), GetOffset(), GetLength()) == 0);
+ return result;
+}
+
+int32_t String::GetLength() const {
+ int32_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(String, count_), false);
+ DCHECK(result >= 0 && result <= GetCharArray()->GetLength());
+ return result;
+}
+
+uint16_t String::CharAt(int32_t index) const {
+ // TODO: do we need this? Equals is the only caller, and could
+ // bounds check itself.
+ if (index < 0 || index >= count_) {
+ Thread* self = Thread::Current();
+ self->ThrowNewException("Ljava/lang/StringIndexOutOfBoundsException;",
+ "length=%i; index=%i", count_, index);
+ return 0;
+ }
+ return GetCharArray()->Get(index + GetOffset());
+}
+
+String* String::AllocFromUtf16(int32_t utf16_length,
+ const uint16_t* utf16_data_in,
+ int32_t hash_code) {
+ String* string = Alloc(GetJavaLangString(), utf16_length);
+ // TODO: use 16-bit wide memset variant
+ CharArray* array = const_cast<CharArray*>(string->GetCharArray());
+ for (int i = 0; i < utf16_length; i++) {
+ array->Set(i, utf16_data_in[i]);
+ }
+ if (hash_code != 0) {
+ string->SetHashCode(hash_code);
+ } else {
+ string->ComputeHashCode();
+ }
+ return string;
+}
+
+String* String::AllocFromModifiedUtf8(const char* utf) {
+ size_t char_count = CountModifiedUtf8Chars(utf);
+ return AllocFromModifiedUtf8(char_count, utf);
+}
+
+String* String::AllocFromModifiedUtf8(int32_t utf16_length,
+ const char* utf8_data_in) {
+ String* string = Alloc(GetJavaLangString(), utf16_length);
+ uint16_t* utf16_data_out =
+ const_cast<uint16_t*>(string->GetCharArray()->GetData());
+ ConvertModifiedUtf8ToUtf16(utf16_data_out, utf8_data_in);
+ string->ComputeHashCode();
+ return string;
+}
+
+String* String::Alloc(Class* java_lang_String, int32_t utf16_length) {
+ return Alloc(java_lang_String, CharArray::Alloc(utf16_length));
+}
+
+String* String::Alloc(Class* java_lang_String, CharArray* array) {
+ String* string = down_cast<String*>(java_lang_String->AllocObject());
+ string->SetArray(array);
+ string->SetCount(array->GetLength());
+ return string;
+}
+
+bool String::Equals(const String* that) const {
+ if (this == that) {
+ // Quick reference equality test
+ return true;
+ } else if (that == NULL) {
+ // Null isn't an instanceof anything
+ return false;
+ } else if (this->GetLength() != that->GetLength()) {
+ // Quick length inequality test
+ return false;
+ } else {
+ // NB don't short circuit on hash code as we're presumably here as the
+ // hash code was already equal
+ for (int32_t i = 0; i < that->GetLength(); ++i) {
+ if (this->CharAt(i) != that->CharAt(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+bool String::Equals(const uint16_t* that_chars, int32_t that_offset,
+ int32_t that_length) const {
+ if (this->GetLength() != that_length) {
+ return false;
+ } else {
+ for (int32_t i = 0; i < that_length; ++i) {
+ if (this->CharAt(i) != that_chars[that_offset + i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+bool String::Equals(const char* modified_utf8) const {
+ for (int32_t i = 0; i < GetLength(); ++i) {
+ uint16_t ch = GetUtf16FromUtf8(&modified_utf8);
+ if (ch == '\0' || ch != CharAt(i)) {
+ return false;
+ }
+ }
+ return *modified_utf8 == '\0';
+}
+
+bool String::Equals(const StringPiece& modified_utf8) const {
+ // TODO: do not assume C-string representation.
+ return Equals(modified_utf8.data());
+}
+
+// Create a modified UTF-8 encoded std::string from a java/lang/String object.
+std::string String::ToModifiedUtf8() const {
+ const uint16_t* chars = GetCharArray()->GetData() + GetOffset();
+ size_t byte_count(CountUtf8Bytes(chars, GetLength()));
+ std::string result(byte_count, char(0));
+ ConvertUtf16ToModifiedUtf8(&result[0], chars, GetLength());
+ return result;
+}
+
Class* StackTraceElement::java_lang_StackTraceElement_ = NULL;
void StackTraceElement::SetClass(Class* java_lang_StackTraceElement) {
@@ -698,6 +1075,23 @@
java_lang_StackTraceElement_ = NULL;
}
+StackTraceElement* StackTraceElement::Alloc(const String* declaring_class,
+ const String* method_name,
+ const String* file_name,
+ int32_t line_number) {
+ StackTraceElement* trace =
+ down_cast<StackTraceElement*>(GetStackTraceElement()->AllocObject());
+ trace->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_),
+ const_cast<String*>(declaring_class), false);
+ trace->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, method_name_),
+ const_cast<String*>(method_name), false);
+ trace->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, file_name_),
+ const_cast<String*>(file_name), false);
+ trace->SetField32(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_),
+ line_number, false);
+ return trace;
+}
+
static const char* kClassStatusNames[] = {
"Error",
"NotReady",
diff --git a/src/object.h b/src/object.h
index bc6e7e5..5a47c46 100644
--- a/src/object.h
+++ b/src/object.h
@@ -9,11 +9,13 @@
#include "casts.h"
#include "constants.h"
#include "globals.h"
+#include "heap.h"
#include "logging.h"
#include "macros.h"
#include "monitor.h"
#include "monitor.h"
#include "offsets.h"
+#include "runtime.h"
#include "stringpiece.h"
#include "thread.h"
#include "utf.h"
@@ -163,9 +165,13 @@
* Return an offset, given a bit number as returned from CLZ.
*/
#define CLASS_OFFSET_FROM_CLZ(rshift) \
- ((static_cast<int>(rshift) * CLASS_OFFSET_ALIGNMENT) + CLASS_SMALLEST_OFFSET)
+ MemberOffset((static_cast<int>(rshift) * CLASS_OFFSET_ALIGNMENT) + \
+ CLASS_SMALLEST_OFFSET)
+#define OFFSET_OF_OBJECT_MEMBER(type, field) \
+ MemberOffset(OFFSETOF_MEMBER(type, field))
+// C++ mirror of java.lang.Object
class Object {
public:
static bool InstanceOf(const Object* object, const Class* klass) {
@@ -175,11 +181,17 @@
return object->InstanceOf(klass);
}
- Class* GetClass() const {
- DCHECK(klass_ != NULL);
- return klass_;
+ static MemberOffset ClassOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(Object, klass_);
}
+ Class* GetClass() const {
+ return
+ GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Object, klass_), false);
+ }
+
+ void SetClass(Class* new_klass);
+
bool InstanceOf(const Class* klass) const;
size_t SizeOf() const;
@@ -189,63 +201,46 @@
return NULL;
}
+ static MemberOffset MonitorOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(Object, monitor_);
+ }
+
+ Monitor* GetMonitor() const {
+ return GetFieldPtr<Monitor*>(
+ OFFSET_OF_OBJECT_MEMBER(Object, monitor_), false);
+ }
+
+ void SetMonitor(Monitor* monitor) {
+ // TODO: threading - compare-and-set
+ SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), monitor, false);
+ }
+
void MonitorEnter() {
- monitor_->Enter();
+ GetMonitor()->Enter();
}
void MonitorExit() {
- monitor_->Exit();
+ GetMonitor()->Exit();
}
void Notify() {
- monitor_->Notify();
+ GetMonitor()->Notify();
}
void NotifyAll() {
- monitor_->NotifyAll();
+ GetMonitor()->NotifyAll();
}
void Wait() {
- monitor_->Wait();
+ GetMonitor()->Wait();
}
void Wait(int64_t timeout) {
- monitor_->Wait(timeout);
+ GetMonitor()->Wait(timeout);
}
void Wait(int64_t timeout, int32_t nanos) {
- monitor_->Wait(timeout, nanos);
- }
-
- Object* GetFieldObject(size_t field_offset) const {
- const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset;
- return *reinterpret_cast<Object* const *>(raw_addr);
- }
-
- void SetFieldObject(size_t offset, const Object* new_value) {
- byte* raw_addr = reinterpret_cast<byte*>(this) + offset;
- *reinterpret_cast<const Object**>(raw_addr) = new_value;
- // TODO: write barrier
- }
-
- uint32_t GetField32(size_t field_offset) const {
- const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset;
- return *reinterpret_cast<const uint32_t*>(raw_addr);
- }
-
- void SetField32(size_t offset, uint32_t new_value) {
- byte* raw_addr = reinterpret_cast<byte*>(this) + offset;
- *reinterpret_cast<uint32_t*>(raw_addr) = new_value;
- }
-
- uint64_t GetField64(size_t field_offset) const {
- const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset;
- return *reinterpret_cast<const uint64_t*>(raw_addr);
- }
-
- void SetField64(size_t offset, uint64_t new_value) {
- byte* raw_addr = reinterpret_cast<byte*>(this) + offset;
- *reinterpret_cast<uint64_t*>(raw_addr) = new_value;
+ GetMonitor()->Wait(timeout, nanos);
}
bool IsClass() const;
@@ -319,12 +314,133 @@
return down_cast<const Field*>(this);
}
- public:
+ bool IsReferenceInstance() const;
+
+ bool IsWeakReferenceInstance() const;
+
+ bool IsSoftReferenceInstance() const;
+
+ bool IsFinalizerReferenceInstance() const;
+
+ bool IsPhantomReferenceInstance() const;
+
+ // Accessors for Java type fields
+ template<class T>
+ T GetFieldObject(MemberOffset field_offset, bool is_volatile) const {
+ Heap::VerifyObject(this);
+ DCHECK(Thread::Current() == NULL ||
+ Thread::Current()->CanAccessDirectReferences());
+ const byte* raw_addr = reinterpret_cast<const byte*>(this) +
+ field_offset.Int32Value();
+ if (is_volatile) {
+ UNIMPLEMENTED(WARNING);
+ }
+ T result = *reinterpret_cast<T const *>(raw_addr);
+ Heap::VerifyObject(result);
+ return result;
+ }
+
+ void SetFieldObject(MemberOffset offset, const Object* new_value,
+ bool is_volatile) {
+ // Avoid verifying this when initializing the Class*
+ if (offset.Int32Value() != ClassOffset().Int32Value()) {
+ Heap::VerifyObject(this);
+ }
+ Heap::VerifyObject(new_value);
+ byte* raw_addr = reinterpret_cast<byte*>(this) + offset.Int32Value();
+ if (is_volatile) {
+ UNIMPLEMENTED(WARNING);
+ }
+ *reinterpret_cast<const Object**>(raw_addr) = new_value;
+ // TODO: write barrier
+ }
+
+ uint32_t GetField32(MemberOffset field_offset, bool is_volatile) const {
+ Heap::VerifyObject(this);
+ const byte* raw_addr = reinterpret_cast<const byte*>(this) +
+ field_offset.Int32Value();
+ if (is_volatile) {
+ UNIMPLEMENTED(WARNING);
+ }
+ return *reinterpret_cast<const uint32_t*>(raw_addr);
+ }
+
+ void SetField32(MemberOffset offset, uint32_t new_value, bool is_volatile) {
+ Heap::VerifyObject(this);
+ byte* raw_addr = reinterpret_cast<byte*>(this) + offset.Int32Value();
+ if (is_volatile) {
+ UNIMPLEMENTED(WARNING);
+ }
+ *reinterpret_cast<uint32_t*>(raw_addr) = new_value;
+ }
+
+ uint64_t GetField64(MemberOffset field_offset, bool is_volatile) const {
+ Heap::VerifyObject(this);
+ const byte* raw_addr = reinterpret_cast<const byte*>(this) +
+ field_offset.Int32Value();
+ if (is_volatile) {
+ UNIMPLEMENTED(WARNING);
+ }
+ return *reinterpret_cast<const uint64_t*>(raw_addr);
+ }
+
+ void SetField64(MemberOffset offset, uint64_t new_value,
+ bool is_volatile = false) {
+ Heap::VerifyObject(this);
+ byte* raw_addr = reinterpret_cast<byte*>(this) + offset.Int32Value();
+ if (is_volatile) {
+ UNIMPLEMENTED(WARNING);
+ }
+ *reinterpret_cast<uint64_t*>(raw_addr) = new_value;
+ }
+
+ protected:
+ // Accessors for non-Java type fields
+ uint16_t GetField16(MemberOffset field_offset, bool is_volatile) const {
+ Heap::VerifyObject(this);
+ const byte* raw_addr = reinterpret_cast<const byte*>(this) +
+ field_offset.Int32Value();
+ if (is_volatile) {
+ UNIMPLEMENTED(WARNING);
+ }
+ return *reinterpret_cast<const uint16_t*>(raw_addr);
+ }
+
+ void SetField16(MemberOffset offset, uint16_t new_value, bool is_volatile) {
+ Heap::VerifyObject(this);
+ byte* raw_addr = reinterpret_cast<byte*>(this) + offset.Int32Value();
+ if (is_volatile) {
+ UNIMPLEMENTED(WARNING);
+ }
+ *reinterpret_cast<uint16_t*>(raw_addr) = new_value;
+ }
+
+ template<class T>
+ T GetFieldPtr(MemberOffset field_offset, bool is_volatile) const {
+ Heap::VerifyObject(this);
+ const byte* raw_addr = reinterpret_cast<const byte*>(this) +
+ field_offset.Int32Value();
+ if (is_volatile) {
+ UNIMPLEMENTED(WARNING);
+ }
+ return *reinterpret_cast<T const *>(raw_addr);
+ }
+
+ template<typename T>
+ void SetFieldPtr(MemberOffset offset, T new_value, bool is_volatile) {
+ Heap::VerifyObject(this);
+ byte* raw_addr = reinterpret_cast<byte*>(this) + offset.Int32Value();
+ if (is_volatile) {
+ UNIMPLEMENTED(WARNING);
+ }
+ *reinterpret_cast<T*>(raw_addr) = new_value;
+ }
+
+ private:
Class* klass_;
Monitor* monitor_;
- private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
};
@@ -356,44 +472,53 @@
DISALLOW_COPY_AND_ASSIGN(ObjectLock);
};
+// C++ mirror of java.lang.reflect.AccessibleObject
class AccessibleObject : public Object {
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
- uint32_t java_flag_;
+ uint32_t java_flag_; // can accessibility checks be bypassed
};
+// C++ mirror of java.lang.reflect.Field
class Field : public AccessibleObject {
public:
- Class* GetDeclaringClass() const {
- DCHECK(declaring_class_ != NULL);
- return declaring_class_;
- }
+ Class* GetDeclaringClass() const;
- const String* GetName() const {
- DCHECK(name_ != NULL);
- return name_;
+ void SetDeclaringClass(Class *new_declaring_class);
+
+ const String* GetName() const;
+
+ void SetName(String* new_name);
+
+ uint32_t GetAccessFlags() const;
+
+ void SetAccessFlags(uint32_t new_access_flags) {
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Field, access_flags_), new_access_flags,
+ false);
}
bool IsStatic() const {
- return (access_flags_ & kAccStatic) != 0;
+ return (GetAccessFlags() & kAccStatic) != 0;
}
- char GetType() const { // TODO: return type
- return GetDescriptor()[0];
- }
+ uint32_t GetTypeIdx() const;
- const StringPiece& GetDescriptor() const {
- DCHECK_NE(0, descriptor_.size());
- return descriptor_;
- }
+ void SetTypeIdx(uint32_t type_idx);
- uint32_t GetOffset() const {
- return offset_;
- }
+ // Gets type using type index and resolved types in the dex cache, may be null
+ // if type isn't yet resolved
+ Class* GetTypeDuringLinking() const;
- void SetOffset(size_t num_bytes) {
- offset_ = num_bytes;
- }
+ // Performs full resolution, may return null and set exceptions if type cannot
+ // be resolved
+ Class* GetType() const;
+
+ // Offset to field within an Object
+ MemberOffset GetOffset() const;
+
+ MemberOffset GetOffsetDuringLinking() const;
+
+ void SetOffset(MemberOffset num_bytes);
// field access, null object for static fields
bool GetBoolean(const Object* object) const;
@@ -415,15 +540,33 @@
Object* GetObject(const Object* object) const;
void SetObject(Object* object, const Object* l) const;
- // slow path routines for static field access when field was unresolved at compile time
- static uint32_t Get32StaticFromCode(uint32_t field_idx, const Method* referrer);
- static void Set32StaticFromCode(uint32_t field_idx, const Method* referrer, uint32_t new_value);
- static uint64_t Get64StaticFromCode(uint32_t field_idx, const Method* referrer);
- static void Set64StaticFromCode(uint32_t field_idx, const Method* referrer, uint64_t new_value);
- static Object* GetObjStaticFromCode(uint32_t field_idx, const Method* referrer);
- static void SetObjStaticFromCode(uint32_t field_idx, const Method* referrer, Object* new_value);
+ // Slow path routines for static field access when field was unresolved at
+ // compile time
+ static uint32_t Get32StaticFromCode(uint32_t field_idx,
+ const Method* referrer);
+ static void Set32StaticFromCode(uint32_t field_idx, const Method* referrer,
+ uint32_t new_value);
+ static uint64_t Get64StaticFromCode(uint32_t field_idx,
+ const Method* referrer);
+ static void Set64StaticFromCode(uint32_t field_idx, const Method* referrer,
+ uint64_t new_value);
+ static Object* GetObjStaticFromCode(uint32_t field_idx,
+ const Method* referrer);
+ static void SetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
+ Object* new_value);
- public: // TODO: private
+ static Class* GetJavaLangReflectField() {
+ DCHECK(java_lang_reflect_Field_ != NULL);
+ return java_lang_reflect_Field_;
+ }
+
+ static void SetClass(Class* java_lang_reflect_Field);
+ static void ResetClass();
+
+ private:
+ bool IsVolatile() const {
+ return (GetAccessFlags() & kAccVolatile) != 0;
+ }
// private implementation of field access using raw data
uint32_t Get32(const Object* object) const;
@@ -439,18 +582,23 @@
Object* generic_type_;
uint32_t generic_types_are_initialized_;
const String* name_;
+ // Offset of field within an instance or in the Class' static fields
uint32_t offset_;
+ // Type of the field
+ // TODO: unused by ART (which uses the type_idx below), remove
Class* type_;
- // e.g. "I", "[C", "Landroid/os/Debug;"
- StringPiece descriptor_;
-
+ // TODO: expose these fields in the Java version of this Object
uint32_t access_flags_;
+ // Dex cache index of resolved type
+ uint32_t type_idx_;
- private:
+ static Class* java_lang_reflect_Field_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(Field);
};
+// C++ mirror of java.lang.reflect.Method
class Method : public AccessibleObject {
public:
// An function that invokes a method with an array of its arguments.
@@ -460,39 +608,54 @@
byte* args,
JValue* result);
- // Returns the method name, e.g. "<init>" or "eatLunch"
- const String* GetName() const {
- DCHECK(name_ != NULL);
- return name_;
- }
+ Class* GetDeclaringClass() const;
- const String* GetSignature() const {
- DCHECK(signature_ != NULL);
- return signature_;
- }
-
- Class* GetDeclaringClass() const {
- DCHECK(declaring_class_ != NULL);
- return declaring_class_;
- }
+ void SetDeclaringClass(Class *new_declaring_class);
static MemberOffset DeclaringClassOffset() {
return MemberOffset(OFFSETOF_MEMBER(Method, declaring_class_));
}
+ // Returns the method name, e.g. "<init>" or "eatLunch"
+ const String* GetName() const;
+
+ void SetName(String* new_name);
+
+ const char* GetShorty() const;
+
+ void SetShorty(const char* new_shorty) {
+ DCHECK(NULL == GetFieldPtr<const char*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, shorty_), false));
+ DCHECK_LE(1u, strlen(new_shorty));
+ SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(Method, shorty_), new_shorty, false);
+ }
+
+ const String* GetSignature() const;
+
+ void SetSignature(String* new_signature);
+
+ bool HasSameNameAndDescriptor(const Method* that) const;
+
+ uint32_t GetAccessFlags() const;
+
+ void SetAccessFlags(uint32_t new_access_flags) {
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), new_access_flags,
+ false);
+ }
+
// Returns true if the method is declared public.
bool IsPublic() const {
- return (access_flags_ & kAccPublic) != 0;
+ return (GetAccessFlags() & kAccPublic) != 0;
}
// Returns true if the method is declared private.
bool IsPrivate() const {
- return (access_flags_ & kAccPrivate) != 0;
+ return (GetAccessFlags() & kAccPrivate) != 0;
}
// Returns true if the method is declared static.
bool IsStatic() const {
- return (access_flags_ & kAccStatic) != 0;
+ return (GetAccessFlags() & kAccStatic) != 0;
}
// Returns true if the method is a constructor.
@@ -508,89 +671,125 @@
// Returns true if the method is declared synchronized.
bool IsSynchronized() const {
uint32_t synchonized = kAccSynchronized | kAccDeclaredSynchronized;
- return (access_flags_ & synchonized) != 0;
+ return (GetAccessFlags() & synchonized) != 0;
}
// Returns true if the method is declared final.
bool IsFinal() const {
- return (access_flags_ & kAccFinal) != 0;
+ return (GetAccessFlags() & kAccFinal) != 0;
}
// Returns true if the method is declared native.
bool IsNative() const {
- return (access_flags_ & kAccNative) != 0;
+ return (GetAccessFlags() & kAccNative) != 0;
}
// Returns true if the method is declared abstract.
bool IsAbstract() const {
- return (access_flags_ & kAccAbstract) != 0;
+ return (GetAccessFlags() & kAccAbstract) != 0;
}
bool IsSynthetic() const {
- return (access_flags_ & kAccSynthetic) != 0;
+ return (GetAccessFlags() & kAccSynthetic) != 0;
}
- // Number of argument registers required by the prototype.
- uint32_t NumArgRegisters() const;
+ uint16_t GetMethodIndex() const;
+
+ size_t GetVtableIndex() const {
+ return GetMethodIndex();
+ }
+
+ void SetMethodIndex(uint16_t new_method_index) {
+ SetField16(OFFSET_OF_OBJECT_MEMBER(Method, method_index_),
+ new_method_index, false);
+ }
+
+ static MemberOffset MethodIndexOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(Method, method_index_);
+ }
+
+ uint32_t GetCodeItemOffset() const {
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, code_item_offset_), false);
+ }
+
+ void SetCodeItemOffset(uint32_t new_code_off) {
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, code_item_offset_),
+ new_code_off, false);
+ }
+
+ // Number of 32bit registers that would be required to hold all the arguments
+ static size_t NumArgRegisters(const StringPiece& shorty);
// Number of argument bytes required for densely packing the
// arguments into an array of arguments.
size_t NumArgArrayBytes() const;
- // Converts a native PC to a virtual PC. TODO: this is a no-op
- // until we associate a PC mapping table with each method.
- uintptr_t ToDexPC(const uintptr_t pc) const {
- return pc;
+ uint16_t NumRegisters() const;
+
+ void SetNumRegisters(uint16_t new_num_registers) {
+ SetField16(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_),
+ new_num_registers, false);
}
- // Converts a virtual PC to a native PC. TODO: this is a no-op
- // until we associate a PC mapping table with each method.
- uintptr_t ToNativePC(const uintptr_t pc) const {
- return pc;
+ uint16_t NumIns() const;
+
+ void SetNumIns(uint16_t new_num_ins) {
+ SetField16(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_),
+ new_num_ins, false);
}
- public: // TODO: private
- // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
- // the class we are a part of
- Class* declaring_class_;
- ObjectArray<Class>* java_exception_types_;
- Object* java_formal_type_parameters_;
- Object* java_generic_exception_types_;
- Object* java_generic_parameter_types_;
- Object* java_generic_return_type_;
- Class* java_return_type_;
- const String* name_;
- ObjectArray<Class>* java_parameter_types_;
- uint32_t java_generic_types_are_initialized_;
- uint32_t java_slot_;
+ uint16_t NumOuts() const;
- const StringPiece& GetShorty() const {
- return shorty_;
+ void SetNumOuts(uint16_t new_num_outs) {
+ SetField16(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_),
+ new_num_outs, false);
}
- bool IsReturnAReference() const {
- return (shorty_[0] == 'L') || (shorty_[0] == '[');
+ uint32_t GetProtoIdx() const;
+
+ void SetProtoIdx(uint32_t new_proto_idx) {
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, proto_idx_), new_proto_idx, false);
}
+ ObjectArray<String>* GetDexCacheStrings() const;
+ void SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings);
+
+ static MemberOffset DexCacheStringsOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_strings_);
+ }
+
+ ObjectArray<Class>* GetDexCacheResolvedTypes() const;
+ void SetDexCacheResolvedTypes(ObjectArray<Class>* new_dex_cache_types);
+
+ ObjectArray<Method>* GetDexCacheResolvedMethods() const;
+ void SetDexCacheResolvedMethods(ObjectArray<Method>* new_dex_cache_methods);
+
+ ObjectArray<Field>* GetDexCacheResolvedFields() const;
+ void SetDexCacheResolvedFields(ObjectArray<Field>* new_dex_cache_fields);
+
+ CodeAndDirectMethods* GetDexCacheCodeAndDirectMethods() const;
+ void SetDexCacheCodeAndDirectMethods(CodeAndDirectMethods* new_value);
+
+ ObjectArray<StaticStorageBase>* GetDexCacheInitializedStaticStorage() const;
+ void SetDexCacheInitializedStaticStorage(ObjectArray<StaticStorageBase>* new_value);
+
+ void SetReturnTypeIdx(uint32_t new_return_type_idx);
+
+ Class* GetReturnType() const;
+
+ bool IsReturnAReference() const;
+
+ bool IsReturnAFloat() const;
+
+ bool IsReturnADouble() const;
+
bool IsReturnAFloatOrDouble() const {
- return (shorty_[0] == 'F') || (shorty_[0] == 'D');
+ return IsReturnAFloat() || IsReturnADouble();
}
- bool IsReturnAFloat() const {
- return shorty_[0] == 'F';
- }
+ bool IsReturnALong() const;
- bool IsReturnADouble() const {
- return shorty_[0] == 'D';
- }
-
- bool IsReturnALong() const {
- return shorty_[0] == 'J';
- }
-
- bool IsReturnVoid() const {
- return shorty_[0] == 'V';
- }
+ bool IsReturnVoid() const;
// "Args" may refer to any of the 3 levels of "Args."
// To avoid confusion, our code will denote which "Args" clearly:
@@ -607,7 +806,7 @@
size_t NumArgs() const {
// "1 +" because the first in Args is the receiver.
// "- 1" because we don't count the return type.
- return (IsStatic() ? 0 : 1) + shorty_.length() - 1;
+ return (IsStatic() ? 0 : 1) + strlen(GetShorty()) - 1;
}
// The number of reference arguments to this method including implicit this
@@ -633,90 +832,137 @@
// Size in bytes of the return value
size_t ReturnSize() const;
- bool HasCode() {
- return code_ != NULL;
+ const void* GetCode() const {
+ return GetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), false);
}
- const void* GetCode() {
- return code_;
+ bool HasCode() const {
+ return GetCode() != NULL;
}
void SetCode(const byte* compiled_code,
size_t byte_count,
- InstructionSet set) {
- // Copy the code into an executable region.
- code_instruction_set_ = set;
- code_area_.reset(MemMap::Map(byte_count,
- PROT_READ | PROT_WRITE | PROT_EXEC));
- CHECK(code_area_.get());
- byte* code = code_area_->GetAddress();
- memcpy(code, compiled_code, byte_count);
- __builtin___clear_cache(code, code + byte_count);
+ InstructionSet set);
- uintptr_t address = reinterpret_cast<uintptr_t>(code);
- if (code_instruction_set_ == kThumb2) {
- // Set the low-order bit so a BLX will switch to Thumb mode
- address |= 0x1;
- }
- code_ = reinterpret_cast<void*>(address);
- }
-
- void SetFrameSizeInBytes(size_t frame_size_in_bytes) {
- frame_size_in_bytes_ = frame_size_in_bytes;
- }
-
- void SetReturnPcOffsetInBytes(size_t return_pc_offset_in_bytes) {
- return_pc_offset_in_bytes_ = return_pc_offset_in_bytes;
+ static MemberOffset GetCodeOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(Method, code_);
}
size_t GetFrameSizeInBytes() const {
- return frame_size_in_bytes_;
+ DCHECK(sizeof(size_t) == sizeof(uint32_t));
+ size_t result = GetField32(
+ OFFSET_OF_OBJECT_MEMBER(Method, frame_size_in_bytes_), false);
+ DCHECK_LE(static_cast<size_t>(kStackAlignment), result);
+ return result;
+ }
+
+ void SetFrameSizeInBytes(size_t new_frame_size_in_bytes) {
+ DCHECK(sizeof(size_t) == sizeof(uint32_t));
+ DCHECK_LE(static_cast<size_t>(kStackAlignment), new_frame_size_in_bytes);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, frame_size_in_bytes_),
+ new_frame_size_in_bytes, false);
}
size_t GetReturnPcOffsetInBytes() const {
- return return_pc_offset_in_bytes_;
+ DCHECK(sizeof(size_t) == sizeof(uint32_t));
+ return GetField32(
+ OFFSET_OF_OBJECT_MEMBER(Method, return_pc_offset_in_bytes_), false);
}
- void SetCoreSpillMask(uint32_t core_spill_mask) {
- core_spill_mask_ = core_spill_mask;
- }
-
- static size_t GetCodeOffset() {
- return OFFSETOF_MEMBER(Method, code_);
- }
-
- void SetFpSpillMask(uint32_t fp_spill_mask) {
- fp_spill_mask_ = fp_spill_mask;
+ void SetReturnPcOffsetInBytes(size_t return_pc_offset_in_bytes) {
+ DCHECK(sizeof(size_t) == sizeof(uint32_t));
+ DCHECK_LT(return_pc_offset_in_bytes, GetFrameSizeInBytes());
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, return_pc_offset_in_bytes_),
+ return_pc_offset_in_bytes, false);
}
void RegisterNative(const void* native_method) {
CHECK(native_method != NULL);
- native_method_ = native_method;
+ SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, native_method_),
+ native_method, false);
}
void UnregisterNative() {
- native_method_ = NULL;
+ SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, native_method_),
+ NULL, false);
}
static MemberOffset NativeMethodOffset() {
- return MemberOffset(OFFSETOF_MEMBER(Method, native_method_));
+ return OFFSET_OF_OBJECT_MEMBER(Method, native_method_);
}
+ // Native to managed invocation stub entry point
InvokeStub* GetInvokeStub() const {
- return invoke_stub_;
+ InvokeStub* result = GetFieldPtr<InvokeStub*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_), false);
+ // TODO: DCHECK(result != NULL); should be ahead of time compiled
+ return result;
}
- void SetInvokeStub(const InvokeStub* invoke_stub) {
- invoke_stub_ = invoke_stub;
+ static MemberOffset GetInvokeStubOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_);
}
- static size_t GetInvokeStubOffset() {
- return OFFSETOF_MEMBER(Method, invoke_stub_);
+ void SetInvokeStub(const InvokeStub* new_invoke_stub) {
+ SetFieldPtr<const InvokeStub*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_), new_invoke_stub, false);
}
- bool HasSameNameAndDescriptor(const Method* that) const;
+ void SetFpSpillMask(uint32_t fp_spill_mask) {
+ // Computed during compilation
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, fp_spill_mask_),
+ fp_spill_mask, false);
+ }
- public: // TODO: private/const
+ void SetCoreSpillMask(uint32_t core_spill_mask) {
+ // Computed during compilation
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, core_spill_mask_),
+ core_spill_mask, false);
+ }
+
+ // Converts a native PC to a dex PC. TODO: this is a no-op
+ // until we associate a PC mapping table with each method.
+ uintptr_t ToDexPC(const uintptr_t pc) const {
+ return pc;
+ }
+
+ // Converts a dex PC to a native PC. TODO: this is a no-op
+ // until we associate a PC mapping table with each method.
+ uintptr_t ToNativePC(const uintptr_t pc) const {
+ return pc;
+ }
+
+ static Class* GetJavaLangReflectMethod() {
+ DCHECK(java_lang_reflect_Method_ != NULL);
+ return java_lang_reflect_Method_;
+ }
+
+ static void SetClass(Class* java_lang_reflect_Method);
+ static void ResetClass();
+
+ private:
+ uint32_t GetReturnTypeIdx() const;
+
+ // TODO: the image writer should know the offsets of these fields as they
+ // should appear in the libcore Java mirror
+ friend class ImageWriter;
+
+ // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
+ // the class we are a part of
+ Class* declaring_class_;
+ ObjectArray<Class>* java_exception_types_;
+ Object* java_formal_type_parameters_;
+ Object* java_generic_exception_types_;
+ Object* java_generic_parameter_types_;
+ Object* java_generic_return_type_;
+ Class* java_return_type_; // Unused by ART
+ String* name_;
+ ObjectArray<Class>* java_parameter_types_;
+ uint32_t java_generic_types_are_initialized_;
+ uint32_t java_slot_;
+
+ // TODO: start of non-Java mirror fields, place these in the Java piece
+
// access flags; low 16 bits are defined by spec (could be uint16_t?)
uint32_t access_flags_;
@@ -758,14 +1004,17 @@
uint32_t proto_idx_;
// Offset to the CodeItem.
- uint32_t code_off_;
+ uint32_t code_item_offset_;
- // The short-form method descriptor string.
- StringPiece shorty_;
+ // Index of the return type
+ uint32_t java_return_type_idx_;
+
+ // The short-form method descriptor string. TODO: make String*
+ const char* shorty_;
// short cuts to declaring_class_->dex_cache_ members for fast compiled code
// access
- ObjectArray<const String>* dex_cache_strings_;
+ ObjectArray<String>* dex_cache_strings_;
ObjectArray<Class>* dex_cache_resolved_types_;
ObjectArray<Method>* dex_cache_resolved_methods_;
ObjectArray<Field>* dex_cache_resolved_fields_;
@@ -776,6 +1025,7 @@
// Compiled code associated with this method
UniquePtr<MemMap> code_area_;
const void* code_;
+
// Instruction set of the compiled code
InstructionSet code_instruction_set_;
@@ -792,6 +1042,8 @@
// Native invocation stub entry point.
const InvokeStub* invoke_stub_;
+ static Class* java_lang_reflect_Method_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(Method);
};
@@ -816,19 +1068,20 @@
size_t SizeOf() const;
int32_t GetLength() const {
- return length_;
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Array, length_), false);
}
- void SetLength(uint32_t length) {
- length_ = length;
+ void SetLength(int32_t length) {
+ CHECK_LE(0, length);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Array, length_), length, false);
}
static MemberOffset LengthOffset() {
- return MemberOffset(OFFSETOF_MEMBER(Array, length_));
+ return OFFSET_OF_OBJECT_MEMBER(Array, length_);
}
static MemberOffset DataOffset() {
- return MemberOffset(OFFSETOF_MEMBER(Array, first_element_));
+ return OFFSET_OF_OBJECT_MEMBER(Array, first_element_);
}
void* GetRawData() {
@@ -860,61 +1113,54 @@
template<class T>
class ObjectArray : public Array {
public:
- static ObjectArray<T>* Alloc(Class* object_array_class,
- int32_t length) {
- return Array::Alloc(object_array_class, length, sizeof(uint32_t))->AsObjectArray<T>();
- }
+ static ObjectArray<T>* Alloc(Class* object_array_class, int32_t length);
- T* const * GetData() const {
- return reinterpret_cast<T* const *>(&elements_);
- }
+ T* Get(int32_t i) const;
- T** GetData() {
- return reinterpret_cast<T**>(&elements_);
- }
+ void Set(int32_t i, T* object);
- T* Get(int32_t i) const {
- if (!IsValidIndex(i)) {
- return NULL;
- }
- return GetData()[i];
- }
+ // Set element without bound and element type checks, to be used in limited
+ // circumstances, such as during boot image writing
+ void SetWithoutChecks(int32_t i, T* object);
- void Set(int32_t i, T* object) {
- if (IsValidIndex(i)) {
- // TODO: ArrayStoreException
- GetData()[i] = object; // TODO: write barrier
- }
- }
-
- static void Copy(ObjectArray<T>* src, int src_pos,
+ static void Copy(const ObjectArray<T>* src, int src_pos,
ObjectArray<T>* dst, int dst_pos,
- size_t length) {
- for (size_t i = 0; i < length; i++) {
- dst->Set(dst_pos + i, src->Get(src_pos + i));
- }
- }
+ size_t length);
- ObjectArray<T>* CopyOf(int32_t new_length) {
- ObjectArray<T>* new_array = Alloc(klass_, new_length);
- Copy(this, 0, new_array, 0, std::min(GetLength(), new_length));
- return new_array;
- }
+ ObjectArray<T>* CopyOf(int32_t new_length);
private:
- // Location of first element.
- T* elements_[0];
-
DISALLOW_IMPLICIT_CONSTRUCTORS(ObjectArray);
};
+template<class T>
+ObjectArray<T>* ObjectArray<T>::Alloc(Class* object_array_class, int32_t length) {
+ return Array::Alloc(object_array_class, length, sizeof(uint32_t))->AsObjectArray<T>();
+}
+
+template<class T>
+T* ObjectArray<T>::Get(int32_t i) const {
+ if (!IsValidIndex(i)) {
+ return NULL;
+ }
+ MemberOffset data_offset(DataOffset().Int32Value() + i * sizeof(Object*));
+ return GetFieldObject<T*>(data_offset, false);
+}
+
+template<class T>
+ObjectArray<T>* ObjectArray<T>::CopyOf(int32_t new_length) {
+ ObjectArray<T>* new_array = Alloc(GetClass(), new_length);
+ Copy(this, 0, new_array, 0, std::min(GetLength(), new_length));
+ return new_array;
+}
+
// Type for the InitializedStaticStorage table. Currently the Class
// provides the static storage. However, this might change to improve
// image sharing, so we use this type to avoid assumptions on the
// current storage.
class StaticStorageBase {};
-// Class objects.
+// C++ mirror of java.lang.Class
class Class : public Object, public StaticStorageBase {
public:
@@ -938,9 +1184,10 @@
// 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.
+ // shows linking is complete and fields of the Class populated by making
+ // it kStatusResolved. Java allows circularities of the form where a super
+ // class has a field that is of the type of the sub class. We need to be able
+ // to fully resolve super classes while resolving types for fields.
enum Status {
kStatusError = -1,
@@ -955,9 +1202,207 @@
};
enum PrimitiveType {
- kPrimNot = -1
+ kPrimNot = 0,
+ kPrimBoolean,
+ kPrimByte,
+ kPrimChar,
+ kPrimShort,
+ kPrimInt,
+ kPrimLong,
+ kPrimFloat,
+ kPrimDouble,
+ kPrimVoid,
};
+ Status GetStatus() const {
+ CHECK(sizeof(Status) == sizeof(uint32_t));
+ return static_cast<Status>(
+ GetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), false));
+ }
+
+ void SetStatus(Status new_status);
+
+ // Returns true if the class has failed to link.
+ bool IsErroneous() const {
+ return GetStatus() == kStatusError;
+ }
+
+ // Returns true if the class has been loaded.
+ bool IsIdxLoaded() const {
+ return GetStatus() >= kStatusIdx;
+ }
+
+ // Returns true if the class has been loaded.
+ bool IsLoaded() const {
+ return GetStatus() >= kStatusLoaded;
+ }
+
+ // Returns true if the class has been linked.
+ bool IsLinked() const {
+ return GetStatus() >= kStatusResolved;
+ }
+
+ // Returns true if the class has been verified.
+ bool IsVerified() const {
+ return GetStatus() >= kStatusVerified;
+ }
+
+ // Returns true if the class is initialized.
+ bool IsInitialized() const {
+ return GetStatus() == kStatusInitialized;
+ }
+
+ uint32_t GetAccessFlags() const;
+
+ void SetAccessFlags(uint32_t new_access_flags) {
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags,
+ false);
+ }
+
+ // Returns true if the class is an interface.
+ bool IsInterface() const {
+ return (GetAccessFlags() & kAccInterface) != 0;
+ }
+
+ // Returns true if the class is declared public.
+ bool IsPublic() const {
+ return (GetAccessFlags() & kAccPublic) != 0;
+ }
+
+ // Returns true if the class is declared final.
+ bool IsFinal() const {
+ return (GetAccessFlags() & kAccFinal) != 0;
+ }
+
+ // Returns true if the class is abstract.
+ bool IsAbstract() const {
+ return (GetAccessFlags() & kAccAbstract) != 0;
+ }
+
+ // Returns true if the class is an annotation.
+ bool IsAnnotation() const {
+ return (GetAccessFlags() & kAccAnnotation) != 0;
+ }
+
+ // Returns true if the class is synthetic.
+ bool IsSynthetic() const {
+ return (GetAccessFlags() & kAccSynthetic) != 0;
+ }
+
+ bool IsReferenceClass() const {
+ return (GetAccessFlags() & kAccClassIsReference) != 0;
+ }
+
+ bool IsWeakReferenceClass() const {
+ return (GetAccessFlags() & kAccClassIsWeakReference) != 0;
+ }
+
+ bool IsSoftReferenceClass() const {
+ return (GetAccessFlags() & ~kAccReferenceFlagsMask) == kAccClassIsReference;
+ }
+
+ bool IsFinalizerReferenceClass() const {
+ return (GetAccessFlags() & kAccClassIsFinalizerReference) != 0;
+ }
+
+ bool IsPhantomReferenceClass() const {
+ return (GetAccessFlags() & kAccClassIsPhantomReference) != 0;
+ }
+
+ PrimitiveType GetPrimitiveType() const {
+ CHECK(sizeof(PrimitiveType) == sizeof(int32_t));
+ return static_cast<PrimitiveType>(
+ GetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), false));
+ }
+
+ void SetPrimitiveType(PrimitiveType new_type) {
+ CHECK(sizeof(PrimitiveType) == sizeof(int32_t));
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), new_type,
+ false);
+ }
+
+ // Returns true if the class is a primitive type.
+ bool IsPrimitive() const {
+ return GetPrimitiveType() != kPrimNot;
+ }
+
+ bool IsPrimitiveBoolean() const {
+ return GetPrimitiveType() == kPrimBoolean;
+ }
+
+ bool IsPrimitiveByte() const {
+ return GetPrimitiveType() == kPrimByte;
+ }
+
+ bool IsPrimitiveChar() const {
+ return GetPrimitiveType() == kPrimChar;
+ }
+
+ bool IsPrimitiveShort() const {
+ return GetPrimitiveType() == kPrimShort;
+ }
+
+ bool IsPrimitiveInt() const {
+ return GetPrimitiveType() == kPrimInt;
+ }
+
+ bool IsPrimitiveLong() const {
+ return GetPrimitiveType() == kPrimLong;
+ }
+
+ bool IsPrimitiveFloat() const {
+ return GetPrimitiveType() == kPrimFloat;
+ }
+
+ bool IsPrimitiveDouble() const {
+ return GetPrimitiveType() == kPrimDouble;
+ }
+
+ bool IsPrimitiveVoid() const {
+ return GetPrimitiveType() == kPrimVoid;
+ }
+
+ size_t PrimitiveSize() const;
+
+ bool IsArrayClass() const {
+ return GetArrayRank() != 0;
+ }
+
+ int32_t GetArrayRank() const {
+ int32_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, array_rank_),
+ false);
+ return result;
+ }
+
+ void SetArrayRank(int32_t new_array_rank) {
+ DCHECK_EQ(0, GetArrayRank());
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, array_rank_), new_array_rank,
+ false);
+ }
+
+ Class* GetComponentType() const {
+ DCHECK(IsArrayClass());
+ return GetFieldObject<Class*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, component_type_), false);
+ }
+
+ void SetComponentType(Class* new_component_type) {
+ DCHECK(GetComponentType() == NULL);
+ DCHECK(new_component_type != NULL);
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, component_type_),
+ new_component_type, false);
+ }
+
+ size_t GetComponentSize() const {
+ return GetTypeSize(GetComponentType()->GetDescriptor());
+ }
+
+ bool IsObjectClass() const {
+ return !IsPrimitive() && GetSuperClass() == NULL;
+ }
+
+ static bool CanPutArrayElementFromCode(const Class* elementClass, const Class* arrayClass);
+
// 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.
@@ -966,92 +1411,54 @@
// Creates a raw object instance but does not invoke the default constructor.
Object* AllocObject();
- Class* GetSuperClass() const {
- return super_class_;
- }
-
- uint32_t GetSuperClassTypeIdx() const {
- return super_class_type_idx_;
- }
-
- bool HasSuperClass() const {
- return super_class_ != NULL;
- }
-
- bool IsAssignableFrom(const Class* klass) const {
- DCHECK(klass != NULL);
- if (this == klass) {
- return true;
- }
- if (IsInterface()) {
- return klass->Implements(this);
- }
- if (klass->IsArrayClass()) {
- return IsAssignableFromArray(klass);
- }
- return klass->IsSubClass(this);
- }
-
- const ClassLoader* GetClassLoader() const {
- return class_loader_;
- }
-
- DexCache* GetDexCache() const {
- return dex_cache_;
- }
-
- Class* GetComponentType() const {
- return component_type_;
- }
-
- static size_t GetTypeSize(String* descriptor);
-
- size_t GetComponentSize() const {
- return GetTypeSize(component_type_->descriptor_);
- }
+ static size_t GetTypeSize(const String* descriptor);
const String* GetDescriptor() const {
- DCHECK(descriptor_ != NULL);
- // DCHECK_NE(0, descriptor_->GetLength()); // TODO: keep?
- return descriptor_;
+ const String* result = GetFieldObject<const String*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, descriptor_), false);
+ // DCHECK(result != NULL); // may be NULL prior to class linker initialization
+ // DCHECK_NE(0, result->GetLength()); // TODO: keep?
+ return result;
+ }
+
+ void SetDescriptor(String* new_descriptor);
+
+ bool IsVariableSize() const {
+ // Classes and arrays vary in size, and so the object_size_ field cannot
+ // be used to get their instance size
+ return IsClassClass() || IsArrayClass();
}
size_t SizeOf() const {
- return class_size_;
+ CHECK(sizeof(size_t) == sizeof(int32_t));
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), false);
}
- Status GetStatus() const {
- return status_;
+ size_t GetClassSize() const {
+ CHECK(sizeof(size_t) == sizeof(uint32_t));
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), false);
}
- void SetStatus(Status new_status) {
- // TODO: validate transition
- status_ = new_status;
+ void SetClassSize(size_t new_class_size) {
+ DCHECK_GE(new_class_size, GetClassSize());
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size,
+ false);
}
- // Returns true if the class has failed to link.
- bool IsErroneous() const {
- return GetStatus() == kStatusError;
+ size_t GetObjectSize() const {
+ CHECK(!IsVariableSize());
+ CHECK(sizeof(size_t) == sizeof(int32_t));
+ size_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, object_size_),
+ false);
+ CHECK_GE(result, sizeof(Object));
+ return result;
}
- // Returns true if the class has been verified.
- bool IsVerified() const {
- return GetStatus() >= kStatusVerified;
- }
-
- // Returns true if the class has been linked.
- bool IsLinked() const {
- return GetStatus() >= kStatusResolved;
- }
-
- // Returns true if the class has been loaded.
- bool IsLoaded() const {
- return GetStatus() >= kStatusLoaded;
- }
-
- // Returns true if the class is initialized.
- bool IsInitialized() const {
- return GetStatus() == kStatusInitialized;
+ void SetObjectSize(size_t new_object_size) {
+ DCHECK(!IsVariableSize());
+ CHECK(sizeof(size_t) == sizeof(int32_t));
+ return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, object_size_),
+ new_object_size, false);
}
// Returns true if this class is in the same packages as that class.
@@ -1060,105 +1467,157 @@
static bool IsInSamePackage(const String* descriptor1,
const String* descriptor2);
- // Returns true if this class represents an array class.
- bool IsArrayClass() const;
-
- // Returns true if the class is an interface.
- bool IsInterface() const {
- return (access_flags_ & kAccInterface) != 0;
- }
-
- // Returns true if the class is declared public.
- bool IsPublic() const {
- return (access_flags_ & kAccPublic) != 0;
- }
-
- // Returns true if the class is declared final.
- bool IsFinal() const {
- return (access_flags_ & kAccFinal) != 0;
- }
-
- // Returns true if the class is abstract.
- bool IsAbstract() const {
- return (access_flags_ & kAccAbstract) != 0;
- }
-
- // Returns true if the class is an annotation.
- bool IsAnnotation() const {
- return (access_flags_ & kAccAnnotation) != 0;
- }
-
- // Returns true if the class is a primitive type.
- bool IsPrimitive() const {
- return primitive_type_ != kPrimNot;
- }
-
- // Returns true if the class is synthetic.
- bool IsSynthetic() const {
- return (access_flags_ & kAccSynthetic) != 0;
- }
-
- bool IsReference() const {
- return (access_flags_ & kAccClassIsReference) != 0;
- }
-
- bool IsWeakReference() const {
- return (access_flags_ & kAccClassIsWeakReference) != 0;
- }
-
- bool IsSoftReference() const {
- return (access_flags_ & ~kAccReferenceFlagsMask) == kAccClassIsReference;
- }
-
- bool IsFinalizerReference() const {
- return (access_flags_ & kAccClassIsFinalizerReference) != 0;
- }
-
- bool IsPhantomReference() const {
- return (access_flags_ & kAccClassIsPhantomReference) != 0;
- }
-
// Returns true if this class can access that class.
bool CanAccess(const Class* that) const {
return that->IsPublic() || this->IsInSamePackage(that);
}
- static bool CanPutArrayElementFromCode(const Class* elementClass, const Class* arrayClass);
+ bool IsAssignableFrom(const Class* klass) const {
+ DCHECK(klass != NULL);
+ if (this == klass) {
+ // Can always assign to things of the same type
+ return true;
+ } else if(IsObjectClass()) {
+ // Can assign any reference to java.lang.Object
+ return !klass->IsPrimitive();
+ } else if (IsInterface()) {
+ return klass->Implements(this);
+ } else if (klass->IsArrayClass()) {
+ return IsAssignableFromArray(klass);
+ } else {
+ return klass->IsSubClass(this);
+ }
+ }
- // Returns the number of static, private, and constructor methods.
- size_t NumDirectMethods() const {
- return (direct_methods_ != NULL) ? direct_methods_->GetLength() : 0;
+ Class* GetSuperClass() const {
+ // Can only get super class for loaded classes (hack for when runtime is
+ // initializing)
+ DCHECK(IsLoaded() || Runtime::Current() == NULL);
+ return GetFieldObject<Class*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, super_class_), false);
+ }
+
+ void SetSuperClass(Class *new_super_class) {
+ // super class is assigned once, except during class linker initialization
+ Class* old_super_class = GetFieldObject<Class*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, super_class_), false);
+ DCHECK(old_super_class == NULL || old_super_class == new_super_class);
+ DCHECK(new_super_class != NULL);
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, super_class_),
+ new_super_class, false);
+ }
+
+ bool HasSuperClass() const {
+ return GetSuperClass() != NULL;
+ }
+
+ uint32_t GetSuperClassTypeIdx() const {
+ DCHECK(IsIdxLoaded());
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, super_class_type_idx_),
+ false);
+ }
+
+ void SetSuperClassTypeIdx(int32_t new_super_class_idx) {
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, super_class_type_idx_),
+ new_super_class_idx, false);
+ }
+
+ const ClassLoader* GetClassLoader() const;
+
+ void SetClassLoader(const ClassLoader* new_cl);
+
+ static MemberOffset DexCacheOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(Class, dex_cache_));
+ }
+
+ DexCache* GetDexCache() const;
+
+ void SetDexCache(DexCache* new_dex_cache);
+
+ ObjectArray<Method>* GetDirectMethods() const {
+ DCHECK(IsLoaded());
+ return GetFieldObject<ObjectArray<Method>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false);
+ }
+
+ void SetDirectMethods(ObjectArray<Method>* new_direct_methods) {
+ DCHECK(NULL == GetFieldObject<ObjectArray<Method>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false));
+ DCHECK_NE(0, new_direct_methods->GetLength());
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_),
+ new_direct_methods, false);
}
Method* GetDirectMethod(int32_t i) const {
- DCHECK_NE(NumDirectMethods(), 0U);
- return direct_methods_->Get(i);
+ return GetDirectMethods()->Get(i);
}
void SetDirectMethod(uint32_t i, Method* f) { // TODO: uint16_t
- DCHECK_NE(NumDirectMethods(), 0U);
- direct_methods_->Set(i, f);
+ ObjectArray<Method>* direct_methods =
+ GetFieldObject<ObjectArray<Method>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false);
+ direct_methods->Set(i, f);
}
- Method* FindDeclaredDirectMethod(const StringPiece& name,
- const StringPiece& signature);
+ // Returns the number of static, private, and constructor methods.
+ size_t NumDirectMethods() const {
+ return (GetDirectMethods() != NULL) ? GetDirectMethods()->GetLength() : 0;
+ }
- Method* FindDirectMethod(const StringPiece& name,
- const StringPiece& signature);
+ ObjectArray<Method>* GetVirtualMethods() const {
+ DCHECK(IsLoaded());
+ return GetFieldObject<ObjectArray<Method>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), false);
+ }
+
+ void SetVirtualMethods(ObjectArray<Method>* new_virtual_methods) {
+ // TODO: we reassign virtual methods to grow the table for miranda
+ // methods.. they should really just be assigned once
+ DCHECK_NE(0, new_virtual_methods->GetLength());
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_),
+ new_virtual_methods, false);
+ }
// Returns the number of non-inherited virtual methods.
size_t NumVirtualMethods() const {
- return (virtual_methods_ != NULL) ? virtual_methods_->GetLength() : 0;
+ return (GetVirtualMethods() != NULL) ? GetVirtualMethods()->GetLength() : 0;
}
Method* GetVirtualMethod(uint32_t i) const {
- DCHECK_NE(NumVirtualMethods(), 0U);
- return virtual_methods_->Get(i);
+ DCHECK(IsLinked());
+ return GetVirtualMethods()->Get(i);
+ }
+
+ Method* GetVirtualMethodDuringLinking(uint32_t i) const {
+ DCHECK(IsLoaded());
+ return GetVirtualMethods()->Get(i);
}
void SetVirtualMethod(uint32_t i, Method* f) { // TODO: uint16_t
- DCHECK_NE(NumVirtualMethods(), 0U);
- virtual_methods_->Set(i, f);
+ ObjectArray<Method>* virtual_methods =
+ GetFieldObject<ObjectArray<Method>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), false);
+ virtual_methods->Set(i, f);
+ }
+
+ ObjectArray<Method>* GetVTable() const {
+ DCHECK(IsLinked());
+ return GetFieldObject<ObjectArray<Method>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false);
+ }
+
+ ObjectArray<Method>* GetVTableDuringLinking() const {
+ DCHECK(IsLoaded());
+ return GetFieldObject<ObjectArray<Method>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false);
+ }
+
+ void SetVTable(ObjectArray<Method>* new_vtable) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false);
+ }
+
+ static MemberOffset VTableOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(Class, vtable_);
}
// Given a method implemented by this class but potentially from a
@@ -1167,8 +1626,8 @@
Method* FindVirtualMethodForVirtual(Method* method) {
DCHECK(!method->GetDeclaringClass()->IsInterface());
// The argument method may from a super class.
- // Use the index to a potentially overriden one for this instance's class.
- return vtable_->Get(method->method_index_);
+ // Use the index to a potentially overridden one for this instance's class.
+ return GetVTable()->Get(method->GetMethodIndex());
}
// Given a method implemented by this class, but potentially from a
@@ -1189,94 +1648,256 @@
Method* FindVirtualMethod(const StringPiece& name,
const StringPiece& descriptor);
- size_t NumInstanceFields() const {
- return (ifields_ != NULL) ? ifields_->GetLength() : 0;
- }
+ Method* FindDeclaredDirectMethod(const StringPiece& name,
+ const StringPiece& signature);
- // Returns the number of instance fields containing reference types.
- size_t NumReferenceInstanceFields() const {
- return num_reference_instance_fields_;
- }
-
- // Returns the number of static fields containing reference types.
- size_t NumReferenceStaticFields() const {
- return num_reference_static_fields_;
- }
-
- // Finds the given instance field in this class or a superclass.
- Field* FindInstanceField(const StringPiece& name,
- const StringPiece& descriptor);
-
- // Finds the given instance field in this class.
- Field* FindDeclaredInstanceField(const StringPiece& name,
- const StringPiece& descriptor);
-
- // Finds the given static field in this class or a superclass.
- Field* FindStaticField(const StringPiece& name,
- const StringPiece& descriptor);
-
- // Finds the given static field in this class.
- Field* FindDeclaredStaticField(const StringPiece& name,
- const StringPiece& descriptor);
-
- Field* GetInstanceField(uint32_t i) const { // TODO: uint16_t
- DCHECK_NE(NumInstanceFields(), 0U);
- return ifields_->Get(i);
- }
-
- void SetInstanceField(uint32_t i, Field* f) { // TODO: uint16_t
- DCHECK_NE(NumInstanceFields(), 0U);
- ifields_->Set(i, f);
- }
-
- size_t NumStaticFields() const {
- return (sfields_ != NULL) ? sfields_->GetLength() : 0;
- }
-
- Field* GetStaticField(uint32_t i) const { // TODO: uint16_t
- DCHECK_NE(NumStaticFields(), 0U);
- return sfields_->Get(i);
- }
-
- void SetStaticField(uint32_t i, Field* f) { // TODO: uint16_t
- DCHECK_NE(NumStaticFields(), 0U);
- sfields_->Set(i, f);
- }
-
- uint32_t GetReferenceInstanceOffsets() const {
- return reference_instance_offsets_;
- }
-
- void SetReferenceInstanceOffsets(uint32_t new_reference_offsets) {
- reference_instance_offsets_ = new_reference_offsets;
- }
-
- uint32_t GetReferenceStaticOffsets() const {
- return reference_static_offsets_;
- }
-
- void SetReferenceStaticOffsets(uint32_t new_reference_offsets) {
- reference_static_offsets_ = new_reference_offsets;
- }
+ Method* FindDirectMethod(const StringPiece& name,
+ const StringPiece& signature);
size_t NumInterfaces() const {
- return (interfaces_ != NULL) ? interfaces_->GetLength() : 0;
+ CHECK(IsIdxLoaded()); // used during loading
+ ObjectArray<Class>* interfaces = GetFieldObject<ObjectArray<Class>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
+ return (interfaces != NULL) ? interfaces->GetLength() : 0;
}
- Class* GetInterface(uint32_t i) const {
- DCHECK_NE(NumInterfaces(), 0U);
- return interfaces_->Get(i);
+ IntArray* GetInterfacesTypeIdx() const {
+ CHECK(IsIdxLoaded());
+ return GetFieldObject<IntArray*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_), false);
+ }
+
+ void SetInterfacesTypeIdx(IntArray* new_interfaces_idx);
+
+ ObjectArray<Class>* GetInterfaces() const {
+ CHECK(IsLoaded());
+ return GetFieldObject<ObjectArray<Class>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
+ }
+
+ void SetInterfaces(ObjectArray<Class>* new_interfaces) {
+ DCHECK(NULL == GetFieldObject<Object*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false));
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, interfaces_),
+ new_interfaces, false);
}
void SetInterface(uint32_t i, Class* f) { // TODO: uint16_t
DCHECK_NE(NumInterfaces(), 0U);
- interfaces_->Set(i, f);
+ ObjectArray<Class>* interfaces =
+ GetFieldObject<ObjectArray<Class>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
+ interfaces->Set(i, f);
+ }
+
+ Class* GetInterface(uint32_t i) const {
+ DCHECK_NE(NumInterfaces(), 0U);
+ return GetInterfaces()->Get(i);
+ }
+
+ size_t GetIFTableCount() const {
+ DCHECK(IsLinked());
+ DCHECK(sizeof(size_t) == sizeof(int32_t));
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, iftable_count_), false);
+ }
+
+ void SetIFTableCount(size_t new_iftable_count) {
+ DCHECK(sizeof(size_t) == sizeof(int32_t));
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, iftable_count_),
+ new_iftable_count, false);
+ }
+
+ InterfaceEntry* GetIFTable() const {
+ DCHECK(IsLinked());
+ return GetFieldPtr<InterfaceEntry*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, iftable_), false);
+ }
+
+ void SetIFTable(InterfaceEntry* new_iftable) {
+ SetFieldPtr<InterfaceEntry*>(OFFSET_OF_OBJECT_MEMBER(Class, iftable_),
+ new_iftable, false);
+ }
+
+ size_t GetIfviPoolCount() const {
+ DCHECK(IsLinked());
+ CHECK(sizeof(size_t) == sizeof(int32_t));
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, ifvi_pool_count_), false);
+ }
+
+ void SetIfviPoolCount(size_t new_count) {
+ CHECK(sizeof(size_t) == sizeof(int32_t));
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, ifvi_pool_count_), new_count,
+ false);
+ }
+
+ uint32_t* GetIfviPool() const {
+ DCHECK(IsLinked());
+ return GetFieldPtr<uint32_t*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, ifvi_pool_), false);
+ }
+
+ void SetIfviPool(uint32_t* new_pool) {
+ SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(Class, ifvi_pool_), new_pool, false);
+ }
+
+ // Get instance fields
+ ObjectArray<Field>* GetIFields() const {
+ DCHECK(IsLoaded());
+ return GetFieldObject<ObjectArray<Field>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false);
+ }
+
+ void SetIFields(ObjectArray<Field>* new_ifields) {
+ DCHECK(NULL == GetFieldObject<ObjectArray<Field>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false));
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, ifields_),
+ new_ifields, false);
+ }
+
+ size_t NumInstanceFields() const {
+ return (GetIFields() != NULL) ? GetIFields()->GetLength() : 0;
+ }
+
+ Field* GetInstanceField(uint32_t i) const { // TODO: uint16_t
+ DCHECK_NE(NumInstanceFields(), 0U);
+ return GetIFields()->Get(i);
+ }
+
+ void SetInstanceField(uint32_t i, Field* f) { // TODO: uint16_t
+ ObjectArray<Field>* ifields= GetFieldObject<ObjectArray<Field>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false);
+ ifields->Set(i, f);
+ }
+
+ // Returns the number of instance fields containing reference types.
+ size_t NumReferenceInstanceFields() const {
+ DCHECK(IsLinked());
+ DCHECK(sizeof(size_t) == sizeof(int32_t));
+ return GetField32(
+ OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
+ }
+
+ size_t NumReferenceInstanceFieldsDuringLinking() const {
+ DCHECK(IsLoaded());
+ DCHECK(sizeof(size_t) == sizeof(int32_t));
+ return GetField32(
+ OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
+ }
+
+ void SetNumReferenceInstanceFields(size_t new_num) {
+ DCHECK(sizeof(size_t) == sizeof(int32_t));
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_),
+ new_num, false);
+ }
+
+ uint32_t GetReferenceInstanceOffsets() const {
+ DCHECK(IsLinked());
+ return GetField32(
+ OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_), false);
+ }
+
+ void SetReferenceInstanceOffsets(uint32_t new_reference_offsets);
+
+ // Beginning of static field data
+ static MemberOffset FieldsOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(Class, fields_);
+ }
+
+ // Returns the number of static fields containing reference types.
+ size_t NumReferenceStaticFields() const {
+ DCHECK(IsLinked());
+ DCHECK(sizeof(size_t) == sizeof(int32_t));
+ return GetField32(
+ OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
+ }
+
+ size_t NumReferenceStaticFieldsDuringLinking() const {
+ DCHECK(IsLoaded());
+ DCHECK(sizeof(size_t) == sizeof(int32_t));
+ return GetField32(
+ OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
+ }
+
+ void SetNumReferenceStaticFields(size_t new_num) {
+ DCHECK(sizeof(size_t) == sizeof(int32_t));
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_),
+ new_num, false);
+ }
+
+ ObjectArray<Field>* GetSFields() const {
+ DCHECK(IsLoaded());
+ return GetFieldObject<ObjectArray<Field>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false);
+ }
+
+ void SetSFields(ObjectArray<Field>* new_sfields) {
+ DCHECK(NULL == GetFieldObject<ObjectArray<Field>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false));
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, sfields_),
+ new_sfields, false);
+ }
+
+ size_t NumStaticFields() const {
+ return (GetSFields() != NULL) ? GetSFields()->GetLength() : 0;
+ }
+
+ Field* GetStaticField(uint32_t i) const { // TODO: uint16_t
+ return GetSFields()->Get(i);
+ }
+
+ void SetStaticField(uint32_t i, Field* f) { // TODO: uint16_t
+ ObjectArray<Field>* sfields= GetFieldObject<ObjectArray<Field>*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false);
+ sfields->Set(i, f);
+ }
+
+ uint32_t GetReferenceStaticOffsets() const {
+ return GetField32(
+ OFFSET_OF_OBJECT_MEMBER(Class, reference_static_offsets_), false);
+ }
+
+ void SetReferenceStaticOffsets(uint32_t new_reference_offsets);
+
+ // Finds the given instance field in this class or a superclass.
+ Field* FindInstanceField(const StringPiece& name, Class* type);
+
+ Field* FindDeclaredInstanceField(const StringPiece& name, Class* type);
+
+ // Finds the given static field in this class or a superclass.
+ Field* FindStaticField(const StringPiece& name, Class* type);
+
+ Field* FindDeclaredStaticField(const StringPiece& name, Class* type);
+
+ uint32_t GetClinitThreadId() const {
+ DCHECK(IsIdxLoaded());
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), false);
+ }
+
+ void SetClinitThreadId(uint32_t new_clinit_thread_id) {
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_),
+ new_clinit_thread_id, false);
+ }
+
+ Class* GetVerifyErrorClass() const {
+ DCHECK(IsErroneous());
+ return GetFieldObject<Class*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), false);
}
void SetVerifyErrorClass(Class* klass) {
- // Note SetFieldObject is used rather than verify_error_class_ directly for the barrier
- size_t field_offset = OFFSETOF_MEMBER(Class, verify_error_class_);
- klass->SetFieldObject(field_offset, klass);
+ klass->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_),
+ klass, false);
+ }
+
+ const char* GetSourceFile() const {
+ DCHECK(IsLoaded());
+ return GetFieldPtr<const char*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, source_file_), false);
+ }
+
+ void SetSourceFile(const char* new_source_file) {
+ SetFieldPtr<const char*>(OFFSET_OF_OBJECT_MEMBER(Class, source_file_),
+ new_source_file, false);
}
private:
@@ -1285,7 +1906,10 @@
bool IsAssignableFromArray(const Class* klass) const;
bool IsSubClass(const Class* klass) const;
- public: // TODO: private
+ // TODO: the image writer should know the offsets of these fields as they
+ // should appear in the libcore Java mirror
+ friend class ImageWriter;
+
// descriptor for the class such as "java.lang.Class" or "[C"
String* name_; // TODO initialize
@@ -1416,56 +2040,210 @@
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Class);
};
+
std::ostream& operator<<(std::ostream& os, const Class::Status& rhs);
+inline void Object::SetClass(Class* new_klass) {
+ // new_klass may be NULL prior to class linker initialization
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Object, klass_), new_klass, false);
+}
+
inline bool Object::InstanceOf(const Class* klass) const {
DCHECK(klass != NULL);
- DCHECK(klass_ != NULL);
- return klass->IsAssignableFrom(klass_);
+ DCHECK(GetClass() != NULL);
+ return klass->IsAssignableFrom(GetClass());
}
inline bool Object::IsClass() const {
- Class* java_lang_Class = klass_->klass_;
- return klass_ == java_lang_Class;
+ Class* java_lang_Class = GetClass()->GetClass();
+ return GetClass() == java_lang_Class;
}
inline bool Object::IsClassClass() const {
- Class* java_lang_Class = klass_->klass_;
+ Class* java_lang_Class = GetClass()->GetClass();
return this == java_lang_Class;
}
inline bool Object::IsObjectArray() const {
- return IsArrayInstance() && !klass_->component_type_->IsPrimitive();
+ return IsArrayInstance() && !GetClass()->GetComponentType()->IsPrimitive();
}
inline bool Object::IsArrayInstance() const {
- return klass_->IsArrayClass();
+ return GetClass()->IsArrayClass();
}
inline bool Object::IsField() const {
Class* java_lang_Class = klass_->klass_;
- Class* java_lang_reflect_Field = java_lang_Class->GetInstanceField(0)->klass_;
- return klass_ == java_lang_reflect_Field;
+ Class* java_lang_reflect_Field =
+ java_lang_Class->GetInstanceField(0)->GetClass();
+ return GetClass() == java_lang_reflect_Field;
}
inline bool Object::IsMethod() const {
- Class* java_lang_Class = klass_->klass_;
- Class* java_lang_reflect_Method = java_lang_Class->GetDirectMethod(0)->klass_;
- return klass_ == java_lang_reflect_Method;
+ Class* java_lang_Class = GetClass()->GetClass();
+ Class* java_lang_reflect_Method =
+ java_lang_Class->GetDirectMethod(0)->GetClass();
+ return GetClass() == java_lang_reflect_Method;
+}
+
+inline bool Object::IsReferenceInstance() const {
+ return GetClass()->IsReferenceClass();
+}
+
+inline bool Object::IsWeakReferenceInstance() const {
+ return GetClass()->IsWeakReferenceClass();
+}
+
+inline bool Object::IsSoftReferenceInstance() const {
+ return GetClass()->IsSoftReferenceClass();
+}
+
+inline bool Object::IsFinalizerReferenceInstance() const {
+ return GetClass()->IsFinalizerReferenceClass();
+}
+
+inline bool Object::IsPhantomReferenceInstance() const {
+ return GetClass()->IsPhantomReferenceClass();
}
inline size_t Object::SizeOf() const {
+ size_t result;
if (IsArrayInstance()) {
- return AsArray()->SizeOf();
+ result = AsArray()->SizeOf();
+ } else if (IsClass()) {
+ result = AsClass()->SizeOf();
+ } else {
+ result = GetClass()->GetObjectSize();
}
- if (IsClass()) {
- return AsClass()->SizeOf();
+ DCHECK(!IsField() || result == sizeof(Field));
+ DCHECK(!IsMethod() || result == sizeof(Method));
+ return result;
+}
+
+inline void Field::SetOffset(MemberOffset num_bytes) {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK_LE(CLASS_SMALLEST_OFFSET, num_bytes.Uint32Value());
+ Class* type = GetTypeDuringLinking();
+ if (type != NULL && (type->IsPrimitiveDouble() || type->IsPrimitiveLong())) {
+ DCHECK(IsAligned(num_bytes.Uint32Value(), 8));
}
- return klass_->object_size_;
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_),
+ num_bytes.Uint32Value(), false);
+}
+
+inline Class* Field::GetDeclaringClass() const {
+ Class* result = GetFieldObject<Class*>(
+ OFFSET_OF_OBJECT_MEMBER(Field, declaring_class_), false);
+ DCHECK(result != NULL);
+ DCHECK(result->IsLoaded());
+ return result;
+}
+
+inline void Field::SetDeclaringClass(Class *new_declaring_class) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Field, declaring_class_),
+ new_declaring_class, false);
+}
+
+inline Class* Method::GetDeclaringClass() const {
+ Class* result =
+ GetFieldObject<Class*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_), false);
+ DCHECK(result != NULL);
+ DCHECK(result->IsLoaded());
+ return result;
+}
+
+inline void Method::SetDeclaringClass(Class *new_declaring_class) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_),
+ new_declaring_class, false);
+}
+
+inline uint32_t Method::GetReturnTypeIdx() const {
+ DCHECK(GetDeclaringClass()->IsLinked());
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, java_return_type_idx_),
+ false);
+}
+
+inline bool Method::IsReturnAReference() const {
+ return !GetReturnType()->IsPrimitive();
+}
+
+inline bool Method::IsReturnAFloat() const {
+ return GetReturnType()->IsPrimitiveFloat();
+}
+
+inline bool Method::IsReturnADouble() const {
+ return GetReturnType()->IsPrimitiveDouble();
+}
+
+inline bool Method::IsReturnALong() const {
+ return GetReturnType()->IsPrimitiveLong();
+}
+
+inline bool Method::IsReturnVoid() const {
+ return GetReturnType()->IsPrimitiveVoid();
}
inline size_t Array::SizeOf() const {
- return SizeOf(GetLength(), klass_->GetComponentSize());
+ return SizeOf(GetLength(), GetClass()->GetComponentSize());
+}
+
+template<class T>
+void ObjectArray<T>::Set(int32_t i, T* object) {
+ if (IsValidIndex(i)) {
+ if (object != NULL) {
+ Class* element_class = GetClass()->GetComponentType();
+ DCHECK(!element_class->IsPrimitive());
+ // TODO: ArrayStoreException
+ CHECK(object->InstanceOf(element_class));
+ }
+ MemberOffset data_offset(DataOffset().Int32Value() + i * sizeof(Object*));
+ SetFieldObject(data_offset, object, false);
+ }
+}
+
+template<class T>
+void ObjectArray<T>::SetWithoutChecks(int32_t i, T* object) {
+ DCHECK(IsValidIndex(i));
+ MemberOffset data_offset(DataOffset().Int32Value() + i * sizeof(Object*));
+ SetFieldObject(data_offset, object, false);
+}
+
+template<class T>
+void ObjectArray<T>::Copy(const ObjectArray<T>* src, int src_pos,
+ ObjectArray<T>* dst, int dst_pos,
+ size_t length) {
+ if (src->IsValidIndex(src_pos) &&
+ src->IsValidIndex(src_pos+length-1) &&
+ dst->IsValidIndex(dst_pos) &&
+ dst->IsValidIndex(dst_pos+length-1)) {
+ MemberOffset src_offset(DataOffset().Int32Value() +
+ src_pos * sizeof(Object*));
+ MemberOffset dst_offset(DataOffset().Int32Value() +
+ dst_pos * sizeof(Object*));
+ Class* array_class = dst->GetClass();
+ if (array_class == src->GetClass()) {
+ // No need for array store checks if arrays are of the same type
+ for (size_t i=0; i < length; i++) {
+ Object* object = src->GetFieldObject<Object*>(src_offset, false);
+ dst->SetFieldObject(dst_offset, object, false);
+ src_offset = MemberOffset(src_offset.Uint32Value() + sizeof(Object*));
+ dst_offset = MemberOffset(dst_offset.Uint32Value() + sizeof(Object*));
+ }
+ } else {
+ Class* element_class = array_class->GetComponentType();
+ CHECK(!element_class->IsPrimitive());
+ for (size_t i=0; i < length; i++) {
+ Object* object = src->GetFieldObject<Object*>(src_offset, false);
+ // TODO: ArrayStoreException
+ CHECK(object == NULL || object->InstanceOf(element_class));
+ dst->SetFieldObject(dst_offset, object, false);
+ src_offset = MemberOffset(src_offset.Uint32Value() + sizeof(Object*));
+ dst_offset = MemberOffset(dst_offset.Uint32Value() + sizeof(Object*));
+ }
+ }
+ // TODO: bulk write barrier
+ }
}
class ClassClass : public Class {
@@ -1563,145 +2341,105 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(PrimitiveArray);
};
+inline void Class::SetInterfacesTypeIdx(IntArray* new_interfaces_idx) {
+ DCHECK(NULL == GetFieldObject<IntArray*>(
+ OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_), false));
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_),
+ new_interfaces_idx, false);
+}
+
+// C++ mirror of java.lang.String
class String : public Object {
public:
const CharArray* GetCharArray() const {
- DCHECK(array_ != NULL);
- return array_;
- }
-
- uint32_t GetHashCode() const {
- return hash_code_;
+ const CharArray* result = GetFieldObject<const CharArray*>(
+ OFFSET_OF_OBJECT_MEMBER(String, array_), false);
+ DCHECK(result != NULL);
+ return result;
}
int32_t GetOffset() const {
- return offset_;
+ int32_t result = GetField32(
+ OFFSET_OF_OBJECT_MEMBER(String, offset_), false);
+ DCHECK_LE(0, result);
+ return result;
}
- int32_t GetLength() const {
- return count_;
+ int32_t GetLength() const;
+
+ int32_t GetHashCode() const;
+
+ void ComputeHashCode() {
+ SetHashCode(ComputeUtf16Hash(GetCharArray(), GetOffset(), GetLength()));
}
int32_t GetUtfLength() const {
- return CountUtf8Bytes(array_->GetData(), count_);
+ return CountUtf8Bytes(GetCharArray()->GetData(), GetLength());
}
- // TODO: do we need this? Equals is the only caller, and could
- // bounds check itself.
- uint16_t CharAt(int32_t index) const {
- if (index < 0 || index >= count_) {
- Thread* self = Thread::Current();
- self->ThrowNewException("Ljava/lang/StringIndexOutOfBoundsException;",
- "length=%i; index=%i", count_, index);
- return 0;
- }
- return GetCharArray()->Get(index + GetOffset());
- }
+ uint16_t CharAt(int32_t index) const;
+
+ const String* Intern() const;
static String* AllocFromUtf16(int32_t utf16_length,
const uint16_t* utf16_data_in,
- int32_t hash_code = 0) {
- String* string = Alloc(GetJavaLangString(),
- utf16_length);
- // TODO: use 16-bit wide memset variant
- for (int i = 0; i < utf16_length; i++ ) {
- string->array_->Set(i, utf16_data_in[i]);
- }
- if (hash_code != 0) {
- string->hash_code_ = hash_code;
- } else {
- string->ComputeHashCode();
- }
- return string;
- }
+ int32_t hash_code = 0);
- static String* AllocFromModifiedUtf8(const char* utf) {
- size_t char_count = CountModifiedUtf8Chars(utf);
- return AllocFromModifiedUtf8(char_count, utf);
- }
+ static String* AllocFromModifiedUtf8(const char* utf);
static String* AllocFromModifiedUtf8(int32_t utf16_length,
- const char* utf8_data_in) {
- String* string = Alloc(GetJavaLangString(), utf16_length);
- uint16_t* utf16_data_out = string->array_->GetData();
- ConvertModifiedUtf8ToUtf16(utf16_data_out, utf8_data_in);
- string->ComputeHashCode();
- return string;
+ const char* utf8_data_in);
+
+ static String* Alloc(Class* java_lang_String, int32_t utf16_length);
+
+ static String* Alloc(Class* java_lang_String, CharArray* array);
+
+ bool Equals(const char* modified_utf8) const;
+
+ // TODO: do we need this overload? give it a more intention-revealing name.
+ bool Equals(const StringPiece& modified_utf8) const;
+
+ bool Equals(const String* that) const;
+
+ // TODO: do we need this overload? give it a more intention-revealing name.
+ bool Equals(const uint16_t* that_chars, int32_t that_offset,
+ int32_t that_length) const;
+
+ // Create a modified UTF-8 encoded std::string from a java/lang/String object.
+ std::string ToModifiedUtf8() const;
+
+ static Class* GetJavaLangString() {
+ DCHECK(java_lang_String_ != NULL);
+ return java_lang_String_;
}
static void SetClass(Class* java_lang_String);
static void ResetClass();
- static String* Alloc(Class* java_lang_String, int32_t utf16_length) {
- return Alloc(java_lang_String, CharArray::Alloc(utf16_length));
- }
-
- static String* Alloc(Class* java_lang_String, CharArray* array) {
- String* string = down_cast<String*>(java_lang_String->AllocObject());
- string->array_ = array;
- string->count_ = array->GetLength();
- return string;
- }
-
- void ComputeHashCode() {
- hash_code_ = ComputeUtf16Hash(array_->GetData(), count_);
- }
-
- // TODO: do we need this overload? give it a more intention-revealing name.
- bool Equals(const char* modified_utf8) const {
- for (int32_t i = 0; i < GetLength(); ++i) {
- uint16_t ch = GetUtf16FromUtf8(&modified_utf8);
- if (ch == '\0' || ch != CharAt(i)) {
- return false;
- }
- }
- return *modified_utf8 == '\0';
- }
-
- // TODO: do we need this overload? give it a more intention-revealing name.
- bool Equals(const StringPiece& modified_utf8) const {
- // TODO: do not assume C-string representation.
- return Equals(modified_utf8.data());
- }
-
- bool Equals(const String* that) const {
- // TODO: short circuit on hash_code_
- if (this->GetLength() != that->GetLength()) {
- return false;
- }
- for (int32_t i = 0; i < that->GetLength(); ++i) {
- if (this->CharAt(i) != that->CharAt(i)) {
- return false;
- }
- }
- return true;
- }
-
- // TODO: do we need this overload? give it a more intention-revealing name.
- bool Equals(const uint16_t* that_chars, int32_t that_offset, int32_t that_length) const {
- if (this->GetLength() != that_length) {
- return false;
- }
- for (int32_t i = 0; i < that_length; ++i) {
- if (this->CharAt(i) != that_chars[that_offset + i]) {
- return false;
- }
- }
- return true;
- }
-
- // Create a modified UTF-8 encoded std::string from a java/lang/String object.
- std::string ToModifiedUtf8() const {
- uint16_t* chars = array_->GetData() + offset_;
- size_t byte_count(CountUtf8Bytes(chars, count_));
- std::string result(byte_count, char(0));
- ConvertUtf16ToModifiedUtf8(&result[0], chars, count_);
- return result;
- }
-
- const String* Intern() const;
-
private:
+ void SetHashCode(int32_t new_hash_code) {
+ DCHECK_EQ(0u,
+ GetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_), false));
+ SetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_),
+ new_hash_code, false);
+ }
+
+ void SetCount(int32_t new_count) {
+ DCHECK_LE(0, new_count);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count, false);
+ }
+
+ void SetOffset(int32_t new_offset) {
+ DCHECK_LE(0, new_offset);
+ DCHECK_GE(GetLength(), new_offset);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset, false);
+ }
+
+ void SetArray(CharArray* new_array) {
+ DCHECK(new_array != NULL);
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(String, array_), new_array, false);
+ }
+
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
CharArray* array_;
@@ -1711,16 +2449,129 @@
int32_t count_;
- static Class* GetJavaLangString() {
- DCHECK(java_lang_String_ != NULL);
- return java_lang_String_;
- }
-
static Class* java_lang_String_;
DISALLOW_IMPLICIT_CONSTRUCTORS(String);
};
+inline const String* Field::GetName() const {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ String* result =
+ GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Field, name_), false);
+ DCHECK(result != NULL);
+ return result;
+}
+
+inline void Field::SetName(String* new_name) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Field, name_),
+ new_name, false);
+
+}
+
+inline uint32_t Field::GetAccessFlags() const {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, access_flags_), false);
+}
+
+inline uint32_t Field::GetTypeIdx() const {
+ DCHECK(GetDeclaringClass()->IsIdxLoaded());
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, type_idx_), false);
+}
+
+inline MemberOffset Field::GetOffset() const {
+ DCHECK(GetDeclaringClass()->IsLinked());
+ return MemberOffset(
+ GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), false));
+}
+
+inline MemberOffset Field::GetOffsetDuringLinking() const {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ return MemberOffset(
+ GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), false));
+}
+
+inline const String* Method::GetName() const {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ const String* result =
+ GetFieldObject<const String*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, name_), false);
+ DCHECK(result != NULL);
+ return result;
+}
+
+inline void Method::SetName(String* new_name) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, name_),
+ new_name, false);
+
+}
+
+inline const char* Method::GetShorty() const {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ return GetFieldPtr<const char*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, shorty_), false);
+}
+
+inline const String* Method::GetSignature() const {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ const String* result =
+ GetFieldObject<const String*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, signature_), false);
+ DCHECK(result != NULL);
+ return result;
+}
+
+inline void Method::SetSignature(String* new_signature) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, signature_),
+ new_signature, false);
+}
+
+inline uint32_t Class::GetAccessFlags() const {
+ // Check class is loaded or this is java.lang.String that has a
+ // circularity issue during loading the names of its members
+ DCHECK(IsLoaded() || this == String::GetJavaLangString() ||
+ this == Field::GetJavaLangReflectField() ||
+ this == Method::GetJavaLangReflectMethod());
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), false);
+}
+
+inline void Class::SetDescriptor(String* new_descriptor) {
+ DCHECK(new_descriptor != NULL);
+ DCHECK_NE(0, new_descriptor->GetLength());
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, descriptor_),
+ new_descriptor, false);
+}
+
+inline uint32_t Method::GetAccessFlags() const {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), false);
+}
+
+inline uint16_t Method::GetMethodIndex() const {
+ DCHECK(GetDeclaringClass()->IsLinked());
+ return GetField16(OFFSET_OF_OBJECT_MEMBER(Method, method_index_), false);
+}
+
+inline uint16_t Method::NumRegisters() const {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ return GetField16(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_), false);
+}
+
+inline uint16_t Method::NumIns() const {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ return GetField16(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_), false);
+}
+
+inline uint16_t Method::NumOuts() const {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ return GetField16(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_), false);
+}
+
+inline uint32_t Method::GetProtoIdx() const {
+ DCHECK(GetDeclaringClass()->IsLoaded());
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, proto_idx_), false);
+}
+
+// C++ mirror of java.lang.Throwable
class Throwable : public Object {
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
@@ -1733,42 +2584,43 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Throwable);
};
+// C++ mirror of java.lang.StackTraceElement
class StackTraceElement : public Object {
public:
const String* GetDeclaringClass() const {
- return declaring_class_;
+ return GetFieldObject<const String*>(
+ OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_), false);
}
const String* GetMethodName() const {
- return method_name_;
+ return GetFieldObject<const String*>(
+ OFFSET_OF_OBJECT_MEMBER(StackTraceElement, method_name_), false);
}
const String* GetFileName() const {
- return file_name_;
+ return GetFieldObject<const String*>(
+ OFFSET_OF_OBJECT_MEMBER(StackTraceElement, file_name_), false);
}
int32_t GetLineNumber() const {
- return line_number_;
+ return GetField32(
+ OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_), false);
}
- static StackTraceElement* Alloc(const String* declaring_class, const String* method_name,
- const String* file_name, int32_t line_number) {
- StackTraceElement* trace = down_cast<StackTraceElement*>(GetStackTraceElement()->AllocObject());
- trace->declaring_class_ = declaring_class;
- trace->method_name_ = method_name;
- trace->file_name_ = file_name;
- trace->line_number_ = line_number;
- return trace;
- }
+ static StackTraceElement* Alloc(const String* declaring_class,
+ const String* method_name,
+ const String* file_name,
+ int32_t line_number);
static void SetClass(Class* java_lang_StackTraceElement);
static void ResetClass();
private:
+ // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
const String* declaring_class_;
- const String* method_name_;
const String* file_name_;
+ const String* method_name_;
int32_t line_number_;
static Class* GetStackTraceElement() {
@@ -1780,33 +2632,6 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(StackTraceElement);
};
-inline bool Object::IsString() const {
- // TODO use "klass_ == String::GetJavaLangString()" instead?
- return klass_ == klass_->descriptor_->klass_;
-}
-
-inline size_t Class::GetTypeSize(String* descriptor) {
- switch (descriptor->CharAt(0)) {
- case 'B': return 1; // byte
- case 'C': return 2; // char
- case 'D': return 8; // double
- case 'F': return 4; // float
- case 'I': return 4; // int
- case 'J': return 8; // long
- case 'S': return 2; // short
- case 'Z': return 1; // boolean
- case 'L': return sizeof(Object*);
- case '[': return sizeof(Array*);
- default:
- LOG(ERROR) << "Unknown type " << descriptor;
- return 0;
- }
-}
-
-inline bool Class::IsArrayClass() const {
- return array_rank_ != 0;
-}
-
class InterfaceEntry {
public:
InterfaceEntry() : interface_(NULL), method_index_array_(NULL) {
@@ -1822,17 +2647,23 @@
interface_ = interface;
}
+ uint32_t* GetMethodIndexArray() const {
+ return method_index_array_;
+ }
+
+ void SetMethodIndexArray(uint32_t* new_mia) {
+ method_index_array_ = new_mia;
+ }
+
private:
// Points to the interface class.
Class* interface_;
- public: // TODO: private
// Index into array of vtable offsets. This points into the
// ifvi_pool_, which holds the vtables for all interfaces declared by
// this class.
uint32_t* method_index_array_;
- private:
DISALLOW_COPY_AND_ASSIGN(InterfaceEntry);
};
diff --git a/src/object_test.cc b/src/object_test.cc
index f397b2e..d485c2e 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -18,7 +18,7 @@
void AssertString(int32_t length,
const char* utf8_in,
const char* utf16_expected_le,
- uint32_t hash_expected) {
+ int32_t expected_hash) {
uint16_t utf16_expected[length];
for (int32_t i = 0; i < length; i++) {
uint16_t ch = (((utf16_expected_le[i*2 + 0] & 0xff) << 8) |
@@ -35,7 +35,7 @@
for (int32_t i = 0; i < length; i++) {
EXPECT_EQ(utf16_expected[i], string->CharAt(i));
}
- EXPECT_EQ(hash_expected, string->GetHashCode());
+ EXPECT_EQ(expected_hash, string->GetHashCode());
}
uint32_t FindTypeIdxByDescriptor(const DexFile& dex_file, const StringPiece& descriptor) {
@@ -317,9 +317,9 @@
TEST_F(ObjectTest, StringHashCode) {
- EXPECT_EQ(0U, String::AllocFromModifiedUtf8("")->GetHashCode());
- EXPECT_EQ(65U, String::AllocFromModifiedUtf8("A")->GetHashCode());
- EXPECT_EQ(64578U, String::AllocFromModifiedUtf8("ABC")->GetHashCode());
+ EXPECT_EQ(0, String::AllocFromModifiedUtf8("")->GetHashCode());
+ EXPECT_EQ(65, String::AllocFromModifiedUtf8("A")->GetHashCode());
+ EXPECT_EQ(64578, String::AllocFromModifiedUtf8("ABC")->GetHashCode());
}
TEST_F(ObjectTest, InstanceOf) {
@@ -420,16 +420,16 @@
ASSERT_TRUE(c != NULL);
// Wrong type.
- EXPECT_TRUE(c->FindDeclaredInstanceField("count", "J") == NULL);
- EXPECT_TRUE(c->FindInstanceField("count", "J") == NULL);
+ EXPECT_TRUE(c->FindDeclaredInstanceField("count", class_linker_->FindSystemClass("J")) == NULL);
+ EXPECT_TRUE(c->FindInstanceField("count", class_linker_->FindSystemClass("J")) == NULL);
// Wrong name.
- EXPECT_TRUE(c->FindDeclaredInstanceField("Count", "I") == NULL);
- EXPECT_TRUE(c->FindInstanceField("Count", "I") == NULL);
+ EXPECT_TRUE(c->FindDeclaredInstanceField("Count", class_linker_->FindSystemClass("I")) == NULL);
+ EXPECT_TRUE(c->FindInstanceField("Count", class_linker_->FindSystemClass("I")) == NULL);
// Right name and type.
- Field* f1 = c->FindDeclaredInstanceField("count", "I");
- Field* f2 = c->FindInstanceField("count", "I");
+ Field* f1 = c->FindDeclaredInstanceField("count", class_linker_->FindSystemClass("I"));
+ Field* f2 = c->FindInstanceField("count", class_linker_->FindSystemClass("I"));
EXPECT_TRUE(f1 != NULL);
EXPECT_TRUE(f2 != NULL);
EXPECT_EQ(f1, f2);
@@ -440,9 +440,9 @@
c = class_linker_->FindSystemClass("Ljava/lang/StringBuilder;");
ASSERT_TRUE(c != NULL);
// No StringBuilder.count...
- EXPECT_TRUE(c->FindDeclaredInstanceField("count", "I") == NULL);
+ EXPECT_TRUE(c->FindDeclaredInstanceField("count", class_linker_->FindSystemClass("I")) == NULL);
// ...but there is an AbstractStringBuilder.count.
- EXPECT_TRUE(c->FindInstanceField("count", "I") != NULL);
+ EXPECT_TRUE(c->FindInstanceField("count", class_linker_->FindSystemClass("I")) != NULL);
}
TEST_F(ObjectTest, FindStaticField) {
@@ -452,16 +452,16 @@
ASSERT_TRUE(c != NULL);
// Wrong type.
- EXPECT_TRUE(c->FindDeclaredStaticField("CASE_INSENSITIVE_ORDER", "I") == NULL);
- EXPECT_TRUE(c->FindStaticField("CASE_INSENSITIVE_ORDER", "I") == NULL);
+ EXPECT_TRUE(c->FindDeclaredStaticField("CASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("I")) == NULL);
+ EXPECT_TRUE(c->FindStaticField("CASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("I")) == NULL);
// Wrong name.
- EXPECT_TRUE(c->FindDeclaredStaticField("cASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;") == NULL);
- EXPECT_TRUE(c->FindStaticField("cASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;") == NULL);
+ EXPECT_TRUE(c->FindDeclaredStaticField("cASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("Ljava/util/Comparator;")) == NULL);
+ EXPECT_TRUE(c->FindStaticField("cASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("Ljava/util/Comparator;")) == NULL);
// Right name and type.
- Field* f1 = c->FindDeclaredStaticField("CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
- Field* f2 = c->FindStaticField("CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
+ Field* f1 = c->FindDeclaredStaticField("CASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("Ljava/util/Comparator;"));
+ Field* f2 = c->FindStaticField("CASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("Ljava/util/Comparator;"));
EXPECT_TRUE(f1 != NULL);
EXPECT_TRUE(f2 != NULL);
EXPECT_EQ(f1, f2);
diff --git a/src/runtime.h b/src/runtime.h
index 9bb60d9..4ae15bf 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -57,7 +57,7 @@
}
private:
- ParsedOptions() {};
+ ParsedOptions() {}
};
// Creates and initializes a new runtime.
diff --git a/src/thread.cc b/src/thread.cc
index f5c1343..7f48fa1 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -146,7 +146,7 @@
void Frame::Next() {
byte* next_sp = reinterpret_cast<byte*>(sp_) +
GetMethod()->GetFrameSizeInBytes();
- sp_ = reinterpret_cast<const Method**>(next_sp);
+ sp_ = reinterpret_cast<Method**>(next_sp);
}
uintptr_t Frame::GetPC() const {
@@ -155,10 +155,10 @@
return *reinterpret_cast<uintptr_t*>(pc_addr);
}
-const Method* Frame::NextMethod() const {
+Method* Frame::NextMethod() const {
byte* next_sp = reinterpret_cast<byte*>(sp_) +
GetMethod()->GetFrameSizeInBytes();
- return *reinterpret_cast<const Method**>(next_sp);
+ return *reinterpret_cast<Method**>(next_sp);
}
void* ThreadStart(void *arg) {
@@ -285,8 +285,7 @@
}
Object* Thread::DecodeJObject(jobject obj) {
- // TODO: Only allowed to hold Object* when in the runnable state
- // DCHECK(state_ == kRunnable);
+ DCHECK(CanAccessDirectReferences());
if (obj == NULL) {
return NULL;
}
@@ -325,7 +324,7 @@
// TODO: make stack indirect reference table lookup more efficient
// Check if this is a local reference in the SIRT
if (SirtContains(obj)) {
- result = *reinterpret_cast<Object**>(obj); // Read from SIRT
+ result = *reinterpret_cast<Object**>(obj); // Read from SIRT
} else if (jni_env_->work_around_app_jni_bugs) {
// Assume an invalid local reference is actually a direct pointer.
result = reinterpret_cast<Object*>(obj);
@@ -363,8 +362,8 @@
class BuildStackTraceVisitor : public Thread::StackVisitor {
public:
- BuildStackTraceVisitor(int depth) : count(0) {
- method_trace = Runtime::Current()->GetClassLinker()->AllocObjectArray<const Method>(depth);
+ explicit BuildStackTraceVisitor(int depth) : count(0) {
+ method_trace = Runtime::Current()->GetClassLinker()->AllocObjectArray<Method>(depth);
pc_trace = IntArray::Alloc(depth);
}
@@ -389,7 +388,7 @@
private:
uint32_t count;
- ObjectArray<const Method>* method_trace;
+ ObjectArray<Method>* method_trace;
IntArray* pc_trace;
};
@@ -406,7 +405,7 @@
if (record == NULL) {
break;
}
- frame.SetSP(reinterpret_cast<const art::Method**>(record->last_top_of_managed_stack)); // last_tos should return Frame instead of sp?
+ frame.SetSP(reinterpret_cast<art::Method**>(record->last_top_of_managed_stack)); // last_tos should return Frame instead of sp?
record = record->link;
}
}
@@ -429,13 +428,12 @@
const Class* klass = method->GetDeclaringClass();
const DexFile& dex_file = class_linker->FindDexFile(klass->GetDexCache());
String* readable_descriptor = String::AllocFromModifiedUtf8(
- PrettyDescriptor(klass->GetDescriptor()).c_str()
- );
+ PrettyDescriptor(klass->GetDescriptor()).c_str());
StackTraceElement* obj =
StackTraceElement::Alloc(readable_descriptor,
method->GetName(),
- String::AllocFromModifiedUtf8(klass->source_file_),
+ String::AllocFromModifiedUtf8(klass->GetSourceFile()),
dex_file.GetLineNumFromPC(method,
method->ToDexPC(build_trace_visitor.GetPC(i))));
java_traces->Set(i, obj);
@@ -451,9 +449,9 @@
va_end(args);
// Convert "Ljava/lang/Exception;" into JNI-style "java/lang/Exception".
- CHECK(exception_class_descriptor[0] == 'L');
+ CHECK_EQ('L', exception_class_descriptor[0]);
std::string descriptor(exception_class_descriptor + 1);
- CHECK(descriptor[descriptor.length() - 1] == ';');
+ CHECK_EQ(';', descriptor[descriptor.length() - 1]);
descriptor.erase(descriptor.length() - 1);
JNIEnv* env = GetJniEnv();
@@ -506,7 +504,7 @@
exception_ = NULL;
intptr_t dex_pc = -1;
- const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->code_off_);
+ const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset());
DexFile::CatchHandlerIterator iter;
for (iter = dex_file.dexFindCatchHandler(*code_item,
method->ToDexPC(reinterpret_cast<intptr_t>(throw_pc)));
diff --git a/src/thread.h b/src/thread.h
index 6933962..87cfb6c 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -127,7 +127,7 @@
public:
Frame() : sp_(NULL) {}
- const Method* GetMethod() const {
+ Method* GetMethod() const {
return (sp_ != NULL) ? *sp_ : NULL;
}
@@ -139,22 +139,22 @@
uintptr_t GetPC() const;
- const Method** GetSP() const {
+ Method** GetSP() const {
return sp_;
}
// TODO: this is here for testing, remove when we have exception unit tests
// that use the real stack
- void SetSP(const Method** sp) {
+ void SetSP(Method** sp) {
sp_ = sp;
}
private:
- const Method* NextMethod() const;
+ Method* NextMethod() const;
friend class Thread;
- const Method** sp_;
+ Method** sp_;
};
class Thread {
@@ -221,7 +221,7 @@
class StackVisitor {
public:
- virtual ~StackVisitor() {};
+ virtual ~StackVisitor() {}
virtual bool VisitFrame(const Frame& frame) = 0;
};
@@ -238,6 +238,20 @@
void Dump(std::ostream& os) const;
+ State GetState() const {
+ return state_;
+ }
+
+ State SetState(State new_state) {
+ State old_state = state_;
+ state_ = new_state;
+ return old_state;
+ }
+
+ bool CanAccessDirectReferences() const {
+ return state_ == kRunnable;
+ }
+
uint32_t GetId() const {
return id_;
}
@@ -248,18 +262,30 @@
return handle_;
}
+ // Returns the Method* for the current method.
+ // This is used by the JNI implementation for logging and diagnostic purposes.
+ const Method* GetCurrentMethod() const {
+ return top_of_managed_stack_.GetMethod();
+ }
+
bool IsExceptionPending() const {
return exception_ != NULL;
}
Throwable* GetException() const {
+ DCHECK(CanAccessDirectReferences());
return exception_;
}
- // Returns the Method* for the current method.
- // This is used by the JNI implementation for logging and diagnostic purposes.
- const Method* GetCurrentMethod() const {
- return top_of_managed_stack_.GetMethod();
+ void SetException(Throwable* new_exception) {
+ DCHECK(CanAccessDirectReferences());
+ CHECK(new_exception != NULL);
+ // TODO: CHECK(exception_ == NULL);
+ exception_ = new_exception; // TODO
+ }
+
+ void ClearException() {
+ exception_ = NULL;
}
Frame GetTopOfStack() const {
@@ -269,13 +295,7 @@
// TODO: this is here for testing, remove when we have exception unit tests
// that use the real stack
void SetTopOfStack(void* stack) {
- top_of_managed_stack_.SetSP(reinterpret_cast<const Method**>(stack));
- }
-
- void SetException(Throwable* new_exception) {
- CHECK(new_exception != NULL);
- // TODO: CHECK(exception_ == NULL);
- exception_ = new_exception; // TODO
+ top_of_managed_stack_.SetSP(reinterpret_cast<Method**>(stack));
}
void ThrowNewException(const char* exception_class_descriptor, const char* fmt, ...)
@@ -284,10 +304,6 @@
// This exception is special, because we need to pre-allocate an instance.
void ThrowOutOfMemoryError();
- void ClearException() {
- exception_ = NULL;
- }
-
Frame FindExceptionHandler(void* throw_pc, void** handler_pc);
void* FindExceptionHandlerInMethod(const Method* method,
@@ -321,16 +337,6 @@
static bool Startup();
static void Shutdown();
- State GetState() const {
- return state_;
- }
-
- State SetState(State new_state) {
- State old_state = state_;
- state_ = new_state;
- return old_state;
- }
-
static ThreadOffset SuspendCountOffset() {
return ThreadOffset(OFFSETOF_MEMBER(Thread, suspend_count_));
}
@@ -402,10 +408,12 @@
}
void PopNativeToManagedRecord(const NativeToManagedRecord& record) {
native_to_managed_record_ = record.link;
- top_of_managed_stack_.SetSP( reinterpret_cast<const Method**>(record.last_top_of_managed_stack) );
+ top_of_managed_stack_.SetSP(reinterpret_cast<Method**>(record.last_top_of_managed_stack));
}
const ClassLoader* GetClassLoaderOverride() {
+ // TODO: need to place the class_loader_override_ in a handle
+ // DCHECK(CanAccessDirectReferences());
return class_loader_override_;
}
@@ -432,7 +440,7 @@
}
~Thread();
- friend class Runtime; // For ~Thread.
+ friend class Runtime; // For ~Thread.
void InitCpu();
void InitFunctionPointers();
diff --git a/src/utf.cc b/src/utf.cc
index 9356197..31fbe97 100644
--- a/src/utf.cc
+++ b/src/utf.cc
@@ -3,6 +3,7 @@
#include "utf.h"
#include "logging.h"
+#include "object.h"
namespace art {
@@ -51,6 +52,15 @@
}
}
+int32_t ComputeUtf16Hash(const CharArray* chars, int32_t offset,
+ size_t char_count) {
+ int32_t hash = 0;
+ for (size_t i = 0; i < char_count; i++) {
+ hash = hash * 31 + chars->Get(offset + i);
+ }
+ return hash;
+}
+
int32_t ComputeUtf16Hash(const uint16_t* chars, size_t char_count) {
int32_t hash = 0;
while (char_count--) {
@@ -59,6 +69,7 @@
return hash;
}
+
uint16_t GetUtf16FromUtf8(const char** utf8_data_in) {
uint8_t one = *(*utf8_data_in)++;
if ((one & 0x80) == 0) {
diff --git a/src/utf.h b/src/utf.h
index 2c22f87..7b9b90e 100644
--- a/src/utf.h
+++ b/src/utf.h
@@ -14,6 +14,9 @@
*/
namespace art {
+template<class T> class PrimitiveArray;
+typedef PrimitiveArray<uint16_t> CharArray;
+
/*
* Returns the number of UTF-16 characters in the given modified UTF-8 string.
*/
@@ -41,6 +44,7 @@
/*
* The java.lang.String hashCode() algorithm.
*/
+int32_t ComputeUtf16Hash(const CharArray* chars, int32_t offset, size_t char_count);
int32_t ComputeUtf16Hash(const uint16_t* chars, size_t char_count);
/*