summaryrefslogtreecommitdiff
path: root/runtime/mirror/class.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/mirror/class.cc')
-rw-r--r--runtime/mirror/class.cc126
1 files changed, 124 insertions, 2 deletions
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 12fbc36926..43dbc43115 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -451,15 +451,28 @@ void Class::DumpClass(std::ostream& os, int flags) {
}
void Class::SetReferenceInstanceOffsets(uint32_t new_reference_offsets) {
- if (kIsDebugBuild && new_reference_offsets != kClassWalkSuper) {
+ if (kIsDebugBuild) {
// Check that the number of bits set in the reference offset bitmap
// agrees with the number of references.
uint32_t count = 0;
for (ObjPtr<Class> c = this; c != nullptr; c = c->GetSuperClass()) {
count += c->NumReferenceInstanceFieldsDuringLinking();
}
+ uint32_t pop_cnt;
+ if ((new_reference_offsets & kVisitReferencesSlowpathMask) == 0) {
+ pop_cnt = static_cast<uint32_t>(POPCOUNT(new_reference_offsets));
+ } else {
+ uint32_t bitmap_num_words = new_reference_offsets & ~kVisitReferencesSlowpathMask;
+ uint32_t* overflow_bitmap =
+ reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(this) +
+ (GetClassSize() - bitmap_num_words * sizeof(uint32_t)));
+ pop_cnt = 0;
+ for (uint32_t i = 0; i < bitmap_num_words; i++) {
+ pop_cnt += static_cast<uint32_t>(POPCOUNT(overflow_bitmap[i]));
+ }
+ }
// +1 for the Class in Object.
- CHECK_EQ(static_cast<uint32_t>(POPCOUNT(new_reference_offsets)) + 1, count);
+ CHECK_EQ(pop_cnt + 1, count);
}
// Not called within a transaction.
SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_),
@@ -1607,6 +1620,114 @@ void Class::PopulateEmbeddedVTable(PointerSize pointer_size) {
}
}
+// Set the bitmap of reference instance field offsets.
+void Class::PopulateReferenceOffsetBitmap() {
+ size_t num_reference_fields;
+ ObjPtr<mirror::Class> super_class;
+ ObjPtr<Class> klass;
+ // Find the first class with non-zero instance reference fields.
+ for (klass = this; klass != nullptr; klass = super_class) {
+ super_class = klass->GetSuperClass();
+ num_reference_fields = klass->NumReferenceInstanceFieldsDuringLinking();
+ if (num_reference_fields != 0) {
+ break;
+ }
+ }
+
+ uint32_t ref_offsets = 0;
+ // Leave the reference offsets as 0 for mirror::Object (the class field is handled specially).
+ if (super_class != nullptr) {
+ // All of the reference fields added by this class are guaranteed to be grouped in memory
+ // starting at an appropriately aligned address after super class object data.
+ uint32_t start_offset =
+ RoundUp(super_class->GetObjectSize(), sizeof(mirror::HeapReference<mirror::Object>));
+ uint32_t start_bit =
+ (start_offset - mirror::kObjectHeaderSize) / sizeof(mirror::HeapReference<mirror::Object>);
+ uint32_t end_bit = start_bit + num_reference_fields;
+ bool overflowing = end_bit > 31;
+ uint32_t* overflow_bitmap; // Pointer to the last word of overflow bitmap to be written into.
+ uint32_t overflow_words_to_write; // Number of overflow bitmap words remaining to write.
+ // Index in 'overflow_bitmap' from where to start writing bitmap words (in reverse order).
+ int32_t overflow_bitmap_word_idx;
+ if (overflowing) {
+ // We will write overflow bitmap in reverse.
+ overflow_bitmap =
+ reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(this) + GetClassSize());
+ DCHECK_ALIGNED(overflow_bitmap, sizeof(uint32_t));
+ overflow_bitmap_word_idx = 0;
+ overflow_words_to_write = RoundUp(end_bit, 32) / 32;
+ }
+ // TODO: Simplify by copying the bitmap from the super-class and then
+ // appending the reference fields added by this class.
+ while (true) {
+ if (UNLIKELY(overflowing)) {
+ // Write all the bitmap words which got skipped between previous
+ // super-class and the current one.
+ for (uint32_t new_words_to_write = RoundUp(end_bit, 32) / 32;
+ overflow_words_to_write > new_words_to_write;
+ overflow_words_to_write--) {
+ overflow_bitmap[--overflow_bitmap_word_idx] = ref_offsets;
+ ref_offsets = 0;
+ }
+ // Handle the references in the current super-class.
+ if (num_reference_fields != 0u) {
+ uint32_t aligned_end_bit = RoundDown(end_bit, 32);
+ uint32_t aligned_start_bit = RoundUp(start_bit, 32);
+ // Handle the case where a class' references are spanning across multiple 32-bit
+ // words of the overflow bitmap.
+ if (aligned_end_bit >= aligned_start_bit) {
+ // handle the unaligned end first
+ if (aligned_end_bit < end_bit) {
+ ref_offsets |= 0xffffffffu >> (32 - (end_bit - aligned_end_bit));
+ overflow_bitmap[--overflow_bitmap_word_idx] = ref_offsets;
+ overflow_words_to_write--;
+ ref_offsets = 0;
+ }
+ // store all the 32-bit bitmap words in between
+ for (; aligned_end_bit > aligned_start_bit; aligned_end_bit -= 32) {
+ overflow_bitmap[--overflow_bitmap_word_idx] = 0xffffffffu;
+ overflow_words_to_write--;
+ }
+ CHECK_EQ(ref_offsets, 0u);
+ // handle the unaligned start now
+ if (aligned_start_bit > start_bit) {
+ ref_offsets = 0xffffffffu << (32 - (aligned_start_bit - start_bit));
+ }
+ } else {
+ DCHECK_EQ(aligned_start_bit - aligned_end_bit, 32u);
+ ref_offsets |= (0xffffffffu << (32 - (aligned_start_bit - start_bit))) &
+ (0xffffffffu >> (32 - (end_bit - aligned_end_bit)));
+ }
+ }
+ } else if (num_reference_fields != 0u) {
+ ref_offsets |= (0xffffffffu << start_bit) & (0xffffffffu >> (32 - end_bit));
+ }
+
+ klass = super_class;
+ super_class = klass->GetSuperClass();
+ if (super_class == nullptr) {
+ break;
+ }
+ num_reference_fields = klass->NumReferenceInstanceFieldsDuringLinking();
+ start_offset =
+ RoundUp(super_class->GetObjectSize(), sizeof(mirror::HeapReference<mirror::Object>));
+ start_bit = (start_offset - mirror::kObjectHeaderSize) /
+ sizeof(mirror::HeapReference<mirror::Object>);
+ end_bit = start_bit + num_reference_fields;
+ }
+ if (overflowing) {
+ // We should not have more than one word left to write in the overflow bitmap.
+ DCHECK_LE(overflow_words_to_write, 1u)
+ << "overflow_bitmap_word_idx:" << -overflow_bitmap_word_idx;
+ if (overflow_words_to_write > 0) {
+ overflow_bitmap[--overflow_bitmap_word_idx] = ref_offsets;
+ }
+ ref_offsets = -overflow_bitmap_word_idx | kVisitReferencesSlowpathMask;
+ }
+ }
+ SetReferenceInstanceOffsets(ref_offsets);
+}
+
class ReadBarrierOnNativeRootsVisitor {
public:
void operator()([[maybe_unused]] ObjPtr<Object> obj,
@@ -1657,6 +1778,7 @@ class CopyClassVisitor {
h_new_class_obj->PopulateEmbeddedVTable(pointer_size_);
h_new_class_obj->SetImt(imt_, pointer_size_);
h_new_class_obj->SetClassSize(new_length_);
+ h_new_class_obj->PopulateReferenceOffsetBitmap();
// Visit all of the references to make sure there is no from space references in the native
// roots.
h_new_class_obj->Object::VisitReferences(ReadBarrierOnNativeRootsVisitor(), VoidFunctor());