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

Commit

Permalink
Merge pull request #44 from MichalStrehovsky/GCStatics
Browse files Browse the repository at this point in the history
Add support for GC static fields
  • Loading branch information
MichalStrehovsky committed Oct 12, 2015
2 parents c1586e6 + 3778479 commit b01f36c
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 10 deletions.
48 changes: 48 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 Expand Up @@ -538,6 +562,30 @@ public int NonGCStaticFieldAlignment
}
}

public int GCStaticFieldSize
{
get
{
if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.HasStaticFieldLayout))
{
ComputeStaticFieldLayout();
}
return _staticBlockInfo == null ? 0 : _staticBlockInfo.GcStatics.Size;
}
}

public int GCStaticFieldAlignment
{
get
{
if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.HasStaticFieldLayout))
{
ComputeStaticFieldLayout();
}
return _staticBlockInfo == null ? 0 : _staticBlockInfo.GcStatics.LargestAlignment;
}
}

internal void ComputeInstanceFieldLayout()
{
var computedLayout = FieldLayoutAlgorithm.ComputeInstanceFieldLayout(this);
Expand Down
87 changes: 84 additions & 3 deletions src/ILToNative.Compiler/src/Compiler/AsmWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,18 @@ void OutputCode()
Out.WriteLine();

OutputReadyToHelpers();

OutputEETypes();

Out.WriteLine();
Out.WriteLine(".data");

OutputStatics();
Out.WriteLine();
Out.WriteLine("// Non-GC statics");
OutputNonGCStatics();

Out.WriteLine();
Out.WriteLine("// GC statics");
OutputGCStatics();

Out.Dispose();
}
Expand Down Expand Up @@ -248,6 +253,15 @@ void OutputReadyToHelpers()
Out.WriteLine("ret");
break;

case ReadyToRunHelperId.GetGCStaticBase:
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;

default:
throw new NotImplementedException();
}
Expand Down Expand Up @@ -296,7 +310,7 @@ void OutputEETypes()
}
}

void OutputStatics()
void OutputNonGCStatics()
{
foreach (var t in _registeredTypes.Values)
{
Expand All @@ -323,6 +337,73 @@ void OutputStatics()
}
}

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)
continue;

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

if (type.GCStaticFieldSize > 0)
{
Out.Write("__GCStaticBase_");
Out.Write(NameMangler.GetMangledTypeName(type));
Out.WriteLine(":");
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);
}
}
}

void OutputVirtualSlots(TypeDesc implType, TypeDesc declType)
{
var baseType = declType.BaseType;
Expand Down
4 changes: 4 additions & 0 deletions src/ILToNative.Compiler/src/Compiler/JitHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace ILToNative
public enum JitHelperId
{
RngChkFail,
AssignRef,
}

class JitHelper
Expand All @@ -35,6 +36,9 @@ public string MangledName
case JitHelperId.RngChkFail:
return "__range_check_fail";

case JitHelperId.AssignRef:
return "WriteBarrier";

default:
throw new NotImplementedException();
}
Expand Down
3 changes: 3 additions & 0 deletions src/ILToNative.Compiler/src/Compiler/ReadyToRunHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public enum ReadyToRunHelperId
IsInstanceOf,
CastClass,
GetNonGCStaticBase,
GetGCStaticBase,
}

class ReadyToRunHelper
Expand Down Expand Up @@ -54,6 +55,8 @@ public string MangledName
return "__CastClass_" + _compilation.NameMangler.GetMangledTypeName((TypeDesc)this.Target);
case ReadyToRunHelperId.GetNonGCStaticBase:
return "__GetNonGCStaticBase_" + _compilation.NameMangler.GetMangledTypeName((TypeDesc)this.Target);
case ReadyToRunHelperId.GetGCStaticBase:
return "__GetGCStaticBase_" + _compilation.NameMangler.GetMangledTypeName((TypeDesc)this.Target);
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
8 changes: 7 additions & 1 deletion src/JitInterface/src/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -861,10 +861,14 @@ void getFieldInfo(IntPtr _this, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORIN
pResult.helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE;

ReadyToRunHelperId helperId;
if (field.IsThreadStatic || field.HasGCStaticBase)
if (field.IsThreadStatic)
{
throw new NotImplementedException();
}
else if (field.HasGCStaticBase)
{
helperId = ReadyToRunHelperId.GetGCStaticBase;
}
else
{
helperId = ReadyToRunHelperId.GetNonGCStaticBase;
Expand Down Expand Up @@ -1066,6 +1070,8 @@ uint getThreadTLSIndex(IntPtr _this, ref void* ppIndirection)
{
case CorInfoHelpFunc.CORINFO_HELP_RNGCHKFAIL:
return (void*)ObjectToHandle(_compilation.GetJitHelper(JitHelperId.RngChkFail));
case CorInfoHelpFunc.CORINFO_HELP_ASSIGN_REF:
return (void*)ObjectToHandle(_compilation.GetJitHelper(JitHelperId.AssignRef));
default:
throw new NotImplementedException();
}
Expand Down

0 comments on commit b01f36c

Please sign in to comment.