Fix GarbageCollector to work with VERIFY_OBJECT_ENABLED
There were two problems with the GC:
1.) roots were being missed for most of the C++ fields
2.) Heap::RecordFree(Object) was not being called, only Space::Free
To solve #1, added all C++ shadow fields to libcore.
This involed updating dalvik to cope with the new sizes and offsets.
This had the positive side effect of allowing a lot of special cases
in the object scanning and image writing.
To solve #2, added a call to the now public Heap::RecordFree from MarkSweep
Given the now better working GC:
- Reenabled HeapTest.GarbageCollectClassLinkerInit which is now passing.
- ImageWriter now GC's before writing an image to avoid garbage.
Change-Id: Ie7d1cc89e0bcf314cb37f0cabcb8593bf6e4d4be
diff --git a/src/class_linker.cc b/src/class_linker.cc
index b533a11..0df0cb7 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -102,7 +102,6 @@
object_array_class->SetArrayRank(1);
object_array_class->SetComponentType(java_lang_Object);
-
// Setup the char[] class to be used for String
Class* char_array_class = AllocClass(java_lang_Class, sizeof(Class));
char_array_class->SetArrayRank(1);
@@ -256,7 +255,6 @@
// 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
@@ -264,14 +262,10 @@
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;");
@@ -1076,7 +1070,11 @@
}
DCHECK_LE(1, new_class->GetArrayRank());
DCHECK(new_class->GetComponentType() != NULL);
- new_class->SetDescriptor(String::AllocFromModifiedUtf8(descriptor.ToString().c_str()));
+ if (new_class->GetDescriptor() != NULL) {
+ DCHECK(new_class->GetDescriptor()->Equals(descriptor));
+ } else {
+ new_class->SetDescriptor(String::AllocFromModifiedUtf8(descriptor.ToString().c_str()));
+ }
Class* java_lang_Object = GetClassRoot(kJavaLangObject);
new_class->SetSuperClass(java_lang_Object);
new_class->SetVTable(java_lang_Object->GetVTable());
@@ -1844,26 +1842,21 @@
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();
+ size_t size;
+ MemberOffset field_offset(0);
if (instance) {
Class* super_class = klass->GetSuperClass();
if (super_class != NULL) {
CHECK(super_class->IsResolved());
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();
+ field_offset = Class::FieldsOffset();
}
- DCHECK_LE(CLASS_SMALLEST_OFFSET, size);
CHECK((num_fields == 0) == (fields == NULL));
@@ -1993,7 +1986,6 @@
}
#endif
size = field_offset.Uint32Value();
- DCHECK_LE(CLASS_SMALLEST_OFFSET, size);
// Update klass
if(instance) {
klass->SetNumReferenceInstanceFields(num_reference_fields);
@@ -2041,7 +2033,6 @@
// object, not the offset into instance data
const Field* field = fields->Get(i);
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());
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 607382b..3362fdc 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -320,7 +320,10 @@
EXPECT_FALSE(JavaLangObject->IsSynthetic());
EXPECT_EQ(2U, JavaLangObject->NumDirectMethods());
EXPECT_EQ(11U, JavaLangObject->NumVirtualMethods());
- EXPECT_EQ(0U, JavaLangObject->NumInstanceFields());
+ EXPECT_EQ(2U, JavaLangObject->NumInstanceFields());
+ EXPECT_TRUE(JavaLangObject->GetInstanceField(0)->GetName()->Equals("shadow$_klass_"));
+ EXPECT_TRUE(JavaLangObject->GetInstanceField(1)->GetName()->Equals("shadow$_monitor_"));
+
EXPECT_EQ(0U, JavaLangObject->NumStaticFields());
EXPECT_EQ(0U, JavaLangObject->NumInterfaces());
@@ -369,68 +372,265 @@
AssertDexFile(java_lang_dex_file_.get(), NULL);
}
+struct CheckOffset {
+ size_t cpp_offset;
+ const char* java_name;
+ CheckOffset(size_t c, const char* j) : cpp_offset(c), java_name(j) {}
+};
+
+struct CheckOffsets {
+ size_t s;
+ std::string c;
+ std::vector<CheckOffset> o;
+
+ bool Check() {
+ Class* klass = Runtime::Current()->GetClassLinker()->FindSystemClass(c);
+ CHECK(klass != NULL) << c;
+
+ bool error = false;
+
+ if (!klass->IsClassClass())
+ if (s != klass->GetObjectSize()) {
+ LG << "Class size mismatch:"
+ << " class=" << c
+ << " Java=" << klass->GetObjectSize()
+ << " C++=" << s;
+ error = true;
+ }
+
+ CHECK_EQ(o.size(), klass->NumInstanceFields());
+ for (size_t i = 0; i < o.size(); i++) {
+ Field* field = klass->GetInstanceField(i);
+ if (!field->GetName()->Equals(o[i].java_name)) {
+ error = true;
+ }
+ }
+ if (error) {
+ for (size_t i = 0; i < o.size(); i++) {
+ CheckOffset& offset = o[i];
+ Field* field = klass->GetInstanceField(i);
+ if (!field->GetName()->Equals(o[i].java_name)) {
+ LG << "JAVA FIELD ORDER MISMATCH NEXT LINE:";
+ }
+ LG << "Java field order:"
+ << " i=" << i << " class=" << c
+ << " Java=" << field->GetName()->ToModifiedUtf8()
+ << " CheckOffsets=" << offset.java_name;
+ }
+ }
+
+ for (size_t i = 0; i < o.size(); i++) {
+ CheckOffset& offset = o[i];
+ Field* field = klass->GetInstanceField(i);
+ if (field->GetOffset().Uint32Value() != offset.cpp_offset) {
+ error = true;
+ }
+ }
+ if (error) {
+ for (size_t i = 0; i < o.size(); i++) {
+ CheckOffset& offset = o[i];
+ Field* field = klass->GetInstanceField(i);
+ if (field->GetOffset().Uint32Value() != offset.cpp_offset) {
+ LG << "OFFSET MISMATCH NEXT LINE:";
+ }
+ LG << "Offset: class=" << c << " field=" << offset.java_name
+ << " Java=" << field->GetOffset().Uint32Value() << " C++=" << offset.cpp_offset;
+ }
+ }
+
+ return !error;
+ };
+};
+
+struct ObjectOffsets : public CheckOffsets {
+ ObjectOffsets() {
+ s = sizeof(Object);
+ c = "Ljava/lang/Object;";
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Object, klass_), "shadow$_klass_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Object, monitor_), "shadow$_monitor_"));
+ };
+};
+
+struct AccessibleObjectOffsets : public CheckOffsets {
+ AccessibleObjectOffsets() {
+ s = sizeof(AccessibleObject);
+ c = "Ljava/lang/reflect/AccessibleObject;";
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(AccessibleObject, java_flag_), "flag"));
+ };
+};
+
+struct FieldOffsets : public CheckOffsets {
+ FieldOffsets() {
+ s = sizeof(Field);
+ c = "Ljava/lang/reflect/Field;";
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, declaring_class_), "declaringClass"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, generic_type_), "genericType"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, type_), "type"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, name_), "name"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, access_flags_), "shadow$_access_flags_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, offset_), "shadow$_offset_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, type_idx_), "shadow$_type_idx_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, slot_), "slot"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, generic_types_are_initialized_), "genericTypesAreInitialized"));
+ };
+};
+
+struct MethodOffsets : public CheckOffsets {
+ MethodOffsets() {
+ s = sizeof(Method);
+ c = "Ljava/lang/reflect/Method;";
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, declaring_class_), "declaringClass"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_exception_types_), "exceptionTypes"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_formal_type_parameters_), "formalTypeParameters"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_exception_types_), "genericExceptionTypes"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_parameter_types_), "genericParameterTypes"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_return_type_), "genericReturnType"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, signature_), "shadow$_signature_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, name_), "name"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_parameter_types_), "parameterTypes"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_return_type_), "returnType"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, mapping_table_), "shadow$_mapping_table_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_array_), "shadow$_invoke_stub_array_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_array_), "shadow$_code_array_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_strings_), "shadow$_dex_cache_strings_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_types_), "shadow$_dex_cache_resolved_types_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_code_and_direct_methods_), "shadow$_dex_cache_code_and_direct_methods_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_initialized_static_storage_), "shadow$_dex_cache_initialized_static_storage_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_fields_), "shadow$_dex_cache_resolved_fields_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_methods_), "shadow$_dex_cache_resolved_methods_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, core_spill_mask_), "shadow$_core_spill_mask_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_item_offset_), "shadow$_code_item_offset_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, fp_spill_mask_), "shadow$_fp_spill_mask_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, frame_size_in_bytes_), "shadow$_frame_size_in_bytes_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_), "shadow$_invoke_stub_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_), "shadow$_code_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_return_type_idx_), "shadow$_java_return_type_idx_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, access_flags_), "shadow$_access_flags_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, method_index_), "shadow$_method_index_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, native_method_), "shadow$_native_method_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_ins_), "shadow$_num_ins_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_outs_), "shadow$_num_outs_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_registers_), "shadow$_num_registers_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, proto_idx_), "shadow$_proto_idx_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, return_pc_offset_in_bytes_), "shadow$_return_pc_offset_in_bytes_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, shorty_), "shadow$_shorty_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_types_are_initialized_), "genericTypesAreInitialized"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_slot_), "slot"));
+ };
+};
+
+struct ClassOffsets : public CheckOffsets {
+ ClassOffsets() {
+ s = sizeof(Class);
+ c = "Ljava/lang/Class;";
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, name_), "name"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, vtable_), "shadow$_vtable_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, virtual_methods_), "shadow$_virtual_methods_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_loader_), "shadow$_class_loader_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, verify_error_class_), "shadow$_verify_error_class_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, super_class_), "shadow$_super_class_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, component_type_), "shadow$_component_type_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, descriptor_), "shadow$_descriptor_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, dex_cache_), "shadow$_dex_cache_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, direct_methods_), "shadow$_direct_methods_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifields_), "shadow$_ifields_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, sfields_), "shadow$_sfields_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, interfaces_type_idx_), "shadow$_interfaces_type_idx_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, interfaces_), "shadow$_interfaces_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifvi_pool_count_), "shadow$_ifvi_pool_count_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifvi_pool_), "shadow$_ifvi_pool_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, iftable_count_), "shadow$_iftable_count_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_instance_fields_), "shadow$_num_reference_instance_fields_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_static_fields_), "shadow$_num_reference_static_fields_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, object_size_), "shadow$_object_size_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, primitive_type_), "shadow$_primitive_type_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_instance_offsets_), "shadow$_reference_instance_offsets_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_static_offsets_), "shadow$_reference_static_offsets_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, iftable_), "shadow$_iftable_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, source_file_), "shadow$_source_file_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, status_), "shadow$_status_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, clinit_thread_id_), "shadow$_clinit_thread_id_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, super_class_type_idx_), "shadow$_super_class_type_idx_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_size_), "shadow$_class_size_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, array_rank_), "shadow$_array_rank_"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, access_flags_), "shadow$_access_flags_"));
+ };
+};
+
+struct StringOffsets : public CheckOffsets {
+ StringOffsets() {
+ s = sizeof(String);
+ c = "Ljava/lang/String;";
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(String, array_), "value"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(String, hash_code_), "hashCode"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(String, offset_), "offset"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(String, count_), "count"));
+ };
+};
+
+struct ThrowableOffsets : public CheckOffsets {
+ ThrowableOffsets() {
+ s = sizeof(Throwable);
+ c = "Ljava/lang/Throwable;";
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, cause_), "cause"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, detail_message_), "detailMessage"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, stack_state_), "stackState"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, stack_trace_), "stackTrace"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, suppressed_exceptions_), "suppressedExceptions"));
+ };
+};
+
+struct StackTraceElementOffsets : public CheckOffsets {
+ StackTraceElementOffsets() {
+ s = sizeof(StackTraceElement);
+ c = "Ljava/lang/StackTraceElement;";
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, declaring_class_), "declaringClass"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, file_name_), "fileName"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, method_name_), "methodName"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, line_number_), "lineNumber"));
+ };
+};
+
+struct ClassLoaderOffsets : public CheckOffsets {
+ ClassLoaderOffsets() {
+ s = sizeof(ClassLoader);
+ c = "Ljava/lang/ClassLoader;";
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(ClassLoader, packages_), "packages"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(ClassLoader, parent_), "parent"));
+ };
+};
+
+struct BaseDexClassLoaderOffsets : public CheckOffsets {
+ BaseDexClassLoaderOffsets() {
+ s = sizeof(BaseDexClassLoader);
+ c = "Ldalvik/system/BaseDexClassLoader;";
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(BaseDexClassLoader, original_path_), "originalPath"));
+ o.push_back(CheckOffset(OFFSETOF_MEMBER(BaseDexClassLoader, path_list_), "pathList"));
+ };
+};
+
+struct PathClassLoaderOffsets : public CheckOffsets {
+ PathClassLoaderOffsets() {
+ s = sizeof(PathClassLoader);
+ c = "Ldalvik/system/PathClassLoader;";
+ };
+};
+
// C++ fields must exactly match the fields in the Java classes. If this fails,
// reorder the fields in the C++ class. Managed class fields are ordered by
-// ClassLinker::LinkInstanceFields.
+// ClassLinker::LinkFields.
TEST_F(ClassLinkerTest, ValidateFieldOrderOfJavaCppUnionClasses) {
- Class* string = class_linker_->FindSystemClass( "Ljava/lang/String;");
- ASSERT_EQ(4U, string->NumInstanceFields());
- EXPECT_TRUE(string->GetInstanceField(0)->GetName()->Equals("value"));
- EXPECT_TRUE(string->GetInstanceField(1)->GetName()->Equals("hashCode"));
- EXPECT_TRUE(string->GetInstanceField(2)->GetName()->Equals("offset"));
- EXPECT_TRUE(string->GetInstanceField(3)->GetName()->Equals("count"));
-
- Class* throwable = class_linker_->FindSystemClass( "Ljava/lang/Throwable;");
- ASSERT_EQ(5U, throwable->NumInstanceFields());
- EXPECT_TRUE(throwable->GetInstanceField(0)->GetName()->Equals("cause"));
- EXPECT_TRUE(throwable->GetInstanceField(1)->GetName()->Equals("detailMessage"));
- EXPECT_TRUE(throwable->GetInstanceField(2)->GetName()->Equals("stackState"));
- 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"));
-
- Class* field = class_linker_->FindSystemClass("Ljava/lang/reflect/Field;");
- ASSERT_EQ(6U, field->NumInstanceFields());
- EXPECT_TRUE(field->GetInstanceField(0)->GetName()->Equals("declaringClass"));
- EXPECT_TRUE(field->GetInstanceField(1)->GetName()->Equals("genericType"));
- EXPECT_TRUE(field->GetInstanceField(2)->GetName()->Equals("type"));
- EXPECT_TRUE(field->GetInstanceField(3)->GetName()->Equals("name"));
- EXPECT_TRUE(field->GetInstanceField(4)->GetName()->Equals("slot"));
- EXPECT_TRUE(field->GetInstanceField(5)->GetName()->Equals("genericTypesAreInitialized"));
-
- Class* method = class_linker_->FindSystemClass("Ljava/lang/reflect/Method;");
- ASSERT_EQ(11U, method->NumInstanceFields());
- EXPECT_TRUE(method->GetInstanceField( 0)->GetName()->Equals("declaringClass"));
- EXPECT_TRUE(method->GetInstanceField( 1)->GetName()->Equals("exceptionTypes"));
- EXPECT_TRUE(method->GetInstanceField( 2)->GetName()->Equals("formalTypeParameters"));
- EXPECT_TRUE(method->GetInstanceField( 3)->GetName()->Equals("genericExceptionTypes"));
- EXPECT_TRUE(method->GetInstanceField( 4)->GetName()->Equals("genericParameterTypes"));
- EXPECT_TRUE(method->GetInstanceField( 5)->GetName()->Equals("genericReturnType"));
- EXPECT_TRUE(method->GetInstanceField( 6)->GetName()->Equals("returnType"));
- EXPECT_TRUE(method->GetInstanceField( 7)->GetName()->Equals("name"));
- EXPECT_TRUE(method->GetInstanceField( 8)->GetName()->Equals("parameterTypes"));
- EXPECT_TRUE(method->GetInstanceField( 9)->GetName()->Equals("genericTypesAreInitialized"));
- EXPECT_TRUE(method->GetInstanceField(10)->GetName()->Equals("slot"));
-
- Class* class_loader = class_linker_->FindSystemClass("Ljava/lang/ClassLoader;");
- ASSERT_EQ(2U, class_loader->NumInstanceFields());
- EXPECT_TRUE(class_loader->GetInstanceField(0)->GetName()->Equals("packages"));
- EXPECT_TRUE(class_loader->GetInstanceField(1)->GetName()->Equals("parent"));
-
- Class* dex_base_class_loader = class_linker_->FindSystemClass("Ldalvik/system/BaseDexClassLoader;");
- ASSERT_EQ(2U, dex_base_class_loader->NumInstanceFields());
- EXPECT_TRUE(dex_base_class_loader->GetInstanceField(0)->GetName()->Equals("originalPath"));
- EXPECT_TRUE(dex_base_class_loader->GetInstanceField(1)->GetName()->Equals("pathList"));
+ EXPECT_TRUE(ObjectOffsets().Check());
+ EXPECT_TRUE(AccessibleObjectOffsets().Check());
+ EXPECT_TRUE(FieldOffsets().Check());
+ EXPECT_TRUE(MethodOffsets().Check());
+ EXPECT_TRUE(ClassOffsets().Check());
+ EXPECT_TRUE(StringOffsets().Check());
+ EXPECT_TRUE(ThrowableOffsets().Check());
+ EXPECT_TRUE(StackTraceElementOffsets().Check());
+ EXPECT_TRUE(ClassLoaderOffsets().Check());
+ EXPECT_TRUE(BaseDexClassLoaderOffsets().Check());
+ EXPECT_TRUE(PathClassLoaderOffsets().Check());
}
// The first reference array element must be a multiple of 8 bytes from the
diff --git a/src/class_loader.h b/src/class_loader.h
index ff62d12..80435c6 100644
--- a/src/class_loader.h
+++ b/src/class_loader.h
@@ -29,6 +29,7 @@
// TODO: remove once we can create a real PathClassLoader
std::vector<const DexFile*> class_path_;
+ friend struct ClassLoaderOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(ClassLoader);
};
@@ -38,6 +39,8 @@
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
String* original_path_;
Object* path_list_;
+
+ friend struct BaseDexClassLoaderOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(BaseDexClassLoader);
};
@@ -49,6 +52,7 @@
static void ResetClass();
private:
static Class* dalvik_system_PathClassLoader_;
+ friend struct PathClassLoaderOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(PathClassLoader);
};
diff --git a/src/heap.h b/src/heap.h
index 4922207..3dc612a 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -134,13 +134,14 @@
verify_object_disabled_ = true;
}
+ static void RecordFree(Space* space, const Object* object);
+
private:
// Allocates uninitialized storage.
static Object* Allocate(size_t num_bytes);
static Object* Allocate(Space* space, size_t num_bytes);
static void RecordAllocation(Space* space, const Object* object);
- static void RecordFree(Space* space, const Object* object);
static void RecordImageAllocations(Space* space);
static void CollectGarbageInternal();
diff --git a/src/heap_test.cc b/src/heap_test.cc
index 53489e4..2a4cbbf 100644
--- a/src/heap_test.cc
+++ b/src/heap_test.cc
@@ -6,7 +6,7 @@
class HeapTest : public CommonTest {};
-TEST_F(HeapTest, DISABLED_GarbageCollectClassLinkerInit) {
+TEST_F(HeapTest, GarbageCollectClassLinkerInit) {
// garbage is created during ClassLinker::Init
Heap::CollectGarbage();
}
diff --git a/src/image_test.cc b/src/image_test.cc
index f07588a..0bd79db 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -16,14 +16,13 @@
class ImageTest : public CommonTest {};
TEST_F(ImageTest, WriteRead) {
- // TODO: move the touching of classes and GC to the ImageWriter proper
+ // TODO: remove the touching of classes, call Compiler instead
for (size_t i = 0; i < java_lang_dex_file_->NumClassDefs(); i++) {
const DexFile::ClassDef& class_def = java_lang_dex_file_->GetClassDef(i);
const char* descriptor = java_lang_dex_file_->GetClassDescriptor(class_def);
Class* klass = class_linker_->FindSystemClass(descriptor);
ASSERT_TRUE(klass != NULL) << descriptor;
}
- // TODO: Heap::CollectGarbage before writing
ImageWriter writer;
ScratchFile tmp;
diff --git a/src/image_writer.cc b/src/image_writer.cc
index a49b261..859da86 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -35,6 +35,7 @@
if (!Init()) {
return false;
}
+ Heap::CollectGarbage();
CalculateNewObjectOffsets();
CopyAndFixupObjects();
@@ -173,10 +174,6 @@
// TODO: special case init of pointers to malloc data (or removal of these pointers)
if (orig->IsClass()) {
FixupClass(orig->AsClass(), down_cast<Class*>(copy));
- } else if (orig->IsMethod()) {
- FixupMethod(orig->AsMethod(), down_cast<Method*>(copy));
- } else if (orig->IsField()) {
- FixupField(orig->AsField(), down_cast<Field*>(copy));
} else if (orig->IsObjectArray()) {
FixupObjectArray(orig->AsObjectArray<Object>(), down_cast<ObjectArray<Object>*>(copy));
} else {
@@ -186,22 +183,6 @@
void ImageWriter::FixupClass(const Class* orig, Class* copy) {
FixupInstanceFields(orig, copy);
- copy->descriptor_ = down_cast<String*>(GetImageAddress(orig->descriptor_));
- copy->dex_cache_ = down_cast<DexCache*>(GetImageAddress(orig->dex_cache_));
- copy->verify_error_class_ = down_cast<Class*>(GetImageAddress(orig->verify_error_class_));
- copy->component_type_ = down_cast<Class*>(GetImageAddress(orig->component_type_));
- copy->super_class_ = down_cast<Class*>(GetImageAddress(orig->super_class_));
- copy->class_loader_ = down_cast<ClassLoader*>(GetImageAddress(orig->class_loader_));
- copy->interfaces_ = down_cast<ObjectArray<Class>*>(GetImageAddress(orig->interfaces_));
- copy->direct_methods_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->direct_methods_));
- copy->virtual_methods_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->virtual_methods_));
- copy->vtable_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->vtable_));
- // TODO: convert iftable_ to heap allocated storage
- // TODO: convert ifvi_pool_ to heap allocated storage
- copy->ifields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->ifields_));
- // TODO: convert source_file_ to heap allocated storage
- copy->sfields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->sfields_));
- copy->interfaces_type_idx_ = down_cast<IntArray*>(GetImageAddress(orig->interfaces_type_idx_));
FixupStaticFields(orig, copy);
}
@@ -218,30 +199,13 @@
return copy_code;
}
-// TODO: remove this slow path
void ImageWriter::FixupMethod(const Method* orig, Method* copy) {
FixupInstanceFields(orig, 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);
// TODO: convert shorty_ to heap allocated storage
- 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_));
- copy->code_array_ = down_cast<ByteArray*>(GetImageAddress(orig->code_array_));
copy->code_ = FixupCode(copy->code_array_, orig->code_);
- copy->invoke_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig->invoke_stub_array_));
copy->invoke_stub_ = reinterpret_cast<Method::InvokeStub*>(FixupCode(copy->invoke_stub_array_, reinterpret_cast<void*>(orig->invoke_stub_)));
}
-void ImageWriter::FixupField(const Field* orig, Field* copy) {
- FixupInstanceFields(orig, copy);
- // TODO: convert descriptor_ to heap allocated storage
-}
-
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);
diff --git a/src/image_writer.h b/src/image_writer.h
index 3352adb..9dac31a 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -75,7 +75,6 @@
static void CopyAndFixupObjectsCallback(Object* obj, void *arg);
void FixupClass(const Class* orig, Class* copy);
void FixupMethod(const Method* orig, Method* copy);
- void FixupField(const Field* orig, Field* copy);
void FixupObject(const Object* orig, Object* copy);
void FixupObjectArray(const ObjectArray<Object>* orig, ObjectArray<Object>* copy);
void FixupInstanceFields(const Object* orig, Object* copy);
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc
index a2f1a56..b3d21a3 100644
--- a/src/mark_sweep.cc
+++ b/src/mark_sweep.cc
@@ -6,6 +6,7 @@
#include <vector>
#include "class_loader.h"
+#include "dex_cache.h"
#include "heap.h"
#include "indirect_reference_table.h"
#include "intern_table.h"
@@ -148,6 +149,7 @@
Space* space = static_cast<Space*>(arg);
for (size_t i = 0; i < num_ptrs; ++i) {
Object* obj = static_cast<Object*>(ptrs[i]);
+ Heap::RecordFree(space, obj);
space->Free(obj);
}
// TODO, unlock heap if concurrent
@@ -219,13 +221,6 @@
}
}
-void MarkSweep::ScanInterfaces(const Class* klass) {
- DCHECK(klass != NULL);
- for (size_t i = 0; i < klass->NumInterfaces(); ++i) {
- MarkObject(klass->GetInterface(i));
- }
-}
-
// Scans the header, static field references, and interface pointers
// of a class object.
void MarkSweep::ScanClass(const Object* obj) {
@@ -233,6 +228,10 @@
DCHECK(obj->IsClass());
const Class* klass = obj->AsClass();
MarkObject(klass->GetClass());
+ ScanInstanceFields(obj);
+ MarkObject(klass->GetDescriptor());
+ MarkObject(klass->GetDexCache());
+ MarkObject(klass->GetVerifyErrorClass());
if (klass->IsArrayClass()) {
MarkObject(klass->GetComponentType());
}
@@ -240,13 +239,14 @@
MarkObject(klass->GetSuperClass());
}
MarkObject(klass->GetClassLoader());
- ScanInstanceFields(obj);
- ScanStaticFields(klass);
- // TODO: scan methods
- // TODO: scan instance fields
if (klass->IsLoaded()) {
- ScanInterfaces(klass);
+ MarkObject(klass->GetInterfaces());
+ MarkObject(klass->GetDirectMethods());
+ MarkObject(klass->GetVirtualMethods());
+ MarkObject(klass->GetIFields());
+ MarkObject(klass->GetSFields());
}
+ ScanStaticFields(klass);
}
// Scans the header of all array objects. If the array object is
diff --git a/src/mark_sweep.h b/src/mark_sweep.h
index 841d819..fe37cab 100644
--- a/src/mark_sweep.h
+++ b/src/mark_sweep.h
@@ -82,9 +82,6 @@
// Used by ScanInstanceFields and ScanStaticFields
void ScanFields(const Object* obj, uint32_t ref_offsets, bool is_static);
- // Grays interface class objects.
- void ScanInterfaces(const Class* klass);
-
// Grays references in an array.
void ScanArray(const Object* obj);
diff --git a/src/object.h b/src/object.h
index 23ce3c4..9e5cf2d 100644
--- a/src/object.h
+++ b/src/object.h
@@ -140,7 +140,6 @@
* fields followed by 2 ref instance fields.]
*/
#define CLASS_WALK_SUPER ((unsigned int)(3))
-#define CLASS_SMALLEST_OFFSET (sizeof(struct Object))
#define CLASS_BITS_PER_WORD (sizeof(unsigned long int) * 8)
#define CLASS_OFFSET_ALIGNMENT 4
#define CLASS_HIGH_BIT ((unsigned int)1 << (CLASS_BITS_PER_WORD - 1))
@@ -149,7 +148,7 @@
* Local use only.
*/
#define _CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset) \
- (((unsigned int)(byteOffset) - CLASS_SMALLEST_OFFSET) / \
+ ((unsigned int)(byteOffset) / \
CLASS_OFFSET_ALIGNMENT)
/*
* Is the given offset too large to be encoded?
@@ -166,8 +165,7 @@
* Return an offset, given a bit number as returned from CLZ.
*/
#define CLASS_OFFSET_FROM_CLZ(rshift) \
- MemberOffset((static_cast<int>(rshift) * CLASS_OFFSET_ALIGNMENT) + \
- CLASS_SMALLEST_OFFSET)
+ MemberOffset((static_cast<int>(rshift) * CLASS_OFFSET_ALIGNMENT))
#define OFFSET_OF_OBJECT_MEMBER(type, field) \
MemberOffset(OFFSETOF_MEMBER(type, field))
@@ -444,6 +442,7 @@
Monitor* monitor_;
+ friend struct ObjectOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
};
@@ -480,6 +479,8 @@
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
uint32_t java_flag_; // can accessibility checks be bypassed
+ friend struct AccessibleObjectOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AccessibleObject);
};
// C++ mirror of java.lang.reflect.Field
@@ -584,24 +585,32 @@
void SetObj(Object* object, const Object* new_value) const;
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
+
// The class in which this field is declared.
Class* declaring_class_;
+
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_;
- // TODO: expose these fields in the Java version of this Object
+ const String* name_;
+
uint32_t access_flags_;
+
+ // Offset of field within an instance or in the Class' static fields
+ uint32_t offset_;
+
// Dex cache index of resolved type
uint32_t type_idx_;
+ int32_t slot_;
+
+ uint32_t generic_types_are_initialized_;
+
static Class* java_lang_reflect_Field_;
+ friend struct FieldOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(Field);
};
@@ -978,10 +987,6 @@
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_;
@@ -990,38 +995,6 @@
Object* java_generic_exception_types_;
Object* java_generic_parameter_types_;
Object* java_generic_return_type_;
- Class* java_return_type_; // Unused by ART
- String* name_;
- ObjectArray<Class>* java_parameter_types_;
- uint32_t java_generic_types_are_initialized_;
- uint32_t java_slot_;
-
- // TODO: start of non-Java mirror fields, place these in the Java piece
-
- // access flags; low 16 bits are defined by spec (could be uint16_t?)
- uint32_t access_flags_;
-
- // For concrete virtual methods, this is the offset of the method
- // in Class::vtable_.
- //
- // For abstract methods in an interface class, this is the offset
- // of the method in "iftable_[n]->method_index_array_".
- uint16_t method_index_;
-
- // Method bounds; not needed for an abstract method.
- //
- // For a native method, we compute the size of the argument list, and
- // set "insSize" and "registerSize" equal to it.
- uint16_t num_registers_; // ins + locals
- uint16_t num_outs_;
- uint16_t num_ins_;
-
- // Total size in bytes of the frame
- size_t frame_size_in_bytes_;
-
- // Architecture-dependent register spill masks
- uint32_t core_spill_mask_;
- uint32_t fp_spill_mask_;
// The method descriptor. This represents the parameters a method
// takes and value it returns. This string is a list of the type
@@ -1035,52 +1008,99 @@
// (IDLjava/lang/Thread;)Ljava/lang/Object;
String* signature_;
- // Method prototype descriptor string (return and argument types).
- uint32_t proto_idx_;
+ String* name_;
+
+ ObjectArray<Class>* java_parameter_types_;
+
+ Class* java_return_type_; // Unused by ART
+
+ // Storage for mapping_table_
+ const ByteArray* mapping_table_;
+
+ // Storage for invoke_stub_
+ const ByteArray* invoke_stub_array_;
+
+ // Storage for code_
+ const ByteArray* code_array_;
+
+ // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
+ ObjectArray<String>* dex_cache_strings_;
+
+ // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
+ ObjectArray<Class>* dex_cache_resolved_types_;
+
+ // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
+ CodeAndDirectMethods* dex_cache_code_and_direct_methods_;
+
+ // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
+ ObjectArray<StaticStorageBase>* dex_cache_initialized_static_storage_;
+
+ // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
+ ObjectArray<Field>* dex_cache_resolved_fields_;
+
+ // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
+ ObjectArray<Method>* dex_cache_resolved_methods_;
+
+ // Architecture-dependent register spill mask
+ uint32_t core_spill_mask_;
// Offset to the CodeItem.
uint32_t code_item_offset_;
- // Index of the return type
- uint32_t java_return_type_idx_;
+ // Architecture-dependent register spill mask
+ uint32_t fp_spill_mask_;
- // The short-form method descriptor string. TODO: make String*
- const char* shorty_;
+ // Total size in bytes of the frame
+ size_t frame_size_in_bytes_;
- // short cuts to declaring_class_->dex_cache_ members for fast compiled code
- // access
- ObjectArray<String>* dex_cache_strings_;
- ObjectArray<Class>* dex_cache_resolved_types_;
- ObjectArray<Method>* dex_cache_resolved_methods_;
- ObjectArray<Field>* dex_cache_resolved_fields_;
- CodeAndDirectMethods* dex_cache_code_and_direct_methods_;
- ObjectArray<StaticStorageBase>* dex_cache_initialized_static_storage_;
-
- private:
- // Storage for code_
- const ByteArray* code_array_;
-
- // Storage for mapping_table_
- const ByteArray* mapping_table_;
+ // Native invocation stub entry point for calling from native to managed code.
+ const InvokeStub* invoke_stub_;
// Compiled code associated with this method for callers from managed code.
// May be compiled managed code or a bridge for invoking a native method.
const void* code_;
- // Offset of return PC within frame for compiled code (in bytes)
- size_t return_pc_offset_in_bytes_;
+ // Index of the return type
+ uint32_t java_return_type_idx_;
+
+ // access flags; low 16 bits are defined by spec (could be uint16_t?)
+ uint32_t access_flags_;
+
+ // For concrete virtual methods, this is the offset of the method
+ // in Class::vtable_.
+ //
+ // For abstract methods in an interface class, this is the offset
+ // of the method in "iftable_[n]->method_index_array_".
+ uint32_t method_index_; // (could be uint16_t)
// The target native method registered with this method
const void* native_method_;
- // Storage for invoke_stub_
- const ByteArray* invoke_stub_array_;
+ // Method bounds; not needed for an abstract method.
+ //
+ // For a native method, we compute the size of the argument list, and
+ // set "insSize" and "registerSize" equal to it.
+ uint32_t num_ins_; // (could be uint16_t)
+ uint32_t num_outs_; // (could be uint16_t)
+ uint32_t num_registers_; // ins + locals // (could be uint16_t)
- // Native invocation stub entry point for calling from native to managed code.
- const InvokeStub* invoke_stub_;
+ // Method prototype descriptor string (return and argument types).
+ uint32_t proto_idx_;
+
+ // Offset of return PC within frame for compiled code (in bytes)
+ size_t return_pc_offset_in_bytes_;
+
+ // The short-form method descriptor string. TODO: make String*
+ const char* shorty_;
+
+ uint32_t java_generic_types_are_initialized_;
+
+ uint32_t java_slot_;
static Class* java_lang_reflect_Method_;
+ friend class ImageWriter; // for relocating code_ and invoke_stub_
+ friend struct MethodOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(Method);
};
@@ -1928,7 +1948,7 @@
}
Class* GetVerifyErrorClass() const {
- DCHECK(IsErroneous());
+ // DCHECK(IsErroneous());
return GetFieldObject<Class*>(
OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), false);
}
@@ -1955,76 +1975,100 @@
bool IsAssignableFromArray(const Class* klass) const;
bool IsSubClass(const Class* klass) const;
- // 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
- // descriptor for the class such as "Ljava/lang/Class;" or "[C"
- String* descriptor_;
+ // Virtual method table (vtable), for use by "invoke-virtual". The
+ // vtable from the superclass is copied in, and virtual methods from
+ // our class either replace those from the super or are appended.
+ ObjectArray<Method>* vtable_;
- // access flags; low 16 bits are defined by VM spec
- uint32_t access_flags_; // TODO: make an instance field?
+ // virtual methods defined in this class; invoked through vtable
+ ObjectArray<Method>* virtual_methods_;
- // DexCache of resolved constant pool entries
- // (will be NULL for VM-generated, e.g. arrays and primitive classes)
- DexCache* dex_cache_;
-
- // state of class initialization
- Status status_;
+ // defining class loader, or NULL for the "bootstrap" system loader
+ const ClassLoader* class_loader_; // TODO: make an instance field
// If class verify fails, we must return same error on subsequent tries.
// Update with SetVerifyErrorClass to ensure a write barrier is used.
const Class* verify_error_class_;
- // threadId, used to check for recursive <clinit> invocation
- pid_t clinit_thread_id_;
-
- // Total object size; used when allocating storage on gc heap. (For
- // interfaces and abstract classes this will be zero.)
- size_t object_size_;
+ // The superclass, or NULL if this is java.lang.Object or a
+ // primitive type.
+ // see also super_class_type_idx_;
+ Class* super_class_;
// For array classes, the class object for base element, for
// instanceof/checkcast (for String[][][], this will be String).
// Otherwise, NULL.
Class* component_type_; // TODO: make an instance field
- // For array classes, the number of array dimensions, e.g. int[][]
- // is 2. Otherwise 0.
- int32_t array_rank_;
+ // descriptor for the class such as "Ljava/lang/Class;" or "[C"
+ String* descriptor_;
- // primitive type index, or kPrimNot (0); set for generated prim classes
- PrimitiveType primitive_type_;
-
- // The superclass, or NULL if this is java.lang.Object or a
- // primitive type.
- Class* super_class_; // TODO: make an instance field
- uint32_t super_class_type_idx_;
-
- // defining class loader, or NULL for the "bootstrap" system loader
- const ClassLoader* class_loader_; // TODO: make an instance field
-
- // initiating class loader list
- // NOTE: for classes with low serialNumber, these are unused, and the
- // values are kept in a table in gDvm.
- // InitiatingLoaderList initiating_loader_list_;
-
- // array of interfaces this class implements directly
- ObjectArray<Class>* interfaces_;
- IntArray* interfaces_type_idx_;
+ // DexCache of resolved constant pool entries
+ // (will be NULL for VM-generated, e.g. arrays and primitive classes)
+ DexCache* dex_cache_;
// static, private, and <init> methods
ObjectArray<Method>* direct_methods_;
- // virtual methods defined in this class; invoked through vtable
- ObjectArray<Method>* virtual_methods_;
+ // instance fields
+ //
+ // These describe the layout of the contents of an Object.
+ // Note that only the fields directly declared by this class are
+ // listed in ifields; fields declared by a superclass are listed in
+ // the superclass's Class.ifields.
+ //
+ // All instance fields that refer to objects are guaranteed to be at
+ // the beginning of the field list. num_reference_instance_fields_
+ // specifies the number of reference fields.
+ ObjectArray<Field>* ifields_;
- // Virtual method table (vtable), for use by "invoke-virtual". The
- // vtable from the superclass is copied in, and virtual methods from
- // our class either replace those from the super or are appended.
- ObjectArray<Method>* vtable_;
+ // Static fields
+ ObjectArray<Field>* sfields_;
+
+ // array of type_idx's for interfaces this class implements directly
+ // see also interfaces_
+ IntArray* interfaces_type_idx_;
+
+ // array of interfaces this class implements directly
+ // see also interfaces_type_idx_
+ ObjectArray<Class>* interfaces_;
+
+ // size of ifvi_pool_
+ size_t ifvi_pool_count_;
+
+ // The interface vtable indices for iftable get stored here. By
+ // placing them all in a single pool for each class that implements
+ // interfaces, we decrease the number of allocations.
+ //
+ // see also ifvi_pool_count_
+ //
+ // TODO convert to IntArray
+ uint32_t* ifvi_pool_;
+
+ // size of iftable_
+ size_t iftable_count_;
+
+ // number of instance fields that are object refs
+ size_t num_reference_instance_fields_;
+
+ // number of static fields that are object refs
+ size_t num_reference_static_fields_;
+
+ // Total object size; used when allocating storage on gc heap.
+ // (For interfaces and abstract classes this will be zero.)
+ size_t object_size_;
+
+ // primitive type index, or kPrimNot (0); set for generated prim classes
+ PrimitiveType primitive_type_;
+
+ // Bitmap of offsets of ifields.
+ uint32_t reference_instance_offsets_;
+
+ // Bitmap of offsets of sfields.
+ uint32_t reference_static_offsets_;
// Interface table (iftable_), one entry per interface supported by
// this class. That means one entry for each interface we support
@@ -2039,54 +2083,45 @@
//
// For every interface a concrete class implements, we create a list
// of virtualMethod indices for the methods in the interface.
- size_t iftable_count_;
+ //
+ // see also iftable_count_;
// TODO convert to ObjectArray<?>
+ //
InterfaceEntry* iftable_;
- // The interface vtable indices for iftable get stored here. By
- // placing them all in a single pool for each class that implements
- // interfaces, we decrease the number of allocations.
- size_t ifvi_pool_count_;
- // TODO convert to IntArray
- uint32_t* ifvi_pool_;
-
- // instance fields
- //
- // These describe the layout of the contents of a
- // DataObject-compatible Object. Note that only the fields directly
- // declared by this class are listed in ifields; fields declared by
- // a superclass are listed in the superclass's Class.ifields.
- //
- // All instance fields that refer to objects are guaranteed to be at
- // the beginning of the field list. num_reference_instance_fields_
- // specifies the number of reference fields.
- ObjectArray<Field>* ifields_;
-
- // number of instance fields that are object refs
- size_t num_reference_instance_fields_;
-
- // Bitmap of offsets of ifields.
- uint32_t reference_instance_offsets_;
-
// source file name, if known. Otherwise, NULL.
const char* source_file_;
- // Static fields
- ObjectArray<Field>* sfields_;
+ // state of class initialization
+ Status status_;
- // number of static fields that are object refs
- size_t num_reference_static_fields_;
+ // threadId, used to check for recursive <clinit> invocation
+ uint32_t clinit_thread_id_;
- // Bitmap of offsets of sfields.
- uint32_t reference_static_offsets_;
+ // Set in LoadClass, used to LinkClass
+ // see also super_class_
+ uint32_t super_class_type_idx_;
// Total class size; used when allocating storage on gc heap.
size_t class_size_;
+ // For array classes, the number of array dimensions, e.g. int[][]
+ // is 2. Otherwise 0.
+ int32_t array_rank_;
+
+ // access flags; low 16 bits are defined by VM spec
+ uint32_t access_flags_;
+
+ // TODO: ?
+ // initiating class loader list
+ // NOTE: for classes with low serialNumber, these are unused, and the
+ // values are kept in a table in gDvm.
+ // InitiatingLoaderList initiating_loader_list_;
+
// Location of first static field.
uint32_t fields_[0];
- private:
+ friend struct ClassOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(Class);
};
@@ -2171,8 +2206,7 @@
inline void Field::SetOffset(MemberOffset num_bytes) {
DCHECK(GetDeclaringClass()->IsLoaded());
- DCHECK_LE(CLASS_SMALLEST_OFFSET, num_bytes.Uint32Value());
- Class* type = GetTypeDuringLinking();
+ Class* type = GetTypeDuringLinking();
if (type != NULL && (type->IsPrimitiveDouble() || type->IsPrimitiveLong())) {
DCHECK(IsAligned(num_bytes.Uint32Value(), 8));
}
@@ -2333,14 +2367,6 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(MethodClass);
};
-class DataObject : public Object {
- public:
- // Location of first instance field.
- uint32_t fields_[0];
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(DataObject);
-};
-
template<class T>
class PrimitiveArray : public Array {
public:
@@ -2500,6 +2526,7 @@
static Class* java_lang_String_;
+ friend struct StringOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(String);
};
@@ -2583,6 +2610,7 @@
}
inline void Class::SetDescriptor(String* new_descriptor) {
+ DCHECK(GetDescriptor() == NULL);
DCHECK(new_descriptor != NULL);
DCHECK_NE(0, new_descriptor->GetLength());
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, descriptor_),
@@ -2635,6 +2663,7 @@
Object* stack_trace_;
Object* suppressed_exceptions_;
+ friend struct ThrowableOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(Throwable);
};
@@ -2683,6 +2712,8 @@
}
static Class* java_lang_StackTraceElement_;
+
+ friend struct StackTraceElementOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(StackTraceElement);
};