blob: c81d0c722de2c91234186ed90160a77c50274432 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Header file of an in-memory representation of DEX files.
*/
#ifndef ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_
#define ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_
#include <memory> // For unique_ptr
#include <unordered_map>
#include "base/data_hash.h"
#include "dex_writer.h"
namespace art {
// Compact dex writer for a single dex.
class CompactDexWriter : public DexWriter {
public:
explicit CompactDexWriter(DexLayout* dex_layout);
protected:
class Deduper {
public:
static const uint32_t kDidNotDedupe = 0;
// if not enabled, Dedupe will always return kDidNotDedupe.
explicit Deduper(bool enabled, DexContainer::Section* section);
// Deduplicate a blob of data that has been written to mem_map.
// Returns the offset of the deduplicated data or kDidNotDedupe did deduplication did not occur.
uint32_t Dedupe(uint32_t data_start, uint32_t data_end, uint32_t item_offset);
// Clear dedupe state to prevent deduplication against existing items in the future.
void Clear() {
dedupe_map_.clear();
}
private:
class HashedMemoryRange {
public:
uint32_t offset_;
uint32_t length_;
class HashEqual {
public:
explicit HashEqual(DexContainer::Section* section) : section_(section) {}
// Equal function.
bool operator()(const HashedMemoryRange& a, const HashedMemoryRange& b) const {
if (a.length_ != b.length_) {
return false;
}
const uint8_t* data = Data();
DCHECK_LE(a.offset_ + a.length_, section_->Size());
DCHECK_LE(b.offset_ + b.length_, section_->Size());
return std::equal(data + a.offset_, data + a.offset_ + a.length_, data + b.offset_);
}
// Hash function.
size_t operator()(const HashedMemoryRange& range) const {
DCHECK_LE(range.offset_ + range.length_, section_->Size());
return HashBytes(Data() + range.offset_, range.length_);
}
ALWAYS_INLINE uint8_t* Data() const {
return section_->Begin();
}
private:
DexContainer::Section* const section_;
};
};
const bool enabled_;
// Dedupe map.
std::unordered_map<HashedMemoryRange,
uint32_t,
HashedMemoryRange::HashEqual,
HashedMemoryRange::HashEqual> dedupe_map_;
};
// Handles alignment and deduping of a data section item.
class ScopedDataSectionItem {
public:
ScopedDataSectionItem(Stream* stream, dex_ir::Item* item, size_t alignment, Deduper* deduper);
~ScopedDataSectionItem();
size_t Written() const;
private:
Stream* const stream_;
dex_ir::Item* const item_;
const size_t alignment_;
Deduper* deduper_;
const uint32_t start_offset_;
};
public:
class Container : public DexContainer {
public:
Section* GetMainSection() override {
return &main_section_;
}
Section* GetDataSection() override {
return &data_section_;
}
bool IsCompactDexContainer() const override {
return true;
}
private:
explicit Container(bool dedupe_code_items);
VectorSection main_section_;
VectorSection data_section_;
Deduper code_item_dedupe_;
Deduper data_item_dedupe_;
friend class CompactDexWriter;
};
protected:
// Return true if we can generate compact dex for the IR.
bool CanGenerateCompactDex(std::string* error_msg);
bool Write(DexContainer* output, std::string* error_msg) override;
std::unique_ptr<DexContainer> CreateDexContainer() const override;
void WriteHeader(Stream* stream) override;
size_t GetHeaderSize() const override;
uint32_t WriteDebugInfoOffsetTable(Stream* stream);
void WriteCodeItem(Stream* stream, dex_ir::CodeItem* code_item, bool reserve_only) override;
void WriteStringData(Stream* stream, dex_ir::StringData* string_data) override;
void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) override;
void SortDebugInfosByMethodIndex();
CompactDexLevel GetCompactDexLevel() const;
private:
// Position in the compact dex file for the debug info table data starts.
uint32_t debug_info_offsets_pos_ = 0u;
// Offset into the debug info table data where the lookup table is.
uint32_t debug_info_offsets_table_offset_ = 0u;
// Base offset of where debug info starts in the dex file.
uint32_t debug_info_base_ = 0u;
// Part of the shared data section owned by this file.
uint32_t owned_data_begin_ = 0u;
uint32_t owned_data_end_ = 0u;
// State for where we are deduping.
Deduper* code_item_dedupe_ = nullptr;
Deduper* data_item_dedupe_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(CompactDexWriter);
};
} // namespace art
#endif // ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_