// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "vm/freelist.h" #include #include #include "vm/bit_set.h" #include "vm/object.h" #include "vm/raw_object.h" namespace dart { FreeListElement* FreeListElement::AsElement(uword addr, intptr_t size) { ASSERT(size >= kObjectAlignment); ASSERT(Utils::IsAligned(size, kObjectAlignment)); FreeListElement* result = reinterpret_cast(addr); uword tags = 0; tags = RawObject::FreeBit::update(true, tags); tags = RawObject::SizeTag::update(size, tags); tags = RawObject::ClassIdTag::update(kFreeListElement, tags); result->tags_ = tags; if (size > RawObject::SizeTag::kMaxSizeTag) { *result->SizeAddress() = size; } result->set_next(NULL); return result; } void FreeListElement::InitOnce() { ASSERT(sizeof(FreeListElement) == kObjectAlignment); ASSERT(OFFSET_OF(FreeListElement, tags_) == Object::tags_offset()); } FreeList::FreeList() { Reset(); } FreeList::~FreeList() { // Nothing to release. } uword FreeList::TryAllocate(intptr_t size) { int index = IndexForSize(size); if ((index != kNumLists) && free_map_.Test(index)) { return reinterpret_cast(DequeueElement(index)); } if ((index + 1) < kNumLists) { intptr_t next_index = free_map_.Next(index + 1); if (next_index != -1) { // Dequeue an element from the list, split and enqueue the remainder in // the appropriate list. FreeListElement* element = DequeueElement(next_index); SplitElementAfterAndEnqueue(element, size); return reinterpret_cast(element); } } FreeListElement* previous = NULL; FreeListElement* current = free_lists_[kNumLists]; while (current != NULL) { if (current->Size() >= size) { // Found an element large enough to hold the requested size. Dequeue, // split and enqueue the remainder. if (previous == NULL) { free_lists_[kNumLists] = current->next(); } else { previous->set_next(current->next()); } SplitElementAfterAndEnqueue(current, size); return reinterpret_cast(current); } previous = current; current = current->next(); } return 0; } void FreeList::Free(uword addr, intptr_t size) { intptr_t index = IndexForSize(size); FreeListElement* element = FreeListElement::AsElement(addr, size); EnqueueElement(element, index); } void FreeList::Reset() { free_map_.Reset(); for (int i = 0; i < (kNumLists + 1); i++) { free_lists_[i] = NULL; } } intptr_t FreeList::IndexForSize(intptr_t size) { ASSERT(size >= kObjectAlignment); ASSERT(Utils::IsAligned(size, kObjectAlignment)); intptr_t index = size / kObjectAlignment; if (index >= kNumLists) { index = kNumLists; } return index; } void FreeList::EnqueueElement(FreeListElement* element, intptr_t index) { FreeListElement* next = free_lists_[index]; if (next == NULL && index != kNumLists) { free_map_.Set(index, true); } element->set_next(next); free_lists_[index] = element; } FreeListElement* FreeList::DequeueElement(intptr_t index) { FreeListElement* result = free_lists_[index]; FreeListElement* next = result->next(); if (next == NULL && index != kNumLists) { free_map_.Set(index, false); } free_lists_[index] = next; return result; } intptr_t FreeList::Length(int index) const { ASSERT(index >= 0); ASSERT(index < kNumLists); intptr_t result = 0; FreeListElement* element = free_lists_[index]; while (element != NULL) { ++result; element = element->next(); } return result; } void FreeList::PrintSmall() const { int small_sizes = 0; int small_objects = 0; intptr_t small_bytes = 0; for (int i = 0; i < kNumLists; ++i) { if (free_lists_[i] == NULL) { continue; } small_sizes += 1; intptr_t list_length = Length(i); small_objects += list_length; intptr_t list_bytes = list_length * i * kObjectAlignment; small_bytes += list_bytes; OS::Print("small %3d [%8d bytes] : " "%8"Pd" objs; %8.1f KB; %8.1f cum KB\n", i, i * kObjectAlignment, list_length, list_bytes / static_cast(KB), small_bytes / static_cast(KB)); } } void FreeList::PrintLarge() const { int large_sizes = 0; int large_objects = 0; intptr_t large_bytes = 0; std::map sorted; std::map::iterator it; FreeListElement* node; for (node = free_lists_[kNumLists]; node != NULL; node = node->next()) { it = sorted.find(node->Size()); if (it != sorted.end()) { it->second += 1; } else { large_sizes += 1; sorted.insert(std::make_pair(node->Size(), 1)); } large_objects += 1; } for (it = sorted.begin(); it != sorted.end(); ++it) { intptr_t size = it->first; intptr_t list_length = it->second; intptr_t list_bytes = list_length * size; large_bytes += list_bytes; OS::Print("large %3"Pd" [%8"Pd" bytes] : " "%8"Pd" objs; %8.1f KB; %8.1f cum KB\n", size / kObjectAlignment, size, list_length, list_bytes / static_cast(KB), large_bytes / static_cast(KB)); } } void FreeList::Print() const { PrintSmall(); PrintLarge(); } void FreeList::SplitElementAfterAndEnqueue(FreeListElement* element, intptr_t size) { intptr_t remainder_size = element->Size() - size; if (remainder_size == 0) return; element = FreeListElement::AsElement(reinterpret_cast(element) + size, remainder_size); intptr_t remainder_index = IndexForSize(remainder_size); EnqueueElement(element, remainder_index); } } // namespace dart