Add number of methods to OatClass.
And use it for checks when reading oat file data.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 148412019
Change-Id: I3a2433f94397107a2ce3c198d22e660871c505a8
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 9898e7e..dae9d89 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -271,7 +271,15 @@
dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_;
// Data to write.
- uint32_t method_bitmap_size_;
+
+ // Number of methods recorded in OatClass. For `OatClassType::kNoneCompiled`
+ // this shall be zero and shall not be written to the file, otherwise it
+ // shall be the number of methods in the class definition. It is used to
+ // determine the size of `BitVector` data for `OatClassType::kSomeCompiled` and
+ // the size of the `OatMethodOffsets` table for `OatClassType::kAllCompiled`.
+ // (The size of the `OatMethodOffsets` table for `OatClassType::kSomeCompiled`
+ // is determined by the number of bits set in the `BitVector` data.)
+ uint32_t num_methods_;
// Bit vector indexed by ClassDef method index. When OatClass::type_ is
// OatClassType::kSomeCompiled, a set bit indicates the method has an
@@ -466,6 +474,7 @@
size_oat_class_offsets_(0),
size_oat_class_type_(0),
size_oat_class_status_(0),
+ size_oat_class_num_methods_(0),
size_oat_class_method_bitmaps_(0),
size_oat_class_method_offsets_(0),
size_method_bss_mappings_(0u),
@@ -2665,6 +2674,7 @@
DO_STAT(size_oat_class_offsets_);
DO_STAT(size_oat_class_type_);
DO_STAT(size_oat_class_status_);
+ DO_STAT(size_oat_class_num_methods_);
DO_STAT(size_oat_class_method_bitmaps_);
DO_STAT(size_oat_class_method_offsets_);
DO_STAT(size_method_bss_mappings_);
@@ -3986,15 +3996,18 @@
method_headers_.resize(compiled_methods_with_code);
uint32_t oat_method_offsets_offset_from_oat_class = OatClassHeader::SizeOf();
- // We only create this instance if there are at least some compiled.
- if (oat_class_type == enum_cast<uint16_t>(OatClassType::kSomeCompiled)) {
- method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator()));
- method_bitmap_size_ = method_bitmap_->GetSizeOf();
- oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_);
- oat_method_offsets_offset_from_oat_class += method_bitmap_size_;
- } else {
- method_bitmap_ = nullptr;
- method_bitmap_size_ = 0;
+ // We only write method-related data if there are at least some compiled methods.
+ num_methods_ = 0u;
+ DCHECK(method_bitmap_ == nullptr);
+ if (oat_class_type != enum_cast<uint16_t>(OatClassType::kNoneCompiled)) {
+ num_methods_ = num_methods;
+ oat_method_offsets_offset_from_oat_class += sizeof(num_methods_);
+ if (oat_class_type == enum_cast<uint16_t>(OatClassType::kSomeCompiled)) {
+ method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator()));
+ uint32_t bitmap_size = BitVector::BitsToWords(num_methods) * BitVector::kWordBytes;
+ DCHECK_EQ(bitmap_size, method_bitmap_->GetSizeOf());
+ oat_method_offsets_offset_from_oat_class += bitmap_size;
+ }
}
for (size_t i = 0; i < num_methods; i++) {
@@ -4012,9 +4025,9 @@
}
size_t OatWriter::OatClass::SizeOf() const {
- return ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_))
- + method_bitmap_size_
- + (sizeof(method_offsets_[0]) * method_offsets_.size());
+ return ((num_methods_ == 0) ? 0 : sizeof(num_methods_)) +
+ ((method_bitmap_ != nullptr) ? method_bitmap_->GetSizeOf() : 0u) +
+ (sizeof(method_offsets_[0]) * method_offsets_.size());
}
bool OatWriter::OatClassHeader::Write(OatWriter* oat_writer,
@@ -4036,18 +4049,20 @@
}
bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out) const {
- if (method_bitmap_size_ != 0) {
- if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
- PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
+ if (num_methods_ != 0u) {
+ if (!out->WriteFully(&num_methods_, sizeof(num_methods_))) {
+ PLOG(ERROR) << "Failed to write number of methods to " << out->GetLocation();
return false;
}
- oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
+ oat_writer->size_oat_class_num_methods_ += sizeof(num_methods_);
+ }
- if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
+ if (method_bitmap_ != nullptr) {
+ if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_->GetSizeOf())) {
PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
return false;
}
- oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
+ oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_->GetSizeOf();
}
if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) {
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index 5fbc01b..87174eb 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -538,6 +538,7 @@
uint32_t size_oat_class_offsets_;
uint32_t size_oat_class_type_;
uint32_t size_oat_class_status_;
+ uint32_t size_oat_class_num_methods_;
uint32_t size_oat_class_method_bitmaps_;
uint32_t size_oat_class_method_offsets_;
uint32_t size_method_bss_mappings_;
diff --git a/runtime/oat.h b/runtime/oat.h
index 9d872f9..8205935 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
class PACKED(4) OatHeader {
public:
static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } };
- // Last oat version changed reason: Move TypeLookupTables in .vdex file.
- static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '9', '3', '\0' } };
+ // Last oat version changed reason: Record number of methods in OatClass.
+ static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '9', '4', '\0' } };
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDebuggableKey = "debuggable";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index b646eb1..d4afe0c 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -2089,30 +2089,35 @@
ClassStatus status = enum_cast<ClassStatus>(status_value);
OatClassType type = enum_cast<OatClassType>(type_value);
- uint32_t bitmap_size = 0;
+ uint32_t num_methods = 0;
const uint32_t* bitmap_pointer = nullptr;
const OatMethodOffsets* methods_pointer = nullptr;
if (type != OatClassType::kNoneCompiled) {
+ CHECK_LE(sizeof(uint32_t), static_cast<size_t>(oat_file_->End() - current_pointer))
+ << oat_file_->GetLocation();
+ num_methods = *reinterpret_cast<const uint32_t*>(current_pointer);
+ current_pointer += sizeof(uint32_t);
+ CHECK_NE(num_methods, 0u) << oat_file_->GetLocation();
+ uint32_t num_method_offsets;
if (type == OatClassType::kSomeCompiled) {
- CHECK_LE(sizeof(uint32_t), static_cast<size_t>(oat_file_->End() - current_pointer))
- << oat_file_->GetLocation();
- bitmap_size = *reinterpret_cast<const uint32_t*>(current_pointer);
- current_pointer += sizeof(uint32_t);
+ uint32_t bitmap_size = BitVector::BitsToWords(num_methods) * BitVector::kWordBytes;
CHECK_LE(bitmap_size, static_cast<size_t>(oat_file_->End() - current_pointer))
<< oat_file_->GetLocation();
bitmap_pointer = reinterpret_cast<const uint32_t*>(current_pointer);
current_pointer += bitmap_size;
- CHECK_LE(BitVector::NumSetBits(bitmap_pointer, bitmap_size * kBitsPerByte),
- static_cast<size_t>(oat_file_->End() - current_pointer) / sizeof(OatMethodOffsets))
- << oat_file_->GetLocation();
+ // Note: The bits in range [num_methods, bitmap_size * kBitsPerByte)
+ // should be zero but we're not verifying that.
+ num_method_offsets = BitVector::NumSetBits(bitmap_pointer, num_methods);
} else {
- // TODO: We do not have enough information here to check if the array extends beyond
- // the end of the oat file. We should record the number of methods in the oat file.
+ num_method_offsets = num_methods;
}
+ CHECK_LE(num_method_offsets,
+ static_cast<size_t>(oat_file_->End() - current_pointer) / sizeof(OatMethodOffsets))
+ << oat_file_->GetLocation();
methods_pointer = reinterpret_cast<const OatMethodOffsets*>(current_pointer);
}
- return OatFile::OatClass(oat_file_, status, type, bitmap_size, bitmap_pointer, methods_pointer);
+ return OatFile::OatClass(oat_file_, status, type, num_methods, bitmap_pointer, methods_pointer);
}
const dex::ClassDef* OatDexFile::FindClassDef(const DexFile& dex_file,
@@ -2182,35 +2187,18 @@
OatFile::OatClass::OatClass(const OatFile* oat_file,
ClassStatus status,
OatClassType type,
- uint32_t bitmap_size,
+ uint32_t num_methods,
const uint32_t* bitmap_pointer,
const OatMethodOffsets* methods_pointer)
- : oat_file_(oat_file), status_(status), type_(type),
- bitmap_(bitmap_pointer), methods_pointer_(methods_pointer) {
- switch (type_) {
- case OatClassType::kAllCompiled: {
- CHECK_EQ(0U, bitmap_size);
- CHECK(bitmap_pointer == nullptr);
- CHECK(methods_pointer != nullptr);
- break;
- }
- case OatClassType::kSomeCompiled: {
- CHECK_NE(0U, bitmap_size);
- CHECK(bitmap_pointer != nullptr);
- CHECK(methods_pointer != nullptr);
- break;
- }
- case OatClassType::kNoneCompiled: {
- CHECK_EQ(0U, bitmap_size);
- CHECK(bitmap_pointer == nullptr);
- CHECK(methods_pointer_ == nullptr);
- break;
- }
- case OatClassType::kOatClassMax: {
- LOG(FATAL) << "Invalid OatClassType " << type_;
- UNREACHABLE();
- }
- }
+ : oat_file_(oat_file),
+ status_(status),
+ type_(type),
+ num_methods_(num_methods),
+ bitmap_(bitmap_pointer),
+ methods_pointer_(methods_pointer) {
+ DCHECK_EQ(num_methods != 0u, type != OatClassType::kNoneCompiled);
+ DCHECK_EQ(bitmap_pointer != nullptr, type == OatClassType::kSomeCompiled);
+ DCHECK_EQ(methods_pointer != nullptr, type != OatClassType::kNoneCompiled);
}
uint32_t OatFile::OatClass::GetOatMethodOffsetsOffset(uint32_t method_index) const {
@@ -2222,11 +2210,13 @@
}
const OatMethodOffsets* OatFile::OatClass::GetOatMethodOffsets(uint32_t method_index) const {
- // NOTE: We don't keep the number of methods and cannot do a bounds check for method_index.
+ // NOTE: We don't keep the number of methods for `kNoneCompiled` and cannot do
+ // a bounds check for `method_index` in that case.
if (methods_pointer_ == nullptr) {
CHECK_EQ(OatClassType::kNoneCompiled, type_);
return nullptr;
}
+ CHECK_LT(method_index, num_methods_) << oat_file_->GetLocation();
size_t methods_pointer_index;
if (bitmap_ == nullptr) {
CHECK_EQ(OatClassType::kAllCompiled, type_);
@@ -2239,6 +2229,12 @@
size_t num_set_bits = BitVector::NumSetBits(bitmap_, method_index);
methods_pointer_index = num_set_bits;
}
+ if (kIsDebugBuild) {
+ size_t size_until_end = dchecked_integral_cast<size_t>(
+ oat_file_->End() - reinterpret_cast<const uint8_t*>(methods_pointer_));
+ CHECK_LE(methods_pointer_index, size_until_end / sizeof(OatMethodOffsets))
+ << oat_file_->GetLocation();
+ }
const OatMethodOffsets& oat_method_offsets = methods_pointer_[methods_pointer_index];
return &oat_method_offsets;
}
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 3940bfe..0fd7032 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -283,18 +283,15 @@
OatClass(const OatFile* oat_file,
ClassStatus status,
OatClassType type,
- uint32_t bitmap_size,
+ uint32_t num_methods,
const uint32_t* bitmap_pointer,
const OatMethodOffsets* methods_pointer);
const OatFile* const oat_file_;
-
const ClassStatus status_;
-
const OatClassType type_;
-
+ const uint32_t num_methods_;
const uint32_t* const bitmap_;
-
const OatMethodOffsets* const methods_pointer_;
friend class art::OatDexFile;