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

[CppCodeGen] Use ClassConstructorRunner to run cctor #6635

Merged
merged 2 commits into from
Dec 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
117 changes: 64 additions & 53 deletions src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1266,6 +1266,8 @@ reloc.Target is SealedVTableNode || reloc.Target is TypeGenericDictionaryNode ||
{
ObjectAndOffsetSymbolNode symbolNode = reloc.Target as ObjectAndOffsetSymbolNode;

bool isEagerCctorTable = symbolNode.Target is ArrayOfEmbeddedPointersNode<IMethodNode>;

if ((symbolNode.Target is GenericVirtualMethodTableNode ||
symbolNode.Target is InterfaceGenericVirtualMethodTableNode ||
symbolNode.Target is ExactMethodInstantiationsNode ||
Expand All @@ -1277,12 +1279,21 @@ symbolNode.Target is ExternalReferencesTableNode ||
symbolNode.Target is GenericTypesTemplateMap ||
symbolNode.Target is GenericMethodsTemplateMap ||
symbolNode.Target is GenericTypesHashtableNode ||
symbolNode.Target is TypeMetadataMapNode
symbolNode.Target is TypeMetadataMapNode ||
isEagerCctorTable
) && !(symbolNode.Target as ObjectNode).ShouldSkipEmittingObjectNode(factory))
{
string symbolName = isEagerCctorTable ? "eagerCctorTable" :
(symbolNode.Target as ISymbolNode).GetMangledName(factory.NameMangler);

relocCode.Append("((char *)");
relocCode.Append((symbolNode.Target as ISymbolNode).GetMangledName(factory.NameMangler));
relocCode.Append("()) + ");
relocCode.Append(symbolName);

if (!isEagerCctorTable)
relocCode.Append("()");

relocCode.Append(") + ");

relocCode.Append((symbolNode as ISymbolDefinitionNode).Offset.ToString());
}
else
Expand Down Expand Up @@ -1378,7 +1389,7 @@ private void BuildMethodLists(IEnumerable<DependencyNode> nodes)
var method = methodCodeNode.Method;
var type = method.OwningType;

if (type.HasStaticConstructor && method.Equals(type.GetStaticConstructor()))
if (_compilation.TypeSystemContext.HasLazyStaticConstructor(type) && method.Equals(type.GetStaticConstructor()))
_typesWithCctor.Add(type);

List<MethodDesc> methodList;
Expand Down Expand Up @@ -1418,6 +1429,7 @@ private void BuildMethodLists(IEnumerable<DependencyNode> nodes)
public void OutputNodes(IEnumerable<DependencyNode> nodes, NodeFactory factory)
{
CppGenerationBuffer dispatchPointers = new CppGenerationBuffer();
CppGenerationBuffer eagerCctorPointers = new CppGenerationBuffer();
CppGenerationBuffer forwardDefinitions = new CppGenerationBuffer();
CppGenerationBuffer typeDefinitions = new CppGenerationBuffer();
CppGenerationBuffer methodTables = new CppGenerationBuffer();
Expand All @@ -1430,6 +1442,10 @@ public void OutputNodes(IEnumerable<DependencyNode> nodes, NodeFactory factory)
dispatchPointers.AppendLine();
dispatchPointers.Indent();

int eagerCctorCount = 0;
eagerCctorPointers.AppendLine();
eagerCctorPointers.Indent();

//RTR header needs to be declared after all modules have already been output
ReadyToRunHeaderNode rtrHeaderNode = null;
string rtrHeader = string.Empty;
Expand Down Expand Up @@ -1520,6 +1536,21 @@ node is RuntimeMethodHandleNode ||
additionalNodes.Append(GetCodeForObjectNode(reloc.Target as ObjectNode, factory));
}
}
else if (node is ArrayOfEmbeddedPointersNode<IMethodNode> eagerCctorTable)
{
var eagerCctorTableData = eagerCctorTable.GetData(factory, false);
Debug.Assert(eagerCctorTableData.Relocs.Length == eagerCctorTableData.Data.Length / factory.Target.PointerSize);
foreach (Relocation reloc in eagerCctorTableData.Relocs)
{
var method = reloc.Target as CppMethodCodeNode;

eagerCctorPointers.Append("(void *)&");
eagerCctorPointers.Append(GetCppMethodDeclarationName(method.Method.OwningType, GetCppMethodName(method.Method), false));
eagerCctorPointers.Append(",");
eagerCctorPointers.AppendLine();
eagerCctorCount++;
}
}
else if (node is ReadyToRunHeaderNode)
rtrHeaderNode = node as ReadyToRunHeaderNode;
else if (node is ReadyToRunGenericHelperNode)
Expand Down Expand Up @@ -1556,6 +1587,13 @@ node is RuntimeMethodHandleNode ||
Out.Write(dispatchPointers.ToString());
Out.Write("};");

// Emit pointers to eager cctor table nodes
Out.Write("void * eagerCctorTable[");
Out.Write(eagerCctorCount);
Out.Write("] = {");
Out.Write(eagerCctorPointers.ToString());
Out.Write("};");

Out.Write(rtrHeader);
}

Expand Down Expand Up @@ -1699,7 +1737,7 @@ private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenera

if (nodeType.IsDefType && !nodeType.IsGenericDefinition)
{
if (nodeType.HasStaticConstructor)
if (_compilation.TypeSystemContext.HasLazyStaticConstructor(nodeType))
{
MethodDesc cctor = nodeType.GetStaticConstructor().GetCanonMethodTarget(CanonicalFormKind.Specific);

Expand All @@ -1714,19 +1752,9 @@ private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenera
_statics[nodeType] = staticsBuffer;
}

if (cctor.RequiresInstArg())
{
staticsBuffer.Append("void (*__cctor)(void *);");
staticsBuffer.AppendLine();
staticsBuffer.Append("void *__ctx;");
}
else
{
staticsBuffer.Append("void (*__cctor)();");
}

staticsBuffer.Append("void *__cctorMethodAddress;");
staticsBuffer.AppendLine();
staticsBuffer.Append("bool __cctor_has_run;");
staticsBuffer.Append("int __initialized;");
staticsBuffer.AppendLine();
}
}
Expand Down Expand Up @@ -1841,8 +1869,8 @@ private String GetCodeForReadyToRunHeader(ReadyToRunHeaderNode headerNode, NodeF
return rtrHeader.ToString();
}

private void OutputCodeForTriggerCctor(CppGenerationBuffer sb, TypeDesc type,
string staticsBaseVarName, string staticsVarName)
private void OutputCodeForTriggerCctor(CppGenerationBuffer sb, NodeFactory factory,
TypeDesc type, string staticsBaseVarName, string staticsVarName)
{
type = type.ConvertToCanonForm(CanonicalFormKind.Specific);
MethodDesc cctor = type.GetStaticConstructor();
Expand All @@ -1858,30 +1886,15 @@ private void OutputCodeForTriggerCctor(CppGenerationBuffer sb, TypeDesc type,
sb.Append(";");
sb.AppendLine();

sb.Append("if (!");
sb.Append(staticsVarName);
sb.Append("->__cctor_has_run) {");
sb.Indent();
sb.AppendLine();

sb.Append(staticsVarName);
sb.Append("->__cctor_has_run = true;");
sb.AppendLine();

sb.Append(staticsVarName);
sb.Append("->__cctor(");

if (cctor.RequiresInstArg())
{
sb.Append(staticsVarName);
sb.Append("->__ctx");
}
IMethodNode helperNode = (IMethodNode)factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase);

sb.Append(GetCppMethodDeclarationName(helperNode.Method.OwningType, GetCppMethodName(helperNode.Method), false));
sb.Append("((::System_Private_CoreLib::System::Runtime::CompilerServices::StaticClassConstructionContext*)");
sb.Append(staticsBaseVarName);
sb.Append(", (intptr_t)");
sb.Append(staticsBaseVarName);
sb.Append(");");

sb.Exdent();
sb.AppendLine();
sb.Append("}");
sb.AppendLine();
}

Expand Down Expand Up @@ -2044,11 +2057,11 @@ private string GetCodeForReadyToRunGenericHelper(ReadyToRunGenericHelperNode nod
{
MetadataType target = (MetadataType)node.Target;

if (target.HasStaticConstructor)
if (_compilation.TypeSystemContext.HasLazyStaticConstructor(target))
{
string staticsVarName = "statics";

OutputCodeForTriggerCctor(sb, target, resVarName, staticsVarName);
OutputCodeForTriggerCctor(sb, factory, target, resVarName, staticsVarName);
}
}
break;
Expand All @@ -2057,7 +2070,7 @@ private string GetCodeForReadyToRunGenericHelper(ReadyToRunGenericHelperNode nod
{
MetadataType target = (MetadataType)node.Target;

if (target.HasStaticConstructor)
if (_compilation.TypeSystemContext.HasLazyStaticConstructor(target))
{
string staticsVarName = "statics";
string nonGcStaticsBase = "nonGcBase";
Expand All @@ -2071,7 +2084,7 @@ private string GetCodeForReadyToRunGenericHelper(ReadyToRunGenericHelperNode nod

OutputCodeForDictionaryLookup(sb, factory, node, nonGcRegionLookup, ctxVarName, nonGcStaticsBase);

OutputCodeForTriggerCctor(sb, target, nonGcStaticsBase, staticsVarName);
OutputCodeForTriggerCctor(sb, factory, target, nonGcStaticsBase, staticsVarName);
}
}
break;
Expand All @@ -2080,7 +2093,7 @@ private string GetCodeForReadyToRunGenericHelper(ReadyToRunGenericHelperNode nod
{
MetadataType target = (MetadataType)node.Target;

if (target.HasStaticConstructor)
if (_compilation.TypeSystemContext.HasLazyStaticConstructor(target))
{
string staticsVarName = "statics";
string nonGcStaticsBase = "nonGcBase";
Expand All @@ -2094,7 +2107,7 @@ private string GetCodeForReadyToRunGenericHelper(ReadyToRunGenericHelperNode nod

OutputCodeForDictionaryLookup(sb, factory, node, nonGcRegionLookup, ctxVarName, nonGcStaticsBase);

OutputCodeForTriggerCctor(sb, target, nonGcStaticsBase, staticsVarName);
OutputCodeForTriggerCctor(sb, factory, target, nonGcStaticsBase, staticsVarName);
}
}
break;
Expand Down Expand Up @@ -2273,7 +2286,7 @@ private void OutputStaticsCode(Dictionary<TypeDesc, CppGenerationBuffer> statics
sb.Append(" ");
sb.Append(GetCppStaticsName(t, isGCStatic, isThreadStatic));

if (!isGCStatic && t.HasStaticConstructor)
if (!isGCStatic && _compilation.TypeSystemContext.HasLazyStaticConstructor(t))
{
MethodDesc cctor = t.GetStaticConstructor();
MethodDesc canonCctor = cctor.GetCanonMethodTarget(CanonicalFormKind.Specific);
Expand All @@ -2286,16 +2299,14 @@ private void OutputStaticsCode(Dictionary<TypeDesc, CppGenerationBuffer> statics

if (canonCctor.RequiresInstArg())
{
sb.Append("(void (*)(void *)) *(void **)");
sb.Append(GetCppFatFunctionPointerNameForMethod(cctor));
sb.Append("(),");
sb.Append("**(void***) (((intptr_t)");
sb.Append("(char *)");
sb.Append(GetCppFatFunctionPointerNameForMethod(cctor));
sb.Append("()) + sizeof(void*))");
sb.Append("() + ");
sb.Append(FatFunctionPointerConstants.Offset.ToString());
}
else
{
sb.Append("&");
sb.Append("(void*)&");
sb.Append(GetCppMethodDeclarationName(canonCctor.OwningType, GetCppMethodName(canonCctor)));
}

Expand Down
39 changes: 15 additions & 24 deletions src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3509,40 +3509,31 @@ private void TriggerCctor(TypeDesc type)
{
Debug.Assert(!type.IsRuntimeDeterminedSubtype);

// TODO: Before field init

MethodDesc cctor = type.GetStaticConstructor();
if (cctor == null)
return;

// TODO: Thread safety

MethodDesc canonCctor = cctor.GetCanonMethodTarget(CanonicalFormKind.Specific);

string ctorHasRun = _writer.GetCppStaticsName(type) + ".__cctor_has_run";
AppendLine();
Append("if (!" + ctorHasRun + ") {");
Indent();
AppendLine();
Append(ctorHasRun + " = true;");
AppendLine();
Append(_writer.GetCppTypeName(canonCctor.OwningType));
Append("::");
Append(_writer.GetCppMethodName(canonCctor));
Append("(");

if (canonCctor != cctor)
if (_nodeFactory.TypeSystemContext.HasEagerStaticConstructor(type))
{
Append(_writer.GetCppTypeName(cctor.OwningType));
Append("::__getMethodTable()");
_dependencies.Add(_nodeFactory.EagerCctorIndirection(canonCctor));
}
else if (_nodeFactory.TypeSystemContext.HasLazyStaticConstructor(type))
{
IMethodNode helperNode = (IMethodNode)_nodeFactory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase);

Append(");");
Exdent();
AppendLine();
Append("}");
Append(_writer.GetCppTypeName(helperNode.Method.OwningType));
Append("::");
Append(_writer.GetCppMethodName(helperNode.Method));
Append("((::System_Private_CoreLib::System::Runtime::CompilerServices::StaticClassConstructionContext*)&");
Append(_writer.GetCppStaticsName(type));
Append(", (intptr_t)&");
Append(_writer.GetCppStaticsName(type));
Append(");");

AddMethodReference(canonCctor);
AddMethodReference(canonCctor);
}
}

private void AddTypeReference(TypeDesc type, bool constructed)
Expand Down