Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Commit

Permalink
Allocate GC statics on the GC heap
Browse files Browse the repository at this point in the history
We were previously allocating the GC static region statically in the
image, but for Ready to Run, we will require GC static regions to be
allocated on the GC heap.
  • Loading branch information
MichalStrehovsky committed Oct 12, 2015
1 parent 2aa5004 commit 3778479
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 24 deletions.
24 changes: 24 additions & 0 deletions src/Common/src/TypeSystem/Common/FieldLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,26 @@ out byteCount
return algorithm._computedLayout;
}

#region Runtime specific adjustements to the static field layout
// TODO: these should be factored out to make the static field layout algorithm more general purpose

private static void PrepareRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout)
{
// GC statics start with a pointer to the "EEType" that signals the size and GCDesc to the GC
layout.GcStatics.Size = context.Target.PointerSize;
}

private static void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout)
{
// If the size of GCStatics is equal to the size set in PrepareRuntimeSpecificStaticFieldLayout, we
// don't have any GC statics
if (layout.GcStatics.Size == context.Target.PointerSize)
{
layout.GcStatics.Size = 0;
}
}
#endregion

public static unsafe ComputedStaticFieldLayout ComputeStaticFieldLayout(MetadataType type)
{
int numStaticFields = 0;
Expand All @@ -178,6 +198,8 @@ public static unsafe ComputedStaticFieldLayout ComputeStaticFieldLayout(Metadata

result.Offsets = new FieldAndOffset[numStaticFields];

PrepareRuntimeSpecificStaticFieldLayout(type.Context, ref result);

int index = 0;

foreach (var field in type.GetFields())
Expand Down Expand Up @@ -206,6 +228,8 @@ public static unsafe ComputedStaticFieldLayout ComputeStaticFieldLayout(Metadata
index++;
}

FinalizeRuntimeSpecificStaticFieldLayout(type.Context, ref result);

return result;
}

Expand Down
65 changes: 48 additions & 17 deletions src/ILToNative.Compiler/src/Compiler/AsmWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ void OutputCode()
Out.WriteLine();

OutputReadyToHelpers();
OutputJitHelpers();

OutputEETypes();

Out.WriteLine();
Expand Down Expand Up @@ -169,15 +167,6 @@ void OutputMethodCode(RegisteredMethod m)
Out.WriteLine();
}

void OutputJitHelpers()
{
// assignReference is always the same. This will be a call into the runtime.
Out.WriteLine("__assignReference:");
Out.WriteLine("movq %rdx, (%rcx)");
Out.WriteLine("ret");
Out.WriteLine();
}

void OutputReadyToHelpers()
{
foreach (var helper in _readyToRunHelpers.Values)
Expand Down Expand Up @@ -268,6 +257,8 @@ void OutputReadyToHelpers()
Out.Write("leaq __GCStaticBase_");
Out.Write(NameMangler.GetMangledTypeName((TypeDesc)helper.Target));
Out.WriteLine("(%rip), %rax");
Out.WriteLine("mov (%rax), %rax");
Out.WriteLine("mov (%rax), %rax"); // RAX is now a GC pointer
Out.WriteLine("ret");
break;

Expand Down Expand Up @@ -348,6 +339,13 @@ void OutputNonGCStatics()

void OutputGCStatics()
{
// Emit an array of GCHandle-sized elements for each type with GC statics
// Each element will be initially pointing at the pseudo EEType for the static.
// At runtime, it will be replaced by a GC handle to the GC-heap allocated object.

Out.WriteLine(".global __GCStaticRegionStart");
Out.WriteLine("__GCStaticRegionStart:");

foreach (var t in _registeredTypes.Values)
{
if (!t.IncludedInCompilation)
Expand All @@ -359,17 +357,50 @@ void OutputGCStatics()

if (type.GCStaticFieldSize > 0)
{
Out.Write(".align ");
Out.WriteLine(type.GCStaticFieldAlignment);
Out.Write("__GCStaticBase_");
Out.Write(NameMangler.GetMangledTypeName(type));
Out.WriteLine(":");
Out.Write(".rept ");
Out.WriteLine(type.GCStaticFieldSize);
Out.WriteLine(".byte 0");
Out.WriteLine(".endr");
Out.Write(".quad ");
Out.Write("__GCStaticEEType_");
Out.Write(NameMangler.GetMangledTypeName(type));
Out.WriteLine();
}
}

Out.WriteLine(".global __GCStaticRegionEnd");
Out.WriteLine("__GCStaticRegionEnd:");

// Next emit a GCDesc followed by the size of the region described by the GCDesc
// for each type with GC statics.

// It should be possible to intern these at some point.

foreach (var t in _registeredTypes.Values)
{
if (!t.IncludedInCompilation)
continue;

var type = t.Type as MetadataType;
if (type == null)
continue;

if (type.GCStaticFieldSize > 0)
{
// numSeries
Out.WriteLine(".quad 0");

Out.Write("__GCStaticEEType_");
Out.Write(NameMangler.GetMangledTypeName(type));
Out.WriteLine(":");
Out.WriteLine(".int 0");
Out.Write(".int ");

// GC requires a minimum object size
int minimumObjectSize = type.Context.Target.PointerSize * 3;
int gcStaticSize = Math.Max(type.GCStaticFieldSize, minimumObjectSize);

Out.WriteLine(gcStaticSize);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/ILToNative.Compiler/src/Compiler/JitHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public string MangledName
return "__range_check_fail";

case JitHelperId.AssignRef:
return "__assignReference";
return "WriteBarrier";

default:
throw new NotImplementedException();
Expand Down
12 changes: 6 additions & 6 deletions src/ILToNative.TypeSystem/tests/StaticFieldLayoutTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,10 @@ public void TestHasPointers()
switch (field.Name)
{
case "string1":
Assert.Equal(0, field.Offset);
Assert.Equal(8, field.Offset);
break;
case "class1":
Assert.Equal(8, field.Offset);
Assert.Equal(16, field.Offset);
break;
default:
throw new Exception(field.Name);
Expand All @@ -152,19 +152,19 @@ public void TestMixPointersAndNonPointers()
switch (field.Name)
{
case "string1":
Assert.Equal(0, field.Offset);
Assert.Equal(8, field.Offset);
break;
case "int1":
Assert.Equal(0, field.Offset);
break;
case "class1":
Assert.Equal(8, field.Offset);
Assert.Equal(16, field.Offset);
break;
case "int2":
Assert.Equal(4, field.Offset);
break;
case "string2":
Assert.Equal(16, field.Offset);
Assert.Equal(24, field.Offset);
break;
default:
throw new Exception(field.Name);
Expand Down Expand Up @@ -193,7 +193,7 @@ public void TestEnsureInheritanceResetsStaticOffsets()
Assert.Equal(0, field.Offset);
break;
case "string3":
Assert.Equal(0, field.Offset);
Assert.Equal(8, field.Offset);
break;
default:
throw new Exception(field.Name);
Expand Down
45 changes: 45 additions & 0 deletions src/ILToNative/reproNative/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,24 @@ void __reverse_pinvoke_return(ReversePInvokeFrame* pRevFrame)
#endif // USE_MRT
}

extern "C" void* __GCStaticRegionStart;
extern "C" void* __GCStaticRegionEnd;

void __register_module(SimpleModuleHeader* pModule)
{
#if USE_MRT
RhpRegisterSimpleModule(pModule);
#endif // USE_MRT


// Initialize GC statics in the module
// TODO: emit a ModuleHeader and use it here

for (void** currentBlock = &__GCStaticRegionStart; currentBlock < &__GCStaticRegionEnd; currentBlock++)
{
Object* gcBlock = __allocate_object((MethodTable*)*currentBlock);
*currentBlock = CreateGlobalHandle(ObjectToOBJECTREF(gcBlock));
}
}

namespace mscorlib { namespace System {
Expand Down Expand Up @@ -231,6 +244,38 @@ extern "C" Object * __allocate_array(size_t elements, MethodTable * pMT)
#endif
}

#if defined(_WIN64)
// Card byte shift is different on 64bit.
#define card_byte_shift 11
#else
#define card_byte_shift 10
#endif

#define card_byte(addr) (((size_t)(addr)) >> card_byte_shift)

inline void ErectWriteBarrier(Object ** dst, Object * ref)
{
// if the dst is outside of the heap (unboxed value classes) then we
// simply exit
if (((BYTE*)dst < g_lowest_address) || ((BYTE*)dst >= g_highest_address))
return;

if ((BYTE*)ref >= g_ephemeral_low && (BYTE*)ref < g_ephemeral_high)
{
// volatile is used here to prevent fetch of g_card_table from being reordered
// with g_lowest/highest_address check above. See comment in code:gc_heap::grow_brick_card_tables.
BYTE* pCardByte = (BYTE *)*(volatile BYTE **)(&g_card_table) + card_byte((BYTE *)dst);
if (*pCardByte != 0xFF)
*pCardByte = 0xFF;
}
}

extern "C" void WriteBarrier(Object ** dst, Object * ref)
{
*dst = ref;
ErectWriteBarrier(dst, ref);
}

void __throw_exception(void * pEx)
{
// TODO: Exception throwing
Expand Down

0 comments on commit 3778479

Please sign in to comment.