/*
 * Copyright (C) 2011 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 "assembler.h"

#include <algorithm>
#include <vector>

#include "base/casts.h"
#include "base/globals.h"
#include "base/memory_region.h"

namespace art HIDDEN {

AssemblerBuffer::AssemblerBuffer(ArenaAllocator* allocator)
    : allocator_(allocator) {
  static const size_t kInitialBufferCapacity = 4 * KB;
  contents_ = allocator_->AllocArray<uint8_t>(kInitialBufferCapacity, kArenaAllocAssembler);
  cursor_ = contents_;
  limit_ = ComputeLimit(contents_, kInitialBufferCapacity);
  fixup_ = nullptr;
  slow_path_ = nullptr;
#ifndef NDEBUG
  has_ensured_capacity_ = false;
  fixups_processed_ = false;
#endif

  // Verify internal state.
  CHECK_EQ(Capacity(), kInitialBufferCapacity);
  CHECK_EQ(Size(), 0U);
}


AssemblerBuffer::~AssemblerBuffer() {
  if (allocator_->IsRunningOnMemoryTool()) {
    allocator_->MakeInaccessible(contents_, Capacity());
  }
}


void AssemblerBuffer::ProcessFixups(const MemoryRegion& region) {
  AssemblerFixup* fixup = fixup_;
  while (fixup != nullptr) {
    fixup->Process(region, fixup->position());
    fixup = fixup->previous();
  }
#ifndef NDEBUG
  fixups_processed_ = true;
#endif
}


void AssemblerBuffer::ProcessFixups() {
  MemoryRegion from(reinterpret_cast<void*>(contents()), Size());
  ProcessFixups(from);
}


void AssemblerBuffer::CopyInstructions(const MemoryRegion& instructions) {
  MemoryRegion from(reinterpret_cast<void*>(contents()), Size());
  instructions.CopyFrom(0, from);
}


void AssemblerBuffer::ExtendCapacity(size_t min_capacity) {
  size_t old_size = Size();
  size_t old_capacity = Capacity();
  DCHECK_GT(min_capacity, old_capacity);
  size_t new_capacity = std::min(old_capacity * 2, old_capacity + 1 * MB);
  new_capacity = std::max(new_capacity, min_capacity);

  // Allocate the new data area and copy contents of the old one to it.
  contents_ = reinterpret_cast<uint8_t*>(
      allocator_->Realloc(contents_, old_capacity, new_capacity, kArenaAllocAssembler));

  // Update the cursor and recompute the limit.
  cursor_ = contents_ + old_size;
  limit_ = ComputeLimit(contents_, new_capacity);

  // Verify internal state.
  CHECK_EQ(Capacity(), new_capacity);
  CHECK_EQ(Size(), old_size);
}

void DebugFrameOpCodeWriterForAssembler::ImplicitlyAdvancePC() {
  uint32_t pc = dchecked_integral_cast<uint32_t>(assembler_->CodeSize());
  if (delay_emitting_advance_pc_) {
    uint32_t stream_pos = dchecked_integral_cast<uint32_t>(opcodes_.size());
    delayed_advance_pcs_.push_back(DelayedAdvancePC {stream_pos, pc});
  } else {
    AdvancePC(pc);
  }
}

}  // namespace art
