Move mapping table and vmap table offsets to OatMethodHeader.
This change has a libcore/ companion CL
"Remove ArtMethod's quick fields mapping table and vmap table."
https://android-review.googlesource.com/91254
Bug: 11767815
Change-Id: I46ce2067e1ecd915da3890606498e31ffc332813
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index fdf09a5..8bba84a 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -132,34 +132,24 @@
class CommonCompilerTest : public CommonRuntimeTest {
public:
- static void MakeExecutable(const std::vector<uint8_t>& code) {
- CHECK_NE(code.size(), 0U);
- MakeExecutable(&code[0], code.size());
- }
-
// Create an OatMethod based on pointers (for unit tests).
OatFile::OatMethod CreateOatMethod(const void* code,
const size_t frame_size_in_bytes,
const uint32_t core_spill_mask,
const uint32_t fp_spill_mask,
- const uint8_t* mapping_table,
- const uint8_t* vmap_table,
const uint8_t* gc_map) {
+ CHECK(code != nullptr);
const byte* base;
- uint32_t code_offset, mapping_table_offset, vmap_table_offset, gc_map_offset;
- if (mapping_table == nullptr && vmap_table == nullptr && gc_map == nullptr) {
+ uint32_t code_offset, gc_map_offset;
+ if (gc_map == nullptr) {
base = reinterpret_cast<const byte*>(code); // Base of data points at code.
base -= kPointerSize; // Move backward so that code_offset != 0.
code_offset = kPointerSize;
- mapping_table_offset = 0;
- vmap_table_offset = 0;
gc_map_offset = 0;
} else {
// TODO: 64bit support.
base = nullptr; // Base of data in oat file, ie 0.
code_offset = PointerToLowMemUInt32(code);
- mapping_table_offset = PointerToLowMemUInt32(mapping_table);
- vmap_table_offset = PointerToLowMemUInt32(vmap_table);
gc_map_offset = PointerToLowMemUInt32(gc_map);
}
return OatFile::OatMethod(base,
@@ -167,8 +157,6 @@
frame_size_in_bytes,
core_spill_mask,
fp_spill_mask,
- mapping_table_offset,
- vmap_table_offset,
gc_map_offset);
}
@@ -185,19 +173,44 @@
}
if (compiled_method != nullptr) {
const std::vector<uint8_t>* code = compiled_method->GetQuickCode();
- if (code == nullptr) {
+ const void* code_ptr;
+ if (code != nullptr) {
+ uint32_t code_size = code->size();
+ CHECK_NE(0u, code_size);
+ const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
+ uint32_t vmap_table_offset = vmap_table.empty() ? 0u
+ : sizeof(OatMethodHeader) + vmap_table.size();
+ const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
+ uint32_t mapping_table_offset = mapping_table.empty() ? 0u
+ : sizeof(OatMethodHeader) + vmap_table.size() + mapping_table.size();
+ OatMethodHeader method_header(vmap_table_offset, mapping_table_offset, code_size);
+
+ header_code_and_maps_chunks_.push_back(std::vector<uint8_t>());
+ std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back();
+ size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table.size();
+ size_t code_offset = compiled_method->AlignCode(size - code_size);
+ size_t padding = code_offset - (size - code_size);
+ chunk->reserve(padding + size);
+ chunk->resize(sizeof(method_header));
+ memcpy(&(*chunk)[0], &method_header, sizeof(method_header));
+ chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end());
+ chunk->insert(chunk->begin(), mapping_table.begin(), mapping_table.end());
+ chunk->insert(chunk->begin(), padding, 0);
+ chunk->insert(chunk->end(), code->begin(), code->end());
+ CHECK_EQ(padding + size, chunk->size());
+ code_ptr = &(*chunk)[code_offset];
+ } else {
code = compiled_method->GetPortableCode();
+ code_ptr = &(*code)[0];
}
- MakeExecutable(*code);
- const void* method_code = CompiledMethod::CodePointer(&(*code)[0],
+ MakeExecutable(code_ptr, code->size());
+ const void* method_code = CompiledMethod::CodePointer(code_ptr,
compiled_method->GetInstructionSet());
LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
OatFile::OatMethod oat_method = CreateOatMethod(method_code,
compiled_method->GetFrameSizeInBytes(),
compiled_method->GetCoreSpillMask(),
compiled_method->GetFpSpillMask(),
- &compiled_method->GetMappingTable()[0],
- &compiled_method->GetVmapTable()[0],
nullptr);
oat_method.LinkMethod(method);
method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
@@ -211,8 +224,6 @@
kStackAlignment,
0,
0,
- nullptr,
- nullptr,
nullptr);
oat_method.LinkMethod(method);
method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
@@ -230,8 +241,6 @@
sirt_size,
callee_save_method->GetCoreSpillMask(),
callee_save_method->GetFpSpillMask(),
- nullptr,
- nullptr,
nullptr);
oat_method.LinkMethod(method);
method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
@@ -436,6 +445,9 @@
private:
UniquePtr<MemMap> image_reservation_;
+
+ // Chunks must not move their storage after being created - use the node-based std::list.
+ std::list<std::vector<uint8_t> > header_code_and_maps_chunks_;
};
} // namespace art
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 3400b01..c35d400 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -680,14 +680,6 @@
copy->SetNativeMethod<kVerifyNone>(GetOatAddress(jni_dlsym_lookup_offset_));
} else {
// Normal (non-abstract non-native) methods have various tables to relocate.
- uint32_t mapping_table_off = orig->GetOatMappingTableOffset();
- const byte* mapping_table = GetOatAddress(mapping_table_off);
- copy->SetMappingTable<kVerifyNone>(mapping_table);
-
- uint32_t vmap_table_offset = orig->GetOatVmapTableOffset();
- const byte* vmap_table = GetOatAddress(vmap_table_offset);
- copy->SetVmapTable<kVerifyNone>(vmap_table);
-
uint32_t native_gc_map_offset = orig->GetOatNativeGcMapOffset();
const byte* native_gc_map = GetOatAddress(native_gc_map_offset);
copy->SetNativeGcMap<kVerifyNone>(reinterpret_cast<const uint8_t*>(native_gc_map));
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 766ef7b..b5d3923 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -176,7 +176,8 @@
// If this test is failing and you have to update these constants,
// it is time to update OatHeader::kOatVersion
EXPECT_EQ(80U, sizeof(OatHeader));
- EXPECT_EQ(28U, sizeof(OatMethodOffsets));
+ EXPECT_EQ(20U, sizeof(OatMethodOffsets));
+ EXPECT_EQ(12U, sizeof(OatMethodHeader));
}
TEST_F(OatTest, OatHeaderIsValid) {
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 2114fe9..bbc9c3e 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -155,12 +155,15 @@
}
static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
- return oat_class->method_offsets_[method_offsets_index].mapping_table_offset_;
+ uint32_t offset = oat_class->method_headers_[method_offsets_index].mapping_table_offset_;
+ return offset == 0u ? 0u :
+ (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
}
static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
ALWAYS_INLINE {
- oat_class->method_offsets_[method_offsets_index].mapping_table_offset_ = offset;
+ oat_class->method_headers_[method_offsets_index].mapping_table_offset_ =
+ (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
}
static const char* Name() ALWAYS_INLINE {
@@ -174,12 +177,15 @@
}
static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
- return oat_class->method_offsets_[method_offsets_index].vmap_table_offset_;
+ uint32_t offset = oat_class->method_headers_[method_offsets_index].vmap_table_offset_;
+ return offset == 0u ? 0u :
+ (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
}
static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
ALWAYS_INLINE {
- oat_class->method_offsets_[method_offsets_index].vmap_table_offset_ = offset;
+ oat_class->method_headers_[method_offsets_index].vmap_table_offset_ =
+ (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
}
static const char* Name() ALWAYS_INLINE {
@@ -368,17 +374,22 @@
}
}
+ DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
+ OatMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
+ method_header->code_size_ = code_size;
+
// Deduplicate code arrays.
- auto code_iter = dedupe_map_.find(quick_code);
+ auto code_iter = dedupe_map_.find(compiled_method);
if (code_iter != dedupe_map_.end()) {
quick_code_offset = code_iter->second;
+ FixupMethodHeader(method_header, quick_code_offset - thumb_offset);
} else {
- dedupe_map_.Put(quick_code, quick_code_offset);
- OatMethodHeader method_header(code_size);
- offset_ += sizeof(method_header); // Method header is prepended before code.
- writer_->oat_header_->UpdateChecksum(&method_header, sizeof(method_header));
- offset_ += code_size;
+ dedupe_map_.Put(compiled_method, quick_code_offset);
+ FixupMethodHeader(method_header, quick_code_offset - thumb_offset);
+ writer_->oat_header_->UpdateChecksum(method_header, sizeof(*method_header));
+ offset_ += sizeof(*method_header); // Method header is prepended before code.
writer_->oat_header_->UpdateChecksum(&(*quick_code)[0], code_size);
+ offset_ += code_size;
}
}
frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
@@ -420,9 +431,22 @@
}
private:
+ static void FixupMethodHeader(OatMethodHeader* method_header, uint32_t code_offset) {
+ // The code offset was 0 when the mapping/vmap table offset was set, so it's set
+ // to 0-offset and we need to adjust it by code_offset.
+ if (method_header->mapping_table_offset_ != 0u) {
+ method_header->mapping_table_offset_ += code_offset;
+ DCHECK_LT(method_header->mapping_table_offset_, code_offset);
+ }
+ if (method_header->vmap_table_offset_ != 0u) {
+ method_header->vmap_table_offset_ += code_offset;
+ DCHECK_LT(method_header->vmap_table_offset_, code_offset);
+ }
+ }
+
// Deduplication is already done on a pointer basis by the compiler driver,
// so we can simply compare the pointers to find out if things are duplicated.
- SafeMap<const std::vector<uint8_t>*, uint32_t> dedupe_map_;
+ SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
};
template <typename DataAccess>
@@ -477,7 +501,7 @@
OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
- OatMethodOffsets offsets(0u, kStackAlignment, 0u, 0u, 0u, 0u, 0u);
+ OatMethodOffsets offsets(0u, kStackAlignment, 0u, 0u, 0u);
if (compiled_method != nullptr) {
DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
offsets = oat_class->method_offsets_[method_offsets_index_];
@@ -511,8 +535,6 @@
offsets.frame_size_in_bytes_ = callee_save_method->GetFrameSizeInBytes() + sirt_size;
offsets.core_spill_mask_ = callee_save_method->GetCoreSpillMask();
offsets.fp_spill_mask_ = callee_save_method->GetFpSpillMask();
- DCHECK_EQ(offsets.mapping_table_offset_, 0u);
- DCHECK_EQ(offsets.vmap_table_offset_, 0u);
DCHECK_EQ(offsets.gc_map_offset_, 0u);
}
@@ -528,10 +550,8 @@
method->SetFrameSizeInBytes(offsets.frame_size_in_bytes_);
method->SetCoreSpillMask(offsets.core_spill_mask_);
method->SetFpSpillMask(offsets.fp_spill_mask_);
- method->SetOatMappingTableOffset(offsets.mapping_table_offset_);
// Portable code offsets are set by ElfWriterMclinker::FixupCompiledCodeOffset after linking.
method->SetQuickOatCodeOffset(offsets.code_offset_);
- method->SetOatVmapTableOffset(offsets.vmap_table_offset_);
method->SetOatNativeGcMapOffset(offsets.gc_map_offset_);
return true;
@@ -584,7 +604,7 @@
offset_ + sizeof(OatMethodHeader) + compiled_method->CodeDelta())
<< PrettyMethod(it.GetMemberIndex(), *dex_file_);
if (method_offsets.code_offset_ >= offset_) {
- OatMethodHeader method_header(code_size);
+ const OatMethodHeader& method_header = oat_class->method_headers_[method_offsets_index_];
if (!out->WriteFully(&method_header, sizeof(method_header))) {
ReportWriteFailure("method header", it);
return false;
@@ -1153,6 +1173,7 @@
status_ = status;
method_offsets_.resize(num_non_null_compiled_methods);
+ method_headers_.resize(num_non_null_compiled_methods);
uint32_t oat_method_offsets_offset_from_oat_class = sizeof(type_) + sizeof(status_);
if (type_ == kOatClassSomeCompiled) {
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 1abacd8..7cdd532 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -225,12 +225,13 @@
// not is kOatClassBitmap, the bitmap will be NULL.
BitVector* method_bitmap_;
- // OatMethodOffsets for each CompiledMethod present in the
- // OatClass. Note that some may be missing if
+ // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
+ // present in the OatClass. Note that some may be missing if
// OatClass::compiled_methods_ contains NULL values (and
// oat_method_offsets_offsets_from_oat_class_ should contain 0
// values in this case).
std::vector<OatMethodOffsets> method_offsets_;
+ std::vector<OatMethodHeader> method_headers_;
private:
DISALLOW_COPY_AND_ASSIGN(OatClass);
@@ -299,6 +300,22 @@
uint32_t size_oat_class_method_bitmaps_;
uint32_t size_oat_class_method_offsets_;
+ struct CodeOffsetsKeyComparator {
+ bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
+ if (lhs->GetQuickCode() != rhs->GetQuickCode()) {
+ return lhs->GetQuickCode() < rhs->GetQuickCode();
+ }
+ // If the code is the same, all other fields are likely to be the same as well.
+ if (UNLIKELY(&lhs->GetMappingTable() != &rhs->GetMappingTable())) {
+ return &lhs->GetMappingTable() < &rhs->GetMappingTable();
+ }
+ if (UNLIKELY(&lhs->GetVmapTable() != &rhs->GetVmapTable())) {
+ return &lhs->GetVmapTable() < &rhs->GetVmapTable();
+ }
+ return false;
+ }
+ };
+
DISALLOW_COPY_AND_ASSIGN(OatWriter);
};