Merge pull request #69 from MichalStrehovsky/cctorsupport
Add support for running class constructors
This commit is contained in:
Коммит
49072fb834
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using Debug = System.Diagnostics.Debug;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
|
@ -31,17 +32,25 @@ namespace System.Collections.Generic
|
|||
|
||||
public void Append(T[] newItems)
|
||||
{
|
||||
if (_items == null || (_count + newItems.Length) >= _items.Length)
|
||||
var oldCount = _count;
|
||||
ZeroExtend(newItems.Length);
|
||||
Array.Copy(newItems, 0, _items, oldCount, newItems.Length);
|
||||
}
|
||||
|
||||
public void ZeroExtend(int numItems)
|
||||
{
|
||||
Debug.Assert(numItems >= 0);
|
||||
|
||||
if (_items == null || (_count + numItems) >= _items.Length)
|
||||
{
|
||||
int newCount = 2 * _count + 1;
|
||||
while ((_count + newItems.Length) >= newCount)
|
||||
while ((_count + numItems) >= newCount)
|
||||
{
|
||||
newCount = 2 * newCount + 1;
|
||||
}
|
||||
Array.Resize(ref _items, newCount);
|
||||
}
|
||||
Array.Copy(newItems, 0, _items, _count, newItems.Length);
|
||||
_count += newItems.Length;
|
||||
_count += numItems;
|
||||
}
|
||||
|
||||
public int Count
|
||||
|
|
|
@ -695,6 +695,14 @@ namespace Internal.TypeSystem
|
|||
}
|
||||
}
|
||||
|
||||
public override bool IsBeforeFieldInit
|
||||
{
|
||||
get
|
||||
{
|
||||
return _typeDef.IsBeforeFieldInit;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsModuleType { get { return false; } }
|
||||
}
|
||||
|
||||
|
|
|
@ -157,6 +157,14 @@ namespace Internal.TypeSystem
|
|||
return _typeDef.Context.GetMethodForInstantiatedType(typicalMethodDef, this);
|
||||
}
|
||||
|
||||
public override MethodDesc GetStaticConstructor()
|
||||
{
|
||||
MethodDesc typicalCctor = _typeDef.GetStaticConstructor();
|
||||
if (typicalCctor == null)
|
||||
return null;
|
||||
return _typeDef.Context.GetMethodForInstantiatedType(typicalCctor, this);
|
||||
}
|
||||
|
||||
public override IEnumerable<FieldDesc> GetFields()
|
||||
{
|
||||
foreach (var fieldDef in _typeDef.GetFields())
|
||||
|
|
|
@ -5,12 +5,22 @@ namespace Internal.TypeSystem
|
|||
{
|
||||
public abstract partial class MetadataType : TypeDesc
|
||||
{
|
||||
public override bool HasStaticConstructor
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetStaticConstructor() != null;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract ClassLayoutMetadata GetClassLayout();
|
||||
|
||||
public abstract bool IsExplicitLayout { get; }
|
||||
|
||||
public abstract bool IsSequentialLayout { get; }
|
||||
|
||||
public abstract bool IsBeforeFieldInit { get; }
|
||||
|
||||
public abstract bool IsModuleType { get; }
|
||||
}
|
||||
|
||||
|
|
|
@ -251,6 +251,14 @@ namespace Internal.TypeSystem
|
|||
}
|
||||
}
|
||||
|
||||
public bool IsStaticConstructor
|
||||
{
|
||||
get
|
||||
{
|
||||
return this == this.OwningType.GetStaticConstructor();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string Name
|
||||
{
|
||||
get
|
||||
|
|
|
@ -336,6 +336,14 @@ namespace Internal.TypeSystem
|
|||
}
|
||||
}
|
||||
|
||||
public virtual bool HasStaticConstructor
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<MethodDesc> GetMethods()
|
||||
{
|
||||
return MethodDesc.EmptyMethods;
|
||||
|
@ -355,6 +363,11 @@ namespace Internal.TypeSystem
|
|||
return null;
|
||||
}
|
||||
|
||||
public virtual MethodDesc GetStaticConstructor()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<FieldDesc> GetFields()
|
||||
{
|
||||
return FieldDesc.EmptyFields;
|
||||
|
|
|
@ -248,6 +248,25 @@ namespace Internal.TypeSystem.Ecma
|
|||
return null;
|
||||
}
|
||||
|
||||
public override MethodDesc GetStaticConstructor()
|
||||
{
|
||||
var metadataReader = this.MetadataReader;
|
||||
var stringComparer = metadataReader.StringComparer;
|
||||
|
||||
foreach (var handle in _typeDefinition.GetMethods())
|
||||
{
|
||||
var methodDefinition = metadataReader.GetMethodDefinition(handle);
|
||||
if ((methodDefinition.Attributes & MethodAttributes.SpecialName) != 0 &&
|
||||
stringComparer.Equals(methodDefinition.Name, ".cctor"))
|
||||
{
|
||||
MethodDesc method = (MethodDesc)this.Module.GetObject(handle);
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override IEnumerable<FieldDesc> GetFields()
|
||||
{
|
||||
foreach (var handle in _typeDefinition.GetFields())
|
||||
|
@ -397,6 +416,14 @@ namespace Internal.TypeSystem.Ecma
|
|||
}
|
||||
}
|
||||
|
||||
public override bool IsBeforeFieldInit
|
||||
{
|
||||
get
|
||||
{
|
||||
return (_typeDefinition.Attributes & TypeAttributes.BeforeFieldInit) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsModuleType
|
||||
{
|
||||
get
|
||||
|
|
|
@ -288,6 +288,18 @@ namespace ILToNative
|
|||
Out.WriteLine("ret");
|
||||
break;
|
||||
|
||||
case ReadyToRunHelperId.CCtorTrigger:
|
||||
Out.Write("leaq __NonGCStaticBase_");
|
||||
Out.Write(NameMangler.GetMangledTypeName((TypeDesc)helper.Target));
|
||||
Out.WriteLine(" - 16(%rip), %rax");
|
||||
|
||||
Out.WriteLine("jmp *(%rax)");
|
||||
|
||||
// TODO: actually call into the managed helper that does a better job at this
|
||||
// and won't call the same constructor twice...
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
@ -382,19 +394,63 @@ namespace ILToNative
|
|||
if (type == null)
|
||||
continue;
|
||||
|
||||
if (type.NonGCStaticFieldSize == 0 && !type.HasStaticConstructor)
|
||||
continue;
|
||||
|
||||
// If the type has a class constructor, the GC statics section is prepended
|
||||
// by System.Runtime.CompilerServices.StaticClassConstructionContext.
|
||||
|
||||
bool isAligned = false;
|
||||
|
||||
if (type.HasStaticConstructor && _registeredMethods.ContainsKey(type.GetStaticConstructor()))
|
||||
{
|
||||
int pointerSize = type.Context.Target.PointerSize;
|
||||
|
||||
// TODO: Assert that StaticClassConstructionContext type has the expected size and alignment
|
||||
// (need to make it a well known type?)
|
||||
int alignmentRequired = Math.Max(type.NonGCStaticFieldAlignment, pointerSize);
|
||||
int classConstructionContextSize = 2 * pointerSize;
|
||||
|
||||
Out.Write(".align ");
|
||||
Out.WriteLine(alignmentRequired);
|
||||
|
||||
// Prepend the context to the existing fields without messing up the alignment of those fields.
|
||||
int classConstructorContextStorageSize = AlignmentHelper.AlignUp(classConstructionContextSize, alignmentRequired);
|
||||
|
||||
// Add padding before the context if alignment forces us to do so
|
||||
if (classConstructorContextStorageSize - classConstructionContextSize > 0)
|
||||
{
|
||||
Out.Write(".rept ");
|
||||
Out.WriteLine(classConstructorContextStorageSize - classConstructionContextSize);
|
||||
}
|
||||
|
||||
isAligned = true;
|
||||
|
||||
var cctorMethod = type.GetStaticConstructor();
|
||||
|
||||
Out.Write(".quad ");
|
||||
Out.WriteLine(NameMangler.GetMangledMethodName(cctorMethod));
|
||||
Out.WriteLine(".quad 0");
|
||||
}
|
||||
|
||||
Out.Write("__NonGCStaticBase_");
|
||||
Out.Write(NameMangler.GetMangledTypeName(type));
|
||||
Out.WriteLine(":");
|
||||
|
||||
if (type.NonGCStaticFieldSize > 0)
|
||||
{
|
||||
Out.Write(".align ");
|
||||
Out.WriteLine(type.NonGCStaticFieldAlignment);
|
||||
Out.Write("__NonGCStaticBase_");
|
||||
Out.Write(NameMangler.GetMangledTypeName(type));
|
||||
Out.WriteLine(":");
|
||||
if (!isAligned)
|
||||
{
|
||||
Out.Write(".align ");
|
||||
Out.WriteLine(type.NonGCStaticFieldAlignment);
|
||||
}
|
||||
Out.Write(".rept ");
|
||||
Out.WriteLine(type.NonGCStaticFieldSize);
|
||||
Out.WriteLine(".byte 0");
|
||||
Out.WriteLine(".endr");
|
||||
Out.WriteLine();
|
||||
}
|
||||
|
||||
Out.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ namespace ILToNative
|
|||
|
||||
if (!_options.IsCppCodeGen)
|
||||
{
|
||||
_nodeFactory = new NodeFactory(this._typeSystemContext.Target);
|
||||
_nodeFactory = new NodeFactory(this._typeSystemContext);
|
||||
NodeFactory.NameMangler = NameMangler;
|
||||
var rootNode = _nodeFactory.MethodEntrypoint(_mainMethod);
|
||||
|
||||
|
|
|
@ -49,8 +49,14 @@ namespace ILToNative
|
|||
"RuntimeFieldHandle",
|
||||
};
|
||||
|
||||
static readonly string[][] s_wellKnownEntrypointNames = new string[][] {
|
||||
new string[] { "System.Runtime.CompilerServices", "CctorHelper", "CheckStaticClassConstruction" }
|
||||
};
|
||||
|
||||
MetadataType[] _wellKnownTypes = new MetadataType[s_wellKnownTypeNames.Length];
|
||||
|
||||
MethodDesc[] _wellKnownEntrypoints = new MethodDesc[s_wellKnownEntrypointNames.Length];
|
||||
|
||||
EcmaModule _systemModule;
|
||||
|
||||
Dictionary<string, EcmaModule> _modules = new Dictionary<string, EcmaModule>(StringComparer.OrdinalIgnoreCase);
|
||||
|
@ -93,6 +99,16 @@ namespace ILToNative
|
|||
type.SetWellKnownType((WellKnownType)(typeIndex + 1));
|
||||
_wellKnownTypes[typeIndex] = type;
|
||||
}
|
||||
|
||||
// Initialize all well known entrypoints
|
||||
for (int entrypointIndex = 0; entrypointIndex < _wellKnownEntrypoints.Length; entrypointIndex++)
|
||||
{
|
||||
MetadataType type = _systemModule.GetType(
|
||||
s_wellKnownEntrypointNames[entrypointIndex][0],
|
||||
s_wellKnownEntrypointNames[entrypointIndex][1]);
|
||||
MethodDesc method = type.GetMethod(s_wellKnownEntrypointNames[entrypointIndex][2], null);
|
||||
_wellKnownEntrypoints[entrypointIndex] = method;
|
||||
}
|
||||
}
|
||||
|
||||
public override MetadataType GetWellKnownType(WellKnownType wellKnownType)
|
||||
|
@ -100,6 +116,11 @@ namespace ILToNative
|
|||
return _wellKnownTypes[(int)wellKnownType - 1];
|
||||
}
|
||||
|
||||
public MethodDesc GetWellKnownEntryPoint(WellKnownEntrypoint entryPoint)
|
||||
{
|
||||
return _wellKnownEntrypoints[(int)entryPoint - 1];
|
||||
}
|
||||
|
||||
public override object ResolveAssembly(System.Reflection.AssemblyName name)
|
||||
{
|
||||
return GetModuleForSimpleName(name.Name);
|
||||
|
@ -203,4 +224,10 @@ namespace ILToNative
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum WellKnownEntrypoint
|
||||
{
|
||||
Unknown,
|
||||
EnsureClassConstructorRun,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,12 @@ namespace ILToNative.DependencyAnalysis
|
|||
public class NodeFactory
|
||||
{
|
||||
TargetDetails _target;
|
||||
CompilerTypeSystemContext _context;
|
||||
|
||||
public NodeFactory(TargetDetails target)
|
||||
public NodeFactory(CompilerTypeSystemContext context)
|
||||
{
|
||||
_target = target;
|
||||
_target = context.Target;
|
||||
_context = context;
|
||||
CreateNodeCaches();
|
||||
}
|
||||
|
||||
|
@ -141,6 +143,11 @@ namespace ILToNative.DependencyAnalysis
|
|||
return _nonGCStatics.GetOrAdd(type);
|
||||
}
|
||||
|
||||
public ISymbolNode TypeCctorContextSymbol(MetadataType type)
|
||||
{
|
||||
return _nonGCStatics.GetOrAdd(type).ClassConstructorContext;
|
||||
}
|
||||
|
||||
private NodeCache<MetadataType, GCStaticsNode> _GCStatics;
|
||||
|
||||
public GCStaticsNode TypeGCStaticsSymbol(MetadataType type)
|
||||
|
@ -206,6 +213,12 @@ namespace ILToNative.DependencyAnalysis
|
|||
return _methodCode.GetOrAdd(method);
|
||||
}
|
||||
|
||||
public ISymbolNode WellKnownEntrypoint(WellKnownEntrypoint entrypoint)
|
||||
{
|
||||
MethodDesc method = _context.GetWellKnownEntryPoint(entrypoint);
|
||||
return MethodEntrypoint(method);
|
||||
}
|
||||
|
||||
private NodeCache<MethodDesc, VirtualMethodUseNode> _virtMethods;
|
||||
|
||||
public DependencyNode VirtualMethodUse(MethodDesc decl)
|
||||
|
|
|
@ -2,21 +2,32 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Internal.TypeSystem;
|
||||
|
||||
using Debug = System.Diagnostics.Debug;
|
||||
|
||||
namespace ILToNative.DependencyAnalysis
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a node with non-GC static data associated with a type, along
|
||||
/// with it's class constructor context. The non-GC static data region shall be prefixed
|
||||
/// with the class constructor context if the type has a class constructor that
|
||||
/// needs to be triggered before the type members can be accessed.
|
||||
/// </summary>
|
||||
class NonGCStaticsNode : ObjectNode, ISymbolNode
|
||||
{
|
||||
MetadataType _type;
|
||||
ISymbolNode _classConstructorContext;
|
||||
|
||||
public NonGCStaticsNode(MetadataType type)
|
||||
{
|
||||
_type = type;
|
||||
|
||||
if (HasClassConstructorContext)
|
||||
{
|
||||
_classConstructorContext = new ObjectAndOffsetSymbolNode(this, 0,
|
||||
"__CCtorContext_" + NodeFactory.NameMangler.GetMangledTypeName(_type));
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetName()
|
||||
|
@ -32,14 +43,6 @@ namespace ILToNative.DependencyAnalysis
|
|||
}
|
||||
}
|
||||
|
||||
public override bool StaticDependenciesAreComputed
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
string ISymbolNode.MangledName
|
||||
{
|
||||
get
|
||||
|
@ -52,17 +55,97 @@ namespace ILToNative.DependencyAnalysis
|
|||
{
|
||||
get
|
||||
{
|
||||
return 0;
|
||||
if (!HasClassConstructorContext)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Prepend the context to the existing fields without messing up the alignment of those fields.
|
||||
int alignmentRequired = Math.Max(_type.NonGCStaticFieldAlignment, ClassConstructorContextAlignment);
|
||||
int classConstructorContextStorageSize = AlignmentHelper.AlignUp(ClassConstructorContextSize, alignmentRequired);
|
||||
return classConstructorContextStorageSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasClassConstructorContext
|
||||
{
|
||||
get
|
||||
{
|
||||
return _type.HasStaticConstructor;
|
||||
}
|
||||
}
|
||||
|
||||
public ISymbolNode ClassConstructorContext
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(HasClassConstructorContext);
|
||||
return _classConstructorContext;
|
||||
}
|
||||
}
|
||||
|
||||
private int ClassConstructorContextSize
|
||||
{
|
||||
get
|
||||
{
|
||||
// TODO: Assert that StaticClassConstructionContext type has the expected size
|
||||
// (need to make it a well known type?)
|
||||
return _type.Context.Target.PointerSize * 2;
|
||||
}
|
||||
}
|
||||
|
||||
private int ClassConstructorContextAlignment
|
||||
{
|
||||
get
|
||||
{
|
||||
// TODO: Assert that StaticClassConstructionContext type has the expected alignment
|
||||
// (need to make it a well known type?)
|
||||
return _type.Context.Target.PointerSize;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool StaticDependenciesAreComputed
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
|
||||
{
|
||||
ObjectData data = new ObjectData(new byte[_type.NonGCStaticFieldSize],
|
||||
Array.Empty<Relocation>(),
|
||||
_type.NonGCStaticFieldAlignment,
|
||||
new ISymbolNode[] { this });
|
||||
return data;
|
||||
ObjectDataBuilder builder = new ObjectDataBuilder(factory);
|
||||
|
||||
// If the type has a class constructor, it's non-GC statics section is prefixed
|
||||
// by System.Runtime.CompilerServices.StaticClassConstructionContext struct.
|
||||
if (HasClassConstructorContext)
|
||||
{
|
||||
int alignmentRequired = Math.Max(_type.NonGCStaticFieldAlignment, ClassConstructorContextAlignment);
|
||||
builder.RequireAlignment(alignmentRequired);
|
||||
|
||||
Debug.Assert(((ISymbolNode)this).Offset >= ClassConstructorContextSize);
|
||||
|
||||
// Add padding before the context if alignment forces us to do so
|
||||
builder.EmitZeros(((ISymbolNode)this).Offset - ClassConstructorContextSize);
|
||||
|
||||
// Emit the actual StaticClassConstructionContext
|
||||
var cctorMethod = _type.GetStaticConstructor();
|
||||
builder.EmitPointerReloc(factory.MethodEntrypoint(cctorMethod));
|
||||
builder.EmitZeroPointer();
|
||||
|
||||
builder.DefinedSymbols.Add(_classConstructorContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.RequireAlignment(_type.NonGCStaticFieldAlignment);
|
||||
}
|
||||
|
||||
builder.EmitZeros(_type.NonGCStaticFieldSize);
|
||||
builder.DefinedSymbols.Add(this);
|
||||
|
||||
return builder.ToObjectData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace ILToNative.DependencyAnalysis
|
|||
|
||||
public void RequireAlignment(int align)
|
||||
{
|
||||
Alignment = Math.Min(align, Alignment);
|
||||
Alignment = Math.Max(align, Alignment);
|
||||
}
|
||||
|
||||
public void RequirePointerAlignment()
|
||||
|
@ -83,8 +83,12 @@ namespace ILToNative.DependencyAnalysis
|
|||
|
||||
public void EmitZeroPointer()
|
||||
{
|
||||
for (int i = 0; i < _target.PointerSize; i++)
|
||||
EmitByte(0);
|
||||
_data.ZeroExtend(_target.PointerSize);
|
||||
}
|
||||
|
||||
public void EmitZeros(int numBytes)
|
||||
{
|
||||
_data.ZeroExtend(numBytes);
|
||||
}
|
||||
|
||||
public void AddRelocAtOffset(ISymbolNode symbol, RelocType relocType, int offset, int instructionLength)
|
||||
|
|
|
@ -93,6 +93,11 @@ namespace ILToNative.DependencyAnalysis
|
|||
encoder.EmitRET();
|
||||
break;
|
||||
|
||||
case ReadyToRunHelperId.CCtorTrigger:
|
||||
encoder.EmitLEAQ(Register.RCX, factory.TypeCctorContextSymbol((MetadataType)Helper.Target));
|
||||
encoder.EmitJMP(factory.WellKnownEntrypoint(WellKnownEntrypoint.EnsureClassConstructorRun));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace ILToNative
|
|||
CastClass,
|
||||
GetNonGCStaticBase,
|
||||
GetGCStaticBase,
|
||||
CCtorTrigger,
|
||||
}
|
||||
|
||||
public class ReadyToRunHelper : IEquatable<ReadyToRunHelper>
|
||||
|
@ -57,6 +58,8 @@ namespace ILToNative
|
|||
return "__GetNonGCStaticBase_" + _compilation.NameMangler.GetMangledTypeName((TypeDesc)this.Target);
|
||||
case ReadyToRunHelperId.GetGCStaticBase:
|
||||
return "__GetGCStaticBase_" + _compilation.NameMangler.GetMangledTypeName((TypeDesc)this.Target);
|
||||
case ReadyToRunHelperId.CCtorTrigger:
|
||||
return "__CCtorTrigger_" + _compilation.NameMangler.GetMangledTypeName((TypeDesc)this.Target);
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -257,7 +257,7 @@ namespace Internal.JitInterface
|
|||
[UnmanagedFunctionPointerAttribute(CallingConvention.ThisCall)]
|
||||
delegate void _embedGenericHandle(IntPtr _this, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.Bool)]bool fEmbedParent, ref CORINFO_GENERICHANDLE_RESULT pResult);
|
||||
[UnmanagedFunctionPointerAttribute(CallingConvention.ThisCall)]
|
||||
delegate CORINFO_LOOKUP_KIND _getLocationOfThisType(IntPtr _this, CORINFO_METHOD_STRUCT_* context);
|
||||
delegate void _getLocationOfThisType(IntPtr _this, CORINFO_LOOKUP_KIND* result, CORINFO_METHOD_STRUCT_* context);
|
||||
[UnmanagedFunctionPointerAttribute(CallingConvention.ThisCall)]
|
||||
delegate void* _getPInvokeUnmanagedTarget(IntPtr _this, CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection);
|
||||
[UnmanagedFunctionPointerAttribute(CallingConvention.ThisCall)]
|
||||
|
|
|
@ -292,6 +292,30 @@ namespace Internal.JitInterface
|
|||
return corInfoType;
|
||||
}
|
||||
|
||||
MethodDesc methodFromContext(CORINFO_CONTEXT_STRUCT* contextStruct)
|
||||
{
|
||||
if (((ulong)contextStruct & (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK) == (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_CLASS)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HandleToObject((CORINFO_METHOD_STRUCT_*)((ulong)contextStruct & ~(ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK));
|
||||
}
|
||||
}
|
||||
|
||||
TypeDesc typeFromContext(CORINFO_CONTEXT_STRUCT* contextStruct)
|
||||
{
|
||||
if (((ulong)contextStruct & (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK) == (ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_CLASS)
|
||||
{
|
||||
return HandleToObject((CORINFO_CLASS_STRUCT_*)((ulong)contextStruct & ~(ulong)CorInfoContextFlags.CORINFO_CONTEXTFLAGS_MASK));
|
||||
}
|
||||
else
|
||||
{
|
||||
return methodFromContext(contextStruct).OwningType;
|
||||
}
|
||||
}
|
||||
|
||||
uint getMethodAttribsInternal(MethodDesc method)
|
||||
{
|
||||
CorInfoFlag result = 0;
|
||||
|
@ -808,6 +832,12 @@ namespace Internal.JitInterface
|
|||
pLookup.addr = (void*)ObjectToHandle(_compilation.GetReadyToRunHelper(ReadyToRunHelperId.CastClass, type));
|
||||
}
|
||||
break;
|
||||
case CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE:
|
||||
{
|
||||
var type = HandleToObject(pResolvedToken.hClass);
|
||||
pLookup.addr = (void*)ObjectToHandle(_compilation.GetReadyToRunHelper(ReadyToRunHelperId.CCtorTrigger, type));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
@ -818,8 +848,57 @@ namespace Internal.JitInterface
|
|||
|
||||
CorInfoInitClassResult initClass(IntPtr _this, CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context, [MarshalAs(UnmanagedType.Bool)]bool speculative)
|
||||
{
|
||||
// TODO: Cctor triggers
|
||||
return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED;
|
||||
FieldDesc fd = field == null ? null : HandleToObject(field);
|
||||
Debug.Assert(fd == null || fd.IsStatic);
|
||||
|
||||
MethodDesc md = HandleToObject(method);
|
||||
MetadataType typeToInit = (MetadataType)(fd != null ? fd.OwningType : typeFromContext(context));
|
||||
|
||||
if (!typeToInit.HasStaticConstructor)
|
||||
{
|
||||
return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED;
|
||||
}
|
||||
|
||||
if (typeToInit.IsModuleType)
|
||||
{
|
||||
// For both jitted and ngen code the global class is always considered initialized
|
||||
return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED;
|
||||
}
|
||||
|
||||
if (fd == null)
|
||||
{
|
||||
if (typeToInit.IsBeforeFieldInit)
|
||||
{
|
||||
// We can wait for field accesses to run .cctor
|
||||
return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED;
|
||||
}
|
||||
|
||||
// Run .cctor on statics & constructors
|
||||
if (md.Signature.IsStatic)
|
||||
{
|
||||
// Except don't class construct on .cctor - it would be circular
|
||||
if (md.IsStaticConstructor)
|
||||
{
|
||||
return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED;
|
||||
}
|
||||
}
|
||||
else if (!md.IsConstructor && !typeToInit.IsValueType)
|
||||
{
|
||||
// According to the spec, we should be able to do this optimization for both reference and valuetypes.
|
||||
// To maintain backward compatibility, we are doing it for reference types only.
|
||||
// For instance methods of types with precise-initialization
|
||||
// semantics, we can assume that the .ctor triggerred the
|
||||
// type initialization.
|
||||
// This does not hold for NULL "this" object. However, the spec does
|
||||
// not require that case to work.
|
||||
return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: before giving up and asking to generate a helper call, check to see if this is some pattern we can
|
||||
// prove doesn't need initclass anymore because we initialized it earlier.
|
||||
|
||||
return CorInfoInitClassResult.CORINFO_INITCLASS_USE_HELPER;
|
||||
}
|
||||
|
||||
void classMustBeLoadedBeforeCodeIsRun(IntPtr _this, CORINFO_CLASS_STRUCT_* cls)
|
||||
|
@ -1190,8 +1269,14 @@ namespace Internal.JitInterface
|
|||
{ throw new NotImplementedException(); }
|
||||
void embedGenericHandle(IntPtr _this, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.Bool)]bool fEmbedParent, ref CORINFO_GENERICHANDLE_RESULT pResult)
|
||||
{ throw new NotImplementedException(); }
|
||||
CORINFO_LOOKUP_KIND getLocationOfThisType(IntPtr _this, CORINFO_METHOD_STRUCT_* context)
|
||||
{ throw new NotImplementedException(); }
|
||||
void getLocationOfThisType(IntPtr _this, CORINFO_LOOKUP_KIND* result, CORINFO_METHOD_STRUCT_* context)
|
||||
{
|
||||
result->needsRuntimeLookup = false;
|
||||
result->runtimeLookupKind = CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ;
|
||||
|
||||
// TODO: shared generics
|
||||
}
|
||||
|
||||
void* getPInvokeUnmanagedTarget(IntPtr _this, CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection)
|
||||
{ throw new NotImplementedException(); }
|
||||
void* getAddressOfPInvokeFixup(IntPtr _this, CORINFO_METHOD_STRUCT_* method, ref void* ppIndirection)
|
||||
|
|
|
@ -277,7 +277,8 @@ FUNCTIONS
|
|||
CORINFO_METHOD_HANDLE embedMethodHandle(CORINFO_METHOD_HANDLE handle, void **ppIndirection);
|
||||
CORINFO_FIELD_HANDLE embedFieldHandle(CORINFO_FIELD_HANDLE handle, void **ppIndirection);
|
||||
void embedGenericHandle(CORINFO_RESOLVED_TOKEN * pResolvedToken, BOOL fEmbedParent, CORINFO_GENERICHANDLE_RESULT * pResult);
|
||||
CORINFO_LOOKUP_KIND getLocationOfThisType(CORINFO_METHOD_HANDLE context);
|
||||
; WORKAROUND: CLR doesn't marshal the return struct right, so explicitly list the pointer to it as the first parameter
|
||||
void getLocationOfThisType(CORINFO_LOOKUP_KIND * result, CORINFO_METHOD_HANDLE context);
|
||||
void* getPInvokeUnmanagedTarget(CORINFO_METHOD_HANDLE method, void **ppIndirection);
|
||||
void* getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method, void **ppIndirection);
|
||||
LPVOID GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void ** ppIndirection);
|
||||
|
|
Загрузка…
Ссылка в новой задаче