mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:19:47 +00:00
6d5f763952
In many cases, the Mutexes and Monitors have to be marked "mutable" because they're used to synchronize const accessor methods. Small text segment improvement for Product builds: $ size dart.{arm,x64}.{before,after} text data bss dec hex filename 19726069 409960 392332 20528361 1393ce9 dart.arm.before 19725525 409960 392332 20527817 1393ac9 dart.arm.after 22576021 600376 1782824 24959221 17cd8f5 dart.x64.before 22574821 600376 1782824 24958021 17cd445 dart.x64.after Change-Id: I68f5cd5ad452044df8bfebd160910496036a3e6b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101745 Commit-Queue: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
179 lines
5.4 KiB
C++
179 lines
5.4 KiB
C++
// Copyright (c) 2012, 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.
|
|
|
|
#ifndef RUNTIME_VM_HEAP_FREELIST_H_
|
|
#define RUNTIME_VM_HEAP_FREELIST_H_
|
|
|
|
#include "platform/assert.h"
|
|
#include "vm/allocation.h"
|
|
#include "vm/bit_set.h"
|
|
#include "vm/os_thread.h"
|
|
#include "vm/raw_object.h"
|
|
|
|
namespace dart {
|
|
|
|
// FreeListElement describes a freelist element. Smallest FreeListElement is
|
|
// two words in size. Second word of the raw object is used to keep a next_
|
|
// pointer to chain elements of the list together. For objects larger than the
|
|
// object size encodable in tags field, the size of the element is embedded in
|
|
// the element at the address following the next_ field. All words written by
|
|
// the freelist are guaranteed to look like Smis.
|
|
// A FreeListElement never has its header mark bit set.
|
|
class FreeListElement {
|
|
public:
|
|
FreeListElement* next() const { return next_; }
|
|
uword next_address() const { return reinterpret_cast<uword>(&next_); }
|
|
|
|
void set_next(FreeListElement* next) { next_ = next; }
|
|
|
|
intptr_t HeapSize() {
|
|
intptr_t size = RawObject::SizeTag::decode(tags_);
|
|
if (size != 0) return size;
|
|
return *SizeAddress();
|
|
}
|
|
|
|
static FreeListElement* AsElement(uword addr, intptr_t size);
|
|
|
|
static void Init();
|
|
|
|
static intptr_t HeaderSizeFor(intptr_t size);
|
|
|
|
// Used to allocate class for free list elements in Object::InitOnce.
|
|
class FakeInstance {
|
|
public:
|
|
FakeInstance() {}
|
|
static cpp_vtable vtable() { return 0; }
|
|
static intptr_t InstanceSize() { return 0; }
|
|
static intptr_t NextFieldOffset() { return -kWordSize; }
|
|
static const ClassId kClassId = kFreeListElement;
|
|
static bool IsInstance() { return true; }
|
|
|
|
private:
|
|
DISALLOW_ALLOCATION();
|
|
DISALLOW_COPY_AND_ASSIGN(FakeInstance);
|
|
};
|
|
|
|
private:
|
|
// This layout mirrors the layout of RawObject.
|
|
uint32_t tags_;
|
|
#if defined(HASH_IN_OBJECT_HEADER)
|
|
uint32_t hash_;
|
|
#endif
|
|
FreeListElement* next_;
|
|
|
|
// Returns the address of the embedded size.
|
|
intptr_t* SizeAddress() const {
|
|
uword addr = reinterpret_cast<uword>(&next_) + kWordSize;
|
|
return reinterpret_cast<intptr_t*>(addr);
|
|
}
|
|
|
|
// FreeListElements cannot be allocated. Instead references to them are
|
|
// created using the AsElement factory method.
|
|
DISALLOW_ALLOCATION();
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(FreeListElement);
|
|
};
|
|
|
|
class FreeList {
|
|
public:
|
|
FreeList();
|
|
~FreeList();
|
|
|
|
uword TryAllocate(intptr_t size, bool is_protected);
|
|
void Free(uword addr, intptr_t size);
|
|
|
|
void Reset();
|
|
|
|
void Print() const;
|
|
|
|
Mutex* mutex() { return &mutex_; }
|
|
uword TryAllocateLocked(intptr_t size, bool is_protected);
|
|
void FreeLocked(uword addr, intptr_t size);
|
|
|
|
// Returns a large element, at least 'minimum_size', or NULL if none exists.
|
|
FreeListElement* TryAllocateLarge(intptr_t minimum_size);
|
|
FreeListElement* TryAllocateLargeLocked(intptr_t minimum_size);
|
|
|
|
// Allocates locked and unprotected memory, but only from small elements
|
|
// (i.e., fixed size lists).
|
|
uword TryAllocateSmallLocked(intptr_t size) {
|
|
DEBUG_ASSERT(mutex_.IsOwnedByCurrentThread());
|
|
if (size > last_free_small_size_) {
|
|
return 0;
|
|
}
|
|
int index = IndexForSize(size);
|
|
if (index != kNumLists && free_map_.Test(index)) {
|
|
return reinterpret_cast<uword>(DequeueElement(index));
|
|
}
|
|
if ((index + 1) < kNumLists) {
|
|
intptr_t next_index = free_map_.Next(index + 1);
|
|
if (next_index != -1) {
|
|
FreeListElement* element = DequeueElement(next_index);
|
|
SplitElementAfterAndEnqueue(element, size, false);
|
|
return reinterpret_cast<uword>(element);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
static const int kNumLists = 128;
|
|
static const intptr_t kInitialFreeListSearchBudget = 1000;
|
|
|
|
static intptr_t IndexForSize(intptr_t size) {
|
|
ASSERT(size >= kObjectAlignment);
|
|
ASSERT(Utils::IsAligned(size, kObjectAlignment));
|
|
|
|
intptr_t index = size >> kObjectAlignmentLog2;
|
|
if (index >= kNumLists) {
|
|
index = kNumLists;
|
|
}
|
|
return index;
|
|
}
|
|
|
|
intptr_t LengthLocked(int index) const;
|
|
|
|
void EnqueueElement(FreeListElement* element, intptr_t index);
|
|
FreeListElement* DequeueElement(intptr_t index) {
|
|
FreeListElement* result = free_lists_[index];
|
|
FreeListElement* next = result->next();
|
|
if (next == NULL && index != kNumLists) {
|
|
intptr_t size = index << kObjectAlignmentLog2;
|
|
if (size == last_free_small_size_) {
|
|
// Note: This is -1 * kObjectAlignment if no other small sizes remain.
|
|
last_free_small_size_ =
|
|
free_map_.ClearLastAndFindPrevious(index) * kObjectAlignment;
|
|
} else {
|
|
free_map_.Set(index, false);
|
|
}
|
|
}
|
|
free_lists_[index] = next;
|
|
return result;
|
|
}
|
|
|
|
void SplitElementAfterAndEnqueue(FreeListElement* element,
|
|
intptr_t size,
|
|
bool is_protected);
|
|
|
|
void PrintSmall() const;
|
|
void PrintLarge() const;
|
|
|
|
// Lock protecting the free list data structures.
|
|
mutable Mutex mutex_;
|
|
|
|
BitSet<kNumLists> free_map_;
|
|
|
|
FreeListElement* free_lists_[kNumLists + 1];
|
|
|
|
intptr_t freelist_search_budget_;
|
|
|
|
// The largest available small size in bytes, or negative if there is none.
|
|
intptr_t last_free_small_size_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(FreeList);
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_HEAP_FREELIST_H_
|