lin
2025-07-31 065ea569db06206874bbfa18eb25ff6121aec09b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
 * 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_