diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs
index b9ccd7b07b9..d16c63afe2b 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs
@@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis
///
/// Represents a hashtable of all type blocked from reflection.
///
- internal sealed class BlockReflectionTypeMapNode : ObjectNode, ISymbolDefinitionNode
+ public sealed class BlockReflectionTypeMapNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs
index 945e49c39cf..1c6e84c2d1e 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs
@@ -19,14 +19,13 @@ namespace ILCompiler.DependencyAnalysis
/// Similarly, the dependencies that we track for canonicl type instantiations are minimal, and are just the ones used
/// by the dynamic type loader
///
- internal sealed class CanonicalEETypeNode : EETypeNode
+ public sealed class CanonicalEETypeNode : EETypeNode
{
public CanonicalEETypeNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
Debug.Assert(!type.IsCanonicalDefinitionType(CanonicalFormKind.Any));
Debug.Assert(type.IsCanonicalSubtype(CanonicalFormKind.Any));
Debug.Assert(type == type.ConvertToCanonForm(CanonicalFormKind.Specific));
- Debug.Assert(!type.IsMdArray);
}
public override bool StaticDependenciesAreComputed => true;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs
index b4bf6659e9f..57177b0d855 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs
@@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis
///
/// Hashtable of all exact (non-canonical) generic method instantiations compiled in the module.
///
- internal sealed class ExactMethodInstantiationsNode : ObjectNode, ISymbolDefinitionNode
+ public sealed class ExactMethodInstantiationsNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExternalReferencesTableNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExternalReferencesTableNode.cs
index d37a4be9529..c4c91c4dfa2 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExternalReferencesTableNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExternalReferencesTableNode.cs
@@ -97,14 +97,8 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
foreach (SymbolAndDelta symbolAndDelta in _insertedSymbols)
{
- if (factory.Target.Abi == TargetAbi.CoreRT)
+ if (factory.Target.Abi == TargetAbi.ProjectN)
{
- // TODO: set low bit if the linkage of the symbol is IAT_PVALUE.
- builder.EmitReloc(symbolAndDelta.Symbol, RelocType.IMAGE_REL_BASED_RELPTR32, symbolAndDelta.Delta);
- }
- else
- {
- Debug.Assert(factory.Target.Abi == TargetAbi.ProjectN);
int delta = symbolAndDelta.Delta;
if (symbolAndDelta.Symbol.RepresentsIndirectionCell)
{
@@ -112,6 +106,15 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
}
builder.EmitReloc(symbolAndDelta.Symbol, RelocType.IMAGE_REL_BASED_ADDR32NB, delta);
}
+ else if (factory.Target.SupportsRelativePointers)
+ {
+ // TODO: set low bit if the linkage of the symbol is IAT_PVALUE.
+ builder.EmitReloc(symbolAndDelta.Symbol, RelocType.IMAGE_REL_BASED_RELPTR32, symbolAndDelta.Delta);
+ }
+ else
+ {
+ builder.EmitPointerReloc(symbolAndDelta.Symbol, symbolAndDelta.Delta);
+ }
}
_endSymbol.SetSymbolOffset(builder.CountBytes);
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/FatFunctionPointerNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/FatFunctionPointerNode.cs
index e54f189198a..c7c68651843 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/FatFunctionPointerNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/FatFunctionPointerNode.cs
@@ -19,6 +19,8 @@ public class FatFunctionPointerNode : ObjectNode, IMethodNode, ISymbolDefinition
{
private bool _isUnboxingStub;
+ public bool IsUnboxingStub => _isUnboxingStub;
+
public FatFunctionPointerNode(MethodDesc methodRepresented, bool isUnboxingStub)
{
// We should not create these for methods that don't have a canonical method body
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs
index efbe77897a4..cf83c65c8aa 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs
@@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis
///
/// Represents a hashtable of all compiled generic method instantiations
///
- internal sealed class GenericMethodsHashtableNode : ObjectNode, ISymbolDefinitionNode
+ public sealed class GenericMethodsHashtableNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs
index c4a7432195b..b03a4564996 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs
@@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis
///
/// Hashtable of all generic method templates used by the TypeLoader at runtime
///
- internal sealed class GenericMethodsTemplateMap : ObjectNode, ISymbolDefinitionNode
+ public sealed class GenericMethodsTemplateMap : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs
index 0bf0f385004..7645ffc987f 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs
@@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis
///
/// Represents a hashtable of all compiled generic type instantiations
///
- internal sealed class GenericTypesHashtableNode : ObjectNode, ISymbolDefinitionNode
+ public sealed class GenericTypesHashtableNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs
index 77b0ee180b2..08bd8b7b1cd 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs
@@ -15,7 +15,7 @@ namespace ILCompiler.DependencyAnalysis
///
/// Represents a map of generic virtual method implementations.
///
- internal sealed class GenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode
+ public sealed class GenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs
index 38fc2bd52f2..75e12016ccf 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs
@@ -15,7 +15,7 @@ namespace ILCompiler.DependencyAnalysis
///
/// Represents a map between reflection metadata and generated method bodies.
///
- internal sealed class InterfaceGenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode
+ public sealed class InterfaceGenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs
index fda760c8ce6..ba1e97e3a8f 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs
@@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis
/// Represents a blob of native metadata describing assemblies, the types in them, and their members.
/// The data is used at runtime to e.g. support reflection.
///
- internal sealed class MetadataNode : ObjectNode, ISymbolDefinitionNode
+ public sealed class MetadataNode : ObjectNode, ISymbolDefinitionNode
{
ObjectAndOffsetSymbolNode _endSymbol;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs
index 2b61d0ff485..570260af9bc 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs
@@ -14,7 +14,7 @@ namespace ILCompiler.DependencyAnalysis
///
/// Native layout info blob.
///
- internal sealed class NativeLayoutInfoNode : ObjectNode, ISymbolDefinitionNode
+ public sealed class NativeLayoutInfoNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutSignatureNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutSignatureNode.cs
index f4a0044ea76..935daacc790 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutSignatureNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutSignatureNode.cs
@@ -21,6 +21,8 @@ public class NativeLayoutSignatureNode : ObjectNode, ISymbolDefinitionNode
private Utf8String _identityPrefix;
private NativeLayoutSavedVertexNode _nativeSignature;
+ public TypeSystemEntity Identity => _identity;
+
public NativeLayoutSignatureNode(NativeLayoutSavedVertexNode nativeSignature, TypeSystemEntity identity, Utf8String identityPrefix)
{
_nativeSignature = nativeSignature;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs
index a55b62860ad..8515b69ef5a 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs
@@ -12,14 +12,13 @@ namespace ILCompiler.DependencyAnalysis
///
/// The node is used in ProjectX to represent a canonical type that does not have a vtable.
///
- internal sealed class NecessaryCanonicalEETypeNode : EETypeNode
+ public sealed class NecessaryCanonicalEETypeNode : EETypeNode
{
public NecessaryCanonicalEETypeNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
Debug.Assert(!type.IsCanonicalDefinitionType(CanonicalFormKind.Any));
Debug.Assert(type.IsCanonicalSubtype(CanonicalFormKind.Any));
Debug.Assert(type == type.ConvertToCanonForm(CanonicalFormKind.Specific));
- Debug.Assert(!type.IsMdArray);
}
protected override ISymbolNode GetBaseTypeNode(NodeFactory factory)
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs
index f68ccbf0a5d..e3065acfe89 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs
@@ -20,6 +20,11 @@ public abstract partial class ReadyToRunGenericHelperNode : AssemblyStubNode, IN
protected TypeSystemEntity _dictionaryOwner;
protected GenericLookupResult _lookupSignature;
+ public ReadyToRunHelperId Id => _id;
+ public Object Target => _target;
+ public TypeSystemEntity DictionaryOwner => _dictionaryOwner;
+ public GenericLookupResult LookupSignature => _lookupSignature;
+
public ReadyToRunGenericHelperNode(NodeFactory factory, ReadyToRunHelperId helperId, object target, TypeSystemEntity dictionaryOwner)
{
_id = helperId;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs
index 469d86dd5bc..13c89dba7ef 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs
@@ -13,7 +13,7 @@ namespace ILCompiler.DependencyAnalysis
///
/// Represents a map between EETypes and metadata records within the .
///
- internal sealed class TypeMetadataMapNode : ObjectNode, ISymbolDefinitionNode
+ public sealed class TypeMetadataMapNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeThreadStaticIndexNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeThreadStaticIndexNode.cs
index 2c20841bb25..44ba5283526 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeThreadStaticIndexNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeThreadStaticIndexNode.cs
@@ -10,7 +10,7 @@ namespace ILCompiler.DependencyAnalysis
///
/// Represents a node containing information necessary at runtime to locate type's thread static base.
///
- internal class TypeThreadStaticIndexNode : ObjectNode, ISymbolDefinitionNode
+ public class TypeThreadStaticIndexNode : ObjectNode, ISymbolDefinitionNode
{
private MetadataType _type;
@@ -67,6 +67,8 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
return objData.ToObjectData();
}
+ public MetadataType Type => _type;
+
public override int ClassCode => -149601250;
public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilation.cs b/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilation.cs
index 61e8c8d594d..291612b8188 100644
--- a/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilation.cs
+++ b/src/ILCompiler.CppCodeGen/src/Compiler/CppCodegenCompilation.cs
@@ -53,9 +53,22 @@ protected override void CompileInternal(string outputFile, ObjectDumper dumper)
protected override void ComputeDependencyNodeDependencies(List> obj)
{
- foreach (CppMethodCodeNode methodCodeNodeNeedingCode in obj)
+ foreach (var dependency in obj)
{
- _cppWriter.CompileMethod(methodCodeNodeNeedingCode);
+ var methodCodeNodeNeedingCode = dependency as CppMethodCodeNode;
+ if (methodCodeNodeNeedingCode == null)
+ {
+ // To compute dependencies of the shadow method that tracks dictionary
+ // dependencies we need to ensure there is code for the canonical method body.
+ var dependencyMethod = (ShadowConcreteMethodNode)dependency;
+ methodCodeNodeNeedingCode = (CppMethodCodeNode)dependencyMethod.CanonicalMethodNode;
+ }
+
+ // We might have already compiled this method.
+ if (methodCodeNodeNeedingCode.StaticDependenciesAreComputed)
+ continue;
+
+ _cppWriter.CompileMethod((CppMethodCodeNode)methodCodeNodeNeedingCode);
}
}
diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/CppNodeMangler.cs b/src/ILCompiler.CppCodeGen/src/Compiler/CppNodeMangler.cs
index b4a01d6b2a1..ad2813eb4bc 100644
--- a/src/ILCompiler.CppCodeGen/src/Compiler/CppNodeMangler.cs
+++ b/src/ILCompiler.CppCodeGen/src/Compiler/CppNodeMangler.cs
@@ -47,7 +47,8 @@ public sealed override string TypeGenericDictionary(TypeDesc type)
public sealed override string MethodGenericDictionary(MethodDesc method)
{
- return GenericDictionaryNamePrefix + NameMangler.GetMangledMethodName(method);
+ return GenericDictionaryNamePrefix + NameMangler.GetMangledTypeName(method.OwningType) +
+ "_" + NameMangler.GetMangledMethodName(method);
}
}
}
diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs
index d282e1f270f..0a558175ded 100644
--- a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs
+++ b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs
@@ -28,6 +28,14 @@ public CppCodegenNodeFactory(CompilerTypeSystemContext context, CompilationModul
protected override IMethodNode CreateMethodEntrypointNode(MethodDesc method)
{
+ if (method.IsInternalCall)
+ {
+ if (method.IsArrayAddressMethod())
+ {
+ return MethodEntrypoint(((ArrayType)method.OwningType).GetArrayMethod(ArrayMethodKind.AddressWithHiddenArg));
+ }
+ }
+
if (CompilationModuleGroup.ContainsMethodBody(method, false))
{
return new CppMethodCodeNode(method);
diff --git a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppMethodCodeNode.cs b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppMethodCodeNode.cs
index 49f610ef456..b6c9737915b 100644
--- a/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppMethodCodeNode.cs
+++ b/src/ILCompiler.CppCodeGen/src/Compiler/DependencyAnalysis/CppMethodCodeNode.cs
@@ -70,6 +70,8 @@ public override IEnumerable GetStaticDependencies(NodeFacto
foreach (Object node in _dependencies)
dependencies.Add(node, "CPP code ");
+ CodeBasedDependencyAlgorithm.AddDependenciesDueToMethodCodePresence(ref dependencies, factory, _method);
+
return dependencies;
}
diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs
index c37a53382e7..7899c267423 100644
--- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs
+++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Text;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -78,6 +79,8 @@ private string GetMangledTypeName(TypeDesc type)
public string GetCppSignatureTypeName(TypeDesc type)
{
+ type = ConvertToCanonFormIfNecessary(type, CanonicalFormKind.Specific);
+
string mangledName;
if (_cppSignatureNames.TryGetValue(type, out mangledName))
return mangledName;
@@ -125,7 +128,13 @@ private IEnumerable GetParameterNamesForMethod(MethodDesc method)
return null;
}
- public void AppendCppMethodDeclaration(CppGenerationBuffer sb, MethodDesc method, bool implementation, string externalMethodName = null, MethodSignature methodSignature = null, string cppMethodName = null)
+ public string GetCppHiddenParam()
+ {
+ return "___hidden";
+ }
+
+ public void AppendCppMethodDeclaration(CppGenerationBuffer sb, MethodDesc method, bool implementation, string externalMethodName = null,
+ MethodSignature methodSignature = null, string cppMethodName = null, bool isUnboxingStub = false)
{
if (methodSignature == null)
methodSignature = method.Signature;
@@ -159,14 +168,31 @@ public void AppendCppMethodDeclaration(CppGenerationBuffer sb, MethodDesc method
}
}
sb.Append("(");
+
bool hasThis = !methodSignature.IsStatic;
+ bool hasHiddenParam = false;
int argCount = methodSignature.Length;
+
+ int hiddenArgIdx = -1;
+ int thisArgIdx = -1;
+ int signatureArgOffset = 0;
+ int paramListOffset = 0;
+
if (hasThis)
+ {
argCount++;
+ thisArgIdx++;
+ signatureArgOffset++;
+ }
List parameterNames = null;
if (method != null)
{
+ if (isUnboxingStub)
+ hasHiddenParam = method.IsSharedByGenericInstantiations &&
+ (method.HasInstantiation || method.Signature.IsStatic);
+ else
+ hasHiddenParam = method.RequiresInstArg();
IEnumerable parameters = GetParameterNamesForMethod(method);
if (parameters != null)
{
@@ -182,43 +208,66 @@ public void AppendCppMethodDeclaration(CppGenerationBuffer sb, MethodDesc method
}
}
- for (int i = 0; i < argCount; i++)
+ if (hasHiddenParam)
{
+ argCount++;
+ hiddenArgIdx++;
if (hasThis)
+ hiddenArgIdx++;
+ signatureArgOffset++;
+ paramListOffset++;
+ }
+
+ for (int i = 0; i < argCount; i++)
+ {
+ if (i == thisArgIdx)
{
- if (i == 0)
- {
- var thisType = method.OwningType;
- if (thisType.IsValueType)
- thisType = thisType.MakeByRefType();
- sb.Append(GetCppSignatureTypeName(thisType));
- }
- else
- {
- sb.Append(GetCppSignatureTypeName(methodSignature[i - 1]));
- }
+ var thisType = method.OwningType;
+ if (thisType.IsValueType)
+ thisType = thisType.MakeByRefType();
+ sb.Append(GetCppSignatureTypeName(thisType));
+ }
+ else if (i == hiddenArgIdx)
+ {
+ sb.Append("void*");
}
else
{
- sb.Append(GetCppSignatureTypeName(methodSignature[i]));
+ sb.Append(GetCppSignatureTypeName(methodSignature[i - signatureArgOffset]));
}
+
if (implementation)
{
sb.Append(" ");
- if (parameterNames != null)
+ if (i == hiddenArgIdx)
{
- sb.Append(SanitizeCppVarName(parameterNames[i]));
+ sb.Append(" ");
+ sb.Append(GetCppHiddenParam());
}
else
{
- sb.Append("_a");
- sb.Append(i.ToStringInvariant());
+ int idx;
+ if (i == thisArgIdx)
+ idx = i;
+ else
+ idx = i - paramListOffset;
+
+ if (parameterNames != null)
+ {
+ sb.Append(SanitizeCppVarName(parameterNames[idx]));
+ }
+ else
+ {
+ sb.Append("_a");
+ sb.Append(idx.ToStringInvariant());
+ }
}
}
if (i != argCount - 1)
sb.Append(", ");
}
+
sb.Append(")");
if (!implementation)
sb.Append(";");
@@ -229,9 +278,18 @@ public void AppendCppMethodCallParamList(CppGenerationBuffer sb, MethodDesc meth
var methodSignature = method.Signature;
bool hasThis = !methodSignature.IsStatic;
+ bool hasHiddenParam = method.RequiresInstArg();
int argCount = methodSignature.Length;
+
+ int hiddenArgIdx = -1;
+ int thisArgIdx = -1;
+ int paramListOffset = 0;
+
if (hasThis)
+ {
argCount++;
+ thisArgIdx++;
+ }
List parameterNames = null;
IEnumerable parameters = GetParameterNamesForMethod(method);
@@ -248,9 +306,18 @@ public void AppendCppMethodCallParamList(CppGenerationBuffer sb, MethodDesc meth
}
}
+ if (hasHiddenParam)
+ {
+ argCount++;
+ hiddenArgIdx++;
+ if (hasThis)
+ hiddenArgIdx++;
+ paramListOffset++;
+ }
+
for (int i = 0; i < argCount; i++)
{
- if(i == 0 && unbox)
+ if (i == thisArgIdx && unbox)
{
// Unboxing stubs only valid for non-static methods on value types
System.Diagnostics.Debug.Assert(hasThis);
@@ -261,20 +328,52 @@ public void AppendCppMethodCallParamList(CppGenerationBuffer sb, MethodDesc meth
sb.Append("(");
sb.Append(GetCppSignatureTypeName(thisType));
sb.Append(")((uint8_t*)(");
+
+ if (parameterNames != null)
+ {
+ sb.Append(SanitizeCppVarName(parameterNames[i]));
+ }
+ else
+ {
+ sb.Append("_a");
+ sb.Append(i.ToStringInvariant());
+ }
+
+ sb.Append(")+sizeof(void*))");
}
- if (parameterNames != null)
+ else if (i == hiddenArgIdx)
{
- sb.Append(SanitizeCppVarName(parameterNames[i]));
+ bool unboxStubHasHiddenArg = method.IsSharedByGenericInstantiations &&
+ (method.HasInstantiation || method.Signature.IsStatic);
+
+ if (unbox && !unboxStubHasHiddenArg)
+ {
+ sb.Append("*(void**)");
+ if (parameterNames != null)
+ sb.Append(SanitizeCppVarName(parameterNames[thisArgIdx]));
+ else
+ sb.Append("_a" + thisArgIdx);
+ }
+ else
+ {
+ sb.Append(GetCppHiddenParam());
+ }
}
else
{
- sb.Append("_a");
- sb.Append(i.ToStringInvariant());
- }
- if (i == 0 && hasThis && unbox)
- {
- sb.Append(")+sizeof(void*))");
+ int idx = i - paramListOffset;
+
+ if (parameterNames != null)
+ {
+ sb.Append(SanitizeCppVarName(parameterNames[idx]));
+ }
+ else
+ {
+ sb.Append("_a");
+ sb.Append(idx.ToStringInvariant());
+ }
}
+
if (i != argCount - 1)
sb.Append(", ");
}
@@ -316,6 +415,103 @@ public string GetCppMethodName(MethodDesc method)
return _compilation.NameMangler.GetMangledMethodName(method).ToString();
}
+ public string GetCppReadyToRunGenericHelperNodeName(NodeFactory factory, ReadyToRunGenericHelperNode node)
+ {
+ if (node.DictionaryOwner is MethodDesc)
+ {
+ Utf8StringBuilder sb = new Utf8StringBuilder();
+ MethodDesc method = (MethodDesc)node.DictionaryOwner;
+
+ if (node is ReadyToRunGenericLookupFromDictionaryNode)
+ sb.Append("__GenericLookupFromDict_");
+ else
+ sb.Append("__GenericLookupFromType_");
+
+ sb.Append(factory.NameMangler.GetMangledTypeName(method.OwningType));
+ sb.Append("_");
+ sb.Append(factory.NameMangler.GetMangledMethodName(method));
+ sb.Append("_");
+
+ if (node.Id != ReadyToRunHelperId.DelegateCtor)
+ node.LookupSignature.AppendMangledName(factory.NameMangler, sb);
+ else
+ ((DelegateCreationInfo)node.Target).AppendMangledName(factory.NameMangler, sb);
+
+ return sb.ToString().Replace("::", "_");
+ }
+
+ return node.GetMangledName(factory.NameMangler).Replace("::", "_");
+ }
+
+ public string GetCppRuntimeMethodHandleName(RuntimeMethodHandleNode node)
+ {
+ MethodDesc method = node.Method;
+ StringBuilder sb = new StringBuilder();
+
+ sb.Append("__RuntimeMethodHandle_");
+ sb.Append(GetMangledTypeName(method.OwningType));
+ sb.Append("_");
+ sb.Append(GetCppMethodName(method));
+
+ return sb.ToString().Replace("::", "_");
+ }
+
+ private string GetCppNativeLayoutSignatureName(NodeFactory factory, NativeLayoutSignatureNode node)
+ {
+ if (node.Identity is MethodDesc)
+ {
+ MethodDesc method = node.Identity as MethodDesc;
+ StringBuilder sb = new StringBuilder();
+
+ sb.Append("__RMHSignature_");
+ sb.Append(GetMangledTypeName(method.OwningType));
+ sb.Append("_");
+ sb.Append(GetCppMethodName(method));
+
+ return sb.ToString().Replace("::", "_");
+ }
+
+ return node.GetMangledName(factory.NameMangler).Replace("::", "_");;
+ }
+
+ private string GetCppFatFunctionPointerNameForMethod(MethodDesc method,
+ bool isUnboxingStub = false)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.Append(isUnboxingStub ? "__fatunboxpointer_" : "__fatpointer_");
+ sb.Append(GetMangledTypeName(method.OwningType));
+ sb.Append("_");
+ sb.Append(GetCppMethodName(method));
+
+ return sb.ToString().Replace("::", "_");
+ }
+
+ private string GetCppFatFunctionPointerName(FatFunctionPointerNode node)
+ {
+ return GetCppFatFunctionPointerNameForMethod(node.Method, node.IsUnboxingStub);
+ }
+
+ public string GetCppSymbolNodeName(NodeFactory factory, ISymbolNode node)
+ {
+ if (node is RuntimeMethodHandleNode)
+ {
+ return GetCppRuntimeMethodHandleName(node as RuntimeMethodHandleNode);
+ }
+ else if (node is NativeLayoutSignatureNode)
+ {
+ return GetCppNativeLayoutSignatureName(factory, node as NativeLayoutSignatureNode);
+ }
+ else if (node is FatFunctionPointerNode)
+ {
+ return GetCppFatFunctionPointerName(node as FatFunctionPointerNode);
+ }
+ else
+ {
+ return node.GetMangledName(factory.NameMangler);
+ }
+ }
+
public string GetCppFieldName(FieldDesc field)
{
string name = _compilation.NameMangler.GetMangledFieldName(field).ToString();
@@ -327,11 +523,44 @@ public string GetCppFieldName(FieldDesc field)
return name;
}
- public string GetCppStaticFieldName(FieldDesc field)
+ public string GetCppStaticsName(TypeDesc type, bool isGCStatic = false, bool isThreadStatic = false)
{
- TypeDesc type = field.OwningType;
+ string name;
+ if (isThreadStatic)
+ {
+ name = "threadStatics";
+ }
+ else if (isGCStatic)
+ {
+ name = "gcStatics";
+ }
+ else
+ {
+ name = "statics";
+ }
+
string typeName = GetCppTypeName(type);
- return typeName.Replace("::", "__") + "__" + _compilation.NameMangler.GetMangledFieldName(field);
+ return typeName.Replace("::", "_") + "_" + name;
+ }
+
+ public string GetCppStaticsTypeName(TypeDesc type, bool isGCStatic = false, bool isThreadStatic = false)
+ {
+ string name;
+ if (isThreadStatic)
+ {
+ name = "ThreadStatics";
+ }
+ else if (isGCStatic)
+ {
+ name = "GCStatics";
+ }
+ else
+ {
+ name = "Statics";
+ }
+
+ string typeName = GetCppTypeName(type);
+ return typeName.Replace("::", "_") + "_" + name;
}
public string SanitizeCppVarName(string varName)
@@ -479,11 +708,14 @@ private TextWriter Out
private StreamWriter _out;
private Dictionary> _methodLists;
+ private HashSet _typesWithCctor;
+
+ private Dictionary _statics;
+ private Dictionary _gcStatics;
+ private Dictionary _threadStatics;
- private CppGenerationBuffer _statics;
- private CppGenerationBuffer _gcStatics;
- private CppGenerationBuffer _threadStatics;
- private CppGenerationBuffer _gcThreadStatics;
+ private Dictionary, int> _methodNameAndSignatures =
+ new Dictionary, int>();
// Base classes and valuetypes has to be emitted before they are used.
private HashSet _emittedTypes;
@@ -530,7 +762,6 @@ private void OutputTypeFields(CppGenerationBuffer sb, TypeDesc t)
sb.Append("struct {");
sb.Indent();
}
-
}
foreach (var field in t.GetFields())
@@ -542,19 +773,39 @@ private void OutputTypeFields(CppGenerationBuffer sb, TypeDesc t)
TypeDesc fieldType = GetFieldTypeOrPlaceholder(field);
CppGenerationBuffer builder;
- if (!fieldType.IsValueType)
+
+ if (field.IsThreadStatic)
{
- builder = _gcStatics;
+ if (!_threadStatics.TryGetValue(t, out builder))
+ {
+ builder = new CppGenerationBuffer();
+ builder.Indent();
+ _threadStatics[t] = builder;
+ }
+ }
+ else if (field.HasGCStaticBase)
+ {
+ if (!_gcStatics.TryGetValue(t, out builder))
+ {
+ builder = new CppGenerationBuffer();
+ builder.Indent();
+ _gcStatics[t] = builder;
+ }
}
else
{
- // TODO: Valuetype statics with GC references
- builder = _statics;
+ if (!_statics.TryGetValue(t, out builder))
+ {
+ // TODO: Valuetype statics with GC references
+ builder = new CppGenerationBuffer();
+ builder.Indent();
+ _statics[t] = builder;
+ }
}
builder.AppendLine();
builder.Append(GetCppSignatureTypeName(fieldType));
builder.Append(" ");
- builder.Append(GetCppStaticFieldName(field) + ";");
+ builder.Append(GetCppFieldName(field) + ";");
}
else
{
@@ -614,7 +865,7 @@ private void AppendSlotTypeDef(CppGenerationBuffer sb, MethodDesc method)
AppendSignatureTypeDef(sb, "__slot__" + GetCppMethodName(method), methodSignature, thisArgument);
}
- internal void AppendSignatureTypeDef(CppGenerationBuffer sb, string name, MethodSignature methodSignature, TypeDesc thisArgument)
+ internal void AppendSignatureTypeDef(CppGenerationBuffer sb, string name, MethodSignature methodSignature, TypeDesc thisArgument, bool needsHiddenArg = false)
{
sb.AppendLine();
sb.Append("typedef ");
@@ -624,25 +875,42 @@ internal void AppendSignatureTypeDef(CppGenerationBuffer sb, string name, Method
sb.Append(")(");
int argCount = methodSignature.Length;
+
+ int hiddenArgIdx = -1;
+ int thisArgIdx = -1;
+ int signatureArgOffset = 0;
+
if (thisArgument != null)
+ {
argCount++;
- for (int i = 0; i < argCount; i++)
+ signatureArgOffset++;
+ thisArgIdx++;
+ }
+
+ if (needsHiddenArg)
{
+ argCount++;
+ hiddenArgIdx++;
if (thisArgument != null)
+ hiddenArgIdx++;
+ signatureArgOffset++;
+ }
+
+ for (int i = 0; i < argCount; i++)
+ {
+ if (i == thisArgIdx)
{
- if (i == 0)
- {
- sb.Append(GetCppSignatureTypeName(thisArgument));
- }
- else
- {
- sb.Append(GetCppSignatureTypeName(methodSignature[i - 1]));
- }
+ sb.Append(GetCppSignatureTypeName(thisArgument));
+ }
+ else if (i == hiddenArgIdx)
+ {
+ sb.Append("void*");
}
else
{
- sb.Append(GetCppSignatureTypeName(methodSignature[i]));
+ sb.Append(GetCppSignatureTypeName(methodSignature[i - signatureArgOffset]));
}
+
if (i != argCount - 1)
sb.Append(", ");
}
@@ -731,7 +999,7 @@ private String GetCodeForVirtualMethod(MethodDesc method, int slot)
return sb.ToString();
}
- private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory)
+ private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory, bool generateMethod = true, string structType = null)
{
// virtual slots
var nodeData = node.GetData(factory, false);
@@ -796,22 +1064,32 @@ private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory)
}
}
- bool generateMethod = !(node is BlobNode);
+ generateMethod = generateMethod && !(node is BlobNode);
+
+ string retType;
+
+ if (node is EETypeNode)
+ retType = "MethodTable * ";
+ else if (node is RuntimeMethodHandleNode)
+ retType = "::System_Private_CoreLib::System::RuntimeMethodHandle ";
+ else
+ retType = "void * ";
+
+ string mangledName = GetCppSymbolNodeName(factory, (ISymbolNode)node);
- string pointerType = node is EETypeNode ? "MethodTable * " : "void* ";
if (generateMethod)
{
- nodeCode.Append(pointerType);
+ nodeCode.Append(retType);
if (node is EETypeNode)
{
nodeCode.Append(GetCppMethodDeclarationName((node as EETypeNode).Type, "__getMethodTable"));
}
else
{
- string mangledName = ((ISymbolNode)node).GetMangledName(factory.NameMangler);
+ // Rename nodes to avoid name clash with types
+ bool shouldReplaceNamespaceQualifier = node is GenericCompositionNode || node is EETypeOptionalFieldsNode ||
+ node is SealedVTableNode || node is TypeGenericDictionaryNode || node is IndirectionNode || node is MethodGenericDictionaryNode;
- // Rename generic composition and optional fields nodes to avoid name clash with types
- bool shouldReplaceNamespaceQualifier = node is GenericCompositionNode || node is EETypeOptionalFieldsNode || node is SealedVTableNode;
nodeCode.Append(shouldReplaceNamespaceQualifier ? mangledName.Replace("::", "_") : mangledName);
}
nodeCode.Append("()");
@@ -823,9 +1101,18 @@ private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory)
}
else
{
- nodeCode.Append("extern \"C\" ");
+ if (node is BlobNode)
+ nodeCode.Append("extern \"C\" ");
}
- nodeCode.Append("struct {");
+ nodeCode.Append("struct ");
+
+ if (structType != null)
+ {
+ nodeCode.Append(structType);
+ nodeCode.Append(" ");
+ }
+
+ nodeCode.Append("{");
nodeCode.AppendLine();
nodeCode.Append(GetCodeForNodeStruct(nodeDataSections, node));
@@ -835,7 +1122,8 @@ private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory)
if (generateMethod)
nodeCode.Append("} mt = {");
else
- nodeCode.Append(" } " + ((ISymbolNode)node).GetMangledName(factory.NameMangler) + " = {");
+ nodeCode.Append(" } " + mangledName.Replace("::", "_") + " = {");
+
nodeCode.Append(GetCodeForNodeData(nodeDataSections, relocs, nodeData.Data, node, offset, factory));
nodeCode.Append("};");
@@ -843,9 +1131,21 @@ private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory)
if (generateMethod)
{
nodeCode.AppendLine();
- nodeCode.Append("return ( ");
- nodeCode.Append(pointerType);
- nodeCode.Append(")&mt;");
+
+ if (node is RuntimeMethodHandleNode)
+ {
+ nodeCode.Append(retType);
+ nodeCode.Append(" r = {(intptr_t)&mt};");
+ nodeCode.AppendLine();
+ nodeCode.Append("return r;");
+ }
+ else
+ {
+ nodeCode.Append("return ( ");
+ nodeCode.Append(retType);
+ nodeCode.Append(")&mt;");
+ }
+
nodeCode.Exdent();
nodeCode.AppendLine();
nodeCode.Append("}");
@@ -893,9 +1193,17 @@ private String GetCodeForReloc(Relocation reloc, DependencyNode node, NodeFactor
relocCode.Append("(void*)&");
relocCode.Append(GetCppMethodDeclarationName(method.Method.OwningType, GetCppMethodName(method.Method), false));
}
- else if (reloc.Target is EETypeNode && node is EETypeNode)
+ else if (reloc.Target is EETypeNode &&
+ (node is EETypeNode ||
+ node is IndirectionNode ||
+ node is GenericCompositionNode ||
+ node is TypeGenericDictionaryNode ||
+ node is MethodGenericDictionaryNode ||
+ node is ExternalReferencesTableNode))
{
- relocCode.Append(GetCppMethodDeclarationName((reloc.Target as EETypeNode).Type, "__getMethodTable", false));
+ var type = (reloc.Target as EETypeNode).Type;
+
+ relocCode.Append(GetCppMethodDeclarationName(type, "__getMethodTable", false));
relocCode.Append("()");
}
// Node is either an non-emitted type or a generic composition - both are ignored for CPP codegen
@@ -903,26 +1211,112 @@ private String GetCodeForReloc(Relocation reloc, DependencyNode node, NodeFactor
reloc.Target is InterfaceDispatchMapNode ||
reloc.Target is EETypeOptionalFieldsNode ||
reloc.Target is GenericCompositionNode ||
- reloc.Target is SealedVTableNode
+ reloc.Target is SealedVTableNode ||
+ reloc.Target is TypeGenericDictionaryNode ||
+ reloc.Target is MethodGenericDictionaryNode ||
+ reloc.Target is IndirectionNode ||
+ reloc.Target is GenericVirtualMethodTableNode ||
+ reloc.Target is InterfaceGenericVirtualMethodTableNode ||
+ reloc.Target is RuntimeMethodHandleNode ||
+ reloc.Target is NativeLayoutSignatureNode ||
+ reloc.Target is ExactMethodInstantiationsNode ||
+ reloc.Target is GenericMethodsHashtableNode ||
+ reloc.Target is NativeLayoutInfoNode ||
+ reloc.Target is MetadataNode ||
+ reloc.Target is BlockReflectionTypeMapNode ||
+ reloc.Target is ExternalReferencesTableNode ||
+ reloc.Target is GenericTypesTemplateMap ||
+ reloc.Target is GenericMethodsTemplateMap ||
+ reloc.Target is GenericTypesHashtableNode ||
+ reloc.Target is TypeMetadataMapNode ||
+ reloc.Target is FatFunctionPointerNode
) && !(reloc.Target as ObjectNode).ShouldSkipEmittingObjectNode(factory))
{
- string mangledTargetName = reloc.Target.GetMangledName(factory.NameMangler);
- bool shouldReplaceNamespaceQualifier = reloc.Target is GenericCompositionNode || reloc.Target is EETypeOptionalFieldsNode || reloc.Target is SealedVTableNode;
+ string mangledTargetName = GetCppSymbolNodeName(factory, reloc.Target);
+
+ bool shouldReplaceNamespaceQualifier = reloc.Target is GenericCompositionNode || reloc.Target is EETypeOptionalFieldsNode ||
+ reloc.Target is SealedVTableNode || reloc.Target is TypeGenericDictionaryNode || reloc.Target is IndirectionNode ||
+ reloc.Target is MethodGenericDictionaryNode;
+
+ bool shouldUsePointer = reloc.Target is GenericCompositionNode || reloc.Target is TypeGenericDictionaryNode ||
+ reloc.Target is MethodGenericDictionaryNode;
+
+ bool isRuntimeMethodHandle = reloc.Target is RuntimeMethodHandleNode;
+
+ if (shouldUsePointer)
+ relocCode.Append("(void *)&");
+ else if (isRuntimeMethodHandle)
+ relocCode.Append("(void *)(");
+
relocCode.Append(shouldReplaceNamespaceQualifier ? mangledTargetName.Replace("::", "_") : mangledTargetName);
- relocCode.Append("()");
+
+ if (!shouldUsePointer)
+ relocCode.Append("()");
+
+ if (isRuntimeMethodHandle)
+ relocCode.Append("._value)");
}
else if (reloc.Target is ObjectAndOffsetSymbolNode &&
(reloc.Target as ObjectAndOffsetSymbolNode).Target is ArrayOfEmbeddedPointersNode)
{
relocCode.Append("dispatchMapModule");
}
- else if(reloc.Target is CppUnboxingStubNode)
+ else if (reloc.Target is ObjectAndOffsetSymbolNode)
+ {
+ ObjectAndOffsetSymbolNode symbolNode = reloc.Target as ObjectAndOffsetSymbolNode;
+
+ if ((symbolNode.Target is GenericVirtualMethodTableNode ||
+ symbolNode.Target is InterfaceGenericVirtualMethodTableNode ||
+ symbolNode.Target is ExactMethodInstantiationsNode ||
+ symbolNode.Target is GenericMethodsHashtableNode ||
+ symbolNode.Target is NativeLayoutInfoNode ||
+ symbolNode.Target is MetadataNode ||
+ symbolNode.Target is BlockReflectionTypeMapNode ||
+ symbolNode.Target is ExternalReferencesTableNode ||
+ symbolNode.Target is GenericTypesTemplateMap ||
+ symbolNode.Target is GenericMethodsTemplateMap ||
+ symbolNode.Target is GenericTypesHashtableNode ||
+ symbolNode.Target is TypeMetadataMapNode
+ ) && !(symbolNode.Target as ObjectNode).ShouldSkipEmittingObjectNode(factory))
+ {
+ relocCode.Append("((char *)");
+ relocCode.Append((symbolNode.Target as ISymbolNode).GetMangledName(factory.NameMangler));
+ relocCode.Append("()) + ");
+ relocCode.Append((symbolNode as ISymbolDefinitionNode).Offset.ToString());
+ }
+ else
+ {
+ relocCode.Append("NULL");
+ }
+ }
+ else if (reloc.Target is CppUnboxingStubNode)
{
var method = reloc.Target as CppUnboxingStubNode;
relocCode.Append("(void*)&");
relocCode.Append(GetCppMethodDeclarationName(method.Method.OwningType, method.GetMangledName(factory.NameMangler), false));
}
+ else if (reloc.Target is GCStaticsNode)
+ {
+ var gcStaticNode = reloc.Target as GCStaticsNode;
+
+ relocCode.Append("(void*)&");
+ relocCode.Append(GetCppStaticsName(gcStaticNode.Type, true));
+ }
+ else if (reloc.Target is NonGCStaticsNode)
+ {
+ var nonGcStaticNode = reloc.Target as NonGCStaticsNode;
+
+ relocCode.Append("(void*)&");
+ relocCode.Append(GetCppStaticsName(nonGcStaticNode.Type));
+ }
+ else if (reloc.Target is TypeThreadStaticIndexNode)
+ {
+ var threadStaticIndexNode = reloc.Target as TypeThreadStaticIndexNode;
+
+ relocCode.Append("(void*)&");
+ relocCode.Append(GetCppStaticsName(threadStaticIndexNode.Type, true, true));
+ }
else
{
relocCode.Append("NULL");
@@ -973,6 +1367,7 @@ private static void AppendFormattedByteArray(CppGenerationBuffer sb, byte[] arra
private void BuildMethodLists(IEnumerable nodes)
{
_methodLists = new Dictionary>();
+ _typesWithCctor = new HashSet();
foreach (var node in nodes)
{
if (node is CppMethodCodeNode)
@@ -982,6 +1377,9 @@ private void BuildMethodLists(IEnumerable nodes)
var method = methodCodeNode.Method;
var type = method.OwningType;
+ if (type.HasStaticConstructor && method.Equals(type.GetStaticConstructor()))
+ _typesWithCctor.Add(type);
+
List methodList;
if (!_methodLists.TryGetValue(type, out methodList))
{
@@ -1023,6 +1421,7 @@ public void OutputNodes(IEnumerable nodes, NodeFactory factory)
CppGenerationBuffer typeDefinitions = new CppGenerationBuffer();
CppGenerationBuffer methodTables = new CppGenerationBuffer();
CppGenerationBuffer additionalNodes = new CppGenerationBuffer();
+ CppGenerationBuffer indirectionNodes = new CppGenerationBuffer();
DependencyNodeIterator nodeIterator = new DependencyNodeIterator(nodes, factory);
// Number of InterfaceDispatchMapNodes needs to be declared explicitly for Ubuntu and OSX
@@ -1031,6 +1430,7 @@ public void OutputNodes(IEnumerable nodes, NodeFactory factory)
dispatchPointers.Indent();
//RTR header needs to be declared after all modules have already been output
+ ReadyToRunHeaderNode rtrHeaderNode = null;
string rtrHeader = string.Empty;
// Iterate through nodes
@@ -1042,8 +1442,69 @@ public void OutputNodes(IEnumerable nodes, NodeFactory factory)
node is TypeManagerIndirectionNode ||
node is GenericCompositionNode ||
node is BlobNode ||
- node is SealedVTableNode) && !(node as ObjectNode).ShouldSkipEmittingObjectNode(factory))
- additionalNodes.Append(GetCodeForObjectNode(node as ObjectNode, factory));
+ node is SealedVTableNode ||
+ node is TypeGenericDictionaryNode ||
+ node is MethodGenericDictionaryNode ||
+ node is IndirectionNode ||
+ node is GenericVirtualMethodTableNode ||
+ node is InterfaceGenericVirtualMethodTableNode ||
+ node is RuntimeMethodHandleNode ||
+ node is NativeLayoutSignatureNode ||
+ node is ExactMethodInstantiationsNode ||
+ node is GenericMethodsHashtableNode ||
+ node is NativeLayoutInfoNode ||
+ node is MetadataNode ||
+ node is BlockReflectionTypeMapNode ||
+ node is ExternalReferencesTableNode ||
+ node is GenericTypesTemplateMap ||
+ node is GenericMethodsTemplateMap ||
+ node is GenericTypesHashtableNode ||
+ node is TypeMetadataMapNode ||
+ node is FatFunctionPointerNode
+ ) && !(node as ObjectNode).ShouldSkipEmittingObjectNode(factory))
+ {
+ if (node is IndirectionNode)
+ {
+ indirectionNodes.Append(GetCodeForObjectNode(node as ObjectNode, factory));
+ }
+ else
+ {
+ bool shouldUsePointer = node is GenericCompositionNode || node is TypeGenericDictionaryNode ||
+ node is MethodGenericDictionaryNode;
+
+ if (shouldUsePointer)
+ {
+ string varName = GetCppSymbolNodeName(factory, (ISymbolNode)node).Replace("::", "_");
+ string structType = "T_" + varName;
+
+ additionalNodes.Append(GetCodeForObjectNode(node as ObjectNode, factory, false, structType));
+
+ forwardDefinitions.AppendLine();
+ forwardDefinitions.Append("extern struct ");
+ forwardDefinitions.Append(structType);
+ forwardDefinitions.Append(" ");
+ forwardDefinitions.Append(varName);
+ forwardDefinitions.Append(";");
+ }
+ else
+ {
+ additionalNodes.Append(GetCodeForObjectNode(node as ObjectNode, factory));
+ }
+ }
+
+ if (node is NativeLayoutSignatureNode ||
+ node is RuntimeMethodHandleNode ||
+ node is FatFunctionPointerNode)
+ {
+ forwardDefinitions.AppendLine();
+ if (node is RuntimeMethodHandleNode)
+ forwardDefinitions.Append("::System_Private_CoreLib::System::RuntimeMethodHandle ");
+ else
+ forwardDefinitions.Append("void * ");
+ forwardDefinitions.Append(GetCppSymbolNodeName(factory, (ISymbolNode)node));
+ forwardDefinitions.Append("();");
+ }
+ }
else if (node is ArrayOfEmbeddedPointersNode dispatchMap)
{
var dispatchMapData = dispatchMap.GetData(factory, false);
@@ -1059,16 +1520,30 @@ node is BlobNode ||
}
}
else if (node is ReadyToRunHeaderNode)
- rtrHeader = GetCodeForReadyToRunHeader(node as ReadyToRunHeaderNode, factory);
+ rtrHeaderNode = node as ReadyToRunHeaderNode;
+ else if (node is ReadyToRunGenericHelperNode)
+ additionalNodes.Append(GetCodeForReadyToRunGenericHelper(node as ReadyToRunGenericHelperNode, factory));
}
+ rtrHeader = GetCodeForReadyToRunHeader(rtrHeaderNode, factory);
+
dispatchPointers.AppendLine();
dispatchPointers.Exdent();
WriteForwardDefinitions();
+ Out.Write(forwardDefinitions.ToString());
+
Out.Write(typeDefinitions.ToString());
+ OutputStaticsCode(_statics);
+
+ OutputStaticsCode(_gcStatics, true);
+
+ OutputStaticsCode(_threadStatics, true, true);
+
+ Out.Write(indirectionNodes.ToString());
+
Out.Write(additionalNodes.ToString());
Out.Write(methodTables.ToString());
@@ -1224,9 +1699,42 @@ private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenera
if (nodeType.IsDefType && !nodeType.IsGenericDefinition)
{
OutputTypeFields(typeDefinitions, nodeType);
+
+ if (nodeType.HasStaticConstructor)
+ {
+ MethodDesc cctor = nodeType.GetStaticConstructor().GetCanonMethodTarget(CanonicalFormKind.Specific);
+
+ if (_typesWithCctor.Contains(cctor.OwningType))
+ {
+ CppGenerationBuffer staticsBuffer;
+
+ if (!_statics.TryGetValue(nodeType, out staticsBuffer))
+ {
+ staticsBuffer = new CppGenerationBuffer();
+ staticsBuffer.Indent();
+ _statics[nodeType] = staticsBuffer;
+ }
+
+ staticsBuffer.AppendLine();
+ staticsBuffer.Append("bool __cctor_has_run;");
+ staticsBuffer.AppendLine();
+
+ if (cctor.RequiresInstArg())
+ {
+ staticsBuffer.Append("void (*__cctor)(void *);");
+ staticsBuffer.AppendLine();
+ staticsBuffer.Append("void *__ctx;");
+ }
+ else
+ {
+ staticsBuffer.Append("void (*__cctor)();");
+ }
+ }
+ }
}
- if (typeNode is ConstructedEETypeNode)
+ if ((typeNode is ConstructedEETypeNode || typeNode is CanonicalEETypeNode ||
+ typeNode is NecessaryCanonicalEETypeNode) && nodeType is DefType)
{
DefType closestDefType = nodeType.GetClosestDefType();
@@ -1246,12 +1754,6 @@ private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenera
}
}
- if (nodeType.HasStaticConstructor)
- {
- _statics.AppendLine();
- _statics.Append("bool __cctor_" + GetCppTypeName(nodeType).Replace("::", "__") + ";");
- }
-
List methodList;
if (_methodLists.TryGetValue(nodeType, out methodList))
{
@@ -1260,7 +1762,7 @@ private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenera
typeDefinitions.AppendLine();
AppendCppMethodDeclaration(typeDefinitions, m, false);
typeDefinitions.AppendLine();
- AppendCppMethodDeclaration(typeDefinitions, m, false, null, null, CppUnboxingStubNode.GetMangledName(factory.NameMangler, m));
+ AppendCppMethodDeclaration(typeDefinitions, m, false, null, null, CppUnboxingStubNode.GetMangledName(factory.NameMangler, m), true);
}
}
@@ -1338,6 +1840,359 @@ private String GetCodeForReadyToRunHeader(ReadyToRunHeaderNode headerNode, NodeF
return rtrHeader.ToString();
}
+ private void OutputCodeForTriggerCctor(CppGenerationBuffer sb, TypeDesc type,
+ string staticsBaseVarName, string staticsVarName)
+ {
+ type = type.ConvertToCanonForm(CanonicalFormKind.Specific);
+ MethodDesc cctor = type.GetStaticConstructor();
+
+ sb.Append(GetCppStaticsTypeName(type));
+ sb.Append(" *");
+ sb.Append(staticsVarName);
+ sb.Append(" = ");
+ sb.Append("(");
+ sb.Append(GetCppStaticsTypeName(type));
+ sb.Append("*)");
+ sb.Append(staticsBaseVarName);
+ 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");
+ }
+
+ sb.Append(");");
+
+ sb.Exdent();
+ sb.AppendLine();
+ sb.Append("}");
+ sb.AppendLine();
+ }
+
+ private void OutputCodeForDictionaryLookup(CppGenerationBuffer sb, NodeFactory factory,
+ ReadyToRunGenericHelperNode node, GenericLookupResult lookup, string ctxVarName,
+ string resVarName)
+ {
+ // Find the generic dictionary slot
+ int dictionarySlot = factory.GenericDictionaryLayout(node.DictionaryOwner).GetSlotForEntry(lookup);
+
+ int offset = dictionarySlot * factory.Target.PointerSize;
+
+ // Load the generic dictionary cell
+ sb.Append(resVarName);
+ sb.Append(" = *(void **)((intptr_t)");
+ sb.Append(ctxVarName);
+ sb.Append(" + ");
+ sb.Append(offset);
+ sb.Append(");");
+ sb.AppendLine();
+
+ switch (lookup.LookupResultReferenceType(factory))
+ {
+ case GenericLookupResultReferenceType.Indirect:
+ {
+ sb.Append(resVarName);
+ sb.Append(" = *(void **)");
+ sb.Append(resVarName);
+ sb.Append(";");
+ sb.AppendLine();
+ }
+ break;
+
+ case GenericLookupResultReferenceType.ConditionalIndirect:
+ throw new NotImplementedException();
+
+ default:
+ break;
+ }
+ }
+
+ private string GetCodeForReadyToRunGenericHelper(ReadyToRunGenericHelperNode node, NodeFactory factory)
+ {
+ CppGenerationBuffer sb = new CppGenerationBuffer();
+
+ string mangledName = GetCppReadyToRunGenericHelperNodeName(factory, node);
+ List argNames = new List(new string[] {"arg"});
+ string ctxVarName = "ctx";
+ string resVarName = "res";
+ string retVarName = "ret";
+
+ string retType;
+ switch (node.Id)
+ {
+ case ReadyToRunHelperId.MethodHandle:
+ retType = "::System_Private_CoreLib::System::RuntimeMethodHandle";
+ break;
+ case ReadyToRunHelperId.DelegateCtor:
+ retType = "void";
+ break;
+ default:
+ retType = "void*";
+ break;
+ }
+
+ sb.AppendLine();
+ sb.Append(retType);
+ sb.Append(" ");
+ sb.Append(mangledName);
+ sb.Append("(");
+ sb.Append("void *");
+ sb.Append(argNames[0]);
+
+ if (node.Id == ReadyToRunHelperId.DelegateCtor)
+ {
+ sb.Append(", ");
+
+ DelegateCreationInfo target = (DelegateCreationInfo)node.Target;
+ MethodDesc constructor = target.Constructor.Method;
+
+ bool isStatic = constructor.Signature.IsStatic;
+
+ int argCount = constructor.Signature.Length;
+ if (!isStatic)
+ argCount++;
+
+ int startIdx = argNames.Count;
+ for (int i = 0; i < argCount; i++)
+ {
+ string argName = $"arg{i + startIdx}";
+ argNames.Add(argName);
+
+ TypeDesc argType;
+ if (i == 0 && !isStatic)
+ {
+ argType = constructor.OwningType;
+ }
+ else
+ {
+ argType = constructor.Signature[i - (isStatic ? 0 : 1)];
+ }
+
+ sb.Append(GetCppSignatureTypeName(argType));
+ sb.Append(" ");
+ sb.Append(argName);
+
+ if (i != argCount - 1)
+ sb.Append(", ");
+ }
+ }
+
+ sb.Append(")");
+
+ sb.AppendLine();
+ sb.Append("{");
+ sb.Indent();
+ sb.AppendLine();
+
+ sb.Append("void *");
+ sb.Append(ctxVarName);
+ sb.Append(";");
+ sb.AppendLine();
+
+ sb.Append("void *");
+ sb.Append(resVarName);
+ sb.Append(";");
+ sb.AppendLine();
+
+ if (node is ReadyToRunGenericLookupFromTypeNode)
+ {
+ // Locate the VTable slot that points to the dictionary
+ int vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(factory, (TypeDesc)node.DictionaryOwner);
+
+ int pointerSize = factory.Target.PointerSize;
+ int slotOffset = EETypeNode.GetVTableOffset(pointerSize) + (vtableSlot * pointerSize);
+
+ // Load the dictionary pointer from the VTable
+ sb.Append(ctxVarName);
+ sb.Append(" = *(void **)((intptr_t)");
+ sb.Append(argNames[0]);
+ sb.Append(" + ");
+ sb.Append(slotOffset.ToString());
+ sb.Append(");");
+ sb.AppendLine();
+ }
+ else
+ {
+ sb.Append(ctxVarName);
+ sb.Append(" = ");
+ sb.Append(argNames[0]);
+ sb.Append(";");
+ sb.AppendLine();
+ }
+
+ OutputCodeForDictionaryLookup(sb, factory, node, node.LookupSignature, ctxVarName, resVarName);
+
+ switch (node.Id)
+ {
+ case ReadyToRunHelperId.GetNonGCStaticBase:
+ {
+ MetadataType target = (MetadataType)node.Target;
+
+ if (target.HasStaticConstructor)
+ {
+ string staticsVarName = "statics";
+
+ OutputCodeForTriggerCctor(sb, target, resVarName, staticsVarName);
+ }
+ }
+ break;
+
+ case ReadyToRunHelperId.GetGCStaticBase:
+ {
+ MetadataType target = (MetadataType)node.Target;
+
+ if (target.HasStaticConstructor)
+ {
+ string staticsVarName = "statics";
+ string nonGcStaticsBase = "nonGcBase";
+
+ sb.Append("void *");
+ sb.Append(nonGcStaticsBase);
+ sb.Append(";");
+ sb.AppendLine();
+
+ GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target);
+
+ OutputCodeForDictionaryLookup(sb, factory, node, nonGcRegionLookup, ctxVarName, nonGcStaticsBase);
+
+ OutputCodeForTriggerCctor(sb, target, nonGcStaticsBase, staticsVarName);
+ }
+ }
+ break;
+
+ case ReadyToRunHelperId.GetThreadStaticBase:
+ {
+ MetadataType target = (MetadataType)node.Target;
+
+ if (target.HasStaticConstructor)
+ {
+ string staticsVarName = "statics";
+ string nonGcStaticsBase = "nonGcBase";
+
+ sb.Append("void *");
+ sb.Append(nonGcStaticsBase);
+ sb.Append(";");
+ sb.AppendLine();
+
+ GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target);
+
+ OutputCodeForDictionaryLookup(sb, factory, node, nonGcRegionLookup, ctxVarName, nonGcStaticsBase);
+
+ OutputCodeForTriggerCctor(sb, target, nonGcStaticsBase, staticsVarName);
+ }
+ }
+ break;
+
+ case ReadyToRunHelperId.DelegateCtor:
+ {
+ DelegateCreationInfo target = (DelegateCreationInfo)node.Target;
+ MethodDesc constructor = target.Constructor.Method;
+
+ sb.Append("if (");
+ sb.Append(argNames[3]);
+ sb.Append(" == 0) {");
+ sb.Append(argNames[3]);
+ sb.Append(" = ((intptr_t)");
+ sb.Append(resVarName);
+ sb.Append(") + 0x2;};");
+ sb.AppendLine();
+
+ sb.Append("::");
+ sb.Append(GetCppMethodDeclarationName(constructor.OwningType, GetCppMethodName(constructor)));
+ sb.Append("(");
+
+ for (int i = 1; i < argNames.Count; i++)
+ {
+ sb.Append(argNames[i]);
+
+ if (i != argNames.Count - 1)
+ sb.Append(", ");
+ }
+
+ sb.Append(");");
+ sb.AppendLine();
+ }
+ break;
+
+ // These are all simple: just get the thing from the dictionary and we're done
+ case ReadyToRunHelperId.TypeHandle:
+ case ReadyToRunHelperId.MethodHandle:
+ case ReadyToRunHelperId.FieldHandle:
+ case ReadyToRunHelperId.MethodDictionary:
+ case ReadyToRunHelperId.MethodEntry:
+ case ReadyToRunHelperId.VirtualDispatchCell:
+ case ReadyToRunHelperId.DefaultConstructor:
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+
+ if (node.Id != ReadyToRunHelperId.DelegateCtor)
+ {
+ sb.Append(retType);
+ sb.Append(" ");
+ sb.Append(retVarName);
+ sb.Append(" = ");
+
+ if (node.Id == ReadyToRunHelperId.MethodHandle)
+ {
+ sb.Append("{");
+ sb.Append("(intptr_t)");
+ sb.Append(resVarName);
+ sb.Append("};");
+ }
+ else
+ {
+ sb.Append(resVarName);
+ sb.Append(";");
+ }
+
+ sb.AppendLine();
+
+ sb.Append("return ");
+ sb.Append(retVarName);
+ sb.Append(";");
+ }
+
+ sb.Exdent();
+ sb.AppendLine();
+ sb.Append("}");
+ sb.AppendLine();
+
+ return sb.ToString();
+ }
+
+ private int GetNameAndSignatureId(MethodDesc method)
+ {
+ var nameAndSignature = new Tuple(method.Name, method.Signature);
+
+ int uniqueId;
+
+ if (!_methodNameAndSignatures.TryGetValue(nameAndSignature, out uniqueId))
+ {
+ uniqueId = _methodNameAndSignatures.Count;
+
+ _methodNameAndSignatures[nameAndSignature] = uniqueId;
+ }
+
+ return uniqueId;
+ }
+
private void OutputExternCSignatures()
{
var sb = new CppGenerationBuffer();
@@ -1366,7 +2221,7 @@ private void OutputUnboxingStubNode(CppUnboxingStubNode unboxingStubNode)
CppGenerationBuffer sb = new CppGenerationBuffer();
sb.AppendLine();
- AppendCppMethodDeclaration(sb, unboxingStubNode.Method, true, null, null, unboxingStubNode.GetMangledName(_compilation.NameMangler));
+ AppendCppMethodDeclaration(sb, unboxingStubNode.Method, true, null, null, unboxingStubNode.GetMangledName(_compilation.NameMangler), true);
sb.AppendLine();
sb.Append("{");
sb.Indent();
@@ -1375,6 +2230,7 @@ private void OutputUnboxingStubNode(CppUnboxingStubNode unboxingStubNode)
{
sb.Append("return ");
}
+ sb.Append("::");
sb.Append(GetCppMethodDeclarationName(unboxingStubNode.Method.OwningType, GetCppMethodName(unboxingStubNode.Method)));
sb.Append("(");
AppendCppMethodCallParamList(sb, unboxingStubNode.Method, true);
@@ -1386,6 +2242,92 @@ private void OutputUnboxingStubNode(CppUnboxingStubNode unboxingStubNode)
Out.Write(sb.ToString());
}
+ private void OutputStaticsCode(Dictionary statics,
+ bool isGCStatic = false, bool isThreadStatic = false)
+ {
+ CppGenerationBuffer sb = new CppGenerationBuffer();
+
+ foreach (var entry in statics)
+ {
+ TypeDesc t = entry.Key;
+
+ sb.Append("struct ");
+ sb.Append(GetCppStaticsTypeName(t, isGCStatic, isThreadStatic));
+ sb.Append(" {");
+ sb.Append(entry.Value.ToString());
+ sb.Exdent();
+ sb.AppendLine();
+ sb.Append("};");
+ sb.AppendLine();
+
+ if (t.IsCanonicalSubtype(CanonicalFormKind.Any))
+ continue;
+
+ sb.Append(GetCppStaticsTypeName(t, isGCStatic, isThreadStatic));
+ sb.Append(" ");
+ sb.Append(GetCppStaticsName(t, isGCStatic, isThreadStatic));
+
+ if (!isGCStatic && t.HasStaticConstructor)
+ {
+ MethodDesc cctor = t.GetStaticConstructor();
+ MethodDesc canonCctor = cctor.GetCanonMethodTarget(CanonicalFormKind.Specific);
+
+ if (_typesWithCctor.Contains(canonCctor.OwningType))
+ {
+ sb.Append(" = {");
+ sb.Indent();
+ sb.AppendLine();
+
+ if (canonCctor.RequiresInstArg())
+ {
+ sb.Append(".__cctor = (void (*)(void *)) *(void **)");
+ sb.Append(GetCppFatFunctionPointerNameForMethod(cctor));
+ sb.Append("(),");
+ sb.Append(".__ctx = **(void***) (((intptr_t)");
+ sb.Append(GetCppFatFunctionPointerNameForMethod(cctor));
+ sb.Append("()) + sizeof(void*))");
+ }
+ else
+ {
+ sb.Append(".__cctor = &");
+ sb.Append(GetCppMethodDeclarationName(canonCctor.OwningType, GetCppMethodName(canonCctor)));
+ }
+
+ sb.Exdent();
+ sb.AppendLine();
+ sb.Append("}");
+ }
+ }
+
+ sb.Append(";");
+ sb.AppendLine();
+ }
+
+ Out.Write(sb.ToString());
+ }
+
+ public TypeDesc ConvertToCanonFormIfNecessary(TypeDesc type, CanonicalFormKind policy)
+ {
+ if (!type.IsCanonicalSubtype(CanonicalFormKind.Any))
+ return type;
+
+ if (type.IsPointer || type.IsByRef)
+ {
+ ParameterizedType parameterizedType = (ParameterizedType)type;
+ TypeDesc paramTypeConverted = ConvertToCanonFormIfNecessary(parameterizedType.ParameterType, policy);
+ if (paramTypeConverted == parameterizedType.ParameterType)
+ return type;
+
+ if (type.IsPointer)
+ return _compilation.TypeSystemContext.GetPointerType(paramTypeConverted);
+
+ if (type.IsByRef)
+ return _compilation.TypeSystemContext.GetByRefType(paramTypeConverted);
+ }
+
+ return type.ConvertToCanonForm(policy);
+ }
+
public void OutputCode(IEnumerable nodes, NodeFactory factory)
{
BuildMethodLists(nodes);
@@ -1394,29 +2336,12 @@ public void OutputCode(IEnumerable nodes, NodeFactory factory)
Out.WriteLine("#include \"CppCodeGen.h\"");
Out.WriteLine();
- _statics = new CppGenerationBuffer();
- _statics.Indent();
- _gcStatics = new CppGenerationBuffer();
- _gcStatics.Indent();
- _threadStatics = new CppGenerationBuffer();
- _threadStatics.Indent();
- _gcThreadStatics = new CppGenerationBuffer();
- _gcThreadStatics.Indent();
+ _statics = new Dictionary();
+ _gcStatics = new Dictionary();
+ _threadStatics = new Dictionary();
OutputNodes(nodes, factory);
- Out.Write("struct {");
- Out.Write(_statics.ToString());
- Out.Write("} __statics;");
-
- Out.Write("struct {");
- Out.Write(_gcStatics.ToString());
- Out.Write("} __gcStatics;");
-
- Out.Write("struct {");
- Out.Write(_gcStatics.ToString());
- Out.Write("} __gcThreadStatics;");
-
OutputExternCSignatures();
foreach (var node in nodes)
diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/EvaluationStack.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/EvaluationStack.cs
index feaf2ed2dcd..34ea83ecffe 100644
--- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/EvaluationStack.cs
+++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/EvaluationStack.cs
@@ -489,6 +489,19 @@ protected override void BuildRepresentation(StringBuilder s)
}
}
+ ///
+ /// Entry representing some ftn token along with its string representation
+ ///
+ internal class LdFtnTokenEntry : LdTokenEntry
+ {
+ public bool IsVirtual { get; }
+
+ public LdFtnTokenEntry(StackValueKind kind, string name, MethodDesc token, bool isVirtual, TypeDesc type = null) : base(kind, name, token, type)
+ {
+ IsVirtual = isVirtual;
+ }
+ }
+
internal class InvalidEntry : StackEntry
{
///
diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs
index 92a7626bcfd..3d8962e649e 100644
--- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs
+++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs
@@ -35,6 +35,7 @@ internal partial class ILImporter
private TypeDesc _thisType;
private MethodIL _methodIL;
+ private MethodIL _canonMethodIL;
private byte[] _ilBytes;
private LocalVariableDefinition[] _locals;
@@ -118,12 +119,25 @@ public ILImporter(Compilation compilation, CppWriter writer, MethodDesc method,
if (!_methodSignature.IsStatic)
_thisType = method.OwningType;
- _methodIL = methodIL;
+ _canonMethodIL = methodIL;
- _ilBytes = _methodIL.GetILBytes();
- _locals = _methodIL.GetLocals();
+ // Get the runtime determined method IL so that this works right in shared code
+ // and tokens in shared code resolve to runtime determined types.
+ MethodIL uninstantiatiedMethodIL = methodIL.GetMethodILDefinition();
+ if (methodIL != uninstantiatiedMethodIL)
+ {
+ MethodDesc sharedMethod = method.GetSharedRuntimeFormMethodTarget();
+ _methodIL = new InstantiatedMethodIL(sharedMethod, uninstantiatiedMethodIL);
+ }
+ else
+ {
+ _methodIL = methodIL;
+ }
+
+ _ilBytes = methodIL.GetILBytes();
+ _locals = methodIL.GetLocals();
- var ilExceptionRegions = _methodIL.GetExceptionRegions();
+ var ilExceptionRegions = methodIL.GetExceptionRegions();
_exceptionRegions = new ExceptionRegion[ilExceptionRegions.Length];
for (int i = 0; i < ilExceptionRegions.Length; i++)
{
@@ -185,6 +199,35 @@ public void SetParameterNames(IEnumerable parameters)
_parameterIndexToNameMap = parameterIndexToNameMap;
}
+ private ISymbolNode GetGenericLookupHelper(ReadyToRunHelperId helperId, object helperArgument)
+ {
+ if (_method.RequiresInstMethodDescArg())
+ {
+ return _nodeFactory.ReadyToRunHelperFromDictionaryLookup(helperId, helperArgument, _method);
+ }
+ else
+ {
+ Debug.Assert(_method.RequiresInstMethodTableArg() || _method.AcquiresInstMethodTableFromThis());
+ return _nodeFactory.ReadyToRunHelperFromTypeLookup(helperId, helperArgument, _method.OwningType);
+ }
+ }
+
+ private string GetGenericContext()
+ {
+ Debug.Assert(_method.IsSharedByGenericInstantiations);
+
+ if (_method.AcquiresInstMethodTableFromThis())
+ {
+ return String.Concat(
+ "*(void **)",
+ GetVarName(0, true));
+ }
+ else
+ {
+ return _writer.GetCppHiddenParam();
+ }
+ }
+
private StackValueKind GetStackValueKind(TypeDesc type)
{
switch (type.Category)
@@ -300,9 +343,19 @@ private void AppendCastIfNecessary(TypeDesc destType, StackEntry srcEntry)
ConstantEntry constant = srcEntry as ConstantEntry;
if ((constant != null) && (constant.IsCastNecessary(destType)) || !destType.IsValueType || destType != srcEntry.Type)
{
- Append("(");
- Append(GetSignatureTypeNameAndAddReference(destType));
- Append(")");
+ if (srcEntry.Kind == StackValueKind.ValueType)
+ {
+ Append("*(");
+ Append(GetSignatureTypeNameAndAddReference(destType));
+ Append("*");
+ Append(")&");
+ }
+ else
+ {
+ Append("(");
+ Append(GetSignatureTypeNameAndAddReference(destType));
+ Append(")");
+ }
}
}
@@ -460,6 +513,72 @@ private void AppendComparison(ILOpcode opcode, StackEntry op1, StackEntry op2)
}
}
+ private string GetSymbolNodeName(ISymbolNode node)
+ {
+ return node.GetMangledName(_nodeFactory.NameMangler).Replace("::", "_");
+ }
+
+ private void AppendMethodGenericDictionary(MethodDesc method)
+ {
+ ISymbolNode node = _nodeFactory.MethodGenericDictionary(method);
+ _dependencies.Add(node);
+
+ Append(GetSymbolNodeName(node));
+ }
+
+ private void AppendRuntimeMethodHandle(MethodDesc method)
+ {
+ ISymbolNode node = _nodeFactory.RuntimeMethodHandle(method);
+ _dependencies.Add(node);
+
+ Append(_writer.GetCppSymbolNodeName(_nodeFactory, node));
+ }
+
+ private void AppendFatFunctionPointer(MethodDesc method, bool isUnboxingStub = false)
+ {
+ ISymbolNode node = _nodeFactory.FatFunctionPointer(method, isUnboxingStub);
+ _dependencies.Add(node);
+
+ Append(_writer.GetCppSymbolNodeName(_nodeFactory, node));
+ }
+
+ private string GetGenericLookupHelperAndAddReference(ReadyToRunHelperId helperId, object helperArgument)
+ {
+ ISymbolNode node = GetGenericLookupHelper(helperId, helperArgument);
+ _dependencies.Add(node);
+
+ return _writer.GetCppReadyToRunGenericHelperNodeName(_nodeFactory, node as ReadyToRunGenericHelperNode);
+ }
+
+ private void AppendStaticFieldGenericLookupHelperAndAddReference(FieldDesc field)
+ {
+ Debug.Assert(field.IsStatic);
+
+ ReadyToRunHelperId helperId;
+ if (field.IsThreadStatic)
+ {
+ helperId = ReadyToRunHelperId.GetThreadStaticBase;
+ }
+ else if (field.HasGCStaticBase)
+ {
+ helperId = ReadyToRunHelperId.GetGCStaticBase;
+ }
+ else
+ {
+ helperId = ReadyToRunHelperId.GetNonGCStaticBase;
+ }
+
+ Append(GetGenericLookupHelperAndAddReference(helperId, field.OwningType));
+ }
+
+ private void AppendMethodAndAddReference(MethodDesc method, bool isUnboxingStub = false)
+ {
+ ISymbolNode node = _nodeFactory.MethodEntrypoint(method, isUnboxingStub);
+ _dependencies.Add(node);
+
+ Append(GetSymbolNodeName(node));
+ }
+
private StackEntry NewSpillSlot(StackEntry entry)
{
if (_spillSlots == null)
@@ -575,6 +694,8 @@ private string GetVarName(int index, bool argument)
private TypeDesc GetVarType(int index, bool argument)
{
+ TypeDesc type;
+
if (argument)
{
if (_thisType != null)
@@ -582,15 +703,18 @@ private TypeDesc GetVarType(int index, bool argument)
if (index == -1)
{
if (_thisType.IsValueType)
- return _thisType.MakeByRefType();
- return _thisType;
+ type = _thisType.MakeByRefType();
+ else
+ type = _thisType;
}
- else return _methodSignature[index];
+ else type = _methodSignature[index];
}
else
{
- return _locals[index].Type;
+ type = _locals[index].Type;
}
+
+ return _writer.ConvertToCanonFormIfNecessary(type, CanonicalFormKind.Specific);
}
private TypeDesc GetWellKnownType(WellKnownType wellKnownType)
@@ -600,7 +724,7 @@ private TypeDesc GetWellKnownType(WellKnownType wellKnownType)
private TypeDesc ResolveTypeToken(int token)
{
- return (TypeDesc)_methodIL.GetObject(token);
+ return (TypeDesc)_canonMethodIL.GetObject(token);
}
private void MarkInstructionBoundary()
@@ -636,13 +760,13 @@ public void Compile(CppMethodCodeNode methodCodeNodeNeedingCode)
for (int i = 0; i < methodCodeNodeNeedingCode.Method.Signature.Length; i++)
{
var parameterType = methodCodeNodeNeedingCode.Method.Signature[i];
- AddTypeReference(parameterType, false);
+ AddTypeReference(_writer.ConvertToCanonFormIfNecessary(parameterType, CanonicalFormKind.Specific), false);
}
var returnType = methodCodeNodeNeedingCode.Method.Signature.ReturnType;
if (!returnType.IsByRef)
{
- AddTypeReference(returnType, true);
+ AddTypeReference(_writer.ConvertToCanonFormIfNecessary(returnType, CanonicalFormKind.Specific), true);
}
var owningType = methodCodeNodeNeedingCode.Method.OwningType;
@@ -682,14 +806,15 @@ public void Compile(CppMethodCodeNode methodCodeNodeNeedingCode)
bool initLocals = _methodIL.IsInitLocals;
for (int i = 0; i < _locals.Length; i++)
{
+ TypeDesc localType = _writer.ConvertToCanonFormIfNecessary(_locals[i].Type, CanonicalFormKind.Specific);
+
AppendLine();
- Append(GetSignatureTypeNameAndAddReference(_locals[i].Type));
+ Append(GetSignatureTypeNameAndAddReference(localType));
Append(" ");
Append(GetVarName(i, false));
if (initLocals)
{
- TypeDesc localType = _locals[i].Type;
if (localType.IsValueType && !localType.IsPrimitive && !localType.IsEnum)
{
AppendSemicolon();
@@ -882,19 +1007,32 @@ private void ImportJmp(int token)
private void ImportCasting(ILOpcode opcode, int token)
{
- TypeDesc type = (TypeDesc)_methodIL.GetObject(token);
+ TypeDesc runtimeDeterminedType = (TypeDesc)_methodIL.GetObject(token);
+ TypeDesc type = (TypeDesc)_canonMethodIL.GetObject(token);
+ TypeDesc canonType = _writer.ConvertToCanonFormIfNecessary(type, CanonicalFormKind.Specific);
var value = _stack.Pop();
- PushTemp(StackValueKind.ObjRef, type);
+ PushTemp(StackValueKind.ObjRef, canonType);
- AddTypeReference(type, false);
+ AddTypeReference(canonType, false);
Append(opcode == ILOpcode.isinst ? "__isinst" : "__castclass");
Append("(");
Append(value);
Append(", ");
- Append(_writer.GetCppTypeName(type));
- Append("::__getMethodTable())");
+ if (runtimeDeterminedType.IsRuntimeDeterminedSubtype)
+ {
+ Append("(MethodTable *)");
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeDeterminedType));
+ Append("(");
+ Append(GetGenericContext());
+ Append("))");
+ }
+ else
+ {
+ Append(_writer.GetCppTypeName(runtimeDeterminedType));
+ Append("::__getMethodTable())");
+ }
AppendSemicolon();
}
@@ -973,7 +1111,21 @@ private bool ImportIntrinsicCall(MethodDesc method)
{
var typeHandleSlot = (LdTokenEntry)_stack.Pop();
TypeDesc typeOfEEType = typeHandleSlot.LdToken;
- PushExpression(StackValueKind.NativeInt, string.Concat("((intptr_t)", _writer.GetCppTypeName(typeOfEEType), "::__getMethodTable())"));
+
+ string expr;
+
+ if (typeOfEEType.IsRuntimeDeterminedSubtype)
+ {
+ expr = string.Concat(
+ "(intptr_t)",
+ GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, typeOfEEType),
+ "(", GetGenericContext(), ")");
+ }
+ else
+ {
+ expr = string.Concat("((intptr_t)", _writer.GetCppTypeName(typeOfEEType), "::__getMethodTable())");
+ }
+ PushExpression(StackValueKind.NativeInt, expr);
return true;
}
break;
@@ -1015,13 +1167,15 @@ private bool ImportIntrinsicCall(MethodDesc method)
return false;
}
- private void ImportNewObjArray(TypeDesc owningType, MethodDesc method)
+ private void ImportNewObjArray(TypeDesc owningType, MethodDesc runtimeMethod)
{
AppendLine();
+ TypeDesc canonOwningType = _writer.ConvertToCanonFormIfNecessary(owningType, CanonicalFormKind.Specific);
+
string dimensionsTemp = NewTempName();
Append("int32_t " + dimensionsTemp + "[] = { ");
- int argumentsCount = method.Signature.Length;
+ int argumentsCount = runtimeMethod.Signature.Length;
for (int i = 0; i < argumentsCount; i++)
{
Append("(int32_t)(");
@@ -1032,17 +1186,30 @@ private void ImportNewObjArray(TypeDesc owningType, MethodDesc method)
Append("};");
- PushTemp(StackValueKind.ObjRef, owningType);
+ PushTemp(StackValueKind.ObjRef, canonOwningType);
- AddTypeReference(owningType, true);
+ AddTypeReference(canonOwningType, true);
MethodDesc helper = _typeSystemContext.GetHelperEntryPoint("ArrayHelpers", "NewObjArray");
AddMethodReference(helper);
Append(_writer.GetCppTypeName(helper.OwningType) + "::" + _writer.GetCppMethodName(helper));
Append("((intptr_t)");
- Append(_writer.GetCppTypeName(method.OwningType));
- Append("::__getMethodTable(),");
+
+ if (!runtimeMethod.OwningType.IsRuntimeDeterminedSubtype)
+ {
+ Append(_writer.GetCppTypeName(runtimeMethod.OwningType));
+ Append("::__getMethodTable(),");
+ }
+ else
+ {
+ Append("(MethodTable *)");
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeMethod.OwningType));
+ Append("(");
+ Append(GetGenericContext());
+ Append("),");
+ }
+
Append(argumentsCount.ToStringInvariant());
Append(",");
Append(dimensionsTemp);
@@ -1055,9 +1222,11 @@ private void ImportCall(ILOpcode opcode, int token)
bool callViaSlot = false;
bool delegateInvoke = false;
bool callViaInterfaceDispatch = false;
+ bool callViaGVMDispatch = false;
DelegateCreationInfo delegateInfo = null;
- MethodDesc method = (MethodDesc)_methodIL.GetObject(token);
+ var runtimeDeterminedMethod = (MethodDesc)_methodIL.GetObject(token);
+ var method = (MethodDesc)_canonMethodIL.GetObject(token);
if (method.IsIntrinsic)
{
@@ -1077,12 +1246,16 @@ private void ImportCall(ILOpcode opcode, int token)
}
TypeDesc constrained = null;
+ bool resolvedConstraint = false;
if (opcode != ILOpcode.newobj)
{
if ((_pendingPrefix & Prefix.Constrained) != 0 && opcode == ILOpcode.callvirt)
{
_pendingPrefix &= ~Prefix.Constrained;
constrained = _constrained;
+ if (constrained.IsRuntimeDeterminedSubtype)
+ constrained = constrained.ConvertToCanonForm(CanonicalFormKind.Specific);
+
bool forceUseRuntimeLookup;
var constrainedType = constrained.GetClosestDefType();
MethodDesc directMethod = constrainedType.TryResolveConstraintMethodApprox(method.OwningType, method, out forceUseRuntimeLookup);
@@ -1094,9 +1267,10 @@ private void ImportCall(ILOpcode opcode, int token)
{
method = directMethod;
opcode = ILOpcode.call;
+ resolvedConstraint = true;
}
- //If constrainedType is a value type and constrainedType does not implement method (directMethod == null) then ptr is
- //dereferenced, boxed, and passed as the 'this' pointer to the callvirt method instruction.
+ //If constrainedType is a value type and constrainedType does not implement method (directMethod == null) then ptr is
+ //dereferenced, boxed, and passed as the 'this' pointer to the callvirt method instruction.
else if (constrainedType.IsValueType)
{
int thisPosition = _stack.Top - (method.Signature.Length + 1);
@@ -1112,11 +1286,15 @@ private void ImportCall(ILOpcode opcode, int token)
TypeDesc owningType = method.OwningType;
TypeDesc retType = null;
+ TypeDesc runtimeDeterminedRetType = null;
+
+ string delegateCtorHelper = null;
{
if (opcode == ILOpcode.newobj)
{
retType = owningType;
+ runtimeDeterminedRetType = runtimeDeterminedMethod.OwningType;
if (owningType.IsString)
{
@@ -1128,13 +1306,20 @@ private void ImportCall(ILOpcode opcode, int token)
}
else if (owningType.IsArray)
{
- ImportNewObjArray(owningType, method);
+ ImportNewObjArray(owningType, runtimeDeterminedMethod);
return;
}
else if (owningType.IsDelegate)
{
- delegateInfo = _compilation.GetDelegateCtor(owningType, ((LdTokenEntry)_stack.Peek()).LdToken, followVirtualDispatch: false);
+ TypeDesc canonDelegateType = owningType.ConvertToCanonForm(CanonicalFormKind.Specific);
+ LdFtnTokenEntry ldFtnTokenEntry = (LdFtnTokenEntry)_stack.Peek();
+ delegateInfo = _compilation.GetDelegateCtor(canonDelegateType, ldFtnTokenEntry.LdToken, followVirtualDispatch: false);
method = delegateInfo.Constructor.Method;
+
+ if (delegateInfo.NeedsRuntimeLookup && !ldFtnTokenEntry.IsVirtual)
+ {
+ delegateCtorHelper = GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.DelegateCtor, delegateInfo);
+ }
}
}
else
@@ -1148,6 +1333,16 @@ private void ImportCall(ILOpcode opcode, int token)
}
}
+ bool exactContextNeedsRuntimeLookup;
+ if (method.HasInstantiation)
+ {
+ exactContextNeedsRuntimeLookup = method.IsSharedByGenericInstantiations;
+ }
+ else
+ {
+ exactContextNeedsRuntimeLookup = method.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any);
+ }
+
if (opcode == ILOpcode.callvirt)
{
// TODO: Null checks
@@ -1158,37 +1353,48 @@ private void ImportCall(ILOpcode opcode, int token)
if (!method.IsNewSlot)
throw new NotImplementedException();
- if (method.OwningType.IsInterface)
+ if (method.HasInstantiation)
+ callViaGVMDispatch = true;
+ else if (method.OwningType.IsInterface)
callViaInterfaceDispatch = true;
else
callViaSlot = true;
- if (!_nodeFactory.VTable(method.OwningType).HasFixedSlots)
+ if (!callViaGVMDispatch && !_nodeFactory.VTable(method.OwningType).HasFixedSlots)
_dependencies.Add(_nodeFactory.VirtualMethodUse(method));
+ else if (callViaGVMDispatch)
+ _dependencies.Add(_nodeFactory.GVMDependencies(method));
}
}
- if (!callViaSlot && !delegateInvoke && !callViaInterfaceDispatch)
- AddMethodReference(method);
+ var canonMethod = method.GetCanonMethodTarget(CanonicalFormKind.Specific);
- if (opcode == ILOpcode.newobj)
- AddTypeReference(retType, true);
+ if (!callViaSlot && !delegateInvoke && !callViaInterfaceDispatch && !callViaGVMDispatch)
+ AddMethodReference(canonMethod);
- var methodSignature = method.Signature;
+ var canonMethodSignature = canonMethod.Signature;
if (retType == null)
- retType = methodSignature.ReturnType;
+ retType = method.Signature.ReturnType;
+
+ retType = _writer.ConvertToCanonFormIfNecessary(retType, CanonicalFormKind.Specific);
+
+ if (opcode == ILOpcode.newobj)
+ AddTypeReference(retType, true);
string temp = null;
StackValueKind retKind = StackValueKind.Unknown;
var needNewLine = false;
+ string gvmSlotVarName = null;
if (callViaInterfaceDispatch)
{
- ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (methodSignature.Length + 1)];
+ ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (canonMethodSignature.Length + 1)];
- string typeDefName = _writer.GetCppMethodName(method);
- _writer.AppendSignatureTypeDef(_builder, typeDefName, method.Signature, method.OwningType);
+ string typeDefName = _writer.GetCppTypeName(canonMethod.OwningType) + "_" + _writer.GetCppMethodName(canonMethod);
+ typeDefName = typeDefName.Replace("::", "_");
+ _writer.AppendSignatureTypeDef(_builder, typeDefName, canonMethodSignature,
+ canonMethod.OwningType, canonMethod.RequiresInstMethodDescArg());
string functionPtr = NewTempName();
AppendEmptyLine();
@@ -1196,40 +1402,146 @@ private void ImportCall(ILOpcode opcode, int token)
Append("void*");
Append(functionPtr);
Append(" = (void*) ");
- GetFunctionPointerForInterfaceMethod(method, v, typeDefName);
+ GetFunctionPointerForInterfaceMethod(runtimeDeterminedMethod, v, typeDefName);
PushExpression(StackValueKind.ByRef, functionPtr);
}
+ else if (callViaGVMDispatch)
+ {
+ ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (canonMethodSignature.Length + 1)];
+
+ MethodDesc helper = _typeSystemContext.SystemModule.GetKnownType("System.Runtime", "TypeLoaderExports").GetKnownMethod("GVMLookupForSlot", null);
+ AddMethodReference(helper);
+
+ gvmSlotVarName = NewTempName();
+ AppendEmptyLine();
+
+ Append("intptr_t ");
+ Append(gvmSlotVarName);
+ Append(" = ");
+ Append(_writer.GetCppTypeName(helper.OwningType) + "::" + _writer.GetCppMethodName(helper));
+ Append("(");
+ Append("(::System_Private_CoreLib::System::Object*)");
+ Append(v.Name);
+ Append(", ");
+
+ if (exactContextNeedsRuntimeLookup)
+ {
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.MethodHandle, runtimeDeterminedMethod));
+ Append("(");
+ Append(GetGenericContext());
+ Append(")");
+ }
+ else
+ {
+ AppendRuntimeMethodHandle(runtimeDeterminedMethod);
+ Append("()");
+ }
+ Append(");");
+
+ string functionPtr = NewTempName();
+
+ Append("intptr_t ");
+ Append(functionPtr);
+ AppendSemicolon();
+
+ Append("if (");
+ Append(gvmSlotVarName);
+ Append(" & 0x2) {");
+ Append(functionPtr);
+ Append(" = *(intptr_t*)(");
+ Append(gvmSlotVarName);
+ Append(" - 0x2);} else {");
+ Append(functionPtr);
+ Append(" = ");
+ Append(gvmSlotVarName);
+ Append(";};");
+
+ PushExpression(StackValueKind.ValueType, functionPtr);
+ }
+
+ string arrayAddressMethodHiddenArg = null;
+
+ if (canonMethod.IsArrayAddressMethod())
+ {
+ arrayAddressMethodHiddenArg = NewTempName();
+
+ Append("::System_Private_CoreLib::System::EETypePtr ");
+ Append(arrayAddressMethodHiddenArg);
+ Append(" = {(::System_Private_CoreLib::Internal::Runtime::EEType*)");
+
+ TypeDesc type;
+
+ if (!resolvedConstraint)
+ type = runtimeDeterminedMethod.OwningType;
+ else
+ type = _constrained;
+
+ if (exactContextNeedsRuntimeLookup)
+ {
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, type));
+
+ Append("(");
+ Append(GetGenericContext());
+ Append(")");
+ }
+ else
+ {
+ Append(_writer.GetCppTypeName(type));
+ Append("::__getMethodTable()");
+
+ AddTypeReference(type, true);
+ }
+
+ Append("};");
+ }
+
+ TypeDesc canonRetType = null;
if (!retType.IsVoid)
{
- retKind = GetStackValueKind(retType);
+ if (opcode == ILOpcode.newobj)
+ {
+ canonRetType = retType;
+ }
+ else
+ {
+ canonRetType = _writer.ConvertToCanonFormIfNecessary(canonMethodSignature.ReturnType, CanonicalFormKind.Specific);
+ }
+
+ retKind = GetStackValueKind(canonRetType);
temp = NewTempName();
AppendLine();
- Append(GetStackValueKindCPPTypeName(retKind, retType));
+ Append(GetStackValueKindCPPTypeName(retKind, canonRetType));
Append(" ");
Append(temp);
- if (retType.IsValueType && opcode == ILOpcode.newobj)
+ if (canonRetType.IsValueType && opcode == ILOpcode.newobj || callViaGVMDispatch)
{
- Append(";");
- needNewLine = true;
+ AppendSemicolon();
+
+ if (!callViaGVMDispatch)
+ needNewLine = true;
}
else
{
Append(" = ");
- if (retType.IsPointer)
+ if (canonRetType.IsPointer)
{
Append("(intptr_t)");
}
+ else
+ {
+ AppendCastIfNecessary(retKind, canonRetType);
+ }
}
}
else
{
needNewLine = true;
}
- AddTypeReference(method.OwningType, true);
+ AddTypeReference(canonMethod.OwningType, true);
if (opcode == ILOpcode.newobj)
{
@@ -1239,8 +1551,23 @@ private void ImportCall(ILOpcode opcode, int token)
if (needNewLine)
AppendLine();
Append("__allocate_object(");
- Append(_writer.GetCppTypeName(retType));
- Append("::__getMethodTable())");
+
+ if (runtimeDeterminedRetType.IsRuntimeDeterminedSubtype)
+ {
+ Append("(MethodTable *)");
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeDeterminedRetType));
+ Append("(");
+ Append(GetGenericContext());
+ Append("))");
+ }
+ else
+ {
+ Append(_writer.GetCppTypeName(runtimeDeterminedRetType));
+ Append("::__getMethodTable())");
+
+ AddTypeReference(runtimeDeterminedRetType, true);
+ }
+
AppendSemicolon();
needNewLine = true;
@@ -1269,12 +1596,13 @@ private void ImportCall(ILOpcode opcode, int token)
if (callViaSlot || delegateInvoke)
{
- ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (methodSignature.Length + 1)];
+ ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (canonMethodSignature.Length + 1)];
+
Append("(*");
- Append(_writer.GetCppTypeName(method.OwningType));
+ Append(_writer.GetCppTypeName(canonMethod.OwningType));
Append("::");
Append(delegateInvoke ? "__invoke__" : "__getslot__");
- Append(_writer.GetCppMethodName(method));
+ Append(_writer.GetCppMethodName(canonMethod));
Append("(");
Append(v);
Append("))");
@@ -1289,54 +1617,264 @@ private void ImportCall(ILOpcode opcode, int token)
else if (callViaInterfaceDispatch)
{
Append("((");
- Append(_writer.GetCppMethodName(method));
+ Append(_writer.GetCppTypeName(canonMethod.OwningType).Replace("::", "_"));
+ Append("_");
+ Append(_writer.GetCppMethodName(canonMethod));
Append(")");
ExpressionEntry v = (ExpressionEntry)_stack.Pop();
Append(v);
Append(")");
}
- else
+ else if (delegateCtorHelper != null)
{
- Append(_writer.GetCppTypeName(method.OwningType));
+ Append(delegateCtorHelper);
+ }
+ else if (!callViaGVMDispatch)
+ {
+ Append(_writer.GetCppTypeName(canonMethod.OwningType));
Append("::");
- Append(_writer.GetCppMethodName(method));
+ Append(_writer.GetCppMethodName(canonMethod));
}
TypeDesc thisArgument = null;
- Append("(");
- if (opcode == ILOpcode.newobj)
+ if (opcode != ILOpcode.newobj && !canonMethodSignature.IsStatic)
{
- Append("(");
- if (retType.IsValueType)
+ thisArgument = canonMethod.OwningType;
+ if (thisArgument.IsValueType)
+ thisArgument = thisArgument.MakeByRefType();
+ }
+
+ if (callViaGVMDispatch)
+ {
+ string typeDefName = _writer.GetCppTypeName(canonMethod.OwningType) + "_" + _writer.GetCppMethodName(canonMethod);
+ typeDefName = typeDefName.Replace("::", "_");
+
+ ExpressionEntry v = (ExpressionEntry)_stack.Pop();
+
+ Append("if (");
+ Append(gvmSlotVarName);
+ Append(" & 0x2) {");
+
+ _writer.AppendSignatureTypeDef(_builder, typeDefName, canonMethodSignature,
+ canonMethod.OwningType, true);
+
+ if (canonRetType != null && !canonRetType.IsValueType)
{
- Append(_writer.GetCppSignatureTypeName(retType.MakeByRefType()));
- Append(")");
- Append("&" + temp);
+ Append(temp);
+ Append(" = ");
+
+ if (canonRetType.IsPointer)
+ {
+ Append("(intptr_t)");
+ }
+ else
+ {
+ AppendCastIfNecessary(GetStackValueKind(canonRetType), canonRetType);
+ }
}
- else
+
+ Append("((");
+ Append(_writer.GetCppTypeName(canonMethod.OwningType).Replace("::", "_"));
+ Append("_");
+ Append(_writer.GetCppMethodName(canonMethod));
+ Append(")");
+ Append(v);
+ Append(")(");
+
+ PassThisArgumentIfNeeded(canonMethodSignature, thisArgument);
+
+ if (thisArgument != null)
+ Append(", ");
+
+ Append("**(void***)(");
+ Append(gvmSlotVarName);
+ Append("- 0x2 + sizeof(void*))");
+
+ if (canonMethodSignature.Length > 0)
+ Append(", ");
+
+ PassCallArguments(canonMethodSignature, thisArgument, false);
+
+ Append(");} else {");
+
+ _writer.AppendSignatureTypeDef(_builder, typeDefName, canonMethodSignature,
+ canonMethod.OwningType, false);
+
+ if (canonRetType != null && !canonRetType.IsValueType)
{
- Append(_writer.GetCppSignatureTypeName(retType));
- Append(")");
Append(temp);
+ Append(" = ");
+
+ if (canonRetType.IsPointer)
+ {
+ Append("(intptr_t)");
+ }
+ else
+ {
+ AppendCastIfNecessary(GetStackValueKind(canonRetType), canonRetType);
+ }
}
- if (methodSignature.Length > 0)
+
+ Append("((");
+ Append(_writer.GetCppTypeName(canonMethod.OwningType).Replace("::", "_"));
+ Append("_");
+ Append(_writer.GetCppMethodName(canonMethod));
+ Append(")");
+ Append(v);
+ Append(")(");
+
+ PassThisArgumentIfNeeded(canonMethodSignature, thisArgument);
+
+ if (thisArgument != null && canonMethodSignature.Length > 0)
Append(", ");
+
+ PassCallArguments(canonMethodSignature, thisArgument);
+
+ Append(");};");
}
else
{
- if (!methodSignature.IsStatic)
+ Append("(");
+
+ if (opcode == ILOpcode.newobj)
{
- thisArgument = owningType;
- if (thisArgument.IsValueType)
- thisArgument = thisArgument.MakeByRefType();
+ if (delegateCtorHelper != null)
+ {
+ Append(GetGenericContext());
+ Append(", ");
+ }
+
+ canonRetType = _writer.ConvertToCanonFormIfNecessary(canonMethod.OwningType, CanonicalFormKind.Specific);
+
+ Append("(");
+ if (canonRetType.IsValueType)
+ {
+ Append(_writer.GetCppSignatureTypeName(canonRetType.MakeByRefType()));
+ Append(")");
+ Append("&" + temp);
+ }
+ else
+ {
+ Append(_writer.GetCppSignatureTypeName(canonRetType));
+ Append(")");
+ Append(temp);
+ }
+ if (canonMethodSignature.Length > 0)
+ Append(", ");
}
+
+ PassThisArgumentIfNeeded(canonMethodSignature, thisArgument);
+
+ if (thisArgument != null &&
+ (canonMethod.IsArrayAddressMethod() || canonMethod.RequiresInstArg() || canonMethodSignature.Length > 0))
+ Append(", ");
+
+ if (canonMethod.IsArrayAddressMethod())
+ {
+ Append(arrayAddressMethodHiddenArg);
+
+ if (canonMethodSignature.Length > 0)
+ Append(", ");
+ }
+ else if (canonMethod.RequiresInstArg())
+ {
+ if (exactContextNeedsRuntimeLookup)
+ {
+ if (!resolvedConstraint)
+ {
+ if (canonMethod.RequiresInstMethodDescArg())
+ {
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.MethodDictionary, runtimeDeterminedMethod));
+ }
+ else
+ {
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeDeterminedMethod.OwningType));
+ }
+
+ Append("(");
+ Append(GetGenericContext());
+ Append(")");
+ }
+ else
+ {
+ Debug.Assert(canonMethod.RequiresInstMethodTableArg());
+
+ if (canonMethod.RequiresInstMethodTableArg())
+ {
+ if (_constrained.IsRuntimeDeterminedSubtype)
+ {
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, _constrained));
+
+ Append("(");
+ Append(GetGenericContext());
+ Append(")");
+ }
+ else
+ {
+ Append(_writer.GetCppTypeName(_constrained));
+ Append("::__getMethodTable()");
+
+ AddTypeReference(_constrained, true);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (canonMethod.RequiresInstMethodDescArg())
+ {
+ Append("&");
+ AppendMethodGenericDictionary(method);
+ }
+ else
+ {
+ Append(_writer.GetCppTypeName(method.OwningType));
+ Append("::__getMethodTable()");
+
+ AddTypeReference(method.OwningType, true);
+ }
+ }
+
+ if (canonMethodSignature.Length > 0)
+ Append(", ");
+ }
+
+ PassCallArguments(canonMethodSignature, thisArgument);
+ Append(")");
}
- PassCallArguments(methodSignature, thisArgument);
- Append(")");
if (temp != null)
{
Debug.Assert(retKind != StackValueKind.Unknown, "Valid return type");
+
+ if (opcode != ILOpcode.newobj &&
+ retType != _writer.ConvertToCanonFormIfNecessary(canonMethodSignature.ReturnType, CanonicalFormKind.Specific))
+ {
+ string retVar = temp;
+ retKind = GetStackValueKind(retType);
+ temp = NewTempName();
+
+ AppendSemicolon();
+ Append(GetStackValueKindCPPTypeName(retKind, retType));
+ Append(" ");
+ Append(temp);
+ Append(" = ");
+
+ if (retType.IsValueType && !retType.IsPrimitive)
+ {
+ Append("*(");
+ Append(_writer.GetCppSignatureTypeName(retType));
+ Append("*)&");
+ }
+ else
+ {
+ Append("(");
+ Append(_writer.GetCppSignatureTypeName(retType));
+ Append(")");
+ }
+ Append(retVar);
+ }
+
PushExpression(retKind, temp, retType);
}
AppendSemicolon();
@@ -1388,54 +1926,76 @@ private void GetFunctionPointerForInterfaceMethod(MethodDesc method, ExpressionE
// Get EEType of interface
Append("((::System_Private_CoreLib::Internal::Runtime::EEType *)(");
- Append(_writer.GetCppTypeName(method.OwningType));
- Append("::__getMethodTable()))");
+
+ if (method.OwningType.IsRuntimeDeterminedSubtype)
+ {
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, method.OwningType));
+ Append("(");
+ Append(GetGenericContext());
+ Append(")))");
+ }
+ else
+ {
+ Append(_writer.GetCppTypeName(method.OwningType));
+ Append("::__getMethodTable()))");
+ }
Append(", ");
+ MethodDesc canonMethod = method.GetCanonMethodTarget(CanonicalFormKind.Specific);
+
// Get slot of implementation
Append("(uint16_t)");
Append("(");
- Append(_writer.GetCppTypeName(method.OwningType));
+ Append(_writer.GetCppTypeName(canonMethod.OwningType));
Append("::");
Append("__getslot__");
- Append(_writer.GetCppMethodName(method));
+ Append(_writer.GetCppMethodName(canonMethod));
Append("(");
Append(v.Name);
Append("))");
- Append("));");
+ Append("));");
+ }
+
+ private void PassThisArgumentIfNeeded(MethodSignature methodSignature, TypeDesc thisArgument)
+ {
+ if (thisArgument == null)
+ return;
+
+ int signatureLength = methodSignature.Length;
+ int argumentsCount = (thisArgument != null) ? (signatureLength + 1) : signatureLength;
+ int thisIndex = _stack.Top - argumentsCount;
+
+ var op = _stack[thisIndex];
+ AppendCastIfNecessary(_writer.ConvertToCanonFormIfNecessary(thisArgument, CanonicalFormKind.Specific), op);
+ Append(op);
}
- private void PassCallArguments(MethodSignature methodSignature, TypeDesc thisArgument)
+ private void PassCallArguments(MethodSignature methodSignature, TypeDesc thisArgument, bool clearStack = true)
{
int signatureLength = methodSignature.Length;
int argumentsCount = (thisArgument != null) ? (signatureLength + 1) : signatureLength;
- int startingIndex = _stack.Top - argumentsCount;
- for (int i = 0; i < argumentsCount; i++)
+ int startingIndex = _stack.Top - signatureLength;
+
+ for (int i = 0; i < signatureLength; i++)
{
var op = _stack[startingIndex + i];
- int argIndex = signatureLength - (argumentsCount - i);
- TypeDesc argType;
- if (argIndex == -1)
- {
- argType = thisArgument;
- }
- else
- {
- argType = methodSignature[argIndex];
- }
- AppendCastIfNecessary(argType, op);
+
+ AppendCastIfNecessary(_writer.ConvertToCanonFormIfNecessary(methodSignature[i], CanonicalFormKind.Specific), op);
Append(op);
- if (i + 1 != argumentsCount)
+
+ if (i != signatureLength - 1)
Append(", ");
}
- _stack.PopN(argumentsCount);
+
+ if (clearStack)
+ _stack.PopN(argumentsCount);
}
private void ImportCalli(int token)
{
- MethodSignature methodSignature = (MethodSignature)_methodIL.GetObject(token);
+ MethodSignature methodSignature = (MethodSignature)_canonMethodIL.GetObject(token);
TypeDesc thisArgument = null;
if (!methodSignature.IsStatic)
@@ -1445,9 +2005,6 @@ private void ImportCalli(int token)
thisArgument = thisArgument.MakeByRefType();
}
- string typeDefName = "__calli__" + token.ToStringInvariant("x8");
- _writer.AppendSignatureTypeDef(_builder, typeDefName, methodSignature, thisArgument);
-
TypeDesc retType = methodSignature.ReturnType;
StackValueKind retKind = StackValueKind.Unknown;
@@ -1461,6 +2018,40 @@ private void ImportCalli(int token)
AppendLine();
Append(GetStackValueKindCPPTypeName(retKind, retType));
Append(" ");
+ Append(temp);
+ AppendSemicolon();
+ }
+ else
+ {
+ AppendLine();
+ }
+
+ var fnPtrValue = _stack.Pop();
+
+ string fatPtr = NewTempName();
+
+ Append("intptr_t ");
+ Append(fatPtr);
+ Append(" = ");
+ Append(fnPtrValue);
+
+ AppendSemicolon();
+
+ Append("if (");
+ Append(fatPtr);
+ Append(" & 0x2) {");
+ Append(fnPtrValue);
+ Append(" = *(intptr_t*)(");
+ Append(fatPtr);
+ Append(" - 0x2)");
+
+ AppendSemicolon();
+
+ string typeDefName = "__calli__" + token.ToStringInvariant("x8");
+ _writer.AppendSignatureTypeDef(_builder, typeDefName, methodSignature, thisArgument, true);
+
+ if (!retType.IsVoid)
+ {
Append(temp);
Append(" = ");
@@ -1469,74 +2060,183 @@ private void ImportCalli(int token)
Append("(intptr_t)");
}
}
- else
+
+ Append("((");
+ Append(typeDefName);
+ Append(")");
+ Append(fnPtrValue);
+ Append(")(");
+
+ PassThisArgumentIfNeeded(methodSignature, thisArgument);
+
+ if (thisArgument != null)
+ Append(", ");
+
+ Append("**(void***)(");
+ Append(fatPtr);
+ Append(" - 0x2 + sizeof(void*))");
+
+ if (methodSignature.Length > 0)
+ Append(", ");
+
+ PassCallArguments(methodSignature, thisArgument, false);
+ Append(")");
+
+ AppendSemicolon();
+
+ Append("} else {");
+
+ _writer.AppendSignatureTypeDef(_builder, typeDefName, methodSignature, thisArgument, false);
+
+ if (!retType.IsVoid)
{
- AppendLine();
+ Append(temp);
+ Append(" = ");
+
+ if (retType.IsPointer)
+ {
+ Append("(intptr_t)");
+ }
}
- var fnPtrValue = _stack.Pop();
Append("((");
Append(typeDefName);
Append(")");
Append(fnPtrValue);
Append(")(");
+ PassThisArgumentIfNeeded(methodSignature, thisArgument);
+
+ if (thisArgument != null && methodSignature.Length > 0)
+ Append(", ");
+
PassCallArguments(methodSignature, thisArgument);
Append(")");
+ AppendSemicolon();
+ Append("}");
+
+ AppendSemicolon();
+
if (temp != null)
{
Debug.Assert(retKind != StackValueKind.Unknown, "Valid return type");
PushExpression(retKind, temp, retType);
}
-
- AppendSemicolon();
}
private void ImportLdFtn(int token, ILOpcode opCode)
{
- MethodDesc method = (MethodDesc)_methodIL.GetObject(token);
+ MethodDesc runtimeDeterminedMethod = (MethodDesc)_methodIL.GetObject(token);
+ MethodDesc method = ((MethodDesc)_canonMethodIL.GetObject(token));
+ MethodDesc canonMethod = method.GetCanonMethodTarget(CanonicalFormKind.Specific);
- if (opCode == ILOpcode.ldvirtftn && method.IsVirtual && method.OwningType.IsInterface)
+ if (opCode == ILOpcode.ldvirtftn && canonMethod.IsVirtual && !canonMethod.HasInstantiation && canonMethod.OwningType.IsInterface)
{
- AddVirtualMethodReference(method);
- var entry = new LdTokenEntry(StackValueKind.NativeInt, NewTempName(), method);
+ AddVirtualMethodReference(canonMethod);
+ var entry = new LdFtnTokenEntry(StackValueKind.NativeInt, NewTempName(), runtimeDeterminedMethod, true);
ExpressionEntry v = (ExpressionEntry)_stack.Pop();
- string typeDefName = _writer.GetCppMethodName(method);
- _writer.AppendSignatureTypeDef(_builder, typeDefName, method.Signature, method.OwningType);
+ string typeDefName = _writer.GetCppTypeName(canonMethod.OwningType) + "_" + _writer.GetCppMethodName(canonMethod);
+ typeDefName = typeDefName.Replace("::", "_");
+ _writer.AppendSignatureTypeDef(_builder, typeDefName, canonMethod.Signature, canonMethod.OwningType);
AppendEmptyLine();
PushTemp(entry);
Append("(intptr_t) ");
- GetFunctionPointerForInterfaceMethod(method, v, typeDefName);
+ GetFunctionPointerForInterfaceMethod(runtimeDeterminedMethod, v, typeDefName);
}
else
{
- AddMethodReference(method);
- var entry = new LdTokenEntry(StackValueKind.NativeInt, NewTempName(), method);
-
- if (opCode == ILOpcode.ldvirtftn && method.IsVirtual)
+ bool isVirtual = opCode == ILOpcode.ldvirtftn && canonMethod.IsVirtual;
+ var entry = new LdFtnTokenEntry(StackValueKind.NativeInt, NewTempName(), runtimeDeterminedMethod, isVirtual);
+
+ if (isVirtual)
{
//ldvirtftn requires an object instance, we have to pop one off the stack
//then call the associated getslot method passing in the object instance to get the real function pointer
ExpressionEntry v = (ExpressionEntry)_stack.Pop();
+
PushTemp(entry);
Append("(intptr_t)");
- Append(_writer.GetCppTypeName(method.OwningType));
- Append("::__getslot__");
- Append(_writer.GetCppMethodName(method));
- Append("(");
- Append(v.Name);
- Append(")");
+
+ if (!canonMethod.HasInstantiation)
+ {
+ Append(_writer.GetCppTypeName(canonMethod.OwningType));
+ Append("::__getslot__");
+ Append(_writer.GetCppMethodName(canonMethod));
+ Append("(");
+ Append(v.Name);
+ Append(")");
+ }
+ else
+ {
+ MethodDesc helper = _typeSystemContext.SystemModule.GetKnownType("System.Runtime", "TypeLoaderExports").GetKnownMethod("GVMLookupForSlot", null);
+ AddMethodReference(helper);
+
+ Append(_writer.GetCppTypeName(helper.OwningType) + "::" + _writer.GetCppMethodName(helper));
+ Append("(");
+ Append("(::System_Private_CoreLib::System::Object*)");
+ Append(v.Name);
+ Append(", ");
+
+ if (method.IsSharedByGenericInstantiations)
+ {
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.MethodHandle, runtimeDeterminedMethod));
+ Append("(");
+ Append(GetGenericContext());
+ Append(")");
+ }
+ else
+ {
+ AppendRuntimeMethodHandle(runtimeDeterminedMethod);
+ Append("()");
+ }
+ Append(")");
+ }
AppendSemicolon();
+
+ if (!canonMethod.HasInstantiation && !_nodeFactory.VTable(canonMethod.OwningType).HasFixedSlots)
+ _dependencies.Add(_nodeFactory.VirtualMethodUse(canonMethod));
+ else if (canonMethod.HasInstantiation)
+ _dependencies.Add(_nodeFactory.GVMDependencies(canonMethod));
}
else
{
+ bool exactContextNeedsRuntimeLookup;
+ if (method.HasInstantiation)
+ {
+ exactContextNeedsRuntimeLookup = method.IsSharedByGenericInstantiations;
+ }
+ else
+ {
+ exactContextNeedsRuntimeLookup = method.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any);
+ }
+
PushTemp(entry);
- Append("(intptr_t)&");
- Append(_writer.GetCppTypeName(method.OwningType));
- Append("::");
- Append(_writer.GetCppMethodName(method));
+
+ bool needUnbox = canonMethod.OwningType.IsValueType && !canonMethod.Signature.IsStatic;
+
+ if (canonMethod.IsSharedByGenericInstantiations && (canonMethod.HasInstantiation || canonMethod.Signature.IsStatic))
+ {
+ if (exactContextNeedsRuntimeLookup)
+ {
+ // Actual address will be obtained in runtime helper
+ Append("0");
+ }
+ else
+ {
+ Append("((intptr_t)");
+ AppendFatFunctionPointer(runtimeDeterminedMethod, needUnbox);
+ Append("()) + 0x2");
+ }
+ }
+ else
+ {
+ Append("(intptr_t)&");
+ Append(_writer.GetCppTypeName(canonMethod.OwningType));
+ Append("::");
+ AppendMethodAndAddReference(canonMethod, needUnbox);
+ }
AppendSemicolon();
}
@@ -1863,51 +2563,69 @@ private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool
private void ImportLoadField(int token, bool isStatic)
{
- FieldDesc field = (FieldDesc)_methodIL.GetObject(token);
-
- AddFieldReference(field);
+ FieldDesc runtimeDeterminedField = (FieldDesc)_methodIL.GetObject(token);
+ FieldDesc field = (FieldDesc)_canonMethodIL.GetObject(token);
var thisPtr = isStatic ? InvalidEntry.Entry : _stack.Pop();
- TypeDesc owningType = field.OwningType;
- TypeDesc fieldType = field.FieldType;
+ TypeDesc runtimeDeterminedOwningType = runtimeDeterminedField.OwningType;
+
+ TypeDesc owningType = _writer.ConvertToCanonFormIfNecessary(field.OwningType, CanonicalFormKind.Specific);
+ TypeDesc fieldType = _writer.ConvertToCanonFormIfNecessary(field.FieldType, CanonicalFormKind.Specific);
// TODO: Is this valid combination?
if (!isStatic && !owningType.IsValueType && thisPtr.Kind != StackValueKind.ObjRef)
throw new InvalidProgramException();
- if (field.IsStatic)
- TriggerCctor(field.OwningType);
+ if (!runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic)
+ TriggerCctor(runtimeDeterminedField.OwningType);
StackValueKind kind = GetStackValueKind(fieldType);
PushTemp(kind, fieldType);
AppendCastIfNecessary(kind, fieldType);
- if (field.IsStatic)
+ if (runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic)
{
- if (!fieldType.IsValueType)
- Append("__gcStatics.");
- else
- Append("__statics.");
- Append(_writer.GetCppStaticFieldName(field));
- }
- else
- if (thisPtr.Kind == StackValueKind.ValueType)
- {
- Append(thisPtr);
- Append(".");
+ AddTypeReference(fieldType, false);
+
+ Append("(((");
+ Append(_writer.GetCppStaticsTypeName(owningType, field.HasGCStaticBase, field.IsThreadStatic));
+ Append("*)");
+ AppendStaticFieldGenericLookupHelperAndAddReference(runtimeDeterminedField);
+ Append("(");
+ Append(GetGenericContext());
+ Append("))->");
Append(_writer.GetCppFieldName(field));
+ Append(")");
}
else
{
- Append("((");
- Append(_writer.GetCppTypeName(owningType));
- Append("*)");
- Append(thisPtr);
- Append(")->");
- Append(_writer.GetCppFieldName(field));
+ AddFieldReference(field);
+
+ if (field.IsStatic)
+ {
+ Append(_writer.GetCppStaticsName(owningType, field.HasGCStaticBase, field.IsThreadStatic));
+ Append(".");
+ Append(_writer.GetCppFieldName(field));
+ }
+ else
+ if (thisPtr.Kind == StackValueKind.ValueType)
+ {
+ Append(thisPtr);
+ Append(".");
+ Append(_writer.GetCppFieldName(field));
+ }
+ else
+ {
+ Append("((");
+ Append(_writer.GetCppTypeName(owningType));
+ Append("*)");
+ Append(thisPtr);
+ Append(")->");
+ Append(_writer.GetCppFieldName(field));
- GetSignatureTypeNameAndAddReference(owningType);
+ GetSignatureTypeNameAndAddReference(owningType);
+ }
}
AppendSemicolon();
@@ -1915,52 +2633,75 @@ private void ImportLoadField(int token, bool isStatic)
private void ImportAddressOfField(int token, bool isStatic)
{
- FieldDesc field = (FieldDesc)_methodIL.GetObject(token);
-
- AddFieldReference(field);
+ FieldDesc runtimeDeterminedField = (FieldDesc)_methodIL.GetObject(token);
+ FieldDesc field = (FieldDesc)_canonMethodIL.GetObject(token);
var thisPtr = isStatic ? InvalidEntry.Entry : _stack.Pop();
- TypeDesc owningType = field.OwningType;
- TypeDesc fieldType = field.FieldType;
+ TypeDesc runtimeDeterminedOwningType = runtimeDeterminedField.OwningType;
+
+ TypeDesc owningType = _writer.ConvertToCanonFormIfNecessary(field.OwningType, CanonicalFormKind.Specific);
+ TypeDesc fieldType = _writer.ConvertToCanonFormIfNecessary(field.FieldType, CanonicalFormKind.Specific);
// TODO: Is this valid combination?
if (!isStatic && !owningType.IsValueType && thisPtr.Kind != StackValueKind.ObjRef)
throw new InvalidProgramException();
- if (field.IsStatic)
- TriggerCctor(field.OwningType);
+ if (!runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic)
+ TriggerCctor(runtimeDeterminedField.OwningType);
TypeDesc addressType = fieldType.MakeByRefType();
StackValueKind kind = GetStackValueKind(addressType);
PushTemp(kind, addressType);
- AppendCastIfNecessary(kind, addressType);
- Append("&");
-
- if (field.IsStatic)
- {
- if (!fieldType.IsValueType)
- Append("__gcStatics.");
- else
- Append("__statics.");
- Append(_writer.GetCppStaticFieldName(field));
- }
- else
- if (thisPtr.Kind == StackValueKind.ValueType)
+ if (runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic)
{
- throw new NotImplementedException();
+ AddTypeReference(fieldType, false);
+
+ AppendCastIfNecessary(kind, addressType);
+
+ Append("&");
+
+ Append("(((");
+ Append(_writer.GetCppStaticsTypeName(owningType, field.HasGCStaticBase, field.IsThreadStatic));
+ Append("*)");
+ AppendStaticFieldGenericLookupHelperAndAddReference(runtimeDeterminedField);
+ Append("(");
+ Append(GetGenericContext());
+ Append("))->");
+ Append(_writer.GetCppFieldName(field));
+ Append(")");
}
else
{
- Append("((");
- Append(_writer.GetCppTypeName(owningType));
- Append("*)");
- Append(thisPtr);
- Append(")->");
- Append(_writer.GetCppFieldName(field));
+ AddFieldReference(field);
+
+ AppendCastIfNecessary(kind, addressType);
+
+ Append("&");
+
+ if (field.IsStatic)
+ {
+ Append(_writer.GetCppStaticsName(owningType, field.HasGCStaticBase, field.IsThreadStatic));
+ Append(".");
+ Append(_writer.GetCppFieldName(field));
+ }
+ else
+ if (thisPtr.Kind == StackValueKind.ValueType)
+ {
+ throw new NotImplementedException();
+ }
+ else
+ {
+ Append("((");
+ Append(_writer.GetCppTypeName(owningType));
+ Append("*)");
+ Append(thisPtr);
+ Append(")->");
+ Append(_writer.GetCppFieldName(field));
- GetSignatureTypeNameAndAddReference(owningType);
+ GetSignatureTypeNameAndAddReference(owningType);
+ }
}
AppendSemicolon();
@@ -1969,49 +2710,66 @@ private void ImportAddressOfField(int token, bool isStatic)
private void ImportStoreField(int token, bool isStatic)
{
- FieldDesc field = (FieldDesc)_methodIL.GetObject(token);
-
- AddFieldReference(field);
+ FieldDesc runtimeDeterminedField = (FieldDesc)_methodIL.GetObject(token);
+ FieldDesc field = (FieldDesc)_canonMethodIL.GetObject(token);
var value = _stack.Pop();
var thisPtr = isStatic ? InvalidEntry.Entry : _stack.Pop();
- TypeDesc owningType = field.OwningType;
- TypeDesc fieldType = field.FieldType;
+ TypeDesc runtimeDeterminedOwningType = runtimeDeterminedField.OwningType;
+
+ TypeDesc owningType = _writer.ConvertToCanonFormIfNecessary(field.OwningType, CanonicalFormKind.Specific);
+ TypeDesc fieldType = _writer.ConvertToCanonFormIfNecessary(field.FieldType, CanonicalFormKind.Specific);
// TODO: Is this valid combination?
if (!isStatic && !owningType.IsValueType && thisPtr.Kind != StackValueKind.ObjRef)
throw new InvalidProgramException();
- if (field.IsStatic)
- TriggerCctor(field.OwningType);
-
- // TODO: Write barrier as necessary!!!
+ if (!runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic)
+ TriggerCctor(runtimeDeterminedField.OwningType);
- AppendLine();
- if (field.IsStatic)
- {
- if (!fieldType.IsValueType)
- Append("__gcStatics.");
- else
- Append("__statics.");
- Append(_writer.GetCppStaticFieldName(field));
- }
- else if (thisPtr.Kind == StackValueKind.ValueType)
+ if (runtimeDeterminedOwningType.IsRuntimeDeterminedSubtype && field.IsStatic)
{
- throw new NotImplementedException();
+ Append("(((");
+ Append(_writer.GetCppStaticsTypeName(owningType, field.HasGCStaticBase, field.IsThreadStatic));
+ Append("*)");
+ AppendStaticFieldGenericLookupHelperAndAddReference(runtimeDeterminedField);
+ Append("(");
+ Append(GetGenericContext());
+ Append("))->");
+ Append(_writer.GetCppFieldName(field));
+ Append(")");
}
else
{
- Append("((");
- Append(_writer.GetCppTypeName(owningType));
- Append("*)");
- Append(thisPtr);
- Append(")->");
- Append(_writer.GetCppFieldName(field));
+ AddFieldReference(field);
+
+ // TODO: Write barrier as necessary!!!
+
+ AppendLine();
+ if (field.IsStatic)
+ {
+ Append(_writer.GetCppStaticsName(owningType, field.HasGCStaticBase, field.IsThreadStatic));
+ Append(".");
+ Append(_writer.GetCppFieldName(field));
+ }
+ else if (thisPtr.Kind == StackValueKind.ValueType)
+ {
+ throw new NotImplementedException();
+ }
+ else
+ {
+ Append("((");
+ Append(_writer.GetCppTypeName(owningType));
+ Append("*)");
+ Append(thisPtr);
+ Append(")->");
+ Append(_writer.GetCppFieldName(field));
- GetSignatureTypeNameAndAddReference(owningType);
+ GetSignatureTypeNameAndAddReference(owningType);
+ }
}
+
Append(" = ");
if (!fieldType.IsValueType)
{
@@ -2127,13 +2885,14 @@ private void ImportLoadString(int token)
private void ImportInitObj(int token)
{
- TypeDesc type = (TypeDesc)_methodIL.GetObject(token);
+ TypeDesc type = (TypeDesc)_canonMethodIL.GetObject(token);
+
var addr = _stack.Pop();
AppendLine();
Append("::memset((void*)");
Append(addr);
Append(",0,sizeof(");
- Append(GetSignatureTypeNameAndAddReference(type));
+ Append(GetSignatureTypeNameAndAddReference(_writer.ConvertToCanonFormIfNecessary(type, CanonicalFormKind.Specific)));
Append("))");
AppendSemicolon();
}
@@ -2155,14 +2914,31 @@ private void ImportBox(int token)
private ExpressionEntry BoxValue(TypeDesc type, StackEntry value)
{
string tempName = NewTempName();
+ TypeDesc runtimeDeterminedType = type;
+
+ if (type.IsRuntimeDeterminedSubtype)
+ type = type.ConvertToCanonForm(CanonicalFormKind.Specific);
AddTypeReference(type, true);
Append(GetStackValueKindCPPTypeName(StackValueKind.ObjRef, type));
Append(" ");
Append(tempName);
Append(" = __allocate_object(");
- Append(_writer.GetCppTypeName(type));
- Append("::__getMethodTable())");
+
+ if (runtimeDeterminedType.IsRuntimeDeterminedSubtype)
+ {
+ Append("(MethodTable *)");
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeDeterminedType));
+ Append("(");
+ Append(GetGenericContext());
+ Append("))");
+ }
+ else
+ {
+ Append(_writer.GetCppTypeName(type));
+ Append("::__getMethodTable())");
+ }
+
AppendSemicolon();
string typeName = GetStackValueKindCPPTypeName(GetStackValueKind(type), type);
@@ -2278,20 +3054,35 @@ private void ImportEndFinally()
private void ImportNewArray(int token)
{
- TypeDesc type = (TypeDesc)_methodIL.GetObject(token);
- TypeDesc arrayType = type.Context.GetArrayType(type);
+ TypeDesc runtimeDeterminedType = (TypeDesc)_methodIL.GetObject(token);
+ TypeDesc runtimeDeterminedArrayType = runtimeDeterminedType.MakeArrayType();
+ TypeDesc type = (TypeDesc)_canonMethodIL.GetObject(token);
+ TypeDesc arrayType = _writer.ConvertToCanonFormIfNecessary(type.MakeArrayType(), CanonicalFormKind.Specific);
var numElements = _stack.Pop();
PushTemp(StackValueKind.ObjRef, arrayType);
- AddTypeReference(arrayType, true);
-
Append("__allocate_array(");
Append(numElements);
Append(", ");
- Append(_writer.GetCppTypeName(arrayType));
- Append("::__getMethodTable()");
+
+ AddTypeReference(arrayType, true);
+
+ if (runtimeDeterminedType.IsRuntimeDeterminedSubtype)
+ {
+ Append("(MethodTable *)");
+ Append(GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, runtimeDeterminedArrayType));
+ Append("(");
+ Append(GetGenericContext());
+ Append(")");
+ }
+ else
+ {
+ Append(_writer.GetCppTypeName(runtimeDeterminedArrayType));
+ Append("::__getMethodTable()");
+ }
+
Append(")");
AppendSemicolon();
}
@@ -2381,7 +3172,7 @@ private void ImportStoreElement(TypeDesc elementType)
private void ImportAddressOfElement(int token)
{
- TypeDesc elementType = (TypeDesc)_methodIL.GetObject(token);
+ TypeDesc elementType = (TypeDesc)_canonMethodIL.GetObject(token);
var index = _stack.Pop();
var arrayPtr = _stack.Pop();
@@ -2507,13 +3298,14 @@ private void ImportMkRefAny(int token)
private void ImportLdToken(int token)
{
var ldtokenValue = _methodIL.GetObject(token);
+
WellKnownType ldtokenKind;
string name;
StackEntry value;
if (ldtokenValue is TypeDesc)
{
ldtokenKind = WellKnownType.RuntimeTypeHandle;
- AddTypeReference((TypeDesc)ldtokenValue, false);
+ TypeDesc type = (TypeDesc)ldtokenValue;
MethodDesc helper = _typeSystemContext.GetHelperEntryPoint("LdTokenHelpers", "GetRuntimeTypeHandle");
AddMethodReference(helper);
@@ -2521,12 +3313,30 @@ private void ImportLdToken(int token)
name = String.Concat(
_writer.GetCppTypeName(helper.OwningType),
"::",
- _writer.GetCppMethodName(helper),
- "((intptr_t)",
- _compilation.NameMangler.GetMangledTypeName((TypeDesc)ldtokenValue),
- "::__getMethodTable())");
+ _writer.GetCppMethodName(helper));
+
+ if (type.IsRuntimeDeterminedSubtype)
+ {
+ name = String.Concat(
+ name,
+ "((intptr_t)",
+ GetGenericLookupHelperAndAddReference(ReadyToRunHelperId.TypeHandle, type),
+ "(",
+ GetGenericContext(),
+ "))");
+ }
+ else
+ {
+ AddTypeReference(type, false);
+
+ name = String.Concat(
+ name,
+ "((intptr_t)",
+ _compilation.NameMangler.GetMangledTypeName(type),
+ "::__getMethodTable())");
+ }
- value = new LdTokenEntry(StackValueKind.ValueType, name, (TypeDesc)ldtokenValue, GetWellKnownType(ldtokenKind));
+ value = new LdTokenEntry(StackValueKind.ValueType, name, type, GetWellKnownType(ldtokenKind));
}
else if (ldtokenValue is FieldDesc)
{
@@ -2633,7 +3443,7 @@ private void ImportConstrainedPrefix(int token)
{
_pendingPrefix |= Prefix.Constrained;
- _constrained = ResolveTypeToken(token);
+ _constrained = (TypeDesc)_methodIL.GetObject(token);
}
private void ImportNoPrefix(byte mask)
@@ -2648,6 +3458,8 @@ private void ImportReadOnlyPrefix()
private void TriggerCctor(TypeDesc type)
{
+ Debug.Assert(!type.IsRuntimeDeterminedSubtype);
+
// TODO: Before field init
MethodDesc cctor = type.GetStaticConstructor();
@@ -2656,22 +3468,32 @@ private void TriggerCctor(TypeDesc type)
// TODO: Thread safety
- string ctorHasRun = "__statics.__cctor_" + _writer.GetCppTypeName(type).Replace("::", "__");
+ 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(cctor.OwningType));
+ Append(_writer.GetCppTypeName(canonCctor.OwningType));
Append("::");
- Append(_writer.GetCppMethodName(cctor));
- Append("();");
+ Append(_writer.GetCppMethodName(canonCctor));
+ Append("(");
+
+ if (canonCctor != cctor)
+ {
+ Append(_writer.GetCppTypeName(cctor.OwningType));
+ Append("::__getMethodTable()");
+ }
+
+ Append(");");
Exdent();
AppendLine();
Append("}");
- AddMethodReference(cctor);
+ AddMethodReference(canonCctor);
}
private void AddTypeReference(TypeDesc type, bool constructed)
@@ -2686,13 +3508,16 @@ private void AddTypeReference(TypeDesc type, bool constructed)
{
foreach (var field in type.GetFields())
{
- AddTypeDependency(field.FieldType, false);
+ AddTypeDependency(_writer.ConvertToCanonFormIfNecessary(field.FieldType, CanonicalFormKind.Specific), false);
}
}
}
private void AddTypeDependency(TypeDesc type, bool constructed)
{
- if (type.IsPrimitive)
+ Debug.Assert(!type.IsRuntimeDeterminedSubtype);
+
+ if (type.IsPrimitive ||
+ type.IsCanonicalSubtype(CanonicalFormKind.Any) && (type.IsPointer || type.IsByRef))
{
return;
}
@@ -2712,6 +3537,11 @@ private void AddMethodReference(MethodDesc method)
_dependencies.Add(_nodeFactory.MethodEntrypoint(method));
}
+ private void AddCanonicalReference(MethodDesc method)
+ {
+ _dependencies.Add(_nodeFactory.CanonicalEntrypoint(method));
+ }
+
private void AddVirtualMethodReference(MethodDesc method)
{
_dependencies.Add(_nodeFactory.VirtualMethodUse(method));
@@ -2719,28 +3549,34 @@ private void AddVirtualMethodReference(MethodDesc method)
private void AddFieldReference(FieldDesc field)
{
+ var owningType = field.OwningType;
+
+ Debug.Assert(!owningType.IsRuntimeDeterminedSubtype);
+
if (field.IsStatic)
{
- var owningType = (MetadataType)field.OwningType;
+ var metadataType = owningType as MetadataType;
Object node;
if (field.IsThreadStatic)
{
- node = _nodeFactory.TypeThreadStaticsSymbol(owningType);
+ node = _nodeFactory.TypeThreadStaticsSymbol(metadataType);
}
else
{
if (field.HasGCStaticBase)
- node = _nodeFactory.TypeGCStaticsSymbol(owningType);
+ node = _nodeFactory.TypeGCStaticsSymbol(metadataType);
else
- node = _nodeFactory.TypeNonGCStaticsSymbol(owningType);
+ node = _nodeFactory.TypeNonGCStaticsSymbol(metadataType);
}
// TODO: Remove once the dependencies for static fields are tracked properly
- GetSignatureTypeNameAndAddReference(owningType, true);
+ GetSignatureTypeNameAndAddReference(metadataType, true);
_dependencies.Add(node);
}
- AddTypeReference(field.FieldType, false);
+
+ var fieldType = field.FieldType;
+ AddTypeReference(_writer.ConvertToCanonFormIfNecessary(fieldType, CanonicalFormKind.Specific), false);
}
private string GetSignatureTypeNameAndAddReference(TypeDesc type, bool constructed = true)
diff --git a/src/ILCompiler/src/Program.cs b/src/ILCompiler/src/Program.cs
index 12ca1a33886..8099f113fc9 100644
--- a/src/ILCompiler/src/Program.cs
+++ b/src/ILCompiler/src/Program.cs
@@ -278,7 +278,7 @@ private int Run(string[] args)
// Initialize type system context
//
- SharedGenericsMode genericsMode = _useSharedGenerics || (!_isCppCodegen && !_isWasmCodegen) ?
+ SharedGenericsMode genericsMode = _useSharedGenerics || !_isWasmCodegen ?
SharedGenericsMode.CanonicalReferenceTypes : SharedGenericsMode.Disabled;
// TODO: compiler switch for SIMD support?
@@ -450,7 +450,7 @@ private int Run(string[] args)
useScanner &= !_noScanner;
- bool supportsReflection = !_isWasmCodegen && !_isCppCodegen && _systemModuleName == DefaultSystemModule;
+ bool supportsReflection = !_isWasmCodegen && _systemModuleName == DefaultSystemModule;
MetadataManager compilationMetadataManager = supportsReflection ? metadataManager : (MetadataManager)new EmptyMetadataManager(typeSystemContext);
ILScanResults scanResults = null;
diff --git a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ExternalReferencesTable.cs b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ExternalReferencesTable.cs
index 3c6a9d382a4..7bd5bd845ab 100644
--- a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ExternalReferencesTable.cs
+++ b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ExternalReferencesTable.cs
@@ -105,12 +105,7 @@ unsafe public IntPtr GetIntPtrFromIndex(uint index)
return (IntPtr)(_moduleHandle.ConvertRVAToPointer(rva));
}
#else
- if (index >= _elementsCount)
- throw new BadImageFormatException();
-
- // TODO: indirection through IAT
- int* pRelPtr32 = &((int*)_elements)[index];
- return (IntPtr)((byte*)pRelPtr32 + *pRelPtr32);
+ return GetFieldAddressFromIndex(index);
#endif
}
@@ -128,12 +123,7 @@ unsafe public IntPtr GetFunctionPointerFromIndex(uint index)
return (IntPtr)(_moduleHandle.ConvertRVAToPointer(rva));
}
#else
- if (index >= _elementsCount)
- throw new BadImageFormatException();
-
- // TODO: indirection through IAT
- int* pRelPtr32 = &((int*)_elements)[index];
- return (IntPtr)((byte*)pRelPtr32 + *pRelPtr32);
+ return GetFieldAddressFromIndex(index);
#endif
}
@@ -161,8 +151,13 @@ unsafe public IntPtr GetFieldAddressFromIndex(uint index)
throw new BadImageFormatException();
// TODO: indirection through IAT
- int* pRelPtr32 = &((int*)_elements)[index];
- return (IntPtr)((byte*)pRelPtr32 + *pRelPtr32);
+ if (EEType.SupportsRelativePointers)
+ {
+ int* pRelPtr32 = &((int*)_elements)[index];
+ return (IntPtr)((byte*)pRelPtr32 + *pRelPtr32);
+ }
+
+ return (IntPtr)(((void**)_elements)[index]);
}
#endif