Skip to content

Commit

Permalink
Make Heap threadsafe
Browse files Browse the repository at this point in the history
  • Loading branch information
saintentropy committed Oct 15, 2023
1 parent 5f30633 commit 6fed793
Showing 1 changed file with 31 additions and 56 deletions.
87 changes: 31 additions & 56 deletions src/Engine/ProtoCore/DSASM/Heap.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ProtoCore.Exceptions;
using ProtoCore.Utils;

Expand Down Expand Up @@ -297,8 +299,8 @@ public enum GCMark
Black // Objects that are in use (are not candidates for garbage collection) and have had all their references traced.
}

private readonly List<int> freeList = new List<int>();
private readonly List<HeapElement> heapElements = new List<HeapElement>();
private int index = -1;
private readonly ConcurrentDictionary<int, HeapElement> heapElements = new ConcurrentDictionary<int, HeapElement>();
private HashSet<int> fixedHeapElements = new HashSet<int>();
private readonly StringTable stringTable = new StringTable();
// The expected lifetime of the sweepSet is start of GC to end of GC
Expand Down Expand Up @@ -346,9 +348,9 @@ public StackValue AllocateArray(StackValue[] values)
{
try
{
int index = AllocateInternal(values, PrimitiveType.Array);
var heapElement = heapElements[index];
heapElement.MetaData = new MetaData { type = (int)PrimitiveType.Array };
var index_heap = AllocateInternal(values, PrimitiveType.Array);
int index = index_heap.Item1;
index_heap.Item2.MetaData = new MetaData { type = (int)PrimitiveType.Array };
return StackValue.BuildArrayPointer(index);
}
catch (OutOfMemoryException)
Expand All @@ -365,9 +367,9 @@ public StackValue AllocateArray(StackValue[] values)
/// <returns></returns>
private StackValue AllocatePointer(StackValue[] values, MetaData metaData)
{
int index = AllocateInternal(values, PrimitiveType.Pointer);
var heapElement = heapElements[index];
heapElement.MetaData = metaData;
var index_heap = AllocateInternal(values, PrimitiveType.Pointer);
int index = index_heap.Item1;
index_heap.Item2.MetaData = metaData;
return StackValue.BuildPointer(index, metaData);
}

Expand Down Expand Up @@ -402,9 +404,9 @@ public StackValue AllocatePointer(int size, MetaData metadata)
{
try
{
int index = AllocateInternal(size, PrimitiveType.Pointer);
var hpe = heapElements[index];
hpe.MetaData = metadata;
var index_heap = AllocateInternal(size, PrimitiveType.Pointer);
int index = index_heap.Item1;
index_heap.Item2.MetaData = metadata;
return StackValue.BuildPointer(index, metadata);
}
catch (OutOfMemoryException)
Expand All @@ -427,7 +429,7 @@ private StackValue AllocateStringInternal(string str, bool isConstant)
// Any existing heap elements, marked as white, that are in the sweepSet and that are referenced during the sweep cycle will be marked as Black.
// This will ensure that no reachable data is mistakenly cleaned up.
bool isDuringGCCriticalAsyncCycle = gcState != GCState.Pause;// Between the time the GC takes a snapshot of the stack and heap untill GC cycle is over.
bool isValidHeapIndex = index >= 0 && index < heapElements.Count;
bool isValidHeapIndex = index >= 0;
if (isDuringGCCriticalAsyncCycle && isValidHeapIndex)
{
var he = heapElements[index];
Expand All @@ -445,7 +447,7 @@ private StackValue AllocateStringInternal(string str, bool isConstant)
}
else
{
index = AllocateInternal(new StackValue[] {}, PrimitiveType.String);
index = AllocateInternal(new StackValue[] {}, PrimitiveType.String).Item1;
stringTable.AddString(index, str);
}

Expand Down Expand Up @@ -500,7 +502,7 @@ public StackValue AllocateString(string str)
public string GetString(DSString dsString)
{
int index = dsString.Pointer.StringPointer;
Validity.Assert(index >= 0 && index < heapElements.Count);
Validity.Assert(index >= 0);

string s;
if (stringTable.TryGetString(index, out s))
Expand All @@ -526,7 +528,7 @@ private bool TryGetHeapElement(StackValue pointer, out HeapElement heapElement)
index = pointer.StringPointer;
}

if (index >= 0 && index < heapElements.Count)
if (index >= 0)
{
heapElement = heapElements[index];
}
Expand All @@ -536,29 +538,22 @@ private bool TryGetHeapElement(StackValue pointer, out HeapElement heapElement)
public void Free()
{
heapElements.Clear();
freeList.Clear();
index = -1;
}

private int AddHeapElement(HeapElement hpe)
private int AddHeapElement(ref HeapElement hpe)
{
hpe.Mark = GCMark.White;
ReportAllocation(hpe.MemorySize);

int index;
if (TryFindFreeIndex(out index))
{
heapElements[index] = hpe;
}
else
{
heapElements.Add(hpe);
index = heapElements.Count - 1;
}
var currentIndex = Interlocked.Increment(ref index);

return index;
heapElements.TryAdd(currentIndex, hpe);

return currentIndex;
}

private int AllocateInternal(int size, PrimitiveType type)
private (int, HeapElement) AllocateInternal(int size, PrimitiveType type)
{
HeapElement hpe = null;

Expand All @@ -580,10 +575,10 @@ private int AllocateInternal(int size, PrimitiveType type)
throw new ArgumentException("type");
}

return AddHeapElement(hpe);
return (AddHeapElement(ref hpe), hpe);
}

private int AllocateInternal(StackValue[] values, PrimitiveType type)
private (int,HeapElement) AllocateInternal(StackValue[] values, PrimitiveType type)
{
HeapElement hpe = null;

Expand All @@ -605,23 +600,7 @@ private int AllocateInternal(StackValue[] values, PrimitiveType type)
throw new ArgumentException("type");
}

return AddHeapElement(hpe);
}

private bool TryFindFreeIndex(out int index)
{
int freeItemCount = freeList.Count;
if (freeItemCount > 0)
{
index = freeList[freeItemCount - 1];
freeList.RemoveAt(freeItemCount - 1);
return true;
}
else
{
index = Constants.kInvalidIndex;
return false;
}
return (AddHeapElement(ref hpe), hpe);
}

//cache ClassIndex and ProcdureNode for repeated calls of the same type object.
Expand Down Expand Up @@ -734,8 +713,7 @@ private void StartCollection()
// We start from a clean sweepSet
sweepSet.Clear();

sweepSet.UnionWith(Enumerable.Range(0, heapElements.Count));
sweepSet.ExceptWith(freeList);
sweepSet.UnionWith(heapElements.Keys);
sweepSet.ExceptWith(fixedHeapElements);

grayList = new LinkedList<StackValue>();
Expand Down Expand Up @@ -811,8 +789,7 @@ private void Sweep()
}

totalAllocated -= hp.MemorySize;
heapElements[ptr] = null;
freeList.Add(ptr);
heapElements.TryRemove(ptr, out _);
}

gcDebt = totalAllocated > GC_THRESHOLD ? totalAllocated : GC_THRESHOLD;
Expand All @@ -826,8 +803,7 @@ private void MarkAllWhite()
{
foreach (var hp in heapElements)
{
if (hp != null)
hp.Mark = GCMark.White;
hp.Value.Mark = GCMark.White;
}
}

Expand Down Expand Up @@ -878,9 +854,8 @@ public bool SetRoots(IEnumerable<StackValue> gcroots, Executive exe)
return false;

var validPointers = gcroots.Where(r => r.IsReferenceType &&
r.RawData < heapElements.Count() &&
r.RawData >= 0 &&
heapElements[(int)r.RawData] != null);
heapElements.ContainsKey((int)r.RawData));
roots = new List<StackValue>(validPointers);
executive = exe;
StartCollection();
Expand Down

0 comments on commit 6fed793

Please sign in to comment.