Discriminated Union GC Support #117567
Replies: 3 comments 20 replies
-
My go_through_object macro looks like this: (Note that again, managed value type arrays are not supported just yet, but I think they wont cause to many extra hurdles) #define go_through_object(mt,o,size,parm,start,start_useful,limit,exp){ \
FastGraphWalker<GraphNode> walker; \
walker.parent.SetDesc(CGCDesc::GetCGCDescFromMT((MethodTable*)(mt))); \
walker.parentPushed(); \
GraphNode* n; \
uint8_t** parm = 0; \
printf("\n\nEnter Object:%p\n", o); \
\
while((n = walker.currentNode()) != nullptr){ \
while(n->index > -1){ \
auto e = n->desc->GetEntry(n->index); \
parm = (uint8_t**) ((uint8_t*)o + e->GetOffset()); \
printf("Entry[%d]: o:%p %p->%p Offset:%d Union:%d\n", (size_t) n->index, o, parm, *parm, (int32_t) e->GetOffset(), e->IsUnionType()); \
n->index--; \
if (e->IsUnionType()) { \
auto ot = walker.parent.desc->GetUnionOffsetTable(e->GetUnionOffsetTableOffset());\
printf("Union Type:%u UnionOffsetTableOffset:%d\n", *(UnionTypeType*) parm, e->GetUnionOffsetTableOffset()); \
auto dof = ot->GetUnionDescOffset(*(UnionTypeType*) parm); \
printf("\tUnionDescTableOffset:%d\n", dof); \
if (dof != CGCUnionDescOffsetNull) { \
GraphNode gn; \
gn.SetDesc(walker.parent.desc->GetUnionDesc(dof)); \
walker.pushNode(gn); \
n = walker.currentNode(); \
continue; \
} \
} \
else { \
uint8_t** ppstop = parm + e->GetPointerSpanLength(); \
if (!start_useful || (uint8_t*)ppstop > (start)){ \
if (start_useful && (uint8_t*)parm < (start)) \
parm = (uint8_t**)(start); \
while (parm < ppstop){ \
{exp} \
parm++; \
} \
} \
} \
} \
walker.popNode(); \
} \
} The FastGraphWalker keeps an N-size inline stack to hopefully help speed up most cases where the depth of unions is shallow. It falls back to grabbing memory from a pool when needed (slower, but wont cause overflow). |
Beta Was this translation helpful? Give feedback.
-
This can't really work. Not only the GC is treating GC references differently, but also JIT code (GC field require write barriers), managed BCL (non-GC field can be safely copied with SIMD register), etc. |
Beta Was this translation helpful? Give feedback.
-
My current TODO list
What have I accomplished? (We will see how this holds in further tests)
If anyone has any particular questions about how I did the above, feel free to ask or play around with my repo! |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I have been reading through the dotnet runtime and decided to toy around with how to implement a memory efficient discriminated union deep into the .NET runtime. I have been having quite a bit of success!
Lets say we want to represent the following:
You could create a struct of nullables for each but this will quickly waste ALOT of memory the more fields you begin adding..... it will be exponential especially as the depth of nested unions increase.
What makes this so hard? Managed Structs
Managed Structs allow multiple inline reference to occur thus any reasonable efficient memory representation (that doesnt box) will need to somehow figure out what references are where depending on the type of the union.
Lets make the internal memory representation of the union be the following
So what do we have to do?
First lets define some parameters describing this union
The union fields should be sorted in the following order: ref type, managed structures then last unmanaged structures with an increasing type index assigned to each one.
Note that we don't care about any type index greater than MANAGED_CNT or NULL types.
Size of the union = max size of all ref or struct fields
My current work has dealt with go_through_object (fields inside an object) which is the primary bottleneck in this implementation:
There is a lot of detail that I am going to exclude for now because this post would be massive, but the general memory layout for the GC for our above example is the following:
My current results (let union be a managed object):
Output:
Perfect! This is following the behaviour that we want!!!
Lets try the union being an unmanaged value
Output
Awesome! The GC is not treating "5" like its a valid reference!
Anyhow this isnt meant to be super formal ... just wanted to make yall aware of this.
You can find all my work thus far in my personal fork of the runtime. All code above is in GCSample.cpp
Currently managed value type arrays dont work ... I havent reworked their memory format just yet.
Because of the new data structures I will have to redesign some AOT/JIT methodtablebuilders.
Thoughts?
(If anyone is wondering how I deal with multiple nested union types without having stack overflow I built a special graph traverser to handle this)
Beta Was this translation helpful? Give feedback.
All reactions