/*
 * Copyright (C) 2015 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.
 */

#include "stack_map_stream.h"

#include "art_method-inl.h"
#include "base/stl_util.h"
#include "dex_file_types.h"
#include "optimizing/optimizing_compiler.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"

namespace art {

void StackMapStream::BeginStackMapEntry(uint32_t dex_pc,
                                        uint32_t native_pc_offset,
                                        uint32_t register_mask,
                                        BitVector* sp_mask,
                                        uint32_t num_dex_registers,
                                        uint8_t inlining_depth) {
  DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry";
  DCHECK_NE(dex_pc, static_cast<uint32_t>(-1)) << "invalid dex_pc";
  current_entry_.dex_pc = dex_pc;
  current_entry_.native_pc_code_offset = CodeOffset::FromOffset(native_pc_offset, instruction_set_);
  current_entry_.register_mask = register_mask;
  current_entry_.sp_mask = sp_mask;
  current_entry_.inlining_depth = inlining_depth;
  current_entry_.inline_infos_start_index = inline_infos_.size();
  current_entry_.stack_mask_index = 0;
  current_entry_.dex_method_index = dex::kDexNoIndex;
  current_entry_.dex_register_entry.num_dex_registers = num_dex_registers;
  current_entry_.dex_register_entry.locations_start_index = dex_register_locations_.size();
  current_entry_.dex_register_entry.live_dex_registers_mask = (num_dex_registers != 0)
      ? ArenaBitVector::Create(allocator_, num_dex_registers, true, kArenaAllocStackMapStream)
      : nullptr;
  if (sp_mask != nullptr) {
    stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
  }
  if (inlining_depth > 0) {
    number_of_stack_maps_with_inline_info_++;
  }

  dex_pc_max_ = std::max(dex_pc_max_, dex_pc);
  register_mask_max_ = std::max(register_mask_max_, register_mask);
  current_dex_register_ = 0;
}

void StackMapStream::EndStackMapEntry() {
  current_entry_.dex_register_map_index = AddDexRegisterMapEntry(current_entry_.dex_register_entry);
  stack_maps_.push_back(current_entry_);
  current_entry_ = StackMapEntry();
}

void StackMapStream::AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) {
  if (kind != DexRegisterLocation::Kind::kNone) {
    // Ensure we only use non-compressed location kind at this stage.
    DCHECK(DexRegisterLocation::IsShortLocationKind(kind)) << kind;
    DexRegisterLocation location(kind, value);

    // Look for Dex register `location` in the location catalog (using the
    // companion hash map of locations to indices).  Use its index if it
    // is already in the location catalog.  If not, insert it (in the
    // location catalog and the hash map) and use the newly created index.
    auto it = location_catalog_entries_indices_.Find(location);
    if (it != location_catalog_entries_indices_.end()) {
      // Retrieve the index from the hash map.
      dex_register_locations_.push_back(it->second);
    } else {
      // Create a new entry in the location catalog and the hash map.
      size_t index = location_catalog_entries_.size();
      location_catalog_entries_.push_back(location);
      dex_register_locations_.push_back(index);
      location_catalog_entries_indices_.Insert(std::make_pair(location, index));
    }
    DexRegisterMapEntry* const entry = in_inline_frame_
        ? &current_inline_info_.dex_register_entry
        : &current_entry_.dex_register_entry;
    DCHECK_LT(current_dex_register_, entry->num_dex_registers);
    entry->live_dex_registers_mask->SetBit(current_dex_register_);
    entry->hash += (1 <<
        (current_dex_register_ % (sizeof(DexRegisterMapEntry::hash) * kBitsPerByte)));
    entry->hash += static_cast<uint32_t>(value);
    entry->hash += static_cast<uint32_t>(kind);
  }
  current_dex_register_++;
}

void StackMapStream::AddInvoke(InvokeType invoke_type, uint32_t dex_method_index) {
  current_entry_.invoke_type = invoke_type;
  current_entry_.dex_method_index = dex_method_index;
}

void StackMapStream::BeginInlineInfoEntry(ArtMethod* method,
                                          uint32_t dex_pc,
                                          uint32_t num_dex_registers,
                                          const DexFile* outer_dex_file) {
  DCHECK(!in_inline_frame_);
  in_inline_frame_ = true;
  if (EncodeArtMethodInInlineInfo(method)) {
    current_inline_info_.method = method;
  } else {
    if (dex_pc != static_cast<uint32_t>(-1) && kIsDebugBuild) {
      ScopedObjectAccess soa(Thread::Current());
      DCHECK(IsSameDexFile(*outer_dex_file, *method->GetDexFile()));
    }
    current_inline_info_.method_index = method->GetDexMethodIndexUnchecked();
  }
  current_inline_info_.dex_pc = dex_pc;
  current_inline_info_.dex_register_entry.num_dex_registers = num_dex_registers;
  current_inline_info_.dex_register_entry.locations_start_index = dex_register_locations_.size();
  current_inline_info_.dex_register_entry.live_dex_registers_mask = (num_dex_registers != 0)
      ? ArenaBitVector::Create(allocator_, num_dex_registers, true, kArenaAllocStackMapStream)
      : nullptr;
  current_dex_register_ = 0;
}

void StackMapStream::EndInlineInfoEntry() {
  current_inline_info_.dex_register_map_index =
      AddDexRegisterMapEntry(current_inline_info_.dex_register_entry);
  DCHECK(in_inline_frame_);
  DCHECK_EQ(current_dex_register_, current_inline_info_.dex_register_entry.num_dex_registers)
      << "Inline information contains less registers than expected";
  in_inline_frame_ = false;
  inline_infos_.push_back(current_inline_info_);
  current_inline_info_ = InlineInfoEntry();
}

CodeOffset StackMapStream::ComputeMaxNativePcCodeOffset() const {
  CodeOffset max_native_pc_offset;
  for (const StackMapEntry& entry : stack_maps_) {
    max_native_pc_offset = std::max(max_native_pc_offset, entry.native_pc_code_offset);
  }
  return max_native_pc_offset;
}

size_t StackMapStream::PrepareForFillIn() {
  CodeInfoEncoding encoding;
  encoding.dex_register_map.num_entries = 0;  // TODO: Remove this field.
  encoding.dex_register_map.num_bytes = ComputeDexRegisterMapsSize();
  encoding.location_catalog.num_entries = location_catalog_entries_.size();
  encoding.location_catalog.num_bytes = ComputeDexRegisterLocationCatalogSize();
  encoding.inline_info.num_entries = inline_infos_.size();
  // Must be done before calling ComputeInlineInfoEncoding since ComputeInlineInfoEncoding requires
  // dex_method_index_idx to be filled in.
  PrepareMethodIndices();
  ComputeInlineInfoEncoding(&encoding.inline_info.encoding,
                            encoding.dex_register_map.num_bytes);
  CodeOffset max_native_pc_offset = ComputeMaxNativePcCodeOffset();
  // Prepare the CodeInfo variable-sized encoding.
  encoding.stack_mask.encoding.num_bits = stack_mask_max_ + 1;  // Need room for max element too.
  encoding.stack_mask.num_entries = PrepareStackMasks(encoding.stack_mask.encoding.num_bits);
  encoding.register_mask.encoding.num_bits = MinimumBitsToStore(register_mask_max_);
  encoding.register_mask.num_entries = PrepareRegisterMasks();
  encoding.stack_map.num_entries = stack_maps_.size();
  encoding.stack_map.encoding.SetFromSizes(
      // The stack map contains compressed native PC offsets.
      max_native_pc_offset.CompressedValue(),
      dex_pc_max_,
      encoding.dex_register_map.num_bytes,
      encoding.inline_info.num_entries,
      encoding.register_mask.num_entries,
      encoding.stack_mask.num_entries);
  ComputeInvokeInfoEncoding(&encoding);
  DCHECK_EQ(code_info_encoding_.size(), 0u);
  encoding.Compress(&code_info_encoding_);
  encoding.ComputeTableOffsets();
  // Compute table offsets so we can get the non header size.
  DCHECK_EQ(encoding.HeaderSize(), code_info_encoding_.size());
  needed_size_ = code_info_encoding_.size() + encoding.NonHeaderSize();
  return needed_size_;
}

size_t StackMapStream::ComputeDexRegisterLocationCatalogSize() const {
  size_t size = DexRegisterLocationCatalog::kFixedSize;
  for (const DexRegisterLocation& dex_register_location : location_catalog_entries_) {
    size += DexRegisterLocationCatalog::EntrySize(dex_register_location);
  }
  return size;
}

size_t StackMapStream::DexRegisterMapEntry::ComputeSize(size_t catalog_size) const {
  // For num_dex_registers == 0u live_dex_registers_mask may be null.
  if (num_dex_registers == 0u) {
    return 0u;  // No register map will be emitted.
  }
  DCHECK(live_dex_registers_mask != nullptr);

  // Size of the map in bytes.
  size_t size = DexRegisterMap::kFixedSize;
  // Add the live bit mask for the Dex register liveness.
  size += DexRegisterMap::GetLiveBitMaskSize(num_dex_registers);
  // Compute the size of the set of live Dex register entries.
  size_t number_of_live_dex_registers = live_dex_registers_mask->NumSetBits();
  size_t map_entries_size_in_bits =
      DexRegisterMap::SingleEntrySizeInBits(catalog_size) * number_of_live_dex_registers;
  size_t map_entries_size_in_bytes =
      RoundUp(map_entries_size_in_bits, kBitsPerByte) / kBitsPerByte;
  size += map_entries_size_in_bytes;
  return size;
}

size_t StackMapStream::ComputeDexRegisterMapsSize() const {
  size_t size = 0;
  for (const DexRegisterMapEntry& entry : dex_register_entries_) {
    size += entry.ComputeSize(location_catalog_entries_.size());
  }
  return size;
}

void StackMapStream::ComputeInvokeInfoEncoding(CodeInfoEncoding* encoding) {
  DCHECK(encoding != nullptr);
  uint32_t native_pc_max = 0;
  uint16_t method_index_max = 0;
  size_t invoke_infos_count = 0;
  size_t invoke_type_max = 0;
  for (const StackMapEntry& entry : stack_maps_) {
    if (entry.dex_method_index != dex::kDexNoIndex) {
      native_pc_max = std::max(native_pc_max, entry.native_pc_code_offset.CompressedValue());
      method_index_max = std::max(method_index_max, static_cast<uint16_t>(entry.dex_method_index));
      invoke_type_max = std::max(invoke_type_max, static_cast<size_t>(entry.invoke_type));
      ++invoke_infos_count;
    }
  }
  encoding->invoke_info.num_entries = invoke_infos_count;
  encoding->invoke_info.encoding.SetFromSizes(native_pc_max, invoke_type_max, method_index_max);
}

void StackMapStream::ComputeInlineInfoEncoding(InlineInfoEncoding* encoding,
                                               size_t dex_register_maps_bytes) {
  uint32_t method_index_max = 0;
  uint32_t dex_pc_max = dex::kDexNoIndex;
  uint32_t extra_data_max = 0;

  uint32_t inline_info_index = 0;
  for (const StackMapEntry& entry : stack_maps_) {
    for (size_t j = 0; j < entry.inlining_depth; ++j) {
      InlineInfoEntry inline_entry = inline_infos_[inline_info_index++];
      if (inline_entry.method == nullptr) {
        method_index_max = std::max(method_index_max, inline_entry.dex_method_index_idx);
        extra_data_max = std::max(extra_data_max, 1u);
      } else {
        method_index_max = std::max(
            method_index_max, High32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)));
        extra_data_max = std::max(
            extra_data_max, Low32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)));
      }
      if (inline_entry.dex_pc != dex::kDexNoIndex &&
          (dex_pc_max == dex::kDexNoIndex || dex_pc_max < inline_entry.dex_pc)) {
        dex_pc_max = inline_entry.dex_pc;
      }
    }
  }
  DCHECK_EQ(inline_info_index, inline_infos_.size());

  encoding->SetFromSizes(method_index_max, dex_pc_max, extra_data_max, dex_register_maps_bytes);
}

size_t StackMapStream::MaybeCopyDexRegisterMap(DexRegisterMapEntry& entry,
                                               size_t* current_offset,
                                               MemoryRegion dex_register_locations_region) {
  DCHECK(current_offset != nullptr);
  if ((entry.num_dex_registers == 0) || (entry.live_dex_registers_mask->NumSetBits() == 0)) {
    // No dex register map needed.
    return StackMap::kNoDexRegisterMap;
  }
  if (entry.offset == DexRegisterMapEntry::kOffsetUnassigned) {
    // Not already copied, need to copy and and assign an offset.
    entry.offset = *current_offset;
    const size_t entry_size = entry.ComputeSize(location_catalog_entries_.size());
    DexRegisterMap dex_register_map(
        dex_register_locations_region.Subregion(entry.offset, entry_size));
    *current_offset += entry_size;
    // Fill in the map since it was just added.
    FillInDexRegisterMap(dex_register_map,
                         entry.num_dex_registers,
                         *entry.live_dex_registers_mask,
                         entry.locations_start_index);
  }
  return entry.offset;
}

void StackMapStream::FillInMethodInfo(MemoryRegion region) {
  {
    MethodInfo info(region.begin(), method_indices_.size());
    for (size_t i = 0; i < method_indices_.size(); ++i) {
      info.SetMethodIndex(i, method_indices_[i]);
    }
  }
  if (kIsDebugBuild) {
    // Check the data matches.
    MethodInfo info(region.begin());
    const size_t count = info.NumMethodIndices();
    DCHECK_EQ(count, method_indices_.size());
    for (size_t i = 0; i < count; ++i) {
      DCHECK_EQ(info.GetMethodIndex(i), method_indices_[i]);
    }
  }
}

void StackMapStream::FillInCodeInfo(MemoryRegion region) {
  DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry";
  DCHECK_NE(0u, needed_size_) << "PrepareForFillIn not called before FillIn";

  DCHECK_EQ(region.size(), needed_size_);

  // Note that the memory region does not have to be zeroed when we JIT code
  // because we do not use the arena allocator there.

  // Write the CodeInfo header.
  region.CopyFrom(0, MemoryRegion(code_info_encoding_.data(), code_info_encoding_.size()));

  CodeInfo code_info(region);
  CodeInfoEncoding encoding = code_info.ExtractEncoding();
  DCHECK_EQ(encoding.stack_map.num_entries, stack_maps_.size());

  MemoryRegion dex_register_locations_region = region.Subregion(
      encoding.dex_register_map.byte_offset,
      encoding.dex_register_map.num_bytes);

  // Set the Dex register location catalog.
  MemoryRegion dex_register_location_catalog_region = region.Subregion(
      encoding.location_catalog.byte_offset,
      encoding.location_catalog.num_bytes);
  DexRegisterLocationCatalog dex_register_location_catalog(dex_register_location_catalog_region);
  // Offset in `dex_register_location_catalog` where to store the next
  // register location.
  size_t location_catalog_offset = DexRegisterLocationCatalog::kFixedSize;
  for (DexRegisterLocation dex_register_location : location_catalog_entries_) {
    dex_register_location_catalog.SetRegisterInfo(location_catalog_offset, dex_register_location);
    location_catalog_offset += DexRegisterLocationCatalog::EntrySize(dex_register_location);
  }
  // Ensure we reached the end of the Dex registers location_catalog.
  DCHECK_EQ(location_catalog_offset, dex_register_location_catalog_region.size());

  ArenaBitVector empty_bitmask(allocator_, 0, /* expandable */ false, kArenaAllocStackMapStream);
  uintptr_t next_dex_register_map_offset = 0;
  uintptr_t next_inline_info_index = 0;
  size_t invoke_info_idx = 0;
  for (size_t i = 0, e = stack_maps_.size(); i < e; ++i) {
    StackMap stack_map = code_info.GetStackMapAt(i, encoding);
    StackMapEntry entry = stack_maps_[i];

    stack_map.SetDexPc(encoding.stack_map.encoding, entry.dex_pc);
    stack_map.SetNativePcCodeOffset(encoding.stack_map.encoding, entry.native_pc_code_offset);
    stack_map.SetRegisterMaskIndex(encoding.stack_map.encoding, entry.register_mask_index);
    stack_map.SetStackMaskIndex(encoding.stack_map.encoding, entry.stack_mask_index);

    size_t offset = MaybeCopyDexRegisterMap(dex_register_entries_[entry.dex_register_map_index],
                                            &next_dex_register_map_offset,
                                            dex_register_locations_region);
    stack_map.SetDexRegisterMapOffset(encoding.stack_map.encoding, offset);

    if (entry.dex_method_index != dex::kDexNoIndex) {
      InvokeInfo invoke_info(code_info.GetInvokeInfo(encoding, invoke_info_idx));
      invoke_info.SetNativePcCodeOffset(encoding.invoke_info.encoding, entry.native_pc_code_offset);
      invoke_info.SetInvokeType(encoding.invoke_info.encoding, entry.invoke_type);
      invoke_info.SetMethodIndexIdx(encoding.invoke_info.encoding, entry.dex_method_index_idx);
      ++invoke_info_idx;
    }

    // Set the inlining info.
    if (entry.inlining_depth != 0) {
      InlineInfo inline_info = code_info.GetInlineInfo(next_inline_info_index, encoding);

      // Fill in the index.
      stack_map.SetInlineInfoIndex(encoding.stack_map.encoding, next_inline_info_index);
      DCHECK_EQ(next_inline_info_index, entry.inline_infos_start_index);
      next_inline_info_index += entry.inlining_depth;

      inline_info.SetDepth(encoding.inline_info.encoding, entry.inlining_depth);
      DCHECK_LE(entry.inline_infos_start_index + entry.inlining_depth, inline_infos_.size());

      for (size_t depth = 0; depth < entry.inlining_depth; ++depth) {
        InlineInfoEntry inline_entry = inline_infos_[depth + entry.inline_infos_start_index];
        if (inline_entry.method != nullptr) {
          inline_info.SetMethodIndexIdxAtDepth(
              encoding.inline_info.encoding,
              depth,
              High32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)));
          inline_info.SetExtraDataAtDepth(
              encoding.inline_info.encoding,
              depth,
              Low32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)));
        } else {
          inline_info.SetMethodIndexIdxAtDepth(encoding.inline_info.encoding,
                                               depth,
                                               inline_entry.dex_method_index_idx);
          inline_info.SetExtraDataAtDepth(encoding.inline_info.encoding, depth, 1);
        }
        inline_info.SetDexPcAtDepth(encoding.inline_info.encoding, depth, inline_entry.dex_pc);
        size_t dex_register_map_offset = MaybeCopyDexRegisterMap(
            dex_register_entries_[inline_entry.dex_register_map_index],
            &next_dex_register_map_offset,
            dex_register_locations_region);
        inline_info.SetDexRegisterMapOffsetAtDepth(encoding.inline_info.encoding,
                                                   depth,
                                                   dex_register_map_offset);
      }
    } else if (encoding.stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0) {
      stack_map.SetInlineInfoIndex(encoding.stack_map.encoding, StackMap::kNoInlineInfo);
    }
  }

  // Write stack masks table.
  const size_t stack_mask_bits = encoding.stack_mask.encoding.BitSize();
  if (stack_mask_bits > 0) {
    size_t stack_mask_bytes = RoundUp(stack_mask_bits, kBitsPerByte) / kBitsPerByte;
    for (size_t i = 0; i < encoding.stack_mask.num_entries; ++i) {
      MemoryRegion source(&stack_masks_[i * stack_mask_bytes], stack_mask_bytes);
      BitMemoryRegion stack_mask = code_info.GetStackMask(i, encoding);
      for (size_t bit_index = 0; bit_index < stack_mask_bits; ++bit_index) {
        stack_mask.StoreBit(bit_index, source.LoadBit(bit_index));
      }
    }
  }

  // Write register masks table.
  for (size_t i = 0; i < encoding.register_mask.num_entries; ++i) {
    BitMemoryRegion register_mask = code_info.GetRegisterMask(i, encoding);
    register_mask.StoreBits(0, register_masks_[i], encoding.register_mask.encoding.BitSize());
  }

  // Verify all written data in debug build.
  if (kIsDebugBuild) {
    CheckCodeInfo(region);
  }
}

void StackMapStream::FillInDexRegisterMap(DexRegisterMap dex_register_map,
                                          uint32_t num_dex_registers,
                                          const BitVector& live_dex_registers_mask,
                                          uint32_t start_index_in_dex_register_locations) const {
  dex_register_map.SetLiveBitMask(num_dex_registers, live_dex_registers_mask);
  // Set the dex register location mapping data.
  size_t number_of_live_dex_registers = live_dex_registers_mask.NumSetBits();
  DCHECK_LE(number_of_live_dex_registers, dex_register_locations_.size());
  DCHECK_LE(start_index_in_dex_register_locations,
            dex_register_locations_.size() - number_of_live_dex_registers);
  for (size_t index_in_dex_register_locations = 0;
      index_in_dex_register_locations != number_of_live_dex_registers;
       ++index_in_dex_register_locations) {
    size_t location_catalog_entry_index = dex_register_locations_[
        start_index_in_dex_register_locations + index_in_dex_register_locations];
    dex_register_map.SetLocationCatalogEntryIndex(
        index_in_dex_register_locations,
        location_catalog_entry_index,
        num_dex_registers,
        location_catalog_entries_.size());
  }
}

size_t StackMapStream::AddDexRegisterMapEntry(const DexRegisterMapEntry& entry) {
  const size_t current_entry_index = dex_register_entries_.size();
  auto entries_it = dex_map_hash_to_stack_map_indices_.find(entry.hash);
  if (entries_it == dex_map_hash_to_stack_map_indices_.end()) {
    // We don't have a perfect hash functions so we need a list to collect all stack maps
    // which might have the same dex register map.
    ArenaVector<uint32_t> stack_map_indices(allocator_->Adapter(kArenaAllocStackMapStream));
    stack_map_indices.push_back(current_entry_index);
    dex_map_hash_to_stack_map_indices_.Put(entry.hash, std::move(stack_map_indices));
  } else {
    // We might have collisions, so we need to check whether or not we really have a match.
    for (uint32_t test_entry_index : entries_it->second) {
      if (DexRegisterMapEntryEquals(dex_register_entries_[test_entry_index], entry)) {
        return test_entry_index;
      }
    }
    entries_it->second.push_back(current_entry_index);
  }
  dex_register_entries_.push_back(entry);
  return current_entry_index;
}

bool StackMapStream::DexRegisterMapEntryEquals(const DexRegisterMapEntry& a,
                                               const DexRegisterMapEntry& b) const {
  if ((a.live_dex_registers_mask == nullptr) != (b.live_dex_registers_mask == nullptr)) {
    return false;
  }
  if (a.num_dex_registers != b.num_dex_registers) {
    return false;
  }
  if (a.num_dex_registers != 0u) {
    DCHECK(a.live_dex_registers_mask != nullptr);
    DCHECK(b.live_dex_registers_mask != nullptr);
    if (!a.live_dex_registers_mask->Equal(b.live_dex_registers_mask)) {
      return false;
    }
    size_t number_of_live_dex_registers = a.live_dex_registers_mask->NumSetBits();
    DCHECK_LE(number_of_live_dex_registers, dex_register_locations_.size());
    DCHECK_LE(a.locations_start_index,
              dex_register_locations_.size() - number_of_live_dex_registers);
    DCHECK_LE(b.locations_start_index,
              dex_register_locations_.size() - number_of_live_dex_registers);
    auto a_begin = dex_register_locations_.begin() + a.locations_start_index;
    auto b_begin = dex_register_locations_.begin() + b.locations_start_index;
    if (!std::equal(a_begin, a_begin + number_of_live_dex_registers, b_begin)) {
      return false;
    }
  }
  return true;
}

// Helper for CheckCodeInfo - check that register map has the expected content.
void StackMapStream::CheckDexRegisterMap(const CodeInfo& code_info,
                                         const DexRegisterMap& dex_register_map,
                                         size_t num_dex_registers,
                                         BitVector* live_dex_registers_mask,
                                         size_t dex_register_locations_index) const {
  CodeInfoEncoding encoding = code_info.ExtractEncoding();
  for (size_t reg = 0; reg < num_dex_registers; reg++) {
    // Find the location we tried to encode.
    DexRegisterLocation expected = DexRegisterLocation::None();
    if (live_dex_registers_mask->IsBitSet(reg)) {
      size_t catalog_index = dex_register_locations_[dex_register_locations_index++];
      expected = location_catalog_entries_[catalog_index];
    }
    // Compare to the seen location.
    if (expected.GetKind() == DexRegisterLocation::Kind::kNone) {
      DCHECK(!dex_register_map.IsValid() || !dex_register_map.IsDexRegisterLive(reg))
          << dex_register_map.IsValid() << " " << dex_register_map.IsDexRegisterLive(reg);
    } else {
      DCHECK(dex_register_map.IsDexRegisterLive(reg));
      DexRegisterLocation seen = dex_register_map.GetDexRegisterLocation(
          reg, num_dex_registers, code_info, encoding);
      DCHECK_EQ(expected.GetKind(), seen.GetKind());
      DCHECK_EQ(expected.GetValue(), seen.GetValue());
    }
  }
  if (num_dex_registers == 0) {
    DCHECK(!dex_register_map.IsValid());
  }
}

size_t StackMapStream::PrepareRegisterMasks() {
  register_masks_.resize(stack_maps_.size(), 0u);
  ArenaUnorderedMap<uint32_t, size_t> dedupe(allocator_->Adapter(kArenaAllocStackMapStream));
  for (StackMapEntry& stack_map : stack_maps_) {
    const size_t index = dedupe.size();
    stack_map.register_mask_index = dedupe.emplace(stack_map.register_mask, index).first->second;
    register_masks_[index] = stack_map.register_mask;
  }
  return dedupe.size();
}

void StackMapStream::PrepareMethodIndices() {
  CHECK(method_indices_.empty());
  method_indices_.resize(stack_maps_.size() + inline_infos_.size());
  ArenaUnorderedMap<uint32_t, size_t> dedupe(allocator_->Adapter(kArenaAllocStackMapStream));
  for (StackMapEntry& stack_map : stack_maps_) {
    const size_t index = dedupe.size();
    const uint32_t method_index = stack_map.dex_method_index;
    if (method_index != dex::kDexNoIndex) {
      stack_map.dex_method_index_idx = dedupe.emplace(method_index, index).first->second;
      method_indices_[index] = method_index;
    }
  }
  for (InlineInfoEntry& inline_info : inline_infos_) {
    const size_t index = dedupe.size();
    const uint32_t method_index = inline_info.method_index;
    CHECK_NE(method_index, dex::kDexNoIndex);
    inline_info.dex_method_index_idx = dedupe.emplace(method_index, index).first->second;
    method_indices_[index] = method_index;
  }
  method_indices_.resize(dedupe.size());
}


size_t StackMapStream::PrepareStackMasks(size_t entry_size_in_bits) {
  // Preallocate memory since we do not want it to move (the dedup map will point into it).
  const size_t byte_entry_size = RoundUp(entry_size_in_bits, kBitsPerByte) / kBitsPerByte;
  stack_masks_.resize(byte_entry_size * stack_maps_.size(), 0u);
  // For deduplicating we store the stack masks as byte packed for simplicity. We can bit pack later
  // when copying out from stack_masks_.
  ArenaUnorderedMap<MemoryRegion,
                    size_t,
                    FNVHash<MemoryRegion>,
                    MemoryRegion::ContentEquals> dedup(
                        stack_maps_.size(), allocator_->Adapter(kArenaAllocStackMapStream));
  for (StackMapEntry& stack_map : stack_maps_) {
    size_t index = dedup.size();
    MemoryRegion stack_mask(stack_masks_.data() + index * byte_entry_size, byte_entry_size);
    for (size_t i = 0; i < entry_size_in_bits; i++) {
      stack_mask.StoreBit(i, stack_map.sp_mask != nullptr && stack_map.sp_mask->IsBitSet(i));
    }
    stack_map.stack_mask_index = dedup.emplace(stack_mask, index).first->second;
  }
  return dedup.size();
}

// Check that all StackMapStream inputs are correctly encoded by trying to read them back.
void StackMapStream::CheckCodeInfo(MemoryRegion region) const {
  CodeInfo code_info(region);
  CodeInfoEncoding encoding = code_info.ExtractEncoding();
  DCHECK_EQ(code_info.GetNumberOfStackMaps(encoding), stack_maps_.size());
  size_t invoke_info_index = 0;
  for (size_t s = 0; s < stack_maps_.size(); ++s) {
    const StackMap stack_map = code_info.GetStackMapAt(s, encoding);
    const StackMapEncoding& stack_map_encoding = encoding.stack_map.encoding;
    StackMapEntry entry = stack_maps_[s];

    // Check main stack map fields.
    DCHECK_EQ(stack_map.GetNativePcOffset(stack_map_encoding, instruction_set_),
              entry.native_pc_code_offset.Uint32Value(instruction_set_));
    DCHECK_EQ(stack_map.GetDexPc(stack_map_encoding), entry.dex_pc);
    DCHECK_EQ(stack_map.GetRegisterMaskIndex(stack_map_encoding), entry.register_mask_index);
    DCHECK_EQ(code_info.GetRegisterMaskOf(encoding, stack_map), entry.register_mask);
    const size_t num_stack_mask_bits = code_info.GetNumberOfStackMaskBits(encoding);
    DCHECK_EQ(stack_map.GetStackMaskIndex(stack_map_encoding), entry.stack_mask_index);
    BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map);
    if (entry.sp_mask != nullptr) {
      DCHECK_GE(stack_mask.size_in_bits(), entry.sp_mask->GetNumberOfBits());
      for (size_t b = 0; b < num_stack_mask_bits; b++) {
        DCHECK_EQ(stack_mask.LoadBit(b), entry.sp_mask->IsBitSet(b));
      }
    } else {
      for (size_t b = 0; b < num_stack_mask_bits; b++) {
        DCHECK_EQ(stack_mask.LoadBit(b), 0u);
      }
    }
    if (entry.dex_method_index != dex::kDexNoIndex) {
      InvokeInfo invoke_info = code_info.GetInvokeInfo(encoding, invoke_info_index);
      DCHECK_EQ(invoke_info.GetNativePcOffset(encoding.invoke_info.encoding, instruction_set_),
                entry.native_pc_code_offset.Uint32Value(instruction_set_));
      DCHECK_EQ(invoke_info.GetInvokeType(encoding.invoke_info.encoding), entry.invoke_type);
      DCHECK_EQ(invoke_info.GetMethodIndexIdx(encoding.invoke_info.encoding),
                entry.dex_method_index_idx);
      invoke_info_index++;
    }
    CheckDexRegisterMap(code_info,
                        code_info.GetDexRegisterMapOf(
                            stack_map, encoding, entry.dex_register_entry.num_dex_registers),
                        entry.dex_register_entry.num_dex_registers,
                        entry.dex_register_entry.live_dex_registers_mask,
                        entry.dex_register_entry.locations_start_index);

    // Check inline info.
    DCHECK_EQ(stack_map.HasInlineInfo(stack_map_encoding), (entry.inlining_depth != 0));
    if (entry.inlining_depth != 0) {
      InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
      DCHECK_EQ(inline_info.GetDepth(encoding.inline_info.encoding), entry.inlining_depth);
      for (size_t d = 0; d < entry.inlining_depth; ++d) {
        size_t inline_info_index = entry.inline_infos_start_index + d;
        DCHECK_LT(inline_info_index, inline_infos_.size());
        InlineInfoEntry inline_entry = inline_infos_[inline_info_index];
        DCHECK_EQ(inline_info.GetDexPcAtDepth(encoding.inline_info.encoding, d),
                  inline_entry.dex_pc);
        if (inline_info.EncodesArtMethodAtDepth(encoding.inline_info.encoding, d)) {
          DCHECK_EQ(inline_info.GetArtMethodAtDepth(encoding.inline_info.encoding, d),
                    inline_entry.method);
        } else {
          const size_t method_index_idx =
              inline_info.GetMethodIndexIdxAtDepth(encoding.inline_info.encoding, d);
          DCHECK_EQ(method_index_idx, inline_entry.dex_method_index_idx);
          DCHECK_EQ(method_indices_[method_index_idx], inline_entry.method_index);
        }

        CheckDexRegisterMap(code_info,
                            code_info.GetDexRegisterMapAtDepth(
                                d,
                                inline_info,
                                encoding,
                                inline_entry.dex_register_entry.num_dex_registers),
                            inline_entry.dex_register_entry.num_dex_registers,
                            inline_entry.dex_register_entry.live_dex_registers_mask,
                            inline_entry.dex_register_entry.locations_start_index);
      }
    }
  }
}

size_t StackMapStream::ComputeMethodInfoSize() const {
  DCHECK_NE(0u, needed_size_) << "PrepareForFillIn not called before " << __FUNCTION__;
  return MethodInfo::ComputeSize(method_indices_.size());
}

}  // namespace art
