/*
 * 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 "bitmap-inl.h"

#include "card_table.h"
#include "mem_map.h"

namespace art {
namespace gc {
namespace accounting {

Bitmap* Bitmap::CreateFromMemMap(MemMap* mem_map, size_t num_bits) {
  CHECK(mem_map != nullptr);
  return new Bitmap(mem_map, num_bits);
}

Bitmap::Bitmap(MemMap* mem_map, size_t bitmap_size)
    : mem_map_(mem_map), bitmap_begin_(reinterpret_cast<uintptr_t*>(mem_map->Begin())),
      bitmap_size_(bitmap_size) {
  CHECK(bitmap_begin_ != nullptr);
  CHECK_NE(bitmap_size, 0U);
}

Bitmap::~Bitmap() {
  // Destroys MemMap via std::unique_ptr<>.
}

MemMap* Bitmap::AllocateMemMap(const std::string& name, size_t num_bits) {
  const size_t bitmap_size = RoundUp(
      RoundUp(num_bits, kBitsPerBitmapWord) / kBitsPerBitmapWord * sizeof(uintptr_t), kPageSize);
  std::string error_msg;
  std::unique_ptr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), nullptr, bitmap_size,
                                                       PROT_READ | PROT_WRITE, false, false,
                                                       &error_msg));
  if (UNLIKELY(mem_map.get() == nullptr)) {
    LOG(ERROR) << "Failed to allocate bitmap " << name << ": " << error_msg;
    return nullptr;
  }
  return mem_map.release();
}

Bitmap* Bitmap::Create(const std::string& name, size_t num_bits) {
  auto* const mem_map = AllocateMemMap(name, num_bits);
  if (mem_map == nullptr) {
    return nullptr;
  }
  return CreateFromMemMap(mem_map, num_bits);
}

void Bitmap::Clear() {
  if (bitmap_begin_ != nullptr) {
    mem_map_->MadviseDontNeedAndZero();
  }
}

void Bitmap::CopyFrom(Bitmap* source_bitmap) {
  DCHECK_EQ(BitmapSize(), source_bitmap->BitmapSize());
  std::copy(source_bitmap->Begin(),
            source_bitmap->Begin() + BitmapSize() / kBitsPerBitmapWord, Begin());
}

template<size_t kAlignment>
MemoryRangeBitmap<kAlignment>* MemoryRangeBitmap<kAlignment>::Create(
    const std::string& name, uintptr_t cover_begin, uintptr_t cover_end) {
  CHECK_ALIGNED(cover_begin, kAlignment);
  CHECK_ALIGNED(cover_end, kAlignment);
  const size_t num_bits = (cover_end - cover_begin) / kAlignment;
  auto* const mem_map = Bitmap::AllocateMemMap(name, num_bits);
  return CreateFromMemMap(mem_map, cover_begin, num_bits);
}

template<size_t kAlignment>
MemoryRangeBitmap<kAlignment>* MemoryRangeBitmap<kAlignment>::CreateFromMemMap(
    MemMap* mem_map, uintptr_t begin, size_t num_bits) {
  return new MemoryRangeBitmap(mem_map, begin, num_bits);
}

template class MemoryRangeBitmap<CardTable::kCardSize>;

}  // namespace accounting
}  // namespace gc
}  // namespace art

