Home | History | Annotate | Download | only in dexlayout
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  *
     16  * Header file of an in-memory representation of DEX files.
     17  */
     18 
     19 #ifndef ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_
     20 #define ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_
     21 
     22 #include <memory>  // For unique_ptr
     23 #include <unordered_map>
     24 
     25 #include "base/utils.h"
     26 #include "dex_writer.h"
     27 
     28 namespace art {
     29 
     30 // Compact dex writer for a single dex.
     31 class CompactDexWriter : public DexWriter {
     32  public:
     33   explicit CompactDexWriter(DexLayout* dex_layout);
     34 
     35  protected:
     36   class Deduper {
     37    public:
     38     static const uint32_t kDidNotDedupe = 0;
     39 
     40     // if not enabled, Dedupe will always return kDidNotDedupe.
     41     explicit Deduper(bool enabled, DexContainer::Section* section);
     42 
     43     // Deduplicate a blob of data that has been written to mem_map.
     44     // Returns the offset of the deduplicated data or kDidNotDedupe did deduplication did not occur.
     45     uint32_t Dedupe(uint32_t data_start, uint32_t data_end, uint32_t item_offset);
     46 
     47     // Clear dedupe state to prevent deduplication against existing items in the future.
     48     void Clear() {
     49       dedupe_map_.clear();
     50     }
     51 
     52    private:
     53     class HashedMemoryRange {
     54      public:
     55       uint32_t offset_;
     56       uint32_t length_;
     57 
     58       class HashEqual {
     59        public:
     60         explicit HashEqual(DexContainer::Section* section) : section_(section) {}
     61 
     62         // Equal function.
     63         bool operator()(const HashedMemoryRange& a, const HashedMemoryRange& b) const {
     64           if (a.length_ != b.length_) {
     65             return false;
     66           }
     67           const uint8_t* data = Data();
     68           DCHECK_LE(a.offset_ + a.length_, section_->Size());
     69           DCHECK_LE(b.offset_ + b.length_, section_->Size());
     70           return std::equal(data + a.offset_, data + a.offset_ + a.length_, data + b.offset_);
     71         }
     72 
     73         // Hash function.
     74         size_t operator()(const HashedMemoryRange& range) const {
     75           DCHECK_LE(range.offset_ + range.length_, section_->Size());
     76           return HashBytes(Data() + range.offset_, range.length_);
     77         }
     78 
     79         ALWAYS_INLINE uint8_t* Data() const {
     80           return section_->Begin();
     81         }
     82 
     83        private:
     84         DexContainer::Section* const section_;
     85       };
     86     };
     87 
     88     const bool enabled_;
     89 
     90     // Dedupe map.
     91     std::unordered_map<HashedMemoryRange,
     92                        uint32_t,
     93                        HashedMemoryRange::HashEqual,
     94                        HashedMemoryRange::HashEqual> dedupe_map_;
     95   };
     96 
     97   // Handles alignment and deduping of a data section item.
     98   class ScopedDataSectionItem {
     99    public:
    100     ScopedDataSectionItem(Stream* stream, dex_ir::Item* item, size_t alignment, Deduper* deduper);
    101     ~ScopedDataSectionItem();
    102     size_t Written() const;
    103 
    104    private:
    105     Stream* const stream_;
    106     dex_ir::Item* const item_;
    107     const size_t alignment_;
    108     Deduper* deduper_;
    109     const uint32_t start_offset_;
    110   };
    111 
    112  public:
    113   class Container : public DexContainer {
    114    public:
    115     Section* GetMainSection() OVERRIDE {
    116       return &main_section_;
    117     }
    118 
    119     Section* GetDataSection() OVERRIDE {
    120       return &data_section_;
    121     }
    122 
    123     bool IsCompactDexContainer() const OVERRIDE {
    124       return true;
    125     }
    126 
    127    private:
    128     explicit Container(bool dedupe_code_items);
    129 
    130     VectorSection main_section_;
    131     VectorSection data_section_;
    132     Deduper code_item_dedupe_;
    133     Deduper data_item_dedupe_;
    134 
    135     friend class CompactDexWriter;
    136   };
    137 
    138  protected:
    139   // Return true if we can generate compact dex for the IR.
    140   bool CanGenerateCompactDex(std::string* error_msg);
    141 
    142   bool Write(DexContainer* output, std::string* error_msg) OVERRIDE;
    143 
    144   std::unique_ptr<DexContainer> CreateDexContainer() const OVERRIDE;
    145 
    146   void WriteHeader(Stream* stream) OVERRIDE;
    147 
    148   size_t GetHeaderSize() const OVERRIDE;
    149 
    150   uint32_t WriteDebugInfoOffsetTable(Stream* stream);
    151 
    152   void WriteCodeItem(Stream* stream, dex_ir::CodeItem* code_item, bool reserve_only) OVERRIDE;
    153 
    154   void WriteStringData(Stream* stream, dex_ir::StringData* string_data) OVERRIDE;
    155 
    156   void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) OVERRIDE;
    157 
    158   void SortDebugInfosByMethodIndex();
    159 
    160   CompactDexLevel GetCompactDexLevel() const;
    161 
    162  private:
    163   // Position in the compact dex file for the debug info table data starts.
    164   uint32_t debug_info_offsets_pos_ = 0u;
    165 
    166   // Offset into the debug info table data where the lookup table is.
    167   uint32_t debug_info_offsets_table_offset_ = 0u;
    168 
    169   // Base offset of where debug info starts in the dex file.
    170   uint32_t debug_info_base_ = 0u;
    171 
    172   // Part of the shared data section owned by this file.
    173   uint32_t owned_data_begin_ = 0u;
    174   uint32_t owned_data_end_ = 0u;
    175 
    176   // State for where we are deduping.
    177   Deduper* code_item_dedupe_ = nullptr;
    178   Deduper* data_item_dedupe_ = nullptr;
    179 
    180   DISALLOW_COPY_AND_ASSIGN(CompactDexWriter);
    181 };
    182 
    183 }  // namespace art
    184 
    185 #endif  // ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_
    186