Home | History | Annotate | Download | only in dexlayout
      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 WriteMapItems(Stream* stream, MapItemQueue* queue);
    261   void GenerateAndWriteMapItems(Stream* stream);
    262 
    263   virtual void WriteCodeItemPostInstructionData(Stream* stream,
    264                                                     dex_ir::CodeItem* item,
    265                                                     bool reserve_only);
    266   virtual void WriteCodeItem(Stream* stream, dex_ir::CodeItem* item, bool reserve_only);
    267   virtual void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info);
    268   virtual void WriteStringData(Stream* stream, dex_ir::StringData* string_data);
    269 
    270   // Process an offset, if compute_offset is set, write into the dex ir item, otherwise read the
    271   // existing offset and use that for writing.
    272   void ProcessOffset(Stream* stream, dex_ir::Item* item);
    273 
    274   dex_ir::Header* const header_;
    275   DexLayout* const dex_layout_;
    276   bool compute_offsets_;
    277 
    278  private:
    279   DISALLOW_COPY_AND_ASSIGN(DexWriter);
    280 };
    281 
    282 }  // namespace art
    283 
    284 #endif  // ART_DEXLAYOUT_DEX_WRITER_H_
    285