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 22 #include <functional> 23 #include <memory> // For unique_ptr 24 25 #include "base/os.h" 26 #include "base/unix_file/fd_file.h" 27 #include "dex/compact_dex_level.h" 28 #include "dex_container.h" 29 #include "dex/dex_file.h" 30 #include "dex_ir.h" 31 32 #include <queue> 33 34 namespace art { 35 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; 43 MapItem(uint32_t type, uint32_t size, size_t offset) 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 62 class DexWriter { 63 public: 64 static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2; 65 static constexpr uint32_t kDexSectionWordAlignment = 4; 66 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; 87 EnsureStorage(0u); 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); 132 EnsureStorage(0u); 133 } 134 135 ALWAYS_INLINE void Skip(const size_t count) { 136 position_ += count; 137 EnsureStorage(0u); 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 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 193 class Container : public DexContainer { 194 public: 195 Section* GetMainSection() override { 196 return &main_section_; 197 } 198 199 Section* GetDataSection() override { 200 return &data_section_; 201 } 202 203 bool IsCompactDexContainer() const override { 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 216 static bool Output(DexLayout* dex_layout, 217 std::unique_ptr<DexContainer>* container, 218 bool compute_offsets, 219 std::string* error_msg) WARN_UNUSED; 220 221 virtual ~DexWriter() {} 222 223 protected: 224 virtual bool Write(DexContainer* output, std::string* error_msg); 225 virtual std::unique_ptr<DexContainer> CreateDexContainer() const; 226 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); 233 234 // Header and id section 235 virtual void WriteHeader(Stream* stream); 236 virtual size_t GetHeaderSize() const; 237 // reserve_only means don't write, only reserve space. This is required since the string data 238 // offsets must be assigned. 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); 246 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); 252 253 // Data section. 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); 260 void WriteHiddenapiClassData(Stream* stream); 261 void WriteMapItems(Stream* stream, MapItemQueue* queue); 262 void GenerateAndWriteMapItems(Stream* stream); 263 264 virtual void WriteCodeItemPostInstructionData(Stream* stream, 265 dex_ir::CodeItem* item, 266 bool reserve_only); 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); 270 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. 273 void ProcessOffset(Stream* stream, dex_ir::Item* item); 274 void ProcessOffset(Stream* stream, dex_ir::CollectionBase* item); 275 276 dex_ir::Header* const header_; 277 DexLayout* const dex_layout_; 278 bool compute_offsets_; 279 280 private: 281 DISALLOW_COPY_AND_ASSIGN(DexWriter); 282 }; 283 284 } // namespace art 285 286 #endif // ART_DEXLAYOUT_DEX_WRITER_H_ 287