blob: b85d2623dbdabf6f49b6bc0dc72564b264c8a0ed [file] [log] [blame]
// 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 VM_HEAP_H_
#define VM_HEAP_H_
#include "platform/assert.h"
#include "vm/allocation.h"
#include "vm/flags.h"
#include "vm/globals.h"
#include "vm/pages.h"
#include "vm/scavenger.h"
namespace dart {
// Forward declarations.
class Isolate;
class ObjectPointerVisitor;
class ObjectSet;
class VirtualMemory;
DECLARE_FLAG(bool, verbose_gc);
DECLARE_FLAG(bool, verify_before_gc);
DECLARE_FLAG(bool, verify_after_gc);
DECLARE_FLAG(bool, gc_at_alloc);
class Heap {
public:
enum Space {
kNew,
kOld,
kCode,
};
enum ApiCallbacks {
kIgnoreApiCallbacks,
kInvokeApiCallbacks
};
enum GCReason {
kNewSpace,
kPromotionFailure,
kOldSpace,
kFull,
kGCAtAlloc,
kGCTestCase,
};
// Default allocation sizes in MB for the old gen and code heaps.
static const intptr_t kHeapSizeInMB = 512;
static const intptr_t kCodeHeapSizeInMB = 18;
~Heap();
uword Allocate(intptr_t size, Space space) {
ASSERT(!read_only_);
switch (space) {
case kNew:
// Do not attempt to allocate very large objects in new space.
if (!IsAllocatableInNewSpace(size)) {
return AllocateOld(size, HeapPage::kData);
}
return AllocateNew(size);
case kOld:
return AllocateOld(size, HeapPage::kData);
case kCode:
return AllocateOld(size, HeapPage::kExecutable);
default:
UNREACHABLE();
}
return 0;
}
uword TryAllocate(
intptr_t size,
Space space,
PageSpace::GrowthPolicy growth_policy = PageSpace::kControlGrowth) {
ASSERT(!read_only_);
switch (space) {
case kNew:
return new_space_->TryAllocate(size);
case kOld:
return old_space_->TryAllocate(size,
HeapPage::kData,
growth_policy);
case kCode:
return old_space_->TryAllocate(size,
HeapPage::kExecutable,
growth_policy);
default:
UNREACHABLE();
}
return 0;
}
// Heap contains the specified address.
bool Contains(uword addr) const;
bool NewContains(uword addr) const;
bool OldContains(uword addr) const;
bool CodeContains(uword addr) const;
bool StubCodeContains(uword addr) const;
// Visit all pointers.
void IteratePointers(ObjectPointerVisitor* visitor);
// Visit all pointers in the space.
void IterateNewPointers(ObjectPointerVisitor* visitor);
void IterateOldPointers(ObjectPointerVisitor* visitor);
// Visit all objects.
void IterateObjects(ObjectVisitor* visitor);
// Visit all object in the space.
void IterateNewObjects(ObjectVisitor* visitor);
void IterateOldObjects(ObjectVisitor* visitor);
// Find an object by visiting all pointers in the specified heap space,
// the 'visitor' is used to determine if an object is found or not.
// The 'visitor' function should be set up to return true if the
// object is found, traversal through the heap space stops at that
// point.
// The 'visitor' function should return false if the object is not found,
// traversal through the heap space continues.
RawInstructions* FindObjectInCodeSpace(FindObjectVisitor* visitor);
RawInstructions* FindObjectInStubCodeSpace(FindObjectVisitor* visitor);
void CollectGarbage(Space space);
void CollectGarbage(Space space, ApiCallbacks api_callbacks);
void CollectAllGarbage();
// Enables growth control on the page space heaps. This should be
// called before any user code is executed.
void EnableGrowthControl() { SetGrowthControlState(true); }
void DisableGrowthControl() { SetGrowthControlState(false); }
void SetGrowthControlState(bool state);
bool GrowthControlState();
// Protect access to the heap.
void WriteProtect(bool read_only);
// Accessors for inlined allocation in generated code.
uword TopAddress();
uword EndAddress();
static intptr_t new_space_offset() { return OFFSET_OF(Heap, new_space_); }
// Initialize the heap and register it with the isolate.
static void Init(Isolate* isolate);
// Verify that all pointers in the heap point to the heap.
bool Verify() const;
// Print heap sizes.
void PrintSizes() const;
// Return amount of memory used and capacity in a space.
intptr_t Used(Space space) const;
intptr_t Capacity(Space space) const;
// Returns the [lowest, highest) addresses in the heap.
void StartEndAddress(uword* start, uword* end) const;
ObjectSet* CreateAllocatedObjectSet() const;
// Generates a profile of the current and VM isolate heaps.
void Profile(Dart_FileWriteCallback callback, void* stream) const;
void ProfileToFile(const char* reason) const;
static const char* GCReasonToString(GCReason gc_reason);
// Associates a peer with an object. If an object has a peer, it is
// replaced. A value of NULL disassociate an object from its peer.
void SetPeer(RawObject* raw_obj, void* peer);
// Retrieves the peer associated with an object. Returns NULL if
// there is no association.
void* GetPeer(RawObject* raw_obj);
// Returns the number of objects with a peer.
int64_t PeerCount() const;
// Stats collection.
void RecordTime(int id, int64_t micros) {
ASSERT((id >= 0) && (id < GCStats::kDataEntries));
stats_.times_[id] = micros;
}
void RecordData(int id, intptr_t value) {
ASSERT((id >= 0) && (id < GCStats::kDataEntries));
stats_.data_[id] = value;
}
bool gc_in_progress() const { return gc_in_progress_; }
static bool IsAllocatableInNewSpace(intptr_t size) {
return size <= kNewAllocatableSize;
}
private:
class GCStats : public ValueObject {
public:
GCStats() {}
intptr_t num_;
Heap::Space space_;
Heap::GCReason reason_;
class Data : public ValueObject {
public:
Data() {}
int64_t micros_;
intptr_t new_used_;
intptr_t new_capacity_;
intptr_t old_used_;
intptr_t old_capacity_;
DISALLOW_COPY_AND_ASSIGN(Data);
};
enum {
kDataEntries = 4
};
Data before_;
Data after_;
int64_t times_[kDataEntries];
intptr_t data_[kDataEntries];
DISALLOW_COPY_AND_ASSIGN(GCStats);
};
static const intptr_t kNewAllocatableSize = 256 * KB;
Heap();
uword AllocateNew(intptr_t size);
uword AllocateOld(intptr_t size, HeapPage::PageType type);
// GC stats collection.
void RecordBeforeGC(Space space, GCReason reason);
void RecordAfterGC();
void PrintStats();
// The different spaces used for allocation.
Scavenger* new_space_;
PageSpace* old_space_;
// GC stats collection.
GCStats stats_;
// This heap is in read-only mode: No allocation is allowed.
bool read_only_;
// GC on the heap is in progress.
bool gc_in_progress_;
friend class GCTestHelper;
DISALLOW_COPY_AND_ASSIGN(Heap);
};
#if defined(DEBUG)
class NoGCScope : public StackResource {
public:
NoGCScope();
~NoGCScope();
private:
DISALLOW_COPY_AND_ASSIGN(NoGCScope);
};
#else // defined(DEBUG)
class NoGCScope : public ValueObject {
public:
NoGCScope() {}
private:
DISALLOW_COPY_AND_ASSIGN(NoGCScope);
};
#endif // defined(DEBUG)
class NoHeapGrowthControlScope : public StackResource {
public:
NoHeapGrowthControlScope();
~NoHeapGrowthControlScope();
private:
bool current_growth_controller_state_;
DISALLOW_COPY_AND_ASSIGN(NoHeapGrowthControlScope);
};
} // namespace dart
#endif // VM_HEAP_H_