Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 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_DEX_WRITER_H_ |
| 20 | #define ART_DEXLAYOUT_DEX_WRITER_H_ |
| 21 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 22 | #include <functional> |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 23 | #include <memory> // For unique_ptr |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 24 | |
David Sehr | c431b9d | 2018-03-02 12:01:51 -0800 | [diff] [blame] | 25 | #include "base/os.h" |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 26 | #include "base/unix_file/fd_file.h" |
David Sehr | 9e734c7 | 2018-01-04 17:56:19 -0800 | [diff] [blame] | 27 | #include "dex/compact_dex_level.h" |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 28 | #include "dex_container.h" |
Mathieu Chartier | 8892c6b | 2018-01-09 15:10:17 -0800 | [diff] [blame] | 29 | #include "dex/dex_file.h" |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 30 | #include "dex_ir.h" |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 31 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 32 | #include <queue> |
| 33 | |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 34 | namespace art { |
| 35 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 36 | class DexLayout; |
| 37 | class DexLayoutHotnessInfo; |
| 38 | |
| 39 | struct MapItem { |
| 40 | // Not using DexFile::MapItemType since compact dex and standard dex file may have different |
| 41 | // sections. |
| 42 | MapItem() = default; |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 43 | MapItem(uint32_t type, uint32_t size, size_t offset) |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 44 | : type_(type), size_(size), offset_(offset) { } |
| 45 | |
| 46 | // Sort by decreasing order since the priority_queue puts largest elements first. |
| 47 | bool operator>(const MapItem& other) const { |
| 48 | return offset_ > other.offset_; |
| 49 | } |
| 50 | |
| 51 | uint32_t type_ = 0u; |
| 52 | uint32_t size_ = 0u; |
| 53 | uint32_t offset_ = 0u; |
| 54 | }; |
| 55 | |
| 56 | class MapItemQueue : public |
| 57 | std::priority_queue<MapItem, std::vector<MapItem>, std::greater<MapItem>> { |
| 58 | public: |
| 59 | void AddIfNotEmpty(const MapItem& item); |
| 60 | }; |
| 61 | |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 62 | class DexWriter { |
| 63 | public: |
Mathieu Chartier | 8892c6b | 2018-01-09 15:10:17 -0800 | [diff] [blame] | 64 | static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2; |
| 65 | static constexpr uint32_t kDexSectionWordAlignment = 4; |
Mathieu Chartier | 8892c6b | 2018-01-09 15:10:17 -0800 | [diff] [blame] | 66 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 67 | // Stream that writes into a dex container section. Do not have two streams pointing to the same |
| 68 | // backing storage as there may be invalidation of backing storage to resize the section. |
| 69 | // Random access stream (consider refactoring). |
| 70 | class Stream { |
| 71 | public: |
| 72 | explicit Stream(DexContainer::Section* section) : section_(section) { |
| 73 | SyncWithSection(); |
| 74 | } |
| 75 | |
| 76 | const uint8_t* Begin() const { |
| 77 | return data_; |
| 78 | } |
| 79 | |
| 80 | // Functions are not virtual (yet) for speed. |
| 81 | size_t Tell() const { |
| 82 | return position_; |
| 83 | } |
| 84 | |
| 85 | void Seek(size_t position) { |
| 86 | position_ = position; |
Mathieu Chartier | 4e046e2 | 2018-01-25 16:55:44 -0800 | [diff] [blame] | 87 | EnsureStorage(0u); |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | // Does not allow overwriting for bug prevention purposes. |
| 91 | ALWAYS_INLINE size_t Write(const void* buffer, size_t length) { |
| 92 | EnsureStorage(length); |
| 93 | for (size_t i = 0; i < length; ++i) { |
| 94 | DCHECK_EQ(data_[position_ + i], 0u); |
| 95 | } |
| 96 | memcpy(&data_[position_], buffer, length); |
| 97 | position_ += length; |
| 98 | return length; |
| 99 | } |
| 100 | |
| 101 | ALWAYS_INLINE size_t Overwrite(const void* buffer, size_t length) { |
| 102 | EnsureStorage(length); |
| 103 | memcpy(&data_[position_], buffer, length); |
| 104 | position_ += length; |
| 105 | return length; |
| 106 | } |
| 107 | |
| 108 | ALWAYS_INLINE size_t Clear(size_t position, size_t length) { |
| 109 | EnsureStorage(length); |
| 110 | memset(&data_[position], 0, length); |
| 111 | return length; |
| 112 | } |
| 113 | |
| 114 | ALWAYS_INLINE size_t WriteSleb128(int32_t value) { |
| 115 | EnsureStorage(8); |
| 116 | uint8_t* ptr = &data_[position_]; |
| 117 | const size_t len = EncodeSignedLeb128(ptr, value) - ptr; |
| 118 | position_ += len; |
| 119 | return len; |
| 120 | } |
| 121 | |
| 122 | ALWAYS_INLINE size_t WriteUleb128(uint32_t value) { |
| 123 | EnsureStorage(8); |
| 124 | uint8_t* ptr = &data_[position_]; |
| 125 | const size_t len = EncodeUnsignedLeb128(ptr, value) - ptr; |
| 126 | position_ += len; |
| 127 | return len; |
| 128 | } |
| 129 | |
| 130 | ALWAYS_INLINE void AlignTo(const size_t alignment) { |
| 131 | position_ = RoundUp(position_, alignment); |
Mathieu Chartier | 4e046e2 | 2018-01-25 16:55:44 -0800 | [diff] [blame] | 132 | EnsureStorage(0u); |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | ALWAYS_INLINE void Skip(const size_t count) { |
| 136 | position_ += count; |
Mathieu Chartier | 4e046e2 | 2018-01-25 16:55:44 -0800 | [diff] [blame] | 137 | EnsureStorage(0u); |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 138 | } |
| 139 | |
| 140 | class ScopedSeek { |
| 141 | public: |
| 142 | ScopedSeek(Stream* stream, uint32_t offset) : stream_(stream), offset_(stream->Tell()) { |
| 143 | stream->Seek(offset); |
| 144 | } |
| 145 | |
| 146 | ~ScopedSeek() { |
| 147 | stream_->Seek(offset_); |
| 148 | } |
| 149 | |
| 150 | private: |
| 151 | Stream* const stream_; |
| 152 | const uint32_t offset_; |
| 153 | }; |
| 154 | |
| 155 | private: |
| 156 | ALWAYS_INLINE void EnsureStorage(size_t length) { |
| 157 | size_t end = position_ + length; |
| 158 | while (UNLIKELY(end > data_size_)) { |
| 159 | section_->Resize(data_size_ * 3 / 2 + 1); |
| 160 | SyncWithSection(); |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | void SyncWithSection() { |
| 165 | data_ = section_->Begin(); |
| 166 | data_size_ = section_->Size(); |
| 167 | } |
| 168 | |
| 169 | // Current position of the stream. |
| 170 | size_t position_ = 0u; |
| 171 | DexContainer::Section* const section_ = nullptr; |
| 172 | // Cached Begin() from the container to provide faster accesses. |
| 173 | uint8_t* data_ = nullptr; |
| 174 | // Cached Size from the container to provide faster accesses. |
| 175 | size_t data_size_ = 0u; |
| 176 | }; |
| 177 | |
Mathieu Chartier | 8892c6b | 2018-01-09 15:10:17 -0800 | [diff] [blame] | 178 | static inline constexpr uint32_t SectionAlignment(DexFile::MapItemType type) { |
| 179 | switch (type) { |
| 180 | case DexFile::kDexTypeClassDataItem: |
| 181 | case DexFile::kDexTypeStringDataItem: |
| 182 | case DexFile::kDexTypeDebugInfoItem: |
| 183 | case DexFile::kDexTypeAnnotationItem: |
| 184 | case DexFile::kDexTypeEncodedArrayItem: |
| 185 | return alignof(uint8_t); |
| 186 | |
| 187 | default: |
| 188 | // All other sections are kDexAlignedSection. |
| 189 | return DexWriter::kDexSectionWordAlignment; |
| 190 | } |
| 191 | } |
| 192 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 193 | class Container : public DexContainer { |
| 194 | public: |
Roland Levillain | bbc6e7e | 2018-08-24 16:58:47 +0100 | [diff] [blame] | 195 | Section* GetMainSection() override { |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 196 | return &main_section_; |
| 197 | } |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 198 | |
Roland Levillain | bbc6e7e | 2018-08-24 16:58:47 +0100 | [diff] [blame] | 199 | Section* GetDataSection() override { |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 200 | return &data_section_; |
| 201 | } |
| 202 | |
Roland Levillain | bbc6e7e | 2018-08-24 16:58:47 +0100 | [diff] [blame] | 203 | bool IsCompactDexContainer() const override { |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 204 | return false; |
| 205 | } |
| 206 | |
| 207 | private: |
| 208 | VectorSection main_section_; |
| 209 | VectorSection data_section_; |
| 210 | |
| 211 | friend class CompactDexWriter; |
| 212 | }; |
| 213 | |
| 214 | DexWriter(DexLayout* dex_layout, bool compute_offsets); |
| 215 | |
Mathieu Chartier | 05f90d1 | 2018-02-07 13:47:17 -0800 | [diff] [blame] | 216 | static bool Output(DexLayout* dex_layout, |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 217 | std::unique_ptr<DexContainer>* container, |
Mathieu Chartier | 05f90d1 | 2018-02-07 13:47:17 -0800 | [diff] [blame] | 218 | bool compute_offsets, |
| 219 | std::string* error_msg) WARN_UNUSED; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 220 | |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 221 | virtual ~DexWriter() {} |
| 222 | |
| 223 | protected: |
Mathieu Chartier | 05f90d1 | 2018-02-07 13:47:17 -0800 | [diff] [blame] | 224 | virtual bool Write(DexContainer* output, std::string* error_msg); |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 225 | virtual std::unique_ptr<DexContainer> CreateDexContainer() const; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 226 | |
Mathieu Chartier | 5e49614 | 2018-01-27 13:11:14 -0800 | [diff] [blame] | 227 | void WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value); |
| 228 | void WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg); |
| 229 | void WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values); |
| 230 | void WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation); |
| 231 | void WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields); |
| 232 | void WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 233 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 234 | // Header and id section |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 235 | virtual void WriteHeader(Stream* stream); |
Mathieu Chartier | f6e3147 | 2017-12-28 13:32:08 -0800 | [diff] [blame] | 236 | virtual size_t GetHeaderSize() const; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 237 | // reserve_only means don't write, only reserve space. This is required since the string data |
| 238 | // offsets must be assigned. |
Mathieu Chartier | 5e49614 | 2018-01-27 13:11:14 -0800 | [diff] [blame] | 239 | void WriteStringIds(Stream* stream, bool reserve_only); |
| 240 | void WriteTypeIds(Stream* stream); |
| 241 | void WriteProtoIds(Stream* stream, bool reserve_only); |
| 242 | void WriteFieldIds(Stream* stream); |
| 243 | void WriteMethodIds(Stream* stream); |
| 244 | void WriteClassDefs(Stream* stream, bool reserve_only); |
| 245 | void WriteCallSiteIds(Stream* stream, bool reserve_only); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 246 | |
Mathieu Chartier | 5e49614 | 2018-01-27 13:11:14 -0800 | [diff] [blame] | 247 | void WriteEncodedArrays(Stream* stream); |
| 248 | void WriteAnnotations(Stream* stream); |
| 249 | void WriteAnnotationSets(Stream* stream); |
| 250 | void WriteAnnotationSetRefs(Stream* stream); |
| 251 | void WriteAnnotationsDirectories(Stream* stream); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 252 | |
| 253 | // Data section. |
Mathieu Chartier | 5e49614 | 2018-01-27 13:11:14 -0800 | [diff] [blame] | 254 | void WriteDebugInfoItems(Stream* stream); |
| 255 | void WriteCodeItems(Stream* stream, bool reserve_only); |
| 256 | void WriteTypeLists(Stream* stream); |
| 257 | void WriteStringDatas(Stream* stream); |
| 258 | void WriteClassDatas(Stream* stream); |
| 259 | void WriteMethodHandles(Stream* stream); |
David Brazdil | 20c765f | 2018-10-27 21:45:15 +0000 | [diff] [blame] | 260 | void WriteHiddenapiClassData(Stream* stream); |
Mathieu Chartier | 5e49614 | 2018-01-27 13:11:14 -0800 | [diff] [blame] | 261 | void WriteMapItems(Stream* stream, MapItemQueue* queue); |
| 262 | void GenerateAndWriteMapItems(Stream* stream); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 263 | |
Mathieu Chartier | 5e49614 | 2018-01-27 13:11:14 -0800 | [diff] [blame] | 264 | virtual void WriteCodeItemPostInstructionData(Stream* stream, |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 265 | dex_ir::CodeItem* item, |
Mathieu Chartier | 8892c6b | 2018-01-09 15:10:17 -0800 | [diff] [blame] | 266 | bool reserve_only); |
Mathieu Chartier | b81ecad | 2018-01-23 22:08:26 -0800 | [diff] [blame] | 267 | virtual void WriteCodeItem(Stream* stream, dex_ir::CodeItem* item, bool reserve_only); |
| 268 | virtual void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info); |
| 269 | virtual void WriteStringData(Stream* stream, dex_ir::StringData* string_data); |
Mathieu Chartier | 8892c6b | 2018-01-09 15:10:17 -0800 | [diff] [blame] | 270 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 271 | // Process an offset, if compute_offset is set, write into the dex ir item, otherwise read the |
| 272 | // existing offset and use that for writing. |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 273 | void ProcessOffset(Stream* stream, dex_ir::Item* item); |
David Brazdil | 1783480 | 2019-01-21 19:46:46 +0000 | [diff] [blame] | 274 | void ProcessOffset(Stream* stream, dex_ir::CollectionBase* item); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 275 | |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 276 | dex_ir::Header* const header_; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame] | 277 | DexLayout* const dex_layout_; |
| 278 | bool compute_offsets_; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 279 | |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 280 | private: |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 281 | DISALLOW_COPY_AND_ASSIGN(DexWriter); |
| 282 | }; |
| 283 | |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 284 | } // namespace art |
| 285 | |
| 286 | #endif // ART_DEXLAYOUT_DEX_WRITER_H_ |