Expanding ClassLinkerTest/LibCore to cover more Class details
- Ensure SetReferenceOffsets is always called
- Change Field to use StringPiece instead of const char*
- Removed "shrunk vtable" logging noise
- Fix small bug in Class::Status logging
- Rename Field signature to descriptor for clarity
- Add Class:IsSynthetic
Change-Id: I453f480ad7a87a6a391418684771c92d62f116c9
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 5db2bea..01e1119 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -367,8 +367,8 @@
Field* dst) {
const DexFile::FieldId& field_id = dex_file.GetFieldId(src.field_idx_);
dst->klass_ = klass;
- dst->name_ = dex_file.dexStringById(field_id.name_idx_);
- dst->signature_ = dex_file.dexStringByTypeIdx(field_id.type_idx_);
+ dst->name_.set(dex_file.dexStringById(field_id.name_idx_));
+ dst->descriptor_.set(dex_file.dexStringByTypeIdx(field_id.type_idx_));
dst->access_flags_ = src.access_flags_;
}
@@ -1144,9 +1144,6 @@
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);
- LG << "shrunk vtable: "
- << "was " << max_count << ", "
- << "now " << actual_count;
}
} else {
CHECK(klass->GetDescriptor() == "Ljava/lang/Object;");
@@ -1457,8 +1454,8 @@
break;
}
}
- klass->SetReferenceOffsets(reference_offsets);
}
+ klass->SetReferenceOffsets(reference_offsets);
}
Class* ClassLinker::ResolveClass(const Class* referrer,
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 4f921c4..c571d8a 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -75,13 +75,107 @@
}
void AssertDexFileClass(const DexFile* dex, const char* descriptor) {
- CHECK(descriptor != NULL);
+ ASSERT_TRUE(descriptor != NULL);
Class* klass = class_linker_->FindClass(descriptor, NULL, dex);
- CHECK(klass != NULL);
+ ASSERT_TRUE(klass != NULL);
+ EXPECT_EQ(descriptor, klass->GetDescriptor());
+ if (klass->descriptor_ == "Ljava/lang/Object;") {
+ EXPECT_FALSE(klass->HasSuperClass());
+ } else {
+ EXPECT_TRUE(klass->HasSuperClass());
+ EXPECT_TRUE(klass->GetSuperClass() != NULL);
+ }
+ // EXPECT_TRUE(klass->GetClassLoader() != NULL); // TODO needs class loader
+ 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_TRUE(klass->IsInSamePackage(klass));
+ EXPECT_TRUE(Class::IsInSamePackage(klass->GetDescriptor(), klass->GetDescriptor()));
+ if (klass->IsInterface()) {
+ EXPECT_TRUE(klass->IsAbstract());
+ if (klass->NumDirectMethods() == 1) {
+ EXPECT_EQ("<clinit>", klass->GetDirectMethod(0)->GetName());
+ } else {
+ EXPECT_EQ(0U, klass->NumDirectMethods());
+ }
+ } else {
+ if (!klass->IsSynthetic()) {
+ EXPECT_NE(0U, klass->NumDirectMethods());
+ }
+ }
+ if (klass->IsAbstract()) {
+ EXPECT_FALSE(klass->IsFinal());
+ } else {
+ EXPECT_FALSE(klass->IsAnnotation());
+ }
+ if (klass->IsFinal()) {
+ EXPECT_FALSE(klass->IsAbstract());
+ EXPECT_FALSE(klass->IsAnnotation());
+ }
+ if (klass->IsAnnotation()) {
+ EXPECT_FALSE(klass->IsFinal());
+ EXPECT_TRUE(klass->IsAbstract());
+ }
+
+ EXPECT_FALSE(klass->IsPrimitive());
+ EXPECT_TRUE(klass->CanAccess(klass));
+
+ for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
+ Method* method = klass->GetDirectMethod(i);
+ EXPECT_TRUE(method != NULL);
+ }
+
+ for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
+ Method* method = klass->GetVirtualMethod(i);
+ EXPECT_TRUE(method != NULL);
+ }
+
+ for (size_t i = 0; i < klass->NumInstanceFields(); i++) {
+ InstanceField* field = klass->GetInstanceField(i);
+ EXPECT_TRUE(field != NULL);
+ }
+
+ for (size_t i = 0; i < klass->NumStaticFields(); i++) {
+ StaticField* field = klass->GetStaticField(i);
+ EXPECT_TRUE(field != NULL);
+ }
+
+ // Confirm that all instances fields are packed together at the start
+ EXPECT_GE(klass->NumInstanceFields(), klass->NumReferenceInstanceFields());
+ for (size_t i = 0; i < klass->NumReferenceInstanceFields(); i++) {
+ InstanceField* field = klass->GetInstanceField(i);
+ ASSERT_TRUE(field != NULL);
+ ASSERT_TRUE(field->GetDescriptor() != NULL);
+ Class* fieldType = class_linker_->FindClass(field->GetDescriptor(), NULL, dex);
+ ASSERT_TRUE(fieldType != NULL);
+ EXPECT_FALSE(fieldType->IsPrimitive());
+ }
+ for (size_t i = klass->NumReferenceInstanceFields(); i < klass->NumInstanceFields(); i++) {
+ InstanceField* field = klass->GetInstanceField(i);
+ ASSERT_TRUE(field != NULL);
+ ASSERT_TRUE(field->GetDescriptor() != NULL);
+ Class* fieldType = class_linker_->FindClass(field->GetDescriptor(), NULL, dex);
+ ASSERT_TRUE(fieldType != NULL);
+ EXPECT_TRUE(fieldType->IsPrimitive());
+ }
+
+ size_t total_num_reference_instance_fields = 0;
+ Class* k = klass;
+ while (k != NULL) {
+ total_num_reference_instance_fields += k->NumReferenceInstanceFields();
+ k = k->GetSuperClass();
+ }
+ EXPECT_EQ(klass->GetReferenceOffsets() == 0,
+ total_num_reference_instance_fields == 0);
}
void AssertDexFile(const DexFile* dex) {
- CHECK(dex != NULL);
+ ASSERT_TRUE(dex != NULL);
class_linker_->RegisterDexFile(dex);
for (size_t i = 0; i < dex->NumClassDefs(); i++) {
const DexFile::ClassDef class_def = dex->GetClassDef(i);
diff --git a/src/object.cc b/src/object.cc
index fbcfa8b..69b093d 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -199,7 +199,7 @@
};
std::ostream& operator<<(std::ostream& os, const Class::Status& rhs) {
if (rhs >= Class::kStatusError && rhs <= Class::kStatusInitialized) {
- os << kClassStatusNames[rhs - 1];
+ os << kClassStatusNames[rhs + 1];
} else {
os << "Class::Status[" << static_cast<int>(rhs) << "]";
}
diff --git a/src/object.h b/src/object.h
index a154959..77eb164 100644
--- a/src/object.h
+++ b/src/object.h
@@ -250,16 +250,16 @@
return declaring_class_;
}
- const char* GetName() const {
+ const StringPiece& GetName() const {
return name_;
}
char GetType() const { // TODO: return type
- return signature_[0];
+ return descriptor_[0];
}
- const char* GetSignature() const {
- return signature_;
+ const StringPiece& GetDescriptor() const {
+ return descriptor_;
}
public: // TODO: private
@@ -277,10 +277,10 @@
// The class in which this field is declared.
Class* declaring_class_;
- const char* name_;
+ StringPiece name_;
// e.g. "I", "[C", "Landroid/os/Debug;"
- const char* signature_;
+ StringPiece descriptor_;
uint32_t access_flags_;
@@ -373,8 +373,7 @@
class Method : public Object {
public:
- // Returns the method name.
- // TODO: example
+ // Returns the method name, e.g. "<init>" or "eatLunch"
const StringPiece& GetName() const {
return name_;
}
@@ -749,6 +748,11 @@
return primitive_type_ != kPrimNot;
}
+ // Returns true if the class is synthetic.
+ bool IsSynthetic() const {
+ return (access_flags_ & kAccSynthetic) != 0;
+ }
+
// Returns true if this class can access that class.
bool CanAccess(const Class* that) const {
return that->IsPublic() || this->IsInSamePackage(that);