blob: c73dd6b7bb548f381a1d29de2df5e1804cbae99e [file] [log] [blame]
/*
* 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.
*/
#include "heap.h"
#include "heap_bitmap.h"
#include "mark_sweep.h"
#include "mod_union_table.h"
#include "space.h"
#include "stl_util.h"
#include "UniquePtr.h"
namespace art {
class MarkIfReachesAllocspaceVisitor {
public:
explicit MarkIfReachesAllocspaceVisitor(MarkSweep* const mark_sweep, HeapBitmap* bitmap)
: mark_sweep_(mark_sweep),
bitmap_(bitmap) {
}
// Extra parameters are required since we use this same visitor signature for checking objects.
void operator ()(const Object* obj, const Object* ref, MemberOffset offset, bool is_static) const {
if (mark_sweep_->heap_->GetAllocSpace()->Contains(ref)) {
// This can mark the same object multiple times, but is unlikely to be a performance problem.
bitmap_->Set(obj);
}
// Avoid warnings.
(void)obj;(void)offset;(void)is_static;
}
private:
MarkSweep* const mark_sweep_;
HeapBitmap* bitmap_;
};
class ModUnionVisitor {
public:
explicit ModUnionVisitor(MarkSweep* const mark_sweep, HeapBitmap* bitmap)
: mark_sweep_(mark_sweep),
bitmap_(bitmap) {
}
void operator ()(Object* obj) const {
DCHECK(obj != NULL);
// We don't have an early exit since we use the visitor pattern, an early
// exit should significantly speed this up.
MarkIfReachesAllocspaceVisitor visitor(mark_sweep_, bitmap_);
mark_sweep_->VisitObjectReferences(obj, visitor);
}
private:
MarkSweep* const mark_sweep_;
HeapBitmap* bitmap_;
};
class ModUnionClearCardVisitor {
public:
explicit ModUnionClearCardVisitor(std::vector<byte*>* cleared_cards)
: cleared_cards_(cleared_cards) {
}
void operator ()(byte* card) const {
cleared_cards_->push_back(card);
}
private:
std::vector<byte*>* cleared_cards_;
};
ModUnionTableBitmap::ModUnionTableBitmap(Heap* heap) : heap_(heap) {
// Prevent fragmentation of the heap which is caused by resizing of the vector.
// TODO: Make a new vector which uses madvise (basically same as a mark stack).
cleared_cards_.reserve(4 * KB);
}
ModUnionTableBitmap::~ModUnionTableBitmap() {
STLDeleteValues(&bitmaps_);
}
void ModUnionTableBitmap::Init() {
const std::vector<Space*>& spaces = heap_->GetSpaces();
// Create one heap bitmap per image space.
for (size_t i = 0; i < spaces.size(); ++i) {
if (spaces[i]->IsImageSpace()) {
// Allocate the mod-union table
// The mod-union table is only needed when we have an image space since it's purpose is to cache image roots.
UniquePtr<HeapBitmap> bitmap(HeapBitmap::Create("mod-union table bitmap", spaces[i]->Begin(), spaces[i]->Capacity()));
if (bitmap.get() == NULL) {
LOG(FATAL) << "Failed to create mod-union bitmap";
}
bitmaps_.Put(spaces[i], bitmap.release());
}
}
}
void ModUnionTableBitmap::ClearCards() {
CardTable* card_table = heap_->GetCardTable();
for (BitmapMap::iterator cur = bitmaps_.begin(); cur != bitmaps_.end(); ++cur) {
const Space* space = cur->first;
ModUnionClearCardVisitor visitor(&cleared_cards_);
// Clear dirty cards in the this image space and update the corresponding mod-union bits.
card_table->VisitClear(space->Begin(), space->End(), visitor);
}
}
void ModUnionTableBitmap::Update(MarkSweep* mark_sweep) {
CardTable* card_table = heap_->GetCardTable();
while (!cleared_cards_.empty()) {
byte* card = cleared_cards_.back();
cleared_cards_.pop_back();
// Find out which bitmap the card maps to.
HeapBitmap* bitmap = 0;
for (BitmapMap::iterator cur = bitmaps_.begin(); cur != bitmaps_.end(); ++cur) {
if (cur->first->Contains(reinterpret_cast<Object*>(card_table->AddrFromCard(card)))) {
bitmap = cur->second;
break;
}
}
DCHECK(bitmap != NULL);
uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
uintptr_t end = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card + 1));
// Clear the mod-union bitmap range corresponding to this card so that we
// don't have any objects marked which do not reach the alloc space.
bitmap->VisitRange(start, end, HeapBitmap::ClearVisitor(bitmap));
// At this point we need to update the mod-union bitmap to contain all the
// objects which reach the alloc space.
ModUnionVisitor visitor(mark_sweep, bitmap);
heap_->GetLiveBits()->VisitMarkedRange(start, end, visitor);
}
}
void ModUnionTableBitmap::MarkReferences(MarkSweep* mark_sweep) {
// Some tests have no image space, and therefore no mod-union bitmap.
for (BitmapMap::iterator cur = bitmaps_.begin(); cur != bitmaps_.end(); ++cur) {
const Space* space = cur->first;
uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin());
uintptr_t end = reinterpret_cast<uintptr_t>(space->End());
cur->second->VisitRange(begin, end, MarkSweep::ScanImageRootVisitor, mark_sweep);
}
}
} // namespace art