diff options
Diffstat (limited to 'src')
42 files changed, 3119 insertions, 1618 deletions
diff --git a/src/assembler_arm.cc b/src/assembler_arm.cc index 60b8f38ae9..e613307cf9 100644 --- a/src/assembler_arm.cc +++ b/src/assembler_arm.cc @@ -1419,7 +1419,7 @@ void Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, 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 3037eea50f..8a30279683 100644 --- a/src/check_jni.cc +++ b/src/check_jni.cc @@ -360,34 +360,39 @@ public: 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 @@ public: } 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 36bf6a7300..9a6470b5d2 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::Create(const std::vector<const DexFile*>& boot_class_p 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 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path) { 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"); - // 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); - - // create storage for root classes, save away our work so far + // 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); + + // 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 (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 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path) { CHECK(dex_file != NULL); AppendToBootClassPath(*dex_file); } - // now we can use FindSystemClass, at least for non-arrays classes. - // 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); - 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); - 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); + // 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. + // 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->object_size_, sizeof(Object)); + 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->object_size_, sizeof(String)); + CHECK_EQ(java_lang_String->GetObjectSize(), 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 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)); - // Setup a single, global copy of "interfaces" and "iftable" for - // reuse across array classes + 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); - - 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); + // 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)); - // 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); + // 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); + // No sanity check on size as Class is variably sized - // 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)); + 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->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->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 @@ void ClassLinker::FinishInit() { 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 ClassLinker::InitCallbackState { 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 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, Space } // 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 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, Space 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 @@ void ClassLinker::InitCallback(Object* obj, void *arg) { return; } Class* klass = obj->AsClass(); - CHECK(klass->class_loader_ == NULL); + CHECK(klass->GetClassLoader() == NULL); std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8(); @@ -415,7 +468,7 @@ void ClassLinker::InitCallback(Object* obj, void *arg) { } // 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 @@ void ClassLinker::VisitRoots(Heap::RootVisitor* visitor, void* arg) const { { 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 @@ void ClassLinker::VisitRoots(Heap::RootVisitor* visitor, void* arg) const { ClassLinker::~ClassLinker() { delete classes_lock_; String::ResetClass(); + Field::ResetClass(); + Method::ResetClass(); BooleanArray::ResetArrayClass(); ByteArray::ResetArrayClass(); CharArray::ResetArrayClass(); @@ -478,7 +533,8 @@ CodeAndDirectMethods* ClassLinker::AllocCodeAndDirectMethods(size_t length) { 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 @@ Class* ClassLinker::FindClass(const StringPiece& descriptor, } 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 @@ Class* ClassLinker::FindClass(const StringPiece& descriptor, } 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 @@ Class* ClassLinker::FindClass(const StringPiece& descriptor, 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 @@ void ClassLinker::LoadClass(const DexFile& dex_file, 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; - - // Make sure the aren't any "bonus" flags set, since we use them for runtime state. - CHECK_EQ(klass->access_flags_ & ~kAccClassFlagsMask, 0U); + 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); - 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 @@ void ClassLinker::LoadClass(const DexFile& dex_file, } // 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 @@ void ClassLinker::LoadClass(const DexFile& dex_file, } // 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 @@ void ClassLinker::LoadClass(const DexFile& dex_file, } // 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 @@ void ClassLinker::LoadInterfaces(const DexFile& dex_file, 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 @@ void ClassLinker::LoadField(const DexFile& dex_file, 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 @@ void ClassLinker::LoadMethod(const DexFile& dex_file, 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->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->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->SetSignature(String::AllocFromModifiedUtf8(utf16_length, utf8.c_str())); + } + 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->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 @@ DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) const { 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 @@ Class* ClassLinker::CreatePrimitiveClass(const char* descriptor) { // // 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 @@ Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor, // 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* ClassLinker::CreateArrayClass(const StringPiece& descriptor, 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 @@ Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor, 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 @@ Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor, // 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 @@ Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor, // (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 @@ bool ClassLinker::InsertClass(const StringPiece& descriptor, Class* klass) { 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 @@ bool ClassLinker::InitializeClass(Class* klass) { 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 @@ bool ClassLinker::InitializeClass(Class* klass) { 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 @@ bool ClassLinker::InitializeClass(Class* klass) { 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 @@ bool ClassLinker::ValidateSuperClassDescriptors(const Class* klass) { } } } - 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 @@ bool ClassLinker::HasSameMethodDescriptorClasses(const Method* method, 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 @@ void ClassLinker::InitializeStaticFields(Class* klass) { } } -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 @@ bool ClassLinker::LinkClass(Class* klass, const DexFile& dex_file) { } 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 @@ bool ClassLinker::LinkSuperClass(Class* klass) { } // 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 @@ bool ClassLinker::LinkMethods(Class* klass) { 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::LinkMethods(Class* klass) { 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 @@ bool ClassLinker::LinkVirtualMethods(Class* klass) { 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 @@ bool ClassLinker::LinkVirtualMethods(Class* klass) { 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 @@ bool ClassLinker::LinkInterfaceMethods(Class* klass) { 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 @@ bool ClassLinker::LinkInterfaceMethods(Class* klass) { 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 @@ bool ClassLinker::LinkInterfaceMethods(Class* klass) { } } // 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 @@ bool ClassLinker::LinkInterfaceMethods(Class* klass) { 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 @@ void ClassLinker::LinkAbstractMethods(Class* klass) { 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 @@ bool ClassLinker::LinkFields(size_t field_offset, } 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 @@ bool ClassLinker::LinkFields(size_t field_offset, // 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 @@ bool ClassLinker::LinkFields(size_t field_offset, // 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 @@ bool ClassLinker::LinkFields(size_t field_offset, 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 @@ void ClassLinker::CreateReferenceOffsets(uint32_t& reference_offsets, 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 @@ Class* ClassLinker::ResolveType(const DexFile& dex_file, 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 @@ Field* ClassLinker::ResolveField(const DexFile& dex_file, } 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 3f95b8d7bd..f63ab3c90b 100644 --- a/src/class_linker.h +++ b/src/class_linker.h @@ -45,7 +45,7 @@ class ClassLinker { // 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 @@ class ClassLinker { } // 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 @@ class ClassLinker { 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 @@ class ClassLinker { 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 @@ class ClassLinker { 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 @@ class ClassLinker { 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 @@ class ClassLinker { 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 a34f180b90..6f894e3492 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 @@ class ClassLinkerTest : public CommonTest { 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 @@ class ClassLinkerTest : public CommonTest { 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 @@ class ClassLinkerTest : public CommonTest { 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 @@ class ClassLinkerTest : public CommonTest { 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 @@ class ClassLinkerTest : public CommonTest { 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 @@ TEST_F(ClassLinkerTest, FindClass) { 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 @@ TEST_F(ClassLinkerTest, FindClass) { 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 @@ TEST_F(ClassLinkerTest, ValidateFieldOrderOfJavaCppUnionClasses) { 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 @@ TEST_F(ClassLinkerTest, ValidateObjectArrayElementsOffset) { 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 @@ TEST_F(ClassLinkerTest, StaticFields) { 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 da19539be0..3309a8a629 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 @@ class ClassLoader : public Object { 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 @@ class BaseDexClassLoader : public ClassLoader { 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 c79cea6e10..5318008c9b 100644 --- a/src/common_test.h +++ b/src/common_test.h @@ -89,6 +89,8 @@ class CommonTest : public testing::Test { 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 @@ class CommonTest : public testing::Test { 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 5cfddc0546..4e3c9c4398 100644 --- a/src/compiler/Dataflow.cc +++ b/src/compiler/Dataflow.cc @@ -2092,11 +2092,11 @@ bool oatDoSSAConversion(CompilationUnit* cUnit, BasicBlock* bb) * 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 @@ bool oatDoConstantPropagation(CompilationUnit* cUnit, BasicBlock* bb) 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 9ef2b4fe51..dbd06abe8c 100644 --- a/src/compiler/Frontend.cc +++ b/src/compiler/Frontend.cc @@ -733,7 +733,7 @@ bool oatCompileMethod(Method* method, art::InstructionSet insnSet) 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 @@ bool oatCompileMethod(Method* method, art::InstructionSet insnSet) } /* 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 a4ab76f028..6a4e663e7d 100644 --- a/src/compiler/Ralloc.cc +++ b/src/compiler/Ralloc.cc @@ -119,9 +119,9 @@ void oatSimpleRegAlloc(CompilationUnit* cUnit) } /* 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 42e855de29..95f6db5f9a 100644 --- a/src/compiler/SSATransformation.cc +++ b/src/compiler/SSATransformation.cc @@ -107,8 +107,8 @@ static void computeDefBlockMatrix(CompilationUnit* cUnit) * 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 d643a9065f..dc8bdec806 100644 --- a/src/compiler/codegen/arm/ArchUtility.cc +++ b/src/compiler/codegen/arm/ArchUtility.cc @@ -407,7 +407,7 @@ void oatCodegenDump(CompilationUnit* cUnit) " 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 6223512f16..78d5267c61 100644 --- a/src/compiler/codegen/arm/ArmRallocUtil.cc +++ b/src/compiler/codegen/arm/ArmRallocUtil.cc @@ -94,7 +94,7 @@ static void countRefs(CompilationUnit *cUnit, BasicBlock* bb, 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 @@ static void countRefs(CompilationUnit *cUnit, BasicBlock* bb, } 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 @@ static void dumpCounts(const RefCounts* arr, int size, const char* msg) */ 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 c69a27e77c..8caf0d145a 100644 --- a/src/compiler/codegen/arm/MethodCodegenDriver.cc +++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc @@ -404,12 +404,12 @@ static int nextSDCallInsnSP(CompilationUnit* cUnit, MIR* mir, 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 @@ static int nextSDCallInsnSP(CompilationUnit* cUnit, MIR* mir, 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 @@ static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir, 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 @@ static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir, // 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 @@ static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir, 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 @@ static int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir, * 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 @@ static void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir) * 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 @@ static void flushIns(CompilationUnit* cUnit) } // 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 11146f7ba7..c4a1fed931 100644 --- a/src/compiler/codegen/arm/Thumb2/Gen.cc +++ b/src/compiler/codegen/arm/Thumb2/Gen.cc @@ -389,7 +389,7 @@ static void genIGetX(CompilationUnit* cUnit, MIR* mir, OpSize size, #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 @@ static void genIPutX(CompilationUnit* cUnit, MIR* mir, OpSize size, #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 @@ static void genIGetWideX(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, #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 @@ static void genIPutWideX(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc, #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 genIPutWideX(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc, 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 @@ static void genConstString(CompilationUnit* cUnit, MIR* mir, 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 @@ static void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, /* 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 @@ static void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) * 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 @@ static void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, 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 @@ static void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, 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 @@ static void genMonitorExit(CompilationUnit* cUnit, MIR* mir, 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 @@ static void genMonitorExit(CompilationUnit* cUnit, MIR* mir, 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 @@ static void genArrayObjPut(CompilationUnit* cUnit, MIR* mir, 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 f2cfcc7972..137f267761 100644 --- a/src/dex_cache.h +++ b/src/dex_cache.h @@ -109,11 +109,11 @@ class DexCache : public ObjectArray<Object> { 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 @@ class DexCache : public ObjectArray<Object> { 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 3d66909d75..c8e7c704ed 100644 --- a/src/dex_file.cc +++ b/src/dex_file.cc @@ -543,11 +543,11 @@ String* DexFile::dexArtStringById(int32_t idx) const { 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 @@ void DexFile::dexDecodeDebugInfo0(const CodeItem* code_item, const art::Method* 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 0e62b258bd..f257e78a63 100644 --- a/src/dex_verifier.cc +++ b/src/dex_verifier.cc @@ -655,7 +655,7 @@ bool DexVerify::VerifyMethod(Method* method) { 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 @@ bool DexVerify::VerifyMethod(Method* method) { /* * 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 @@ bool DexVerify::VerifyMethod(Method* method) { * TODO: Code flow analysis */ - delete insn_flags; return true; } diff --git a/src/exception_test.cc b/src/exception_test.cc index 3611b6722d..439e7edd54 100644 --- a/src/exception_test.cc +++ b/src/exception_test.cc @@ -74,18 +74,18 @@ class ExceptionTest : public CommonTest { 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 @@ class ExceptionTest : public CommonTest { }; 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 @@ TEST_F(ExceptionTest, StackTraceElement) { 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 1682cc580a..cb5e0dc748 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -31,11 +31,11 @@ HeapBitmap* Heap::mark_bitmap_ = NULL; 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 @@ bool Heap::Init(size_t initial_size, size_t maximum_size, const char* boot_image 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 @@ void Heap::Destroy() { 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 @@ bool Heap::IsHeapAddress(const Object* obj) { 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::RecordFree(Space* space, const Object* obj) { 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 6420a2ad8f..bc06289d51 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 @@ class Heap { // 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 @@ class Heap { 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 @@ class Heap { 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 @@ class Heap { 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 568ddd2830..53489e454d 100644 --- a/src/heap_test.cc +++ b/src/heap_test.cc @@ -6,9 +6,9 @@ namespace art { 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 b03cbe3584..fd88b20848 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 @@ namespace art { 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 887be66f4b..e0e77c70d3 100644 --- a/src/image_writer.cc +++ b/src/image_writer.cc @@ -118,6 +118,8 @@ void ImageWriter::CalculateNewObjectOffsets() { 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::CopyAndFixupObjectsCallback(Object* object, void *arg) { 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 @@ void ImageWriter::FixupMethod(const Method* orig, Method* copy) { // 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::FixupField(const Field* orig, Field* copy) { 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 @@ void ImageWriter::FixupFields(const Object* orig, // 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 @@ void ImageWriter::FixupFields(const Object* orig, 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 80012bcef6..b63effeb36 100644 --- a/src/image_writer.h +++ b/src/image_writer.h @@ -30,13 +30,13 @@ class ImageWriter { // 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 43335ac205..e45519e4b9 100644 --- a/src/java_lang_System.cc +++ b/src/java_lang_System.cc @@ -183,7 +183,7 @@ void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject // 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 @@ void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject // 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 adc87da84b..238b9ef350 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 3ffc184de9..254fbdf079 100644 --- a/src/jni_compiler_test.cc +++ b/src/jni_compiler_test.cc @@ -349,9 +349,12 @@ TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) { 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 @@ TEST_F(JniCompilerTest, SuspendCountAcknowledgement) { 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 @@ TEST_F(JniCompilerTest, ExceptionHandling) { 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 @@ jint Java_MyClass_nativeUpCall(JNIEnv* env, jobject thisObj, jint i) { 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 36787d8b2b..125401eec5 100644 --- a/src/jni_internal.cc +++ b/src/jni_internal.cc @@ -346,12 +346,26 @@ jfieldID FindFieldID(ScopedJniThreadState& ts, jclass jni_class, const char* nam } Field* field = NULL; + 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_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, sig); + field = c->FindStaticField(name, field_type); } else { - field = c->FindInstanceField(name, sig); + field = c->FindInstanceField(name, field_type); } - if (field == NULL) { Thread* self = Thread::Current(); std::string class_descriptor(c->GetDescriptor()->ToModifiedUtf8()); @@ -360,7 +374,9 @@ jfieldID FindFieldID(ScopedJniThreadState& ts, jclass jni_class, const char* nam 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 0d19c1cfb5..6b4162bc79 100644 --- a/src/jni_internal_arm.cc +++ b/src/jni_internal_arm.cc @@ -49,7 +49,7 @@ void CreateInvokeStub(Assembler* assembler, Method* method) { 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 @@ void CreateInvokeStub(Assembler* assembler, Method* method) { __ 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 @@ void CreateInvokeStub(Assembler* assembler, Method* method) { } // 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 3e3e3814e8..e82b7348dd 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 @@ TEST_F(JniInternalTest, DISABLED_NewDirectBuffer_GetDirectBufferAddress_GetDirec ASSERT_TRUE(env_->GetDirectBufferCapacity(buffer) == sizeof(bytes)); } -} +} // namespace art diff --git a/src/jni_internal_x86.cc b/src/jni_internal_x86.cc index ad30accd98..782ff66b19 100644 --- a/src/jni_internal_x86.cc +++ b/src/jni_internal_x86.cc @@ -60,7 +60,7 @@ void CreateInvokeStub(Assembler* assembler, Method* method) { 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 @@ void CreateInvokeStub(Assembler* assembler, Method* method) { break; } } - __ popl(EDI); // restore EDI + __ popl(EDI); // restore EDI __ ret(); } diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc index af7f1a5015..ac9a7cd65a 100644 --- a/src/mark_sweep.cc +++ b/src/mark_sweep.cc @@ -191,8 +191,8 @@ void MarkSweep::ScanFields(const Object* obj, // 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 @@ void MarkSweep::ScanFields(const Object* obj, 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::ScanArray(const Object* obj) { 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 @@ void MarkSweep::DelayReferenceReferent(Object* obj) { 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 @@ void MarkSweep::ScanOther(const Object* obj) { DCHECK(klass != NULL); MarkObject(klass); ScanInstanceFields(obj); - if (klass->IsReference()) { + if (klass->IsReferenceClass()) { DelayReferenceReferent(const_cast<Object*>(obj)); } } @@ -366,20 +367,22 @@ void MarkSweep::ScanDirtyObjects() { 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 @@ void MarkSweep::PreserveSomeSoftReferences(Object** list) { 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 @@ void MarkSweep::PreserveSomeSoftReferences(Object** list) { // 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 @@ void MarkSweep::ClearWhiteReferences(Object** list) { // 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 f20cc416bf..841d8191cc 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 cdc0e69100..39d3c25dcd 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,198 +20,40 @@ 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); - } - return array; -} - -Array* Array::Alloc(Class* array_class, int32_t component_count) { - return Alloc(array_class, component_count, array_class->GetComponentSize()); +bool Object::IsString() const { + // TODO use "klass_ == String::GetJavaLangString()" instead? + return GetClass() == GetClass()->GetDescriptor()->GetClass(); } -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; - } - } - return Array::Alloc(klass, component_count); -} +// TODO: get global references for these +Class* Field::java_lang_reflect_Field_ = NULL; -Object* Class::AllocObjectFromCode(uint32_t type_idx, Method* method) { - Class* klass = method->dex_cache_resolved_types_->Get(type_idx); - if (klass == NULL) { - klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method); - if (klass == NULL) { - UNIMPLEMENTED(FATAL) << "throw an error"; - return NULL; - } - } - return klass->AllocObject(); +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; } -Object* Class::AllocObject() { - DCHECK(!IsAbstract()); - return Heap::AllocObject(this, this->object_size_); +void Field::ResetClass() { + CHECK(java_lang_reflect_Field_ != NULL); + java_lang_reflect_Field_ = NULL; } -bool Class::CanPutArrayElementFromCode(const Class* elementClass, const Class* arrayClass) { - UNIMPLEMENTED(FATAL); - return false; +void Field::SetTypeIdx(uint32_t type_idx) { + SetField32(OFFSET_OF_OBJECT_MEMBER(Field, type_idx_), type_idx, false); } -bool Class::Implements(const Class* klass) const { - DCHECK(klass != NULL); - DCHECK(klass->IsInterface()); - // All interfaces implemented directly and by our superclass, and - // recursively all super-interfaces of those interfaces, are listed - // in iftable_, so we can just do a linear scan through that. - for (size_t i = 0; i < iftable_count_; i++) { - if (iftable_[i].GetInterface() == klass) { - return true; - } - } - return 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()); } -// Determine whether "this" is assignable from "klazz", where both of these -// are array classes. -// -// Consider an array class, e.g. Y[][], where Y is a subclass of X. -// Y[][] = Y[][] --> true (identity) -// X[][] = Y[][] --> true (element superclass) -// Y = Y[][] --> false -// Y[] = Y[][] --> false -// Object = Y[][] --> true (everything is an object) -// Object[] = Y[][] --> true -// Object[][] = Y[][] --> true -// Object[][][] = Y[][] --> false (too many []s) -// Serializable = Y[][] --> true (all arrays are Serializable) -// Serializable[] = Y[][] --> true -// Serializable[][] = Y[][] --> false (unless Y is Serializable) -// -// Don't forget about primitive types. -// int[] instanceof Object[] --> false -// -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_) { - // Too many []s. - return false; - } - if (array_rank_ == klass->array_rank_) { - return component_type_->IsAssignableFrom(klass->component_type_); - } - DCHECK_LT(array_rank_, klass->array_rank_); - // 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()) { - // 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_); - } - // 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); -} - -bool Class::IsAssignableFromArray(const Class* klass) const { - DCHECK(!IsInterface()); // handled first in IsAssignableFrom - DCHECK(klass->IsArrayClass()); - if (!IsArrayClass()) { - // If "this" is not also an array, it must be Object. - // klass's super should be java_lang_Object, since it is an array. - Class* java_lang_Object = klass->GetSuperClass(); - DCHECK(java_lang_Object != NULL); - DCHECK(java_lang_Object->GetSuperClass() == NULL); - return this == java_lang_Object; - } - return IsArrayAssignableFromArray(klass); -} - -bool Class::IsSubClass(const Class* klass) const { - DCHECK(!IsInterface()); - DCHECK(!klass->IsArrayClass()); - const Class* current = this; - do { - if (current == klass) { - return true; - } - current = current->GetSuperClass(); - } while (current != NULL); - return false; -} - -bool Class::IsInSamePackage(const String* descriptor_string_1, - const String* descriptor_string_2) { - const std::string descriptor1(descriptor_string_1->ToModifiedUtf8()); - const std::string descriptor2(descriptor_string_2->ToModifiedUtf8()); - - size_t i = 0; - while (descriptor1[i] != '\0' && descriptor1[i] == descriptor2[i]) { - ++i; - } - if (descriptor1.find('/', i) != StringPiece::npos || - descriptor2.find('/', i) != StringPiece::npos) { - return false; - } else { - return true; - } -} - -#if 0 -bool Class::IsInSamePackage(const StringPiece& descriptor1, - const StringPiece& descriptor2) { - size_t size = std::min(descriptor1.size(), descriptor2.size()); - std::pair<StringPiece::const_iterator, StringPiece::const_iterator> pos; - pos = std::mismatch(descriptor1.begin(), descriptor1.begin() + size, - descriptor2.begin()); - return !(*(pos.second).rfind('/') != npos && descriptor2.rfind('/') != npos); -} -#endif - -bool Class::IsInSamePackage(const Class* that) const { - const Class* klass1 = this; - const Class* klass2 = that; - if (klass1 == klass2) { - return true; - } - // Class loaders must match. - if (klass1->GetClassLoader() != klass2->GetClassLoader()) { - return false; - } - // Arrays are in the same package when their element classes are. - if (klass1->IsArrayClass()) { - klass1 = klass1->GetComponentType(); - } - if (klass2->IsArrayClass()) { - klass2 = klass2->GetComponentType(); - } - // Compare the package part of the descriptor string. - return IsInSamePackage(klass1->descriptor_, klass2->descriptor_); +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) { @@ -217,6 +62,7 @@ uint32_t Field::Get32StaticFromCode(uint32_t field_idx, const Method* referrer) UNIMPLEMENTED(FATAL) << "throw an error"; return 0; } + 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) { @@ -225,6 +71,7 @@ void Field::Set32StaticFromCode(uint32_t field_idx, const Method* referrer, uint 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) { @@ -233,6 +80,7 @@ uint64_t Field::Get64StaticFromCode(uint32_t field_idx, const Method* referrer) 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) { @@ -241,6 +89,7 @@ void Field::Set64StaticFromCode(uint32_t field_idx, const Method* referrer, uint 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) { @@ -249,6 +98,7 @@ Object* Field::GetObjStaticFromCode(uint32_t field_idx, const Method* referrer) 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) { @@ -257,6 +107,7 @@ void Field::SetObjStaticFromCode(uint32_t field_idx, const Method* referrer, Obj UNIMPLEMENTED(FATAL) << "throw an error"; return; } + DCHECK(!field->GetType()->IsPrimitive()); field->SetObj(NULL, new_value); } @@ -265,8 +116,7 @@ uint32_t Field::Get32(const Object* object) const { if (IsStatic()) { object = declaring_class_; } - // TODO: volatile - return object->GetField32(GetOffset()); + return object->GetField32(GetOffset(), IsVolatile()); } void Field::Set32(Object* object, uint32_t new_value) const { @@ -274,8 +124,7 @@ void Field::Set32(Object* object, uint32_t new_value) const { if (IsStatic()) { object = declaring_class_; } - // TODO: volatile - object->SetField32(GetOffset(), new_value); + object->SetField32(GetOffset(), new_value, IsVolatile()); } uint64_t Field::Get64(const Object* object) const { @@ -283,8 +132,7 @@ uint64_t Field::Get64(const Object* object) const { if (IsStatic()) { object = declaring_class_; } - // TODO: volatile - return object->GetField64(GetOffset()); + return object->GetField64(GetOffset(), IsVolatile()); } void Field::Set64(Object* object, uint64_t new_value) const { @@ -292,8 +140,7 @@ void Field::Set64(Object* object, uint64_t new_value) const { if (IsStatic()) { object = declaring_class_; } - // TODO: volatile - object->SetField64(GetOffset(), new_value); + object->SetField64(GetOffset(), new_value, IsVolatile()); } Object* Field::GetObj(const Object* object) const { @@ -301,8 +148,7 @@ Object* Field::GetObj(const Object* object) const { if (IsStatic()) { object = declaring_class_; } - // TODO: volatile - return object->GetFieldObject(GetOffset()); + return object->GetFieldObject<Object*>(GetOffset(), IsVolatile()); } void Field::SetObj(Object* object, const Object* new_value) const { @@ -310,113 +156,208 @@ void Field::SetObj(Object* object, const Object* new_value) const { if (IsStatic()) { object = declaring_class_; } - // TODO: volatile - object->SetFieldObject(GetOffset(), new_value); + object->SetFieldObject(GetOffset(), new_value, IsVolatile()); } bool Field::GetBoolean(const Object* object) const { - CHECK_EQ(GetType(), 'Z'); + DCHECK(GetType()->IsPrimitiveBoolean()); return Get32(object); } void Field::SetBoolean(Object* object, bool z) const { - CHECK_EQ(GetType(), 'Z'); + DCHECK(GetType()->IsPrimitiveBoolean()); Set32(object, z); } int8_t Field::GetByte(const Object* object) const { - CHECK_EQ(GetType(), 'B'); + DCHECK(GetType()->IsPrimitiveByte()); return Get32(object); } void Field::SetByte(Object* object, int8_t b) const { - CHECK_EQ(GetType(), 'B'); + DCHECK(GetType()->IsPrimitiveByte()); Set32(object, b); } uint16_t Field::GetChar(const Object* object) const { - CHECK_EQ(GetType(), 'C'); + DCHECK(GetType()->IsPrimitiveChar()); return Get32(object); } void Field::SetChar(Object* object, uint16_t c) const { - CHECK_EQ(GetType(), 'C'); + DCHECK(GetType()->IsPrimitiveChar()); Set32(object, c); } uint16_t Field::GetShort(const Object* object) const { - CHECK_EQ(GetType(), 'S'); + DCHECK(GetType()->IsPrimitiveShort()); return Get32(object); } void Field::SetShort(Object* object, uint16_t s) const { - CHECK_EQ(GetType(), 'S'); + DCHECK(GetType()->IsPrimitiveShort()); Set32(object, s); } int32_t Field::GetInt(const Object* object) const { - CHECK_EQ(GetType(), 'I'); + DCHECK(GetType()->IsPrimitiveInt()); return Get32(object); } void Field::SetInt(Object* object, int32_t i) const { - CHECK_EQ(GetType(), 'I'); + DCHECK(GetType()->IsPrimitiveInt()); Set32(object, i); } int64_t Field::GetLong(const Object* object) const { - CHECK_EQ(GetType(), 'J'); + DCHECK(GetType()->IsPrimitiveLong()); return Get64(object); } void Field::SetLong(Object* object, int64_t j) const { - CHECK_EQ(GetType(), 'J'); + DCHECK(GetType()->IsPrimitiveLong()); Set64(object, j); } float Field::GetFloat(const Object* object) const { - CHECK_EQ(GetType(), 'F'); + DCHECK(GetType()->IsPrimitiveFloat()); JValue float_bits; float_bits.i = Get32(object); return float_bits.f; } void Field::SetFloat(Object* object, float f) const { - CHECK_EQ(GetType(), 'F'); + DCHECK(GetType()->IsPrimitiveFloat()); JValue float_bits; float_bits.f = f; Set32(object, float_bits.i); } double Field::GetDouble(const Object* object) const { - CHECK_EQ(GetType(), 'D'); + DCHECK(GetType()->IsPrimitiveDouble()); JValue double_bits; double_bits.j = Get64(object); return double_bits.d; } void Field::SetDouble(Object* object, double d) const { - CHECK_EQ(GetType(), 'D'); + DCHECK(GetType()->IsPrimitiveDouble()); JValue double_bits; double_bits.d = d; Set64(object, double_bits.j); } Object* Field::GetObject(const Object* object) const { - CHECK(GetType() == 'L' || GetType() == '['); + CHECK(!GetType()->IsPrimitive()); return GetObj(object); } void Field::SetObject(Object* object, const Object* l) const { - CHECK(GetType() == 'L' || GetType() == '['); + CHECK(!GetType()->IsPrimitive()); SetObj(object, l); } -uint32_t Method::NumArgRegisters() const { - CHECK(shorty_ != NULL); +// 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]; + for (int i = 1; i < shorty.length(); ++i) { + char ch = shorty[i]; if (ch == 'D' || ch == 'J') { num_registers += 2; } else { @@ -429,7 +370,7 @@ uint32_t Method::NumArgRegisters() const { size_t Method::NumArgArrayBytes() const { const StringPiece& shorty = GetShorty(); size_t num_bytes = 0; - for (int i = 1; i < shorty.size(); ++i) { + for (int i = 1; i < shorty.length(); ++i) { char ch = shorty[i]; if (ch == 'D' || ch == 'J') { num_bytes += 8; @@ -447,9 +388,10 @@ size_t Method::NumArgArrayBytes() const { // 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] == '[')) { + for (int i = 1; i < shorty.length(); i++) { + if ((shorty[i] == 'L') || (shorty[i] == '[')) { result++; } } @@ -458,9 +400,10 @@ size_t Method::NumReferenceArgs() const { // 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')) { + for (int i = 1; i < shorty.length(); i++) { + if ((shorty[i] == 'D') || (shorty[i] == 'J')) { result++; } } @@ -470,11 +413,12 @@ size_t Method::NumLongOrDoubleArgs() const { // 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()) && + for (unsigned int i = 1; (i < (unsigned int)shorty.length()) && (i < (param + 1)); i++) { - if ((shorty_[i] == 'L') || (shorty_[i] == '[')) { + if (shorty[i] == 'L') { result++; } } @@ -489,7 +433,7 @@ bool Method::IsParamAReference(unsigned int param) const { } else if (param == 0) { return true; // this argument } - return ((shorty_[param] == 'L') || (shorty_[param] == '[')); + return GetShorty()[param] == 'L'; } // Is the given method parameter a long or double? @@ -500,7 +444,7 @@ bool Method::IsParamALongOrDouble(unsigned int param) const { } else if (param == 0) { return false; // this argument } - return (shorty_[param] == 'J') || (shorty_[param] == 'D'); + return (GetShorty()[param] == 'J') || (GetShorty()[param] == 'D'); } static size_t ShortyCharToSize(char x) { @@ -521,11 +465,11 @@ size_t Method::ParamSize(unsigned int param) const { } else if (param == 0) { return kPointerSize; // this argument } - return ShortyCharToSize(shorty_[param]); + return ShortyCharToSize(GetShorty()[param]); } size_t Method::ReturnSize() const { - return ShortyCharToSize(shorty_[0]); + return ShortyCharToSize(GetShorty()[0]); } bool Method::HasSameNameAndDescriptor(const Method* that) const { @@ -533,6 +477,278 @@ bool Method::HasSameNameAndDescriptor(const Method* that) const { 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->GetDexCacheResolvedTypes()->Get(type_idx); + if (klass == NULL) { + klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method); + if (klass == NULL) { + UNIMPLEMENTED(FATAL) << "throw an error"; + return NULL; + } + } + return klass->AllocObject(); +} + +Object* Class::AllocObject() { + DCHECK(!IsAbstract()); + return Heap::AllocObject(this, this->object_size_); +} + +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 { + DCHECK(klass != NULL); + DCHECK(klass->IsInterface()); + // All interfaces implemented directly and by our superclass, and + // recursively all super-interfaces of those interfaces, are listed + // in iftable_, so we can just do a linear scan through that. + for (size_t i = 0; i < iftable_count_; i++) { + if (iftable_[i].GetInterface() == klass) { + return true; + } + } + 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. +// +// Consider an array class, e.g. Y[][], where Y is a subclass of X. +// Y[][] = Y[][] --> true (identity) +// X[][] = Y[][] --> true (element superclass) +// Y = Y[][] --> false +// Y[] = Y[][] --> false +// Object = Y[][] --> true (everything is an object) +// Object[] = Y[][] --> true +// Object[][] = Y[][] --> true +// Object[][][] = Y[][] --> false (too many []s) +// Serializable = Y[][] --> true (all arrays are Serializable) +// Serializable[] = Y[][] --> true +// Serializable[][] = Y[][] --> false (unless Y is Serializable) +// +// Don't forget about primitive types. +// int[] instanceof Object[] --> false +// +bool Class::IsArrayAssignableFromArray(const Class* klass) const { + DCHECK(IsArrayClass()); + DCHECK(klass->IsArrayClass()); + 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 (GetArrayRank() == klass->GetArrayRank()) { + return GetComponentType()->IsAssignableFrom(klass->GetComponentType()); + } + 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 (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(GetComponentType()); + } + // See if this is an array of Object, Object[], etc. + return GetComponentType()->IsObjectClass(); +} + +bool Class::IsAssignableFromArray(const Class* klass) const { + DCHECK(!IsInterface()); // handled first in IsAssignableFrom + DCHECK(klass->IsArrayClass()); + if (!IsArrayClass()) { + // If "this" is not also an array, it must be Object. + // klass's super should be java_lang_Object, since it is an array. + Class* java_lang_Object = klass->GetSuperClass(); + DCHECK(java_lang_Object != NULL); + DCHECK(java_lang_Object->GetSuperClass() == NULL); + return this == java_lang_Object; + } + return IsArrayAssignableFromArray(klass); +} + +bool Class::IsSubClass(const Class* klass) const { + DCHECK(!IsInterface()); + DCHECK(!klass->IsArrayClass()); + const Class* current = this; + do { + if (current == klass) { + return true; + } + current = current->GetSuperClass(); + } while (current != NULL); + return false; +} + +bool Class::IsInSamePackage(const String* descriptor_string_1, + const String* descriptor_string_2) { + const std::string descriptor1(descriptor_string_1->ToModifiedUtf8()); + const std::string descriptor2(descriptor_string_2->ToModifiedUtf8()); + + size_t i = 0; + while (descriptor1[i] != '\0' && descriptor1[i] == descriptor2[i]) { + ++i; + } + if (descriptor1.find('/', i) != StringPiece::npos || + descriptor2.find('/', i) != StringPiece::npos) { + return false; + } else { + return true; + } +} + +#if 0 +bool Class::IsInSamePackage(const StringPiece& descriptor1, + const StringPiece& descriptor2) { + size_t size = std::min(descriptor1.size(), descriptor2.size()); + std::pair<StringPiece::const_iterator, StringPiece::const_iterator> pos; + pos = std::mismatch(descriptor1.begin(), descriptor1.begin() + size, + descriptor2.begin()); + return !(*(pos.second).rfind('/') != npos && descriptor2.rfind('/') != npos); +} +#endif + +bool Class::IsInSamePackage(const Class* that) const { + const Class* klass1 = this; + const Class* klass2 = that; + if (klass1 == klass2) { + return true; + } + // Class loaders must match. + if (klass1->GetClassLoader() != klass2->GetClassLoader()) { + return false; + } + // Arrays are in the same package when their element classes are. + if (klass1->IsArrayClass()) { + klass1 = klass1->GetComponentType(); + } + if (klass2->IsArrayClass()) { + klass2 = klass2->GetComponentType(); + } + // Compare the package part of the descriptor string. + return IsInSamePackage(klass1->descriptor_, klass2->descriptor_); +} + +const ClassLoader* Class::GetClassLoader() const { + return GetFieldObject<const ClassLoader*>( + OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), false); +} + +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) { Class* declaring_class = method->GetDeclaringClass(); DCHECK(declaring_class->IsInterface()); @@ -540,7 +756,8 @@ Method* Class::FindVirtualMethodForInterface(Method* method) { 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 @@ Method* Class::FindVirtualMethod(const StringPiece& name, 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 @@ Field* Class::FindInstanceField(const StringPiece& name, const StringPiece& desc 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 @@ Field* Class::FindStaticField(const StringPiece& name, const StringPiece& descri // 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 @@ Field* Class::FindStaticField(const StringPiece& name, const StringPiece& descri 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 @@ void String::SetClass(Class* java_lang_String) { 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 @@ const String* String::Intern() const { 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 @@ void StackTraceElement::ResetClass() { 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 bc6e7e515b..5a47c46d73 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 @@ static const uint32_t kAccReferenceFlagsMask = (kAccClassIsReference * 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 @@ class Object { return object->InstanceOf(klass); } + static MemberOffset ClassOffset() { + return OFFSET_OF_OBJECT_MEMBER(Object, klass_); + } + Class* GetClass() const { - DCHECK(klass_ != NULL); - return klass_; + 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 @@ class Object { 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 @@ class Object { 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 @@ class ObjectLock { 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 @@ class Field : public AccessibleObject { 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); + + 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(); - public: // TODO: private + 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 @@ class Field : public AccessibleObject { 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_; + + static Class* java_lang_reflect_Field_; - private: 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 @@ class Method : public AccessibleObject { 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_; + void SetDeclaringClass(Class *new_declaring_class); + + static MemberOffset DeclaringClassOffset() { + return MemberOffset(OFFSETOF_MEMBER(Method, declaring_class_)); } - Class* GetDeclaringClass() const { - DCHECK(declaring_class_ != NULL); - return 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); } - static MemberOffset DeclaringClassOffset() { - return MemberOffset(OFFSETOF_MEMBER(Method, declaring_class_)); + 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,90 +671,126 @@ class Method : public AccessibleObject { // 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; - // Number of argument bytes required for densely packing the - // arguments into an array of arguments. - size_t NumArgArrayBytes() const; + size_t GetVtableIndex() const { + return GetMethodIndex(); + } - // 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; + void SetMethodIndex(uint16_t new_method_index) { + SetField16(OFFSET_OF_OBJECT_MEMBER(Method, method_index_), + new_method_index, 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; + static MemberOffset MethodIndexOffset() { + return OFFSET_OF_OBJECT_MEMBER(Method, method_index_); } - 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_; + uint32_t GetCodeItemOffset() const { + return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, code_item_offset_), false); + } - const StringPiece& GetShorty() const { - return shorty_; + void SetCodeItemOffset(uint32_t new_code_off) { + SetField32(OFFSET_OF_OBJECT_MEMBER(Method, code_item_offset_), + new_code_off, false); } - bool IsReturnAReference() const { - return (shorty_[0] == 'L') || (shorty_[0] == '['); + // 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; + + uint16_t NumRegisters() const; + + void SetNumRegisters(uint16_t new_num_registers) { + SetField16(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_), + new_num_registers, false); } - bool IsReturnAFloatOrDouble() const { - return (shorty_[0] == 'F') || (shorty_[0] == 'D'); + uint16_t NumIns() const; + + void SetNumIns(uint16_t new_num_ins) { + SetField16(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_), + new_num_ins, false); } - bool IsReturnAFloat() const { - return shorty_[0] == 'F'; + uint16_t NumOuts() const; + + void SetNumOuts(uint16_t new_num_outs) { + SetField16(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_), + new_num_outs, false); } - bool IsReturnADouble() const { - return shorty_[0] == 'D'; + uint32_t GetProtoIdx() const; + + void SetProtoIdx(uint32_t new_proto_idx) { + SetField32(OFFSET_OF_OBJECT_MEMBER(Method, proto_idx_), new_proto_idx, false); } - bool IsReturnALong() const { - return shorty_[0] == 'J'; + ObjectArray<String>* GetDexCacheStrings() const; + void SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings); + + static MemberOffset DexCacheStringsOffset() { + return OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_strings_); } - bool IsReturnVoid() const { - return shorty_[0] == 'V'; + 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 IsReturnAFloat() || IsReturnADouble(); } + bool IsReturnALong() const; + + bool IsReturnVoid() const; + // "Args" may refer to any of the 3 levels of "Args." // To avoid confusion, our code will denote which "Args" clearly: // 1. UserArgs: Args that a user see. @@ -607,7 +806,7 @@ class Method : public AccessibleObject { 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 @@ class Method : public AccessibleObject { // 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); - - 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); - } + InstructionSet set); - 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_; - } - - size_t GetReturnPcOffsetInBytes() const { - return return_pc_offset_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 SetCoreSpillMask(uint32_t core_spill_mask) { - core_spill_mask_ = core_spill_mask; + 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); } - static size_t GetCodeOffset() { - return OFFSETOF_MEMBER(Method, code_); + size_t GetReturnPcOffsetInBytes() const { + DCHECK(sizeof(size_t) == sizeof(uint32_t)); + return GetField32( + OFFSET_OF_OBJECT_MEMBER(Method, return_pc_offset_in_bytes_), false); } - 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); + } + + 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 - public: // TODO: private/const // access flags; low 16 bits are defined by spec (could be uint16_t?) uint32_t access_flags_; @@ -758,14 +1004,17 @@ class Method : public AccessibleObject { 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 @@ class Method : public AccessibleObject { // 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 @@ class Method : public AccessibleObject { // Native invocation stub entry point. const InvokeStub* invoke_stub_; + static Class* java_lang_reflect_Method_; + DISALLOW_IMPLICIT_CONSTRUCTORS(Method); }; @@ -816,19 +1068,20 @@ class Array : public Object { 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 @@ class Array : public Object { 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 @@ class Class : public Object, public StaticStorageBase { // 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,210 +1202,422 @@ class Class : public Object, public StaticStorageBase { }; enum PrimitiveType { - kPrimNot = -1 + kPrimNot = 0, + kPrimBoolean, + kPrimByte, + kPrimChar, + kPrimShort, + kPrimInt, + kPrimLong, + kPrimFloat, + kPrimDouble, + kPrimVoid, }; - // Given the context of a calling Method, use its DexCache to - // resolve a type to a Class. If it cannot be resolved, throw an - // error. If it can, use it to create an instance. - static Object* AllocObjectFromCode(uint32_t type_idx, Method* method); + Status GetStatus() const { + CHECK(sizeof(Status) == sizeof(uint32_t)); + return static_cast<Status>( + GetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), false)); + } - // Creates a raw object instance but does not invoke the default constructor. - Object* AllocObject(); + void SetStatus(Status new_status); - Class* GetSuperClass() const { - return super_class_; + // Returns true if the class has failed to link. + bool IsErroneous() const { + return GetStatus() == kStatusError; } - uint32_t GetSuperClassTypeIdx() const { - return super_class_type_idx_; + // Returns true if the class has been loaded. + bool IsIdxLoaded() const { + return GetStatus() >= kStatusIdx; } - bool HasSuperClass() const { - return super_class_ != NULL; + // Returns true if the class has been loaded. + bool IsLoaded() const { + return GetStatus() >= kStatusLoaded; } - 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); + // Returns true if the class has been linked. + bool IsLinked() const { + return GetStatus() >= kStatusResolved; } - const ClassLoader* GetClassLoader() const { - return class_loader_; + // Returns true if the class has been verified. + bool IsVerified() const { + return GetStatus() >= kStatusVerified; } - DexCache* GetDexCache() const { - return dex_cache_; + // Returns true if the class is initialized. + bool IsInitialized() const { + return GetStatus() == kStatusInitialized; } - Class* GetComponentType() const { - return component_type_; + uint32_t GetAccessFlags() const; + + void SetAccessFlags(uint32_t new_access_flags) { + SetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags, + false); } - static size_t GetTypeSize(String* descriptor); + // Returns true if the class is an interface. + bool IsInterface() const { + return (GetAccessFlags() & kAccInterface) != 0; + } - size_t GetComponentSize() const { - return GetTypeSize(component_type_->descriptor_); + // Returns true if the class is declared public. + bool IsPublic() const { + return (GetAccessFlags() & kAccPublic) != 0; } - const String* GetDescriptor() const { - DCHECK(descriptor_ != NULL); - // DCHECK_NE(0, descriptor_->GetLength()); // TODO: keep? - return descriptor_; + // Returns true if the class is declared final. + bool IsFinal() const { + return (GetAccessFlags() & kAccFinal) != 0; } - size_t SizeOf() const { - return class_size_; + // Returns true if the class is abstract. + bool IsAbstract() const { + return (GetAccessFlags() & kAccAbstract) != 0; } - Status GetStatus() const { - return status_; + // Returns true if the class is an annotation. + bool IsAnnotation() const { + return (GetAccessFlags() & kAccAnnotation) != 0; } - void SetStatus(Status new_status) { - // TODO: validate transition - status_ = new_status; + // Returns true if the class is synthetic. + bool IsSynthetic() const { + return (GetAccessFlags() & kAccSynthetic) != 0; } - // Returns true if the class has failed to link. - bool IsErroneous() const { - return GetStatus() == kStatusError; + bool IsReferenceClass() const { + return (GetAccessFlags() & kAccClassIsReference) != 0; } - // Returns true if the class has been verified. - bool IsVerified() const { - return GetStatus() >= kStatusVerified; + bool IsWeakReferenceClass() const { + return (GetAccessFlags() & kAccClassIsWeakReference) != 0; } - // Returns true if the class has been linked. - bool IsLinked() const { - return GetStatus() >= kStatusResolved; + bool IsSoftReferenceClass() const { + return (GetAccessFlags() & ~kAccReferenceFlagsMask) == kAccClassIsReference; } - // Returns true if the class has been loaded. - bool IsLoaded() const { - return GetStatus() >= kStatusLoaded; + bool IsFinalizerReferenceClass() const { + return (GetAccessFlags() & kAccClassIsFinalizerReference) != 0; } - // Returns true if the class is initialized. - bool IsInitialized() const { - return GetStatus() == kStatusInitialized; + bool IsPhantomReferenceClass() const { + return (GetAccessFlags() & kAccClassIsPhantomReference) != 0; } - // Returns true if this class is in the same packages as that class. - bool IsInSamePackage(const Class* that) const; + PrimitiveType GetPrimitiveType() const { + CHECK(sizeof(PrimitiveType) == sizeof(int32_t)); + return static_cast<PrimitiveType>( + GetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), false)); + } - static bool IsInSamePackage(const String* descriptor1, - const String* descriptor2); + 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 this class represents an array class. - bool IsArrayClass() const; + // Returns true if the class is a primitive type. + bool IsPrimitive() const { + return GetPrimitiveType() != kPrimNot; + } - // Returns true if the class is an interface. - bool IsInterface() const { - return (access_flags_ & kAccInterface) != 0; + bool IsPrimitiveBoolean() const { + return GetPrimitiveType() == kPrimBoolean; } - // Returns true if the class is declared public. - bool IsPublic() const { - return (access_flags_ & kAccPublic) != 0; + bool IsPrimitiveByte() const { + return GetPrimitiveType() == kPrimByte; } - // Returns true if the class is declared final. - bool IsFinal() const { - return (access_flags_ & kAccFinal) != 0; + bool IsPrimitiveChar() const { + return GetPrimitiveType() == kPrimChar; } - // Returns true if the class is abstract. - bool IsAbstract() const { - return (access_flags_ & kAccAbstract) != 0; + bool IsPrimitiveShort() const { + return GetPrimitiveType() == kPrimShort; } - // Returns true if the class is an annotation. - bool IsAnnotation() const { - return (access_flags_ & kAccAnnotation) != 0; + bool IsPrimitiveInt() const { + return GetPrimitiveType() == kPrimInt; } - // Returns true if the class is a primitive type. - bool IsPrimitive() const { - return primitive_type_ != kPrimNot; + bool IsPrimitiveLong() const { + return GetPrimitiveType() == kPrimLong; } - // Returns true if the class is synthetic. - bool IsSynthetic() const { - return (access_flags_ & kAccSynthetic) != 0; + 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); } - bool IsReference() const { - return (access_flags_ & kAccClassIsReference) != 0; + 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. + static Object* AllocObjectFromCode(uint32_t type_idx, Method* method); + + // Creates a raw object instance but does not invoke the default constructor. + Object* AllocObject(); + + static size_t GetTypeSize(const String* descriptor); + + const String* GetDescriptor() const { + 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 { + CHECK(sizeof(size_t) == sizeof(int32_t)); + return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), false); } - bool IsWeakReference() const { - return (access_flags_ & kAccClassIsWeakReference) != 0; + size_t GetClassSize() const { + CHECK(sizeof(size_t) == sizeof(uint32_t)); + return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), false); } - bool IsSoftReference() const { - return (access_flags_ & ~kAccReferenceFlagsMask) == kAccClassIsReference; + 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); } - bool IsFinalizerReference() const { - return (access_flags_ & kAccClassIsFinalizerReference) != 0; + 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; } - bool IsPhantomReference() const { - return (access_flags_ & kAccClassIsPhantomReference) != 0; + 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. + bool IsInSamePackage(const Class* that) const; + + static bool IsInSamePackage(const String* descriptor1, + const String* descriptor2); + // 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 @@ class Class : public Object, public StaticStorageBase { 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 @@ class Class : public Object, public StaticStorageBase { 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); + + Method* FindDirectMethod(const StringPiece& name, + const StringPiece& signature); + + size_t NumInterfaces() const { + CHECK(IsIdxLoaded()); // used during loading + ObjectArray<Class>* interfaces = GetFieldObject<ObjectArray<Class>*>( + OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false); + return (interfaces != NULL) ? interfaces->GetLength() : 0; } - // Returns the number of instance fields containing reference types. - size_t NumReferenceInstanceFields() const { - return num_reference_instance_fields_; + IntArray* GetInterfacesTypeIdx() const { + CHECK(IsIdxLoaded()); + return GetFieldObject<IntArray*>( + OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_), false); } - // Returns the number of static fields containing reference types. - size_t NumReferenceStaticFields() const { - return num_reference_static_fields_; + void SetInterfacesTypeIdx(IntArray* new_interfaces_idx); + + ObjectArray<Class>* GetInterfaces() const { + CHECK(IsLoaded()); + return GetFieldObject<ObjectArray<Class>*>( + OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false); } - // Finds the given instance field in this class or a superclass. - Field* FindInstanceField(const StringPiece& name, - const StringPiece& descriptor); + 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); + } - // Finds the given instance field in this class. - Field* FindDeclaredInstanceField(const StringPiece& name, - const StringPiece& descriptor); + void SetInterface(uint32_t i, Class* f) { // TODO: uint16_t + DCHECK_NE(NumInterfaces(), 0U); + ObjectArray<Class>* interfaces = + GetFieldObject<ObjectArray<Class>*>( + OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false); + interfaces->Set(i, f); + } - // Finds the given static field in this class or a superclass. - Field* FindStaticField(const StringPiece& name, - const StringPiece& descriptor); + 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); + } - // Finds the given static field in this class. - Field* FindDeclaredStaticField(const StringPiece& name, - const StringPiece& descriptor); + 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 ifields_->Get(i); + return GetIFields()->Get(i); } void SetInstanceField(uint32_t i, Field* f) { // TODO: uint16_t - DCHECK_NE(NumInstanceFields(), 0U); - ifields_->Set(i, f); + ObjectArray<Field>* ifields= GetFieldObject<ObjectArray<Field>*>( + OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false); + ifields->Set(i, f); } - size_t NumStaticFields() const { - return (sfields_ != NULL) ? sfields_->GetLength() : 0; + // 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); } - Field* GetStaticField(uint32_t i) const { // TODO: uint16_t - DCHECK_NE(NumStaticFields(), 0U); - return sfields_->Get(i); + 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 SetStaticField(uint32_t i, Field* f) { // TODO: uint16_t - DCHECK_NE(NumStaticFields(), 0U); - sfields_->Set(i, f); + 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 { - return reference_instance_offsets_; + DCHECK(IsLinked()); + return GetField32( + OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_), false); } - void SetReferenceInstanceOffsets(uint32_t new_reference_offsets) { - reference_instance_offsets_ = new_reference_offsets; + void SetReferenceInstanceOffsets(uint32_t new_reference_offsets); + + // Beginning of static field data + static MemberOffset FieldsOffset() { + return OFFSET_OF_OBJECT_MEMBER(Class, fields_); } - uint32_t GetReferenceStaticOffsets() const { - return reference_static_offsets_; + // 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); } - void SetReferenceStaticOffsets(uint32_t new_reference_offsets) { - reference_static_offsets_ = new_reference_offsets; + 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); } - size_t NumInterfaces() const { - return (interfaces_ != NULL) ? interfaces_->GetLength() : 0; + 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); } - Class* GetInterface(uint32_t i) const { - DCHECK_NE(NumInterfaces(), 0U); - return interfaces_->Get(i); + ObjectArray<Field>* GetSFields() const { + DCHECK(IsLoaded()); + return GetFieldObject<ObjectArray<Field>*>( + OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false); } - void SetInterface(uint32_t i, Class* f) { // TODO: uint16_t - DCHECK_NE(NumInterfaces(), 0U); - interfaces_->Set(i, f); + 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 @@ class Class : public Object, public StaticStorageBase { 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 @@ class Class : public Object, public StaticStorageBase { 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(); - } - if (IsClass()) { - return AsClass()->SizeOf(); + result = AsArray()->SizeOf(); + } else if (IsClass()) { + result = AsClass()->SizeOf(); + } else { + result = GetClass()->GetObjectSize(); + } + 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 @@ class PrimitiveArray : public Array { 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 void SetClass(Class* java_lang_String); - static void ResetClass(); + static String* Alloc(Class* java_lang_String, int32_t utf16_length); - 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); - 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_); - } + bool Equals(const char* modified_utf8) const; // 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'; - } + 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 StringPiece& modified_utf8) const { - // TODO: do not assume C-string representation. - return Equals(modified_utf8.data()); + 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_; } - 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; + static void SetClass(Class* java_lang_String); + static void ResetClass(); + + 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); } - // 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; + void SetCount(int32_t new_count) { + DCHECK_LE(0, new_count); + SetField32(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count, false); } - // 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; + 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); } - const String* Intern() const; + void SetArray(CharArray* new_array) { + DCHECK(new_array != NULL); + SetFieldObject(OFFSET_OF_OBJECT_MEMBER(String, array_), new_array, false); + } - private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". CharArray* array_; @@ -1711,16 +2449,129 @@ class String : public Object { 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 @@ class Throwable : public Object { 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 @@ class StackTraceElement : public Object { 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 @@ class InterfaceEntry { 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 f397b2e506..d485c2e59d 100644 --- a/src/object_test.cc +++ b/src/object_test.cc @@ -18,7 +18,7 @@ class ObjectTest : public CommonTest { 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 @@ class ObjectTest : public CommonTest { 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, DescriptorCompare) { 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 @@ TEST_F(ObjectTest, FindInstanceField) { 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 @@ TEST_F(ObjectTest, FindInstanceField) { 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 @@ TEST_F(ObjectTest, FindStaticField) { 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 9bb60d92b8..4ae15bf762 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -57,7 +57,7 @@ class Runtime { } private: - ParsedOptions() {}; + ParsedOptions() {} }; // Creates and initializes a new runtime. diff --git a/src/thread.cc b/src/thread.cc index f5c1343c4c..7f48fa1637 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -146,7 +146,7 @@ void Mutex::Unlock() { 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 @@ uintptr_t Frame::GetPC() const { 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 @@ bool Thread::SirtContains(jobject obj) { } 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 @@ Object* Thread::DecodeJObject(jobject obj) { // 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 CountStackDepthVisitor : public Thread::StackVisitor { 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 @@ class BuildStackTraceVisitor : public Thread::StackVisitor { private: uint32_t count; - ObjectArray<const Method>* method_trace; + ObjectArray<Method>* method_trace; IntArray* pc_trace; }; @@ -406,7 +405,7 @@ void Thread::WalkStack(StackVisitor* visitor) { 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 @@ ObjectArray<StackTraceElement>* Thread::AllocStackTrace() { 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 @@ void Thread::ThrowNewException(const char* exception_class_descriptor, const cha 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 @@ void* Thread::FindExceptionHandlerInMethod(const Method* method, 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 6933962764..87cfb6c5d5 100644 --- a/src/thread.h +++ b/src/thread.h @@ -127,7 +127,7 @@ class Frame { public: Frame() : sp_(NULL) {} - const Method* GetMethod() const { + Method* GetMethod() const { return (sp_ != NULL) ? *sp_ : NULL; } @@ -139,22 +139,22 @@ class Frame { 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 Thread { class StackVisitor { public: - virtual ~StackVisitor() {}; + virtual ~StackVisitor() {} virtual bool VisitFrame(const Frame& frame) = 0; }; @@ -238,6 +238,20 @@ class Thread { 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 @@ class Thread { 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 @@ class Thread { // 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 @@ class Thread { // 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 @@ class Thread { 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 @@ class Thread { } 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 @@ class Thread { } ~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 9356197d64..31fbe97da0 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 @@ void ConvertUtf16ToModifiedUtf8(char* utf8_out, const uint16_t* utf16_in, size_t } } +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 @@ int32_t ComputeUtf16Hash(const uint16_t* chars, size_t char_count) { return hash; } + uint16_t GetUtf16FromUtf8(const char** utf8_data_in) { uint8_t one = *(*utf8_data_in)++; if ((one & 0x80) == 0) { @@ -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 @@ void ConvertUtf16ToModifiedUtf8(char* utf8_out, const uint16_t* utf16_in, size_t /* * 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); /* |