Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2015 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 
     17 #include "stack_map.h"
     18 
     19 #include <iomanip>
     20 #include <stdint.h>
     21 
     22 #include "art_method.h"
     23 #include "base/indenter.h"
     24 #include "base/stats.h"
     25 #include "oat_quick_method_header.h"
     26 #include "scoped_thread_state_change-inl.h"
     27 
     28 namespace art {
     29 
     30 CodeInfo::CodeInfo(const OatQuickMethodHeader* header, DecodeFlags flags)
     31   : CodeInfo(header->GetOptimizedCodeInfoPtr(), flags) {
     32 }
     33 
     34 // Returns true if the decoded table was deduped.
     35 template<typename Accessor>
     36 ALWAYS_INLINE static bool DecodeTable(BitTable<Accessor>& table, BitMemoryReader& reader) {
     37   bool is_deduped = reader.ReadBit();
     38   if (is_deduped) {
     39     ssize_t bit_offset = reader.NumberOfReadBits() - reader.ReadVarint();
     40     BitMemoryReader reader2(reader.data(), bit_offset);  // The offset is negative.
     41     table.Decode(reader2);
     42   } else {
     43     table.Decode(reader);
     44   }
     45   return is_deduped;
     46 }
     47 
     48 void CodeInfo::Decode(const uint8_t* data, DecodeFlags flags) {
     49   BitMemoryReader reader(data);
     50   ForEachHeaderField([this, &reader](auto member_pointer) {
     51     this->*member_pointer = reader.ReadVarint();
     52   });
     53   ForEachBitTableField([this, &reader](auto member_pointer) {
     54     DecodeTable(this->*member_pointer, reader);
     55   }, flags);
     56   size_in_bits_ = reader.NumberOfReadBits();
     57 }
     58 
     59 size_t CodeInfo::Deduper::Dedupe(const uint8_t* code_info_data) {
     60   writer_.ByteAlign();
     61   size_t deduped_offset = writer_.NumberOfWrittenBits() / kBitsPerByte;
     62   BitMemoryReader reader(code_info_data);
     63   CodeInfo code_info;  // Temporary storage for decoded data.
     64   ForEachHeaderField([this, &reader, &code_info](auto member_pointer) {
     65     code_info.*member_pointer = reader.ReadVarint();
     66     writer_.WriteVarint(code_info.*member_pointer);
     67   });
     68   ForEachBitTableField([this, &reader, &code_info](auto member_pointer) {
     69     bool is_deduped = reader.ReadBit();
     70     DCHECK(!is_deduped);
     71     size_t bit_table_start = reader.NumberOfReadBits();
     72     (code_info.*member_pointer).Decode(reader);
     73     BitMemoryRegion region = reader.GetReadRegion().Subregion(bit_table_start);
     74     auto it = dedupe_map_.insert(std::make_pair(region, /* placeholder */ 0));
     75     if (it.second /* new bit table */ || region.size_in_bits() < 32) {
     76       writer_.WriteBit(false);  // Is not deduped.
     77       it.first->second = writer_.NumberOfWrittenBits();
     78       writer_.WriteRegion(region);
     79     } else {
     80       writer_.WriteBit(true);  // Is deduped.
     81       size_t bit_offset = writer_.NumberOfWrittenBits();
     82       writer_.WriteVarint(bit_offset - it.first->second);
     83     }
     84   });
     85 
     86   if (kIsDebugBuild) {
     87     CodeInfo old_code_info(code_info_data);
     88     CodeInfo new_code_info(writer_.data() + deduped_offset);
     89     ForEachHeaderField([&old_code_info, &new_code_info](auto member_pointer) {
     90       DCHECK_EQ(old_code_info.*member_pointer, new_code_info.*member_pointer);
     91     });
     92     ForEachBitTableField([&old_code_info, &new_code_info](auto member_pointer) {
     93       DCHECK((old_code_info.*member_pointer).Equals(new_code_info.*member_pointer));
     94     });
     95   }
     96 
     97   return deduped_offset;
     98 }
     99 
    100 BitTable<StackMap>::const_iterator CodeInfo::BinarySearchNativePc(uint32_t packed_pc) const {
    101   return std::partition_point(
    102       stack_maps_.begin(),
    103       stack_maps_.end(),
    104       [packed_pc](const StackMap& sm) {
    105         return sm.GetPackedNativePc() < packed_pc && sm.GetKind() != StackMap::Kind::Catch;
    106       });
    107 }
    108 
    109 StackMap CodeInfo::GetStackMapForNativePcOffset(uint32_t pc, InstructionSet isa) const {
    110   auto it = BinarySearchNativePc(StackMap::PackNativePc(pc, isa));
    111   // Start at the lower bound and iterate over all stack maps with the given native pc.
    112   for (; it != stack_maps_.end() && (*it).GetNativePcOffset(isa) == pc; ++it) {
    113     StackMap::Kind kind = static_cast<StackMap::Kind>((*it).GetKind());
    114     if (kind == StackMap::Kind::Default || kind == StackMap::Kind::OSR) {
    115       return *it;
    116     }
    117   }
    118   return stack_maps_.GetInvalidRow();
    119 }
    120 
    121 // Scan backward to determine dex register locations at given stack map.
    122 // All registers for a stack map are combined - inlined registers are just appended,
    123 // therefore 'first_dex_register' allows us to select a sub-range to decode.
    124 void CodeInfo::DecodeDexRegisterMap(uint32_t stack_map_index,
    125                                     uint32_t first_dex_register,
    126                                     /*out*/ DexRegisterMap* map) const {
    127   // Count remaining work so we know when we have finished.
    128   uint32_t remaining_registers = map->size();
    129 
    130   // Keep scanning backwards and collect the most recent location of each register.
    131   for (int32_t s = stack_map_index; s >= 0 && remaining_registers != 0; s--) {
    132     StackMap stack_map = GetStackMapAt(s);
    133     DCHECK_LE(stack_map_index - s, kMaxDexRegisterMapSearchDistance) << "Unbounded search";
    134 
    135     // The mask specifies which registers where modified in this stack map.
    136     // NB: the mask can be shorter than expected if trailing zero bits were removed.
    137     uint32_t mask_index = stack_map.GetDexRegisterMaskIndex();
    138     if (mask_index == StackMap::kNoValue) {
    139       continue;  // Nothing changed at this stack map.
    140     }
    141     BitMemoryRegion mask = dex_register_masks_.GetBitMemoryRegion(mask_index);
    142     if (mask.size_in_bits() <= first_dex_register) {
    143       continue;  // Nothing changed after the first register we are interested in.
    144     }
    145 
    146     // The map stores one catalogue index per each modified register location.
    147     uint32_t map_index = stack_map.GetDexRegisterMapIndex();
    148     DCHECK_NE(map_index, StackMap::kNoValue);
    149 
    150     // Skip initial registers which we are not interested in (to get to inlined registers).
    151     map_index += mask.PopCount(0, first_dex_register);
    152     mask = mask.Subregion(first_dex_register, mask.size_in_bits() - first_dex_register);
    153 
    154     // Update registers that we see for first time (i.e. most recent value).
    155     DexRegisterLocation* regs = map->data();
    156     const uint32_t end = std::min<uint32_t>(map->size(), mask.size_in_bits());
    157     const size_t kNumBits = BitSizeOf<uint32_t>();
    158     for (uint32_t reg = 0; reg < end; reg += kNumBits) {
    159       // Process the mask in chunks of kNumBits for performance.
    160       uint32_t bits = mask.LoadBits(reg, std::min<uint32_t>(end - reg, kNumBits));
    161       while (bits != 0) {
    162         uint32_t bit = CTZ(bits);
    163         if (regs[reg + bit].GetKind() == DexRegisterLocation::Kind::kInvalid) {
    164           regs[reg + bit] = GetDexRegisterCatalogEntry(dex_register_maps_.Get(map_index));
    165           remaining_registers--;
    166         }
    167         map_index++;
    168         bits ^= 1u << bit;  // Clear the bit.
    169       }
    170     }
    171   }
    172 
    173   // Set any remaining registers to None (which is the default state at first stack map).
    174   if (remaining_registers != 0) {
    175     DexRegisterLocation* regs = map->data();
    176     for (uint32_t r = 0; r < map->size(); r++) {
    177       if (regs[r].GetKind() == DexRegisterLocation::Kind::kInvalid) {
    178         regs[r] = DexRegisterLocation::None();
    179       }
    180     }
    181   }
    182 }
    183 
    184 // Decode the CodeInfo while collecting size statistics.
    185 void CodeInfo::CollectSizeStats(const uint8_t* code_info_data, /*out*/ Stats* parent) {
    186   Stats* codeinfo_stats = parent->Child("CodeInfo");
    187   BitMemoryReader reader(code_info_data);
    188   ForEachHeaderField([&reader](auto) { reader.ReadVarint(); });
    189   codeinfo_stats->Child("Header")->AddBits(reader.NumberOfReadBits());
    190   CodeInfo code_info;  // Temporary storage for decoded tables.
    191   ForEachBitTableField([codeinfo_stats, &reader, &code_info](auto member_pointer) {
    192     auto& table = code_info.*member_pointer;
    193     size_t bit_offset = reader.NumberOfReadBits();
    194     bool deduped = DecodeTable(table, reader);
    195     if (deduped) {
    196       codeinfo_stats->Child("DedupeOffset")->AddBits(reader.NumberOfReadBits() - bit_offset);
    197     } else {
    198       Stats* table_stats = codeinfo_stats->Child(table.GetName());
    199       table_stats->AddBits(reader.NumberOfReadBits() - bit_offset);
    200       const char* const* column_names = table.GetColumnNames();
    201       for (size_t c = 0; c < table.NumColumns(); c++) {
    202         if (table.NumColumnBits(c) > 0) {
    203           Stats* column_stats = table_stats->Child(column_names[c]);
    204           column_stats->AddBits(table.NumRows() * table.NumColumnBits(c), table.NumRows());
    205         }
    206       }
    207     }
    208   });
    209   codeinfo_stats->AddBytes(BitsToBytesRoundUp(reader.NumberOfReadBits()));
    210 }
    211 
    212 void DexRegisterMap::Dump(VariableIndentationOutputStream* vios) const {
    213   if (HasAnyLiveDexRegisters()) {
    214     ScopedIndentation indent1(vios);
    215     for (size_t i = 0; i < size(); ++i) {
    216       DexRegisterLocation reg = (*this)[i];
    217       if (reg.IsLive()) {
    218         vios->Stream() << "v" << i << ":" << reg << " ";
    219       }
    220     }
    221     vios->Stream() << "\n";
    222   }
    223 }
    224 
    225 void CodeInfo::Dump(VariableIndentationOutputStream* vios,
    226                     uint32_t code_offset,
    227                     bool verbose,
    228                     InstructionSet instruction_set) const {
    229   vios->Stream() << "CodeInfo BitSize=" << size_in_bits_
    230     << " FrameSize:" << packed_frame_size_ * kStackAlignment
    231     << " CoreSpillMask:" << std::hex << core_spill_mask_
    232     << " FpSpillMask:" << std::hex << fp_spill_mask_
    233     << " NumberOfDexRegisters:" << std::dec << number_of_dex_registers_
    234     << "\n";
    235   ScopedIndentation indent1(vios);
    236   ForEachBitTableField([this, &vios, verbose](auto member_pointer) {
    237     const auto& table = this->*member_pointer;
    238     if (table.NumRows() != 0) {
    239       vios->Stream() << table.GetName() << " BitSize=" << table.DataBitSize();
    240       vios->Stream() << " Rows=" << table.NumRows() << " Bits={";
    241       const char* const* column_names = table.GetColumnNames();
    242       for (size_t c = 0; c < table.NumColumns(); c++) {
    243         vios->Stream() << (c != 0 ? " " : "");
    244         vios->Stream() << column_names[c] << "=" << table.NumColumnBits(c);
    245       }
    246       vios->Stream() << "}\n";
    247       if (verbose) {
    248         ScopedIndentation indent1(vios);
    249         for (size_t r = 0; r < table.NumRows(); r++) {
    250           vios->Stream() << "[" << std::right << std::setw(3) << r << "]={";
    251           for (size_t c = 0; c < table.NumColumns(); c++) {
    252             vios->Stream() << (c != 0 ? " " : "");
    253             if (&table == static_cast<const void*>(&stack_masks_) ||
    254                 &table == static_cast<const void*>(&dex_register_masks_)) {
    255               BitMemoryRegion bits = table.GetBitMemoryRegion(r, c);
    256               for (size_t b = 0, e = bits.size_in_bits(); b < e; b++) {
    257                 vios->Stream() << bits.LoadBit(e - b - 1);
    258               }
    259             } else {
    260               vios->Stream() << std::right << std::setw(8) << static_cast<int32_t>(table.Get(r, c));
    261             }
    262           }
    263           vios->Stream() << "}\n";
    264         }
    265       }
    266     }
    267   });
    268 
    269   // Display stack maps along with (live) Dex register maps.
    270   if (verbose) {
    271     for (StackMap stack_map : stack_maps_) {
    272       stack_map.Dump(vios, *this, code_offset, instruction_set);
    273     }
    274   }
    275 }
    276 
    277 void StackMap::Dump(VariableIndentationOutputStream* vios,
    278                     const CodeInfo& code_info,
    279                     uint32_t code_offset,
    280                     InstructionSet instruction_set) const {
    281   const uint32_t pc_offset = GetNativePcOffset(instruction_set);
    282   vios->Stream()
    283       << "StackMap[" << Row() << "]"
    284       << std::hex
    285       << " (native_pc=0x" << code_offset + pc_offset
    286       << ", dex_pc=0x" << GetDexPc()
    287       << ", register_mask=0x" << code_info.GetRegisterMaskOf(*this)
    288       << std::dec
    289       << ", stack_mask=0b";
    290   BitMemoryRegion stack_mask = code_info.GetStackMaskOf(*this);
    291   for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
    292     vios->Stream() << stack_mask.LoadBit(e - i - 1);
    293   }
    294   vios->Stream() << ")\n";
    295   code_info.GetDexRegisterMapOf(*this).Dump(vios);
    296   for (InlineInfo inline_info : code_info.GetInlineInfosOf(*this)) {
    297     inline_info.Dump(vios, code_info, *this);
    298   }
    299 }
    300 
    301 void InlineInfo::Dump(VariableIndentationOutputStream* vios,
    302                       const CodeInfo& code_info,
    303                       const StackMap& stack_map) const {
    304   uint32_t depth = Row() - stack_map.GetInlineInfoIndex();
    305   vios->Stream()
    306       << "InlineInfo[" << Row() << "]"
    307       << " (depth=" << depth
    308       << std::hex
    309       << ", dex_pc=0x" << GetDexPc();
    310   if (EncodesArtMethod()) {
    311     ScopedObjectAccess soa(Thread::Current());
    312     vios->Stream() << ", method=" << GetArtMethod()->PrettyMethod();
    313   } else {
    314     vios->Stream()
    315         << std::dec
    316         << ", method_index=" << code_info.GetMethodIndexOf(*this);
    317   }
    318   vios->Stream() << ")\n";
    319   code_info.GetInlineDexRegisterMapOf(stack_map, *this).Dump(vios);
    320 }
    321 
    322 }  // namespace art
    323