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

#ifndef ART_SRC_HEAP_BITMAP_H_
#define ART_SRC_HEAP_BITMAP_H_

#include "space_bitmap.h"

namespace art {
  class Heap;
  class SpaceBitmap;

  class HeapBitmap {
   public:
    bool Test(const Object* obj) SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
      SpaceBitmap* bitmap = GetSpaceBitmap(obj);
      if (LIKELY(bitmap != NULL)) {
        return bitmap->Test(obj);
      } else {
        return large_objects_->Test(obj);
      }
    }

    void Clear(const Object* obj)
        EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
      SpaceBitmap* bitmap = GetSpaceBitmap(obj);
      if (LIKELY(bitmap != NULL)) {
        return bitmap->Clear(obj);
      } else {
        return large_objects_->Clear(obj);
      }
    }

    void Set(const Object* obj)
        EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
      SpaceBitmap* bitmap = GetSpaceBitmap(obj);
      if (LIKELY(bitmap != NULL)) {
        bitmap->Set(obj);
      } else {
        large_objects_->Set(obj);
      }
    }

    SpaceBitmap* GetSpaceBitmap(const Object* obj) {
      // TODO: C++0x auto
      for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
        if ((*it)->HasAddress(obj)) {
          return *it;
        }
      }
      return NULL;
    }

    void Walk(SpaceBitmap::Callback* callback, void* arg)
        SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);

    template <typename Visitor>
    void Visit(const Visitor& visitor)
        EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
      // TODO: C++0x auto
      for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
        SpaceBitmap* bitmap = *it;
        bitmap->VisitMarkedRange(bitmap->HeapBegin(), bitmap->HeapLimit(), visitor,
                                 IdentityFunctor());
      }
      large_objects_->Visit(visitor);
    }

    // Find and replace a bitmap pointer, this is used by for the bitmap swapping in the GC.
    void ReplaceBitmap(SpaceBitmap* old_bitmap, SpaceBitmap* new_bitmap)
        EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);

    HeapBitmap(Heap* heap);

    inline SpaceSetMap* GetLargeObjects() const {
      return large_objects_;
    }

    void SetLargeObjects(SpaceSetMap* large_objects);

   private:

    const Heap* const heap_;

    void AddSpaceBitmap(SpaceBitmap* bitmap);

    typedef std::vector<SpaceBitmap*> Bitmaps;
    Bitmaps bitmaps_;

    // Large object sets.
    SpaceSetMap* large_objects_;

    friend class Heap;
  };
}  // namespace art

#endif  // ART_SRC_HEAP_BITMAP_H_
