Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d4fb0a4
vm-cpp: move allocator files to a separate dir
melkyades Nov 29, 2024
1c463dc
vm-cpp: fix paths after moving files
melkyades Nov 29, 2024
bba0fbb
[cppvm] use nullptr instead of 0 for pointer init
melkyades Mar 22, 2025
ba771f7
[cppvm] fix a couple of compilation warnings
melkyades Mar 22, 2025
fd0005c
[cpp:gc] add most new code/lasses of old-space compactor
melkyades Mar 23, 2025
a151882
[cppvm] add a couple globally available debug methods
melkyades Mar 23, 2025
08b6dce
[cppvm] remove GC_CRITICAL
melkyades Mar 23, 2025
26a4100
[cppvm] make Egg.h include basic int types, convert WORD_SIZE to a co…
melkyades Mar 23, 2025
0de1dba
[cppvm] after loading an image-segment, relocate the pointer to the m…
melkyades Mar 23, 2025
a498086
[cppvm:gc] make sexpressions store GCedRefs instead of raw pointers w…
melkyades Mar 23, 2025
19c3869
[cppvm:gc] add an object copying method for compactor
melkyades Mar 23, 2025
9820ccf
[cppvm:gc] adapt Runtime class to the existance of a moving GC
melkyades Mar 23, 2025
59f114c
[cppvm:gc] Make evaluator aware of moving GC
melkyades Mar 23, 2025
59c1971
[cppvm:gc] Make evaluation context aware of moving GC
melkyades Mar 23, 2025
11219e3
[cppvm] add a few constants for accessing Process inst vars and friends
melkyades Mar 23, 2025
56dbb67
[cppvm:gc] add a method to decommit memory (in posix)
melkyades Mar 23, 2025
f4218dd
[cppvm:gc] a few last bits in SmallInteger for GC integration
melkyades Mar 23, 2025
6f88741
[kernel] process stacks know their bp, which is used to traverse stac…
melkyades Mar 23, 2025
d280157
[cppvm:gc] make bootstrapper register the kernel space to GC
melkyades Mar 23, 2025
ebfe7a0
[cppvm:gc] add a couple missing declarations
melkyades Mar 23, 2025
d568388
[cppvm] add primitive for measuring time
melkyades Mar 23, 2025
68bdc41
[cppvm] make creation of enviornments optional
melkyades Mar 23, 2025
e1f6c39
[cppvm] enhanced debug pretty-printing of stack objects
melkyades Mar 23, 2025
cd405f7
[cppvm] fix includes in Runtime.h
melkyades Mar 23, 2025
3433bd5
[cppvm:gc] add DecommitMemory version for Windows
melkyades Mar 24, 2025
3fea986
[cppvm] windows requires differentiated version for aligned allocation
melkyades Mar 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion modules/Kernel/ProcessStack.st
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ Class {
#superclass : #Object,
#instVars : [
'process',
'sp'
'sp',
'bp'
],
#category : #Kernel
}
Expand Down
240 changes: 240 additions & 0 deletions runtime/cpp/Allocator/AllocationZone.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@

#include "Egg.h"
#include "Memory.h"
#include "AllocationZone.h"
#include "GCSpace.h"
#include "GCHeap.h"
#include "HeapObject.h"

using namespace Egg;

AllocationZone::AllocationZone(GCHeap* heap, uintptr_t base, uintptr_t limit) :
_heap(heap),
_base(base),
_nextFree(base),
_limit(limit)
{
this->build();
}

uintptr_t AllocationZone::allocate_(uintptr_t size)
{
auto oop = this->allocateIfPossibleBumping_(size);
if (!oop)
error_("Out of memory in old space");

return oop;
}

uintptr_t AllocationZone::allocateIfPossibleCurrent_(uintptr_t size) {
//printf("allocing: %d bytes in current\n", size);
return _current->allocateIfPossible_(size);
}

uintptr_t AllocationZone::allocateIfPossibleBumping_(uintptr_t size)
{
//printf("allocing: %zu bytes bumping\n", size);

auto oop = _current->allocateIfPossible_(size);
if (oop)
return oop;
this->bumpSpace();
return _current->allocateIfPossible_(size);
}

void AllocationZone::assureFree_(uintptr_t size)
{
if (_current->softAvailable() < size) this->bumpSpace();
}

uintptr_t AllocationZone::availableBytes()
{
return this->usableBytes() - this->committedBytes();
}

void AllocationZone::build()
{
auto max = this->indexOfPointer_(_limit - 1);
_occupancy.resize(max, 0);
this->bumpSpace();
this->bumpSpace();
}

GCSpace* AllocationZone::bumpSpace()
{
_current = _next;
//if (_current) // uninitialized on first bump
// printf("bumped space - new limits: 0x%p - 0x%p\n", (void*)_current->base(), (void*)_current->reservedLimit());
if (_emptySpaces.empty()) this->createEmptySpace();

_next = _emptySpaces.back();
_emptySpaces.pop_back();
_next->commitMemory_(_next->reservedSize());
_next->_softLimit = _next->_committedLimit;
this->markAsFull_(_next);
return _next;
}

uintptr_t AllocationZone::committedBytes()
{
auto sum = 0;
for (auto space : _spaces)
sum = sum + space->committedSize();
return sum;
}

GCSpace *AllocationZone::createEmptySpace()
{
if (_nextFree == _limit) {
printf("_nextFree: %" PRIxPTR ". _limit: %" PRIxPTR "\n", _nextFree, _limit);
error_("Out of space in old zone");
}
auto start = _nextFree;
auto end = _nextFree + SPACE_SIZE;
_nextFree = end + SPACE_SIZE;
auto s = GCSpace::allocatedAt_limit_(start, end);
s->_name ="Old";
//printf("adding old space nº %" PRIdPTR "\n", _spaces.size());
_spaces.push_back(s);
_emptySpaces.push_back(s);
_heap->addSpace_(s);

//printf("bumping old zone limit: _nextFree: %" PRIxPTR ". _limit: %" PRIxPTR "\n", _nextFree, _limit);

return s;
}

GCSpace *AllocationZone::currentSpace()
{
return _current;
}

uintptr_t AllocationZone::indexOfPointer_(uintptr_t address)
{
return ((address - _base) >> SPACE_SIZE_SHIFT) / 2 + 1; // half of the space are forwarders
}

uintptr_t AllocationZone::indexOfSpace_(GCSpace *space)
{
return this->indexOfPointer_(space->base());
}

void AllocationZone::markAsFull_(GCSpace *space)
{
/*
We mark spaces as fully occupied so that
the GC doesn't see them as ready to be freed.
*/
auto index = this->indexOfSpace_(space);
_occupancy[index - 1] = SPACE_SIZE;
}

uintptr_t AllocationZone::occupiedBytes()
{
auto sum = 0;
for (size_t i = 0; i < _spaces.size(); i++)
if (!_spaces[i]->isFree())
sum = sum + _occupancy[i];
return sum;
}

void AllocationZone::recycleSpace_(GCSpace *space)
{
_emptySpaces.push_back(space);
}

uintptr_t AllocationZone::regionCount()
{
return this->indexOfPointer_(_nextFree - 1);
}

intptr_t AllocationZone::regionIndexOf_(HeapObject *object)
{
auto pointer = (uintptr_t)object;
if (pointer < _base) return -1;
if (pointer >= _limit) return -1;
return this->indexOfPointer_(pointer);
}

void AllocationZone::releaseEvacuated_(std::vector<bool> *evacuated)
{
for (uint32_t i = 1; i < _spaces.size(); i++)
{
auto space = _spaces[i-1];
auto used = _occupancy[i-1];
bool recycle = (*evacuated)[i-1] || (used == 0 && space->committedSize() > 0);
if (recycle)
{
auto base = space->_base;
auto size = space->reservedSize();
space->_next = base;
space->_committedLimit = base;
space->_softLimit = base;
DecommitMemory(base, size * 2);
this->recycleSpace_(space);
}
}
}

void AllocationZone::relocate_(intptr_t anInteger)
{
_base = _base + anInteger;
_nextFree = _nextFree + anInteger;
_limit = _limit + anInteger;
}

uintptr_t AllocationZone::reservedBytes()
{
return _limit - _base;
}

void AllocationZone::resetOccupancy()
{
std::fill(_occupancy.begin(), _occupancy.end(), 0);
this->markAsFull_(_current);
this->markAsFull_(_next);
}

HeapObject *AllocationZone::shallowCopyCommiting_(HeapObject *object)
{
auto copy = _current->shallowCopyCommitting_(object);
if (copy)
return copy;

auto size = object->bodySizeInBytes();
if (size > GCHeap::LargeThreshold)
{
auto space = _heap->createLargeSpace_(size);
return space->shallowCopyCommitting_(object);
}
this->bumpSpace();
return _current->shallowCopyCommitting_(object);
}

uintptr_t AllocationZone::size()
{
return _limit - _base;
}

void AllocationZone::updateRegionOccupancy_(HeapObject *object)
{
auto index = this->regionIndexOf_(object);
if (index < 0) return;

auto bytes = _occupancy[index - 1];
_occupancy[index-1] = bytes + object->bodySizeInBytes();
}

uintptr_t AllocationZone::usableBytes()
{
// Half of each reserved area is held for evacuation purposes only and not directly usable.
return this->reservedBytes() / 2;
}

uintptr_t AllocationZone::usedBytes()
{
auto count = 0;
for (auto s : _spaces)
count = count + s->usedSize();
return count;
}
64 changes: 64 additions & 0 deletions runtime/cpp/Allocator/AllocationZone.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#ifndef _ALLOCATION_ZONE_H_
#define _ALLOCATION_ZONE_H_

#include <vector>
#include "Egg.h"

namespace Egg {

class HeapObject;
class GCSpace;
class GCHeap;

class AllocationZone {
GCHeap *_heap;
uintptr_t _base, _nextFree, _limit;
GCSpace *_current, *_next;
std::vector<GCSpace*> _spaces;
std::vector<GCSpace*> _emptySpaces;
std::vector<uintptr_t> _occupancy;

public:
AllocationZone(GCHeap* heap, uintptr_t base, uintptr_t limit);

// 256 kb spaces
const uintptr_t SPACE_SIZE_SHIFT = 18;
const uintptr_t SPACE_SIZE = 1 << SPACE_SIZE_SHIFT;

uintptr_t base() { return _base; }
uintptr_t limit() { return _limit; }
std::vector<uintptr_t>* occupancy() { return &_occupancy; }
uintptr_t regionSize() { return SPACE_SIZE; }
std::vector<GCSpace*>& spaces() { return _spaces; }

uintptr_t allocate_(uintptr_t size);
uintptr_t allocateIfPossibleCurrent_(uintptr_t size);
uintptr_t allocateIfPossibleBumping_(uintptr_t size);
void assureFree_(uintptr_t size);
uintptr_t availableBytes();
void build();
GCSpace* bumpSpace();
uintptr_t committedBytes();
GCSpace* createEmptySpace();
GCSpace* currentSpace();
uintptr_t indexOfPointer_(uintptr_t address);
uintptr_t indexOfSpace_(GCSpace *space);
void markAsFull_(GCSpace *space);
uintptr_t occupiedBytes();
void recycleSpace_(GCSpace *space);
uintptr_t regionCount();
intptr_t regionIndexOf_(HeapObject *object);
void releaseEvacuated_(std::vector<bool> *evacuated);
void relocate_(intptr_t anInteger);
uintptr_t reservedBytes();
void resetOccupancy();
HeapObject* shallowCopyCommiting_(HeapObject *object);
uintptr_t size();
void updateRegionOccupancy_(HeapObject *object);
uintptr_t usableBytes();
uintptr_t usedBytes();
};

} // namespace Egg

#endif // ~ _ALLOCATION_ZONE_H_ ~
Loading