* Generic lookup support

This change introduces CPAOT support for all three forms of generic
lookup (THISOBJ, CLASSPARAM, METHODPARAM) and the corresponding new
GenericLookupSignature. I have added several unit tests exercising
the new functionality.

* Further fixes for generic lookup support

My initial generic lookup change only dealt with type-based lookup.
During experimentation with framework compilation I hit the need
to also implement method-based generic lookups. This change mostly
expands the initial implementation to also cater for method lookups
by expanding the RuntimeDeterminedTypeHelper and bits of other code
as appropriate.

I have also managed to get a bit more insight into emitting
signatures for instantited methods. CoreCLR runtime doesn't support
direct consumption of mdtMethodSpec tokens in method signatures -
instantiation type arguments for generic methods must always be
explicitly specified in the signature; it however does support
direct consumption of an instantiated OwningType via a mdtTypeSpec.

* Always emit signatures in instance entrypoint table using Def tokens

I found out that method signatures used to encode methods in the
INSTANCE_METHOD_ENTRYPOINTS R2R header table cannot use MemberRef
encoding for methods on instantiated types as it hits an assertion
failure in the CoreCLR runtime in SigMatchesMethodDesc.
This change introduces a boolean parameter the table can use to
specify it forbids ref-based encoding.

* Version resiliency fix - partial resurrection of tokens

During our today meeting JanK, Michal and David finally made me
comprehend the token problem. Propagation of tokens from JIT to
the managed compiler is indeed necessary due to a corner case
regarding version resiliency, however it's thankfully limited to
methods outside of the version bubble.

The problem is as follows: assume we have a "Program" and a
"Library" outside of its version bubble. At IL compilation time
of "Program" using Roslyn, the "Library" looks as follows:

<code>
class Base { void Method(); };
class Derived : Base { void Method(); }
</code>

When "Program" calls "Base.Method()." vs "Derived.Method()",
the appropriate MemberRef tokens representing
"[Library]Base.Method()" and "[Library]Derived.Method()"
get stored into the MSIL.

In the second step, prior to CPAOT compilation, we replace the
"Library" with an updated version where the Method() only exists
in the Base class (this is supposed to be a safe change w.r.t.
version resiliency):

<code>
class Base { void Method(); };
class Derived : Base { }
</code>

When we now run the CPAOT compiler, a lossy transformation takes
place - both IL tokens, "[Library]Base.Method()" and
"[Library]Derived.Method()" get squashed to the same MethodDesc
"[Library]Base.Method()" (because that's where the compiler sees
the method at CPAOT time).

Without explicit token propagation i.e. with just the reverse
synthetic token lookup, we end up encoding one of the methods
(an arbitrary one based on which one we saw last) into both
indirection cell signatures.

This breaks when later, at runtime, someone puts back the original
"Library" version where the Method() sits in both classes
because both R2R signatures contain the same reference so that
the runtime has no way of knowing they should be in fact separate.

As the problem is obviously limited to methods outside of the
version bubble, we can thankfully keep most of the ModuleTokenResolver
and related logic as for types and fields it's completely fine,
we just need to revive a bit of logic propagating tokens from JIT
for methods.

Amusingly enough it turns out that overall it mostly simplifies
the code rather than making it more complex. The gist of my change
regards splitting "ExternalMethodImport" to two classes,
"ExternalMethodImport" and "LocalMethodImport".

This split has several nice properties - for LocalMethodImport,
we always have a _localMethod available but we don't need to
maintain constrained type information - within the version bubble
we can look up all tokens using the ECMA objects so we don't really
need the constrained calls. The various R2R header tables
(method & instance entrypoints, exception info) also mostly need
to only emit local methods.

ExternalMethodImport's newly include the method token information,
propagating it to the method signature encoder - this is necessary
as we no longer record method token mapping in ModuleTokenResolver
which can now only resolve methods within the version bubble.

The change passes the basic R2R unit tests and seems to have a
comparable pass rate w.r.t. CoreCLR Pri#0 tests. I have yet to verify
that it indeed fixes the above described repro case but in general
I believe the change is sound.

The only problem I hit is in the method getFunctionEntryPoint
where the token is not readily available, for now I highlighted it
with a TODO comment; I'm not completely clear on when JIT uses this
method; if it turns out this can be used for cross-bubble calls,
we'll likely need to fix JIT to pass the appropriate token information
to the managed code.

Thanks

Tomas
This commit is contained in:
Tomáš Rylek 2018-10-25 09:42:01 +02:00 коммит произвёл GitHub
Родитель c547f30176
Коммит 78deb182cd
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
24 изменённых файлов: 1068 добавлений и 279 удалений

Просмотреть файл

@ -80,26 +80,14 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
Section section = writer.NewSection();
VertexArray vertexArray = new VertexArray(section);
section.Place(vertexArray);
ReadyToRunCodegenNodeFactory r2rFactory = (ReadyToRunCodegenNodeFactory)factory;
foreach (MethodDesc method in ((ReadyToRunTableManager)factory.MetadataManager).GetCompiledMethods())
foreach (MethodWithGCInfo method in r2rFactory.EnumerateCompiledMethods())
{
MethodWithGCInfo methodCodeNode = factory.MethodEntrypoint(method) as MethodWithGCInfo;
if (methodCodeNode == null)
{
methodCodeNode = ((ExternalMethodImport)factory.MethodEntrypoint(method))?.MethodCodeNode;
if (methodCodeNode == null)
continue;
}
if (methodCodeNode.IsEmpty)
{
continue;
}
MemoryStream methodDebugBlob = new MemoryStream();
byte[] bounds = CreateBoundsBlobForMethod(methodCodeNode);
byte[] vars = CreateVarBlobForMethod(methodCodeNode);
byte[] bounds = CreateBoundsBlobForMethod(method);
byte[] vars = CreateVarBlobForMethod(method);
NibbleWriter nibbleWriter = new NibbleWriter();
nibbleWriter.WriteUInt((uint)(bounds?.Length ?? 0));
@ -120,7 +108,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
BlobVertex debugBlob = new BlobVertex(methodDebugBlob.ToArray());
vertexArray.Set(((ReadyToRunCodegenNodeFactory)factory).RuntimeFunctionsTable.GetIndex(methodCodeNode), new DebugInfoVertex(debugBlob));
vertexArray.Set(r2rFactory.RuntimeFunctionsTable.GetIndex(method), new DebugInfoVertex(debugBlob));
}
vertexArray.ExpandLayout();

Просмотреть файл

@ -18,15 +18,19 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
private readonly IMethodNode _targetMethod;
private readonly ModuleToken _methodToken;
private readonly SignatureContext _signatureContext;
public DelegateCtorSignature(
TypeDesc delegateType,
IMethodNode targetMethod,
ModuleToken methodToken,
SignatureContext signatureContext)
{
_delegateType = delegateType;
_targetMethod = targetMethod;
_methodToken = methodToken;
_signatureContext = signatureContext;
}
@ -42,10 +46,12 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
builder.EmitByte((byte)ReadyToRunFixupKind.READYTORUN_FIXUP_DelegateCtor);
builder.EmitMethodSignature(
_targetMethod.Method,
constrainedType: null,
isUnboxingStub: false,
isInstantiatingStub: false,
_signatureContext);
constrainedType: null,
methodToken: _methodToken,
enforceDefEncoding: false,
_signatureContext,
isUnboxingStub: false,
isInstantiatingStub: false);
builder.EmitTypeSignature(_delegateType, _signatureContext);
}

Просмотреть файл

@ -65,11 +65,11 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
private List<MethodWithGCInfo> _methodNodes;
private List<int> _ehInfoOffsets;
private readonly NodeFactory _nodeFactory;
private readonly ReadyToRunCodegenNodeFactory _nodeFactory;
private readonly EHInfoNode _ehInfoNode;
public ExceptionInfoLookupTableNode(NodeFactory nodeFactory)
public ExceptionInfoLookupTableNode(ReadyToRunCodegenNodeFactory nodeFactory)
: base(nodeFactory.Target)
{
_nodeFactory = nodeFactory;
@ -94,20 +94,12 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
_methodNodes = new List<MethodWithGCInfo>();
_ehInfoOffsets = new List<int>();
foreach (MethodDesc method in _nodeFactory.MetadataManager.GetCompiledMethods())
foreach (MethodWithGCInfo method in _nodeFactory.EnumerateCompiledMethods())
{
MethodWithGCInfo methodCodeNode = _nodeFactory.MethodEntrypoint(method) as MethodWithGCInfo;
if (methodCodeNode == null)
{
methodCodeNode = ((ExternalMethodImport)_nodeFactory.MethodEntrypoint(method))?.MethodCodeNode;
if (methodCodeNode == null)
continue;
}
ObjectData ehInfo = methodCodeNode.EHInfo;
ObjectData ehInfo = method.EHInfo;
if (ehInfo != null && ehInfo.Data.Length != 0)
{
_methodNodes.Add(methodCodeNode);
_methodNodes.Add(method);
_ehInfoOffsets.Add(_ehInfoNode.AddEHInfo(ehInfo.Data));
}
}

Просмотреть файл

@ -15,48 +15,33 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
private readonly SignatureContext _signatureContext;
private readonly MethodWithGCInfo _localMethod;
public ExternalMethodImport(
ReadyToRunCodegenNodeFactory factory,
ReadyToRunFixupKind fixupKind,
MethodDesc methodDesc,
TypeDesc constrainedType,
SignatureContext signatureContext,
ModuleToken methodToken,
bool isUnboxingStub,
MethodWithGCInfo localMethod)
SignatureContext signatureContext)
: base(
factory,
factory.MethodImports,
factory.MethodImports,
ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_MethodCall,
factory.MethodSignature(
fixupKind,
methodDesc,
constrainedType,
signatureContext,
isUnboxingStub,
fixupKind,
methodDesc,
constrainedType,
methodToken,
signatureContext,
isUnboxingStub,
isInstantiatingStub: false))
{
_methodDesc = methodDesc;
_signatureContext = signatureContext;
_localMethod = localMethod;
}
public MethodDesc Method => _methodDesc;
public MethodWithGCInfo MethodCodeNode => _localMethod;
public override int ClassCode => 458823351;
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
foreach (DependencyListEntry entry in base.GetStaticDependencies(factory))
{
yield return entry;
}
if (_localMethod != null)
{
yield return new DependencyListEntry(_localMethod, "Local method import");
}
}
}
}

Просмотреть файл

@ -0,0 +1,149 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Internal.JitInterface;
using Internal.Text;
using Internal.TypeSystem;
namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
public class GenericLookupSignature : Signature
{
private CORINFO_RUNTIME_LOOKUP_KIND _runtimeLookupKind;
private readonly ReadyToRunFixupKind _fixupKind;
private readonly TypeDesc _typeArgument;
private readonly MethodWithToken _methodArgument;
private readonly TypeDesc _contextType;
private readonly SignatureContext _signatureContext;
public GenericLookupSignature(
CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind,
ReadyToRunFixupKind fixupKind,
TypeDesc typeArgument,
MethodWithToken methodArgument,
TypeDesc contextType,
SignatureContext signatureContext)
{
_runtimeLookupKind = runtimeLookupKind;
_fixupKind = fixupKind;
_typeArgument = typeArgument;
_methodArgument = methodArgument;
_contextType = contextType;
_signatureContext = signatureContext;
}
public override int ClassCode => 258608008;
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
ReadyToRunCodegenNodeFactory r2rFactory = (ReadyToRunCodegenNodeFactory)factory;
ObjectDataSignatureBuilder dataBuilder = new ObjectDataSignatureBuilder();
if (!relocsOnly)
{
dataBuilder.AddSymbol(this);
switch (_runtimeLookupKind)
{
case CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_CLASSPARAM:
dataBuilder.EmitByte((byte)ReadyToRunFixupKind.READYTORUN_FIXUP_TypeDictionaryLookup);
break;
case CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_METHODPARAM:
dataBuilder.EmitByte((byte)ReadyToRunFixupKind.READYTORUN_FIXUP_MethodDictionaryLookup);
break;
case CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ:
dataBuilder.EmitByte((byte)ReadyToRunFixupKind.READYTORUN_FIXUP_ThisObjDictionaryLookup);
dataBuilder.EmitTypeSignature(_contextType, _signatureContext);
break;
default:
throw new NotImplementedException();
}
dataBuilder.EmitByte((byte)_fixupKind);
if (_typeArgument != null)
{
dataBuilder.EmitTypeSignature(_typeArgument, _signatureContext);
}
else if (_methodArgument != null)
{
dataBuilder.EmitMethodSignature(
method: _methodArgument.Method,
constrainedType: null,
methodToken: _methodArgument.Token,
enforceDefEncoding: false,
context: _signatureContext,
isUnboxingStub: false,
isInstantiatingStub: false);
}
else
{
throw new NotImplementedException();
}
}
return dataBuilder.ToObjectData();
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix);
sb.Append("GenericLookupSignature(");
sb.Append(_runtimeLookupKind.ToString());
sb.Append(" / ");
sb.Append(_fixupKind.ToString());
sb.Append(": ");
if (_typeArgument != null)
{
RuntimeDeterminedTypeHelper.WriteTo(_typeArgument, sb);
}
else if (_methodArgument != null)
{
RuntimeDeterminedTypeHelper.WriteTo(_methodArgument.Method, sb);
if (!_methodArgument.Token.IsNull)
{
sb.Append(" [");
sb.Append(_methodArgument.Token.MetadataReader.GetString(_methodArgument.Token.MetadataReader.GetAssemblyDefinition().Name));
sb.Append(":");
sb.Append(((uint)_methodArgument.Token.Token).ToString("X8"));
sb.Append("]");
}
}
else
{
throw new NotImplementedException();
}
if (_contextType != null)
{
sb.Append(" (");
sb.Append(_contextType.ToString());
sb.Append(")");
}
}
public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
{
throw new NotImplementedException();
}
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
{
DependencyList dependencies = new DependencyList();
if (_typeArgument != null && !_typeArgument.IsRuntimeDeterminedSubtype)
{
dependencies.Add(factory.NecessaryTypeSymbol(_typeArgument), "Type referenced in a generic lookup signature");
}
return dependencies;
}
}
}

Просмотреть файл

@ -46,27 +46,21 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
Dictionary<byte[], BlobVertex> uniqueFixups = new Dictionary<byte[], BlobVertex>(ByteArrayComparer.Instance);
Dictionary<byte[], BlobVertex> uniqueSignatures = new Dictionary<byte[], BlobVertex>(ByteArrayComparer.Instance);
foreach (MethodDesc method in factory.MetadataManager.GetCompiledMethods())
foreach (MethodWithGCInfo method in r2rFactory.EnumerateCompiledMethods())
{
MethodWithGCInfo methodCodeNode = factory.MethodEntrypoint(method) as MethodWithGCInfo;
if (methodCodeNode == null)
if (method.Method.HasInstantiation || method.Method.OwningType.HasInstantiation)
{
methodCodeNode = ((ExternalMethodImport)factory.MethodEntrypoint(method))?.MethodCodeNode;
if (methodCodeNode == null)
continue;
}
if (!methodCodeNode.IsEmpty && (methodCodeNode.Method.HasInstantiation || methodCodeNode.Method.OwningType.HasInstantiation))
{
int methodIndex = r2rFactory.RuntimeFunctionsTable.GetIndex(methodCodeNode);
int methodIndex = r2rFactory.RuntimeFunctionsTable.GetIndex(method);
ArraySignatureBuilder signatureBuilder = new ArraySignatureBuilder();
signatureBuilder.EmitMethodSignature(
methodCodeNode.Method,
constrainedType: null,
method.Method,
constrainedType: null,
default(ModuleToken),
enforceDefEncoding: true,
method.SignatureContext,
isUnboxingStub: false,
isInstantiatingStub: false,
methodCodeNode.SignatureContext);
isInstantiatingStub: false);
byte[] signature = signatureBuilder.ToArray();
BlobVertex signatureBlob;
if (!uniqueSignatures.TryGetValue(signature, out signatureBlob))
@ -76,7 +70,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
uniqueSignatures.Add(signature, signatureBlob);
}
byte[] fixup = methodCodeNode.GetFixupBlob(factory);
byte[] fixup = method.GetFixupBlob(factory);
BlobVertex fixupBlob = null;
if (fixup != null && !uniqueFixups.TryGetValue(fixup, out fixupBlob))
{
@ -87,7 +81,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
EntryPointVertex entryPointVertex = new EntryPointWithBlobVertex((uint)methodIndex, fixupBlob, signatureBlob);
hashtableSection.Place(entryPointVertex);
vertexHashtable.Append(unchecked((uint)ReadyToRunHashCode.MethodHashCode(methodCodeNode.Method)), entryPointVertex);
vertexHashtable.Append(unchecked((uint)ReadyToRunHashCode.MethodHashCode(method.Method)), entryPointVertex);
}
}

Просмотреть файл

@ -0,0 +1,55 @@

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Internal.Text;
using Internal.TypeSystem;
namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
public class LocalMethodImport : DelayLoadHelperImport, IMethodNode
{
private readonly SignatureContext _signatureContext;
private readonly MethodWithGCInfo _localMethod;
public LocalMethodImport(
ReadyToRunCodegenNodeFactory factory,
ReadyToRunFixupKind fixupKind,
MethodWithGCInfo localMethod,
bool isUnboxingStub,
SignatureContext signatureContext)
: base(
factory,
factory.MethodImports,
ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_MethodCall,
factory.MethodSignature(
fixupKind,
localMethod.Method,
constrainedType: null,
methodToken: default(ModuleToken),
signatureContext,
isUnboxingStub,
isInstantiatingStub: false))
{
_signatureContext = signatureContext;
_localMethod = localMethod;
}
public MethodDesc Method => _localMethod.Method;
public MethodWithGCInfo MethodCodeNode => _localMethod;
public override int ClassCode => 459923351;
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
foreach (DependencyListEntry entry in base.GetStaticDependencies(factory))
{
yield return entry;
}
yield return new DependencyListEntry(_localMethod, "Local method import");
}
}
}

Просмотреть файл

@ -55,17 +55,9 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
ReadyToRunCodegenNodeFactory r2rFactory = (ReadyToRunCodegenNodeFactory)factory;
List<EntryPoint> ridToEntryPoint = new List<EntryPoint>();
foreach (MethodDesc method in factory.MetadataManager.GetCompiledMethods())
foreach (MethodWithGCInfo method in r2rFactory.EnumerateCompiledMethods())
{
MethodWithGCInfo methodCodeNode = factory.MethodEntrypoint(method) as MethodWithGCInfo;
if (methodCodeNode == null)
{
methodCodeNode = ((ExternalMethodImport)factory.MethodEntrypoint(method))?.MethodCodeNode;
if (methodCodeNode == null)
continue;
}
if (!methodCodeNode.IsEmpty && methodCodeNode.Method is EcmaMethod ecmaMethod)
if (method.Method is EcmaMethod ecmaMethod)
{
// Strip away the token type bits, keep just the low 24 bits RID
uint rid = SignatureBuilder.RidFromToken((mdToken)MetadataTokens.GetToken(ecmaMethod.Handle));
@ -77,8 +69,8 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
ridToEntryPoint.Add(EntryPoint.Null);
}
int methodIndex = r2rFactory.RuntimeFunctionsTable.GetIndex(methodCodeNode);
ridToEntryPoint[(int)rid] = new EntryPoint(methodIndex, methodCodeNode);
int methodIndex = r2rFactory.RuntimeFunctionsTable.GetIndex(method);
ridToEntryPoint[(int)rid] = new EntryPoint(methodIndex, method);
}
}

Просмотреть файл

@ -17,6 +17,8 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
private readonly TypeDesc _constrainedType;
private readonly ModuleToken _methodToken;
private readonly SignatureContext _signatureContext;
private readonly bool _isUnboxingStub;
@ -27,12 +29,14 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
ReadyToRunFixupKind fixupKind,
MethodDesc methodDesc,
TypeDesc constrainedType,
ModuleToken methodToken,
SignatureContext signatureContext,
bool isUnboxingStub,
bool isInstantiatingStub)
{
_fixupKind = fixupKind;
_methodDesc = methodDesc;
_methodToken = methodToken;
_constrainedType = constrainedType;
_signatureContext = signatureContext;
_isUnboxingStub = isUnboxingStub;
@ -54,7 +58,8 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
dataBuilder.AddSymbol(this);
dataBuilder.EmitUInt((uint)_fixupKind);
dataBuilder.EmitMethodSignature(_methodDesc, _constrainedType, _isUnboxingStub, _isInstantiatingStub, _signatureContext);
dataBuilder.EmitMethodSignature(_methodDesc, _constrainedType, _methodToken, enforceDefEncoding: false,
_signatureContext, _isUnboxingStub, _isInstantiatingStub);
return dataBuilder.ToObjectData();
}
@ -68,6 +73,14 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
sb.Append(" @ ");
sb.Append(_constrainedType.ToString());
}
if (!_methodToken.IsNull)
{
sb.Append(" [");
sb.Append(_methodToken.MetadataReader.GetString(_methodToken.MetadataReader.GetAssemblyDefinition().Name));
sb.Append(":");
sb.Append(((uint)_methodToken.Token).ToString("X8"));
sb.Append("]");
}
}
public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)

Просмотреть файл

@ -41,7 +41,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
public override int GetHashCode()
{
return Module.GetHashCode() ^ unchecked((int)(31 * (uint)Token));
return IsNull ? 0 : Module.GetHashCode() ^ unchecked((int)(31 * (uint)Token));
}
public override string ToString()

Просмотреть файл

@ -27,8 +27,6 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
/// </summary>
private readonly Dictionary<EcmaType, ModuleToken> _typeToRefTokens = new Dictionary<EcmaType, ModuleToken>();
private readonly Dictionary<MethodDesc, ModuleToken> _methodToRefTokens = new Dictionary<MethodDesc, ModuleToken>();
private readonly Dictionary<FieldDesc, ModuleToken> _fieldToRefTokens = new Dictionary<FieldDesc, ModuleToken>();
private readonly CompilationModuleGroup _compilationModuleGroup;
@ -41,7 +39,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
_typeSystemContext = typeSystemContext;
}
public ModuleToken GetModuleTokenForType(EcmaType type)
public ModuleToken GetModuleTokenForType(EcmaType type, bool throwIfNotFound = true)
{
if (_compilationModuleGroup.ContainsType(type))
{
@ -55,10 +53,17 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
}
// Reverse lookup failed
throw new NotImplementedException(type.ToString());
if (throwIfNotFound)
{
throw new NotImplementedException(type.ToString());
}
else
{
return default(ModuleToken);
}
}
public ModuleToken GetModuleTokenForMethod(MethodDesc method)
public ModuleToken GetModuleTokenForMethod(MethodDesc method, bool throwIfNotFound = true)
{
if (_compilationModuleGroup.ContainsMethodBody(method, unboxingStub: false) &&
method is EcmaMethod ecmaMethod)
@ -66,72 +71,48 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
return new ModuleToken(ecmaMethod.Module, ecmaMethod.Handle);
}
if (_methodToRefTokens.TryGetValue(method, out ModuleToken token))
{
return token;
}
// Reverse lookup failed
throw new NotImplementedException(method.ToString());
if (throwIfNotFound)
{
throw new NotImplementedException(method.ToString());
}
else
{
return default(ModuleToken);
}
}
public ModuleToken GetModuleTokenForField(FieldDesc field)
public ModuleToken GetModuleTokenForField(FieldDesc field, bool throwIfNotFound = true)
{
if (_compilationModuleGroup.ContainsType(field.OwningType) && field is EcmaField ecmaField)
{
return new ModuleToken(ecmaField.Module, ecmaField.Handle);
}
throw new NotImplementedException();
if (throwIfNotFound)
{
throw new NotImplementedException();
}
else
{
return default(ModuleToken);
}
}
public void AddModuleTokenForMethod(MethodDesc method, ModuleToken token)
{
if (_methodToRefTokens.ContainsKey(method))
if (token.TokenType == CorTokenType.mdtMethodSpec)
{
// This method has already been harvested
return;
MethodSpecification methodSpec = token.MetadataReader.GetMethodSpecification((MethodSpecificationHandle)token.Handle);
token = new ModuleToken(token.Module, methodSpec.Method);
}
if (_compilationModuleGroup.ContainsMethodBody(method, unboxingStub: false) && method is EcmaMethod)
if (token.TokenType == CorTokenType.mdtMemberRef)
{
// We don't need to store handles within the current compilation group
// as we can read them directly from the ECMA objects.
return;
MemberReference memberRef = token.MetadataReader.GetMemberReference((MemberReferenceHandle)token.Handle);
EntityHandle owningTypeHandle = memberRef.Parent;
AddModuleTokenForType(method.OwningType, new ModuleToken(token.Module, owningTypeHandle));
memberRef.DecodeMethodSignature<DummyTypeInfo, ModuleTokenResolver>(new TokenResolverProvider(this, token.Module), this);
}
_methodToRefTokens[method] = token;
switch (token.TokenType)
{
case CorTokenType.mdtMethodSpec:
{
MethodSpecification methodSpec = token.MetadataReader.GetMethodSpecification((MethodSpecificationHandle)token.Handle);
AddModuleTokenForMethod((MethodDesc)token.Module.GetObject(methodSpec.Method), new ModuleToken(token.Module, methodSpec.Method));
}
break;
case CorTokenType.mdtMemberRef:
if ((method.HasInstantiation || method.OwningType.HasInstantiation) &&
!method.IsGenericMethodDefinition && !method.OwningType.IsGenericDefinition)
{
AddModuleTokenForMethod(method.GetTypicalMethodDefinition(), token);
}
AddModuleTokenForMethodReference(method.OwningType, token);
break;
default:
throw new NotImplementedException(token.TokenType.ToString());
}
}
private void AddModuleTokenForMethodReference(TypeDesc owningType, ModuleToken token)
{
MemberReference memberRef = token.MetadataReader.GetMemberReference((MemberReferenceHandle)token.Handle);
EntityHandle owningTypeHandle = memberRef.Parent;
AddModuleTokenForType(owningType, new ModuleToken(token.Module, owningTypeHandle));
memberRef.DecodeMethodSignature<DummyTypeInfo, ModuleTokenResolver>(new TokenResolverProvider(this, token.Module), this);
}
private void AddModuleTokenForFieldReference(TypeDesc owningType, ModuleToken token)

Просмотреть файл

@ -16,10 +16,10 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
private List<MethodWithGCInfo> _methodNodes;
private Dictionary<MethodWithGCInfo, int> _insertedMethodNodes;
private readonly NodeFactory _nodeFactory;
private readonly ReadyToRunCodegenNodeFactory _nodeFactory;
private int _tableSize = -1;
public RuntimeFunctionsTableNode(NodeFactory nodeFactory)
public RuntimeFunctionsTableNode(ReadyToRunCodegenNodeFactory nodeFactory)
: base(nodeFactory.Target)
{
_nodeFactory = nodeFactory;
@ -50,19 +50,11 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
int runtimeFunctionIndex = 0;
foreach (MethodDesc method in _nodeFactory.MetadataManager.GetCompiledMethods())
foreach (MethodWithGCInfo method in _nodeFactory.EnumerateCompiledMethods())
{
MethodWithGCInfo methodCodeNode = _nodeFactory.MethodEntrypoint(method) as MethodWithGCInfo;
if (methodCodeNode == null)
{
methodCodeNode = ((ExternalMethodImport)_nodeFactory.MethodEntrypoint(method))?.MethodCodeNode;
if (methodCodeNode == null)
continue;
}
_methodNodes.Add(methodCodeNode);
_insertedMethodNodes[methodCodeNode] = runtimeFunctionIndex;
runtimeFunctionIndex += methodCodeNode.FrameInfos.Length;
_methodNodes.Add(method);
_insertedMethodNodes[method] = runtimeFunctionIndex;
runtimeFunctionIndex += method.FrameInfos.Length;
}
}

Просмотреть файл

@ -179,6 +179,25 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
public void EmitTypeSignature(TypeDesc typeDesc, SignatureContext context)
{
if (typeDesc is RuntimeDeterminedType runtimeDeterminedType)
{
switch (runtimeDeterminedType.RuntimeDeterminedDetailsType.Kind)
{
case GenericParameterKind.Type:
EmitElementType(CorElementType.ELEMENT_TYPE_VAR);
break;
case GenericParameterKind.Method:
EmitElementType(CorElementType.ELEMENT_TYPE_MVAR);
break;
default:
throw new NotImplementedException();
}
EmitUInt((uint)runtimeDeterminedType.RuntimeDeterminedDetailsType.Index);
return;
}
if (typeDesc.HasInstantiation && !typeDesc.IsGenericDefinition)
{
EmitInstantiatedTypeSignature((InstantiatedType)typeDesc, context);
@ -335,7 +354,14 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
}
}
public void EmitMethodSignature(MethodDesc method, TypeDesc constrainedType, bool isUnboxingStub, bool isInstantiatingStub, SignatureContext context)
public void EmitMethodSignature(
MethodDesc method,
TypeDesc constrainedType,
ModuleToken methodToken,
bool enforceDefEncoding,
SignatureContext context,
bool isUnboxingStub,
bool isInstantiatingStub)
{
uint flags = 0;
if (isUnboxingStub)
@ -353,24 +379,27 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
if (method.HasInstantiation || method.OwningType.HasInstantiation)
{
EmitMethodSpecificationSignature(method, flags, context);
EmitMethodSpecificationSignature(method, methodToken, flags, enforceDefEncoding, context);
}
else
{
ModuleToken token = context.GetModuleTokenForMethod(method.GetTypicalMethodDefinition());
switch (token.TokenType)
if (methodToken.IsNull)
{
methodToken = context.GetModuleTokenForMethod(method.GetTypicalMethodDefinition());
}
switch (methodToken.TokenType)
{
case CorTokenType.mdtMethodDef:
// TODO: module override for methoddefs with external module context
EmitUInt(flags);
EmitMethodDefToken(token);
EmitMethodDefToken(methodToken);
break;
case CorTokenType.mdtMemberRef:
// TODO: module override for methodrefs with external module context
flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MemberRefToken;
EmitUInt(flags);
EmitMethodRefToken(token);
EmitMethodRefToken(methodToken);
break;
default:
@ -396,21 +425,45 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
EmitUInt(RidFromToken(memberRefToken.Token));
}
private void EmitMethodSpecificationSignature(MethodDesc method, uint flags, SignatureContext context)
private void EmitMethodSpecificationSignature(MethodDesc method, ModuleToken methodToken,
uint flags, bool enforceDefEncoding, SignatureContext context)
{
if (method.HasInstantiation)
{
flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation
| (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType;
flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation;
if (!methodToken.IsNull)
{
if (methodToken.TokenType == CorTokenType.mdtMethodSpec)
{
MethodSpecification methodSpecification = methodToken.MetadataReader.GetMethodSpecification((MethodSpecificationHandle)methodToken.Handle);
methodToken = new ModuleToken(methodToken.Module, methodSpecification.Method);
}
else
{
throw new NotImplementedException();
}
}
}
if (methodToken.IsNull && !enforceDefEncoding)
{
methodToken = context.GetModuleTokenForMethod(method.GetMethodDefinition(), throwIfNotFound: false);
}
if (methodToken.IsNull)
{
flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType;
methodToken = context.GetModuleTokenForMethod(method.GetTypicalMethodDefinition());
}
if (method.OwningType.HasInstantiation)
{
// resolveToken currently resolves the token in the context of a given scope;
// in such case, we receive a method on instantiated type along with the
// generic definition token.
flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType;
}
ModuleToken genericMethodToken = context.GetModuleTokenForMethod(method.GetTypicalMethodDefinition());
switch (genericMethodToken.TokenType)
switch (methodToken.TokenType)
{
case CorTokenType.mdtMethodDef:
break;
@ -428,8 +481,8 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
EmitTypeSignature(method.OwningType, context);
}
EmitTokenRid(genericMethodToken.Token);
if (method.HasInstantiation)
EmitTokenRid(methodToken.Token);
if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation) != 0)
{
Instantiation instantiation = method.Instantiation;
EmitUInt((uint)instantiation.Length);

Просмотреть файл

@ -22,19 +22,19 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
_resolver = resolver;
}
public ModuleToken GetModuleTokenForType(EcmaType type)
public ModuleToken GetModuleTokenForType(EcmaType type, bool throwIfNotFound = true)
{
return _resolver.GetModuleTokenForType(type);
return _resolver.GetModuleTokenForType(type, throwIfNotFound);
}
public ModuleToken GetModuleTokenForMethod(MethodDesc method)
public ModuleToken GetModuleTokenForMethod(MethodDesc method, bool throwIfNotFound = true)
{
return _resolver.GetModuleTokenForMethod(method);
return _resolver.GetModuleTokenForMethod(method, throwIfNotFound);
}
public ModuleToken GetModuleTokenForField(FieldDesc field)
public ModuleToken GetModuleTokenForField(FieldDesc field, bool throwIfNotFound = true)
{
return _resolver.GetModuleTokenForField(field);
return _resolver.GetModuleTokenForField(field, throwIfNotFound);
}
}
}

Просмотреть файл

@ -102,47 +102,59 @@ namespace ILCompiler.DependencyAnalysis
return new Import(EagerImports, new ReadyToRunHelperSignature(helperId));
}
public IMethodNode MethodEntrypoint(MethodDesc targetMethod, TypeDesc constrainedType, MethodDesc originalMethod, SignatureContext signatureContext, bool isUnboxingStub = false)
public IMethodNode MethodEntrypoint(
MethodDesc targetMethod,
TypeDesc constrainedType,
MethodDesc originalMethod,
ModuleToken methodToken,
SignatureContext signatureContext,
bool isUnboxingStub = false)
{
if (!CompilationModuleGroup.ContainsMethodBody(targetMethod, false))
{
return ImportedMethodNode(constrainedType != null ? originalMethod : targetMethod, constrainedType, methodToken, signatureContext, isUnboxingStub);
}
return _methodEntrypoints.GetOrAdd(targetMethod, (m) =>
{
return CreateMethodEntrypointNode(targetMethod, constrainedType, originalMethod, signatureContext, isUnboxingStub);
return CreateMethodEntrypointNode(targetMethod, signatureContext, isUnboxingStub);
});
}
private IMethodNode CreateMethodEntrypointNode(MethodDesc targetMethod, TypeDesc constrainedType, MethodDesc originalMethod, SignatureContext signatureContext, bool isUnboxingStub)
private IMethodNode CreateMethodEntrypointNode(MethodDesc targetMethod, SignatureContext signatureContext, bool isUnboxingStub)
{
if (constrainedType != null)
{
// We may be able to optimize away the constrained call if targetMethod is within the version bubble
if (CompilationModuleGroup.ContainsMethodBody(targetMethod, isUnboxingStub))
{
constrainedType = null;
}
else
{
targetMethod = originalMethod;
}
}
MethodWithGCInfo localMethod = new MethodWithGCInfo(targetMethod, signatureContext);
if (targetMethod is InstantiatedMethod instantiatedMethod)
{
return InstantiatedMethodNode(instantiatedMethod, constrainedType, signatureContext, isUnboxingStub);
}
MethodWithGCInfo localMethod = null;
if (CompilationModuleGroup.ContainsMethodBody(targetMethod, false))
{
localMethod = new MethodWithGCInfo(targetMethod, signatureContext);
}
return ImportedMethodNode(targetMethod, unboxingStub: isUnboxingStub, constrainedType: constrainedType, signatureContext: signatureContext, localMethod: localMethod);
return new LocalMethodImport(
this,
ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry,
localMethod,
isUnboxingStub,
signatureContext);
}
public IMethodNode StringAllocator(MethodDesc constructor, SignatureContext signatureContext)
public IEnumerable<MethodWithGCInfo> EnumerateCompiledMethods()
{
return MethodEntrypoint(constructor, constrainedType: null, originalMethod: null, signatureContext: signatureContext, isUnboxingStub: false);
foreach (MethodDesc method in MetadataManager.GetCompiledMethods())
{
IMethodNode methodNode = MethodEntrypoint(method);
MethodWithGCInfo methodCodeNode = methodNode as MethodWithGCInfo;
if (methodCodeNode == null && methodNode is LocalMethodImport localMethodImport)
{
methodCodeNode = localMethodImport.MethodCodeNode;
}
if (methodCodeNode != null && !methodCodeNode.IsEmpty)
{
yield return methodCodeNode;
}
}
}
public IMethodNode StringAllocator(MethodDesc constructor, ModuleToken methodToken, SignatureContext signatureContext)
{
return MethodEntrypoint(constructor, constrainedType: null, originalMethod: null,
methodToken: methodToken, signatureContext: signatureContext, isUnboxingStub: false);
}
protected override ISymbolNode CreateReadyToRunHelperNode(ReadyToRunHelperKey helperCall)
@ -215,6 +227,7 @@ namespace ILCompiler.DependencyAnalysis
ReadyToRunFixupKind fixupKind,
MethodDesc methodDesc,
TypeDesc constrainedType,
ModuleToken methodToken,
SignatureContext signatureContext,
bool isUnboxingStub,
bool isInstantiatingStub)
@ -226,11 +239,12 @@ namespace ILCompiler.DependencyAnalysis
_methodSignatures.Add(fixupKind, perFixupKindMap);
}
TypeAndMethod key = new TypeAndMethod(constrainedType, methodDesc, isUnboxingStub, isInstantiatingStub);
TypeAndMethod key = new TypeAndMethod(constrainedType, methodDesc, methodToken, isUnboxingStub, isInstantiatingStub);
MethodFixupSignature signature;
if (!perFixupKindMap.TryGetValue(key, out signature))
{
signature = new MethodFixupSignature(fixupKind, methodDesc, constrainedType, signatureContext, isUnboxingStub, isInstantiatingStub);
signature = new MethodFixupSignature(fixupKind, methodDesc, constrainedType,
methodToken, signatureContext, isUnboxingStub, isInstantiatingStub);
perFixupKindMap.Add(key, signature);
}
return signature;
@ -349,57 +363,43 @@ namespace ILCompiler.DependencyAnalysis
MetadataManager.AttachToDependencyGraph(graph);
}
public IMethodNode ImportedMethodNode(MethodDesc method, TypeDesc constrainedType, SignatureContext signatureContext, bool unboxingStub, MethodWithGCInfo localMethod)
public IMethodNode ImportedMethodNode(
MethodDesc targetMethod,
TypeDesc constrainedType,
ModuleToken methodToken,
SignatureContext signatureContext,
bool unboxingStub)
{
IMethodNode methodImport;
TypeAndMethod key = new TypeAndMethod(constrainedType, method, unboxingStub, isInstantiatingStub: false);
TypeAndMethod key = new TypeAndMethod(constrainedType, targetMethod, methodToken, unboxingStub, isInstantiatingStub: false);
if (!_importMethods.TryGetValue(key, out methodImport))
{
// First time we see a given external method - emit indirection cell and the import entry
ExternalMethodImport indirectionCell = new ExternalMethodImport(
this,
ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry,
method,
targetMethod,
constrainedType,
signatureContext,
methodToken,
unboxingStub,
localMethod);
signatureContext);
_importMethods.Add(key, indirectionCell);
methodImport = indirectionCell;
}
return methodImport;
}
private readonly Dictionary<InstantiatedMethod, IMethodNode> _instantiatedMethodImports = new Dictionary<InstantiatedMethod, IMethodNode>();
private IMethodNode InstantiatedMethodNode(InstantiatedMethod method, TypeDesc constrainedType, SignatureContext signatureContext, bool isUnboxingStub)
{
IMethodNode methodImport;
if (!_instantiatedMethodImports.TryGetValue(method, out methodImport))
{
methodImport = new ExternalMethodImport(
this,
ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry,
method,
constrainedType,
signatureContext,
isUnboxingStub,
localMethod: null);
_instantiatedMethodImports.Add(method, methodImport);
}
return methodImport;
}
private Dictionary<TypeAndMethod, IMethodNode> _shadowConcreteMethods = new Dictionary<TypeAndMethod, IMethodNode>();
public IMethodNode ShadowConcreteMethod(MethodDesc method, TypeDesc constrainedType, MethodDesc originalMethod,
SignatureContext signatureContext, bool isUnboxingStub = false)
public IMethodNode ShadowConcreteMethod(MethodDesc targetMethod, TypeDesc constrainedType, MethodDesc originalMethod,
ModuleToken methodToken, SignatureContext signatureContext, bool isUnboxingStub = false)
{
IMethodNode result;
TypeAndMethod key = new TypeAndMethod(constrainedType, method, isUnboxingStub, isInstantiatingStub: false);
TypeAndMethod key = new TypeAndMethod(constrainedType, constrainedType != null ? originalMethod : targetMethod,
methodToken, isUnboxingStub, isInstantiatingStub: false);
if (!_shadowConcreteMethods.TryGetValue(key, out result))
{
result = MethodEntrypoint(method, constrainedType, originalMethod, signatureContext, isUnboxingStub);
result = MethodEntrypoint(targetMethod, constrainedType, originalMethod, methodToken, signatureContext, isUnboxingStub);
_shadowConcreteMethods.Add(key, result);
}
return result;
@ -440,7 +440,8 @@ namespace ILCompiler.DependencyAnalysis
throw new NotImplementedException();
}
return MethodEntrypoint(method, constrainedType: null, originalMethod: null, signatureContext: InputModuleContext, isUnboxingStub: false);
return MethodEntrypoint(method, constrainedType: null, originalMethod: null,
methodToken: default(ModuleToken), signatureContext: InputModuleContext, isUnboxingStub: false);
}
protected override IMethodNode CreateUnboxingStubNode(MethodDesc method)

Просмотреть файл

@ -5,6 +5,8 @@
using System;
using System.Collections.Generic;
using ILCompiler.DependencyAnalysis.ReadyToRun;
using Internal.JitInterface;
using Internal.TypeSystem;
namespace ILCompiler.DependencyAnalysis
@ -96,7 +98,7 @@ namespace ILCompiler.DependencyAnalysis
break;
case ReadyToRunHelperId.VirtualCall:
helperNode = CreateVirtualCallHelper((MethodDesc)target, signatureContext);
helperNode = CreateVirtualCallHelper((MethodWithToken)target, signatureContext);
break;
case ReadyToRunHelperId.DelegateCtor:
@ -197,14 +199,19 @@ namespace ILCompiler.DependencyAnalysis
new FieldFixupSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_FieldHandle, field, signatureContext));
}
private ISymbolNode CreateVirtualCallHelper(MethodDesc method, SignatureContext signatureContext)
private ISymbolNode CreateVirtualCallHelper(MethodWithToken methodWithToken, SignatureContext signatureContext)
{
return new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.DispatchImports,
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper_Obj,
_codegenNodeFactory.MethodSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry, method,
constrainedType: null, signatureContext: signatureContext, isUnboxingStub: false, isInstantiatingStub: false));
_codegenNodeFactory.MethodSignature(
ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry, methodWithToken.Method,
constrainedType: null,
methodWithToken.Token,
signatureContext: signatureContext,
isUnboxingStub: false,
isInstantiatingStub: false));
}
private ISymbolNode CreateDelegateCtorHelper(DelegateCreationInfo info, SignatureContext signatureContext)
@ -541,7 +548,7 @@ namespace ILCompiler.DependencyAnalysis
private readonly Dictionary<MethodAndCallSite, ISymbolNode> _interfaceDispatchCells = new Dictionary<MethodAndCallSite, ISymbolNode>();
public ISymbolNode InterfaceDispatchCell(MethodDesc method, SignatureContext signatureContext, bool isUnboxingStub, string callSite)
public ISymbolNode InterfaceDispatchCell(MethodDesc method, ModuleToken methodToken, SignatureContext signatureContext, bool isUnboxingStub, string callSite)
{
MethodAndCallSite cellKey = new MethodAndCallSite(method, callSite);
if (!_interfaceDispatchCells.TryGetValue(cellKey, out ISymbolNode dispatchCell))
@ -552,7 +559,7 @@ namespace ILCompiler.DependencyAnalysis
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_MethodCall |
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_FLAG_VSD,
_codegenNodeFactory.MethodSignature(ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry, method,
null, signatureContext, isUnboxingStub, isInstantiatingStub: false),
null, methodToken, signatureContext, isUnboxingStub, isInstantiatingStub: false),
callSite);
_interfaceDispatchCells.Add(cellKey, dispatchCell);
@ -567,7 +574,7 @@ namespace ILCompiler.DependencyAnalysis
private readonly Dictionary<MethodDesc, ISortableSymbolNode> _genericDictionaryCache = new Dictionary<MethodDesc, ISortableSymbolNode>();
public ISortableSymbolNode MethodGenericDictionary(MethodDesc method, SignatureContext signatureContext)
public ISortableSymbolNode MethodGenericDictionary(MethodDesc method, ModuleToken methodToken, SignatureContext signatureContext)
{
if (!_genericDictionaryCache.TryGetValue(method, out ISortableSymbolNode genericDictionary))
{
@ -577,6 +584,7 @@ namespace ILCompiler.DependencyAnalysis
ReadyToRunFixupKind.READYTORUN_FIXUP_MethodDictionary,
method,
constrainedType: null,
methodToken: methodToken,
signatureContext: signatureContext,
isUnboxingStub: false,
isInstantiatingStub: true));
@ -601,18 +609,24 @@ namespace ILCompiler.DependencyAnalysis
private readonly Dictionary<TypeAndMethod, ISymbolNode> _delegateCtors = new Dictionary<TypeAndMethod, ISymbolNode>();
public ISymbolNode DelegateCtor(TypeDesc delegateType, MethodDesc targetMethod, SignatureContext signatureContext)
public ISymbolNode DelegateCtor(TypeDesc delegateType, MethodDesc targetMethod, ModuleToken methodToken, SignatureContext signatureContext)
{
TypeAndMethod ctorKey = new TypeAndMethod(delegateType, targetMethod, isUnboxingStub: false, isInstantiatingStub: false);
TypeAndMethod ctorKey = new TypeAndMethod(delegateType, targetMethod, methodToken: methodToken, isUnboxingStub: false, isInstantiatingStub: false);
if (!_delegateCtors.TryGetValue(ctorKey, out ISymbolNode ctorNode))
{
IMethodNode targetMethodNode = _codegenNodeFactory.MethodEntrypoint(targetMethod, constrainedType: null, originalMethod: null, signatureContext: signatureContext, isUnboxingStub: false);
IMethodNode targetMethodNode = _codegenNodeFactory.MethodEntrypoint(
targetMethod,
constrainedType: null,
originalMethod: null,
methodToken: methodToken,
signatureContext: signatureContext,
isUnboxingStub: false);
ctorNode = new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper,
new DelegateCtorSignature(delegateType, targetMethodNode, signatureContext));
new DelegateCtorSignature(delegateType, targetMethodNode, methodToken, signatureContext));
_delegateCtors.Add(ctorKey, ctorNode);
}
return ctorNode;
@ -644,5 +658,145 @@ namespace ILCompiler.DependencyAnalysis
return (CallSite != null ? CallSite.GetHashCode() : 0) + unchecked(31 * Method.GetHashCode());
}
}
private class GenericLookupKey : IEquatable<GenericLookupKey>
{
public readonly CORINFO_RUNTIME_LOOKUP_KIND LookupKind;
public readonly ReadyToRunFixupKind FixupKind;
public readonly TypeDesc TypeArgument;
public readonly MethodWithToken MethodArgument;
public readonly TypeDesc ContextType;
public GenericLookupKey(CORINFO_RUNTIME_LOOKUP_KIND lookupKind, ReadyToRunFixupKind fixupKind, TypeDesc typeArgument, MethodWithToken methodArgument, TypeDesc contextType)
{
LookupKind = lookupKind;
FixupKind = fixupKind;
TypeArgument = typeArgument;
MethodArgument = methodArgument;
ContextType = contextType;
}
public bool Equals(GenericLookupKey other)
{
return LookupKind == other.LookupKind &&
FixupKind == other.FixupKind &&
RuntimeDeterminedTypeHelper.Equals(TypeArgument, other.TypeArgument) &&
MethodArgument == other.MethodArgument &&
ContextType == other.ContextType;
}
public override bool Equals(object obj)
{
return obj is GenericLookupKey other && Equals(other);
}
public override int GetHashCode()
{
return unchecked(((int)LookupKind << 24) +
(int)FixupKind +
(TypeArgument != null ? 31 * RuntimeDeterminedTypeHelper.GetHashCode(TypeArgument) : 0) +
(MethodArgument != null ? 31 * RuntimeDeterminedTypeHelper.GetHashCode(MethodArgument.Method) : 0) +
97 * (ContextType?.GetHashCode() ?? 0));
}
}
private Dictionary<GenericLookupKey, ISymbolNode> _genericLookupHelpers = new Dictionary<GenericLookupKey, ISymbolNode>();
public ISymbolNode GenericLookupHelper(
CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind,
ReadyToRunHelperId helperId,
object helperArgument,
TypeDesc contextType,
SignatureContext signatureContext)
{
switch (helperId)
{
case ReadyToRunHelperId.NecessaryTypeHandle:
case ReadyToRunHelperId.TypeHandle:
return GenericLookupTypeHelper(
runtimeLookupKind,
ReadyToRunFixupKind.READYTORUN_FIXUP_TypeHandle,
(TypeDesc)helperArgument,
contextType,
signatureContext);
case ReadyToRunHelperId.MethodHandle:
return GenericLookupMethodHelper(
runtimeLookupKind,
ReadyToRunFixupKind.READYTORUN_FIXUP_MethodHandle,
(MethodWithToken)helperArgument,
contextType,
signatureContext);
case ReadyToRunHelperId.MethodEntry:
return GenericLookupMethodHelper(
runtimeLookupKind,
ReadyToRunFixupKind.READYTORUN_FIXUP_MethodEntry,
(MethodWithToken)helperArgument,
contextType,
signatureContext);
case ReadyToRunHelperId.MethodDictionary:
return GenericLookupMethodHelper(
runtimeLookupKind,
ReadyToRunFixupKind.READYTORUN_FIXUP_MethodDictionary,
(MethodWithToken)helperArgument,
contextType,
signatureContext);
case ReadyToRunHelperId.VirtualDispatchCell:
return GenericLookupMethodHelper(
runtimeLookupKind,
ReadyToRunFixupKind.READYTORUN_FIXUP_VirtualEntry,
(MethodWithToken)helperArgument,
contextType,
signatureContext);
default:
throw new NotImplementedException();
}
}
private ISymbolNode GenericLookupTypeHelper(
CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind,
ReadyToRunFixupKind fixupKind,
TypeDesc typeArgument,
TypeDesc contextType,
SignatureContext signatureContext)
{
GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument, methodArgument: null, contextType);
ISymbolNode node;
if (!_genericLookupHelpers.TryGetValue(key, out node))
{
node = new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper,
new GenericLookupSignature(runtimeLookupKind, fixupKind, typeArgument, methodArgument: null, contextType, signatureContext));
_genericLookupHelpers.Add(key, node);
}
return node;
}
private ISymbolNode GenericLookupMethodHelper(
CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind,
ReadyToRunFixupKind fixupKind,
MethodWithToken methodArgument,
TypeDesc contextType,
SignatureContext signatureContext)
{
GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument, contextType);
ISymbolNode node;
if (!_genericLookupHelpers.TryGetValue(key, out node))
{
node = new DelayLoadHelperImport(
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper,
new GenericLookupSignature(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument, contextType, signatureContext));
_genericLookupHelpers.Add(key, node);
}
return node;
}
}
}

Просмотреть файл

@ -5,19 +5,23 @@
using System;
using Internal.TypeSystem;
using ILCompiler.DependencyAnalysis.ReadyToRun;
namespace ILCompiler.DependencyAnalysis
{
internal struct TypeAndMethod : IEquatable<TypeAndMethod>
{
public readonly TypeDesc Type;
public readonly MethodDesc Method;
public readonly ModuleToken MethodToken;
public readonly bool IsUnboxingStub;
public readonly bool IsInstantiatingStub;
public TypeAndMethod(TypeDesc type, MethodDesc method, bool isUnboxingStub, bool isInstantiatingStub)
public TypeAndMethod(TypeDesc type, MethodDesc method, ModuleToken methodToken, bool isUnboxingStub, bool isInstantiatingStub)
{
Type = type;
Method = method;
MethodToken = methodToken;
IsUnboxingStub = isUnboxingStub;
IsInstantiatingStub = isInstantiatingStub;
}
@ -26,6 +30,7 @@ namespace ILCompiler.DependencyAnalysis
{
return Type == other.Type &&
Method == other.Method &&
MethodToken.Equals(other.MethodToken) &&
IsUnboxingStub == other.IsUnboxingStub &&
IsInstantiatingStub == other.IsInstantiatingStub;
}
@ -37,7 +42,10 @@ namespace ILCompiler.DependencyAnalysis
public override int GetHashCode()
{
return (Type?.GetHashCode() ?? 0) ^ unchecked(Method.GetHashCode() * 31) ^ (IsUnboxingStub ? -0x80000000 : 0) ^ (IsInstantiatingStub ? 0x40000000 : 0);
return (Type?.GetHashCode() ?? 0) ^
unchecked(Method.GetHashCode() * 31 + MethodToken.GetHashCode() * 97) ^
(IsUnboxingStub ? -0x80000000 : 0) ^
(IsInstantiatingStub ? 0x40000000 : 0);
}
}
}

Просмотреть файл

@ -95,7 +95,7 @@ namespace ILCompiler
{
hashcode = NestedTypeHashCode(TypeHashCode(containingType), hashcode);
}
if (type.HasInstantiation)
if (type.HasInstantiation && !type.IsGenericDefinition)
{
return GenericInstanceHashCode(hashcode, type.Instantiation);
}

Просмотреть файл

@ -0,0 +1,204 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using Internal.TypeSystem;
using Internal.Text;
namespace ILCompiler
{
/// <summary>
/// Helper class used to collapse runtime determined types
/// based on their kind and index as we otherwise don't need
/// to distinguish among them for the purpose of emitting
/// signatures and generic lookups.
/// </summary>
public static class RuntimeDeterminedTypeHelper
{
public static bool Equals(Instantiation instantiation1, Instantiation instantiation2)
{
if (instantiation1.Length != instantiation2.Length)
{
return false;
}
for (int argIndex = 0; argIndex < instantiation1.Length; argIndex++)
{
if (!Equals(instantiation1[argIndex], instantiation2[argIndex]))
{
return false;
}
}
return true;
}
public static bool Equals(TypeDesc type1, TypeDesc type2)
{
if (type1 == type2)
{
return true;
}
RuntimeDeterminedType runtimeDeterminedType1 = type1 as RuntimeDeterminedType;
RuntimeDeterminedType runtimeDeterminedType2 = type2 as RuntimeDeterminedType;
if (runtimeDeterminedType1 != null || runtimeDeterminedType2 != null)
{
if (runtimeDeterminedType1 == null || runtimeDeterminedType2 == null)
{
return false;
}
return runtimeDeterminedType1.RuntimeDeterminedDetailsType.Index == runtimeDeterminedType2.RuntimeDeterminedDetailsType.Index &&
runtimeDeterminedType1.RuntimeDeterminedDetailsType.Kind == runtimeDeterminedType2.RuntimeDeterminedDetailsType.Kind;
}
if (type1.GetTypeDefinition() != type2.GetTypeDefinition() ||
!Equals(type1.Instantiation, type2.Instantiation))
{
return false;
}
return true;
}
public static bool Equals(MethodDesc method1, MethodDesc method2)
{
if (method1 == method2)
{
return true;
}
if (!Equals(method1.OwningType, method2.OwningType) ||
method1.Signature.Length != method2.Signature.Length ||
!Equals(method1.Instantiation, method2.Instantiation) ||
!Equals(method1.Signature.ReturnType, method2.Signature.ReturnType))
{
return false;
}
for (int argIndex = 0; argIndex < method1.Signature.Length; argIndex++)
{
if (!Equals(method1.Signature[argIndex], method2.Signature[argIndex]))
{
return false;
}
}
return true;
}
public static int GetHashCode(Instantiation instantiation)
{
int hashcode = unchecked(instantiation.Length << 24);
for (int typeArgIndex = 0; typeArgIndex < instantiation.Length; typeArgIndex++)
{
hashcode = unchecked(hashcode * 73 + GetHashCode(instantiation[typeArgIndex]));
}
return hashcode;
}
public static int GetHashCode(TypeDesc type)
{
if (type is RuntimeDeterminedType runtimeDeterminedType)
{
return runtimeDeterminedType.RuntimeDeterminedDetailsType.Index ^
((int)runtimeDeterminedType.RuntimeDeterminedDetailsType.Kind << 30);
}
return type.GetTypeDefinition().GetHashCode() ^ GetHashCode(type.Instantiation);
}
public static int GetHashCode(MethodDesc method)
{
return unchecked(GetHashCode(method.OwningType) + 97 * (
method.GetTypicalMethodDefinition().GetHashCode() + 31 * GetHashCode(method.Instantiation)));
}
public static void WriteTo(Instantiation instantiation, Utf8StringBuilder sb)
{
sb.Append("<");
for (int typeArgIndex = 0; typeArgIndex < instantiation.Length; typeArgIndex++)
{
if (typeArgIndex != 0)
{
sb.Append(", ");
}
WriteTo(instantiation[typeArgIndex], sb);
}
sb.Append(">");
}
public static void WriteTo(TypeDesc type, Utf8StringBuilder sb)
{
if (type is RuntimeDeterminedType runtimeDeterminedType)
{
switch (runtimeDeterminedType.RuntimeDeterminedDetailsType.Kind)
{
case GenericParameterKind.Type:
sb.Append("T");
break;
case GenericParameterKind.Method:
sb.Append("M");
break;
default:
throw new NotImplementedException();
}
sb.Append(runtimeDeterminedType.RuntimeDeterminedDetailsType.Index.ToString());
}
else if (type is InstantiatedType instantiatedType)
{
sb.Append(instantiatedType.GetTypeDefinition().ToString());
WriteTo(instantiatedType.Instantiation, sb);
}
else if (type is ArrayType arrayType)
{
WriteTo(arrayType.ElementType, sb);
sb.Append("[");
switch (arrayType.Rank)
{
case 0:
break;
case 1:
sb.Append("*");
break;
default:
sb.Append(new String(',', arrayType.Rank - 1));
break;
}
sb.Append("]");
}
else if (type is ByRefType byRefType)
{
WriteTo(byRefType.ParameterType, sb);
sb.Append("&");
}
else
{
Debug.Assert(type is DefType);
sb.Append(type.ToString());
}
}
public static void WriteTo(MethodDesc method, Utf8StringBuilder sb)
{
WriteTo(method.Signature.ReturnType, sb);
sb.Append(" ");
WriteTo(method.OwningType, sb);
sb.Append(method.Name);
if (method.HasInstantiation)
{
WriteTo(method.Instantiation, sb);
}
sb.Append("(");
for (int argIndex = 0; argIndex < method.Signature.Length; argIndex++)
{
if (argIndex != 0)
{
sb.Append(", ");
}
WriteTo(method.Signature[argIndex], sb);
}
sb.Append(")");
}
}
}

Просмотреть файл

@ -36,6 +36,7 @@
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\CompilerIdentifierNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\DebugInfoTableNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\DelayLoadHelperImport.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\GenericLookupSignature.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\ImportThunk.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\DelegateCtorSignature.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\DevirtualizationManager.cs" />
@ -48,6 +49,7 @@
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\ImportSectionsTableNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\InstanceEntryPointTableNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\IReadyToRunMethodCodeNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\LocalMethodImport.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\MethodEntryPointTableNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\MethodFixupSignature.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\MethodGCInfoNode.cs" />
@ -84,6 +86,7 @@
<Compile Include="Compiler\ReadyToRunNodeMangler.cs" />
<Compile Include="Compiler\ReadyToRunSingleAssemblyCompilationModuleGroup.cs" />
<Compile Include="Compiler\ReadyToRunTableManager.cs" />
<Compile Include="Compiler\RuntimeDeterminedTypeHelper.cs" />
<Compile Include="Compiler\SystemObjectFieldLayoutAlgorithm.cs" />
<Compile Include="IL\ReadyToRunILProvider.cs" />
<Compile Include="JitInterface\CorInfoImpl.ReadyToRun.cs" />

Просмотреть файл

@ -16,6 +16,18 @@ using ReadyToRunHelper = ILCompiler.ReadyToRunHelper;
namespace Internal.JitInterface
{
public class MethodWithToken
{
public readonly MethodDesc Method;
public readonly ModuleToken Token;
public MethodWithToken(MethodDesc method, ModuleToken token)
{
Method = method;
Token = token;
}
}
unsafe partial class CorInfoImpl
{
private const CORINFO_RUNTIME_ABI TargetABI = CORINFO_RUNTIME_ABI.CORINFO_CORECLR_ABI;
@ -180,7 +192,21 @@ namespace Internal.JitInterface
Debug.Assert(typeToInitialize.IsCanonicalSubtype(CanonicalFormKind.Any));
DefType helperArg = typeToInitialize.ConvertToSharedRuntimeDeterminedForm();
ISymbolNode helper = GetGenericLookupHelper(pGenericLookupKind.runtimeLookupKind, ReadyToRunHelperId.GetNonGCStaticBase, helperArg);
TypeDesc contextType;
if (pGenericLookupKind.runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ)
{
contextType = methodFromContext(pResolvedToken.tokenContext).OwningType;
}
else
{
contextType = null;
}
ISymbolNode helper = _compilation.SymbolNodeFactory.GenericLookupHelper(
pGenericLookupKind.runtimeLookupKind,
ReadyToRunHelperId.GetNonGCStaticBase,
helperArg,
contextType,
_signatureContext);
pLookup = CreateConstLookupToSymbol(helper);
}
break;
@ -190,7 +216,25 @@ namespace Internal.JitInterface
ReadyToRunHelperId helperId = (ReadyToRunHelperId)pGenericLookupKind.runtimeLookupFlags;
object helperArg = HandleToObject((IntPtr)pGenericLookupKind.runtimeLookupArgs);
ISymbolNode helper = GetGenericLookupHelper(pGenericLookupKind.runtimeLookupKind, helperId, helperArg);
if (helperArg is MethodDesc methodArg)
{
helperArg = new MethodWithToken(methodArg, new ModuleToken(_tokenContext, pResolvedToken.token));
}
TypeDesc contextType;
if (pGenericLookupKind.runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ)
{
contextType = methodFromContext(pResolvedToken.tokenContext).OwningType;
}
else
{
contextType = null;
}
ISymbolNode helper = _compilation.SymbolNodeFactory.GenericLookupHelper(
pGenericLookupKind.runtimeLookupKind,
helperId,
helperArg,
contextType,
_signatureContext);
pLookup = CreateConstLookupToSymbol(helper);
}
break;
@ -240,7 +284,7 @@ namespace Internal.JitInterface
{
pLookup.lookupKind.needsRuntimeLookup = false;
pLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.DelegateCtor(
delegateTypeDesc, targetMethod, _signatureContext));
delegateTypeDesc, targetMethod, new ModuleToken(_tokenContext, (mdToken)pTargetMethod.token), _signatureContext));
}
}
@ -534,7 +578,12 @@ namespace Internal.JitInterface
if (method.IsVirtual)
throw new NotImplementedException("getFunctionEntryPoint");
pResult = CreateConstLookupToSymbol(_compilation.NodeFactory.MethodEntrypoint(method));
pResult = CreateConstLookupToSymbol(_compilation.NodeFactory.MethodEntrypoint(
method,
constrainedType: null,
originalMethod: null,
methodToken: default(ModuleToken), // TODO!!!!
_signatureContext));
}
private InfoAccessType constructStringLiteral(CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue)

Просмотреть файл

@ -836,5 +836,23 @@ namespace Internal.JitInterface
_parameterIndexToNameMap = parameterIndexToNameMap;
}
private ISymbolNode GetGenericLookupHelper(CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind, ReadyToRunHelperId helperId, object helperArgument)
{
// Necessary type handle is not something that can be in a dictionary (only a constructed type).
// We only use necessary type handles if we can do a constant lookup.
if (helperId == ReadyToRunHelperId.NecessaryTypeHandle)
helperId = ReadyToRunHelperId.TypeHandle;
if (runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ
|| runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_CLASSPARAM)
{
return _compilation.NodeFactory.ReadyToRunHelperFromTypeLookup(helperId, helperArgument, MethodBeingCompiled.OwningType);
}
Debug.Assert(runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_METHODPARAM);
return _compilation.NodeFactory.ReadyToRunHelperFromDictionaryLookup(helperId, helperArgument, MethodBeingCompiled);
}
}
}

Просмотреть файл

@ -1428,23 +1428,6 @@ namespace Internal.JitInterface
return type.IsNullable ? CorInfoHelpFunc.CORINFO_HELP_UNBOX_NULLABLE : CorInfoHelpFunc.CORINFO_HELP_UNBOX;
}
private ISymbolNode GetGenericLookupHelper(CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind, ReadyToRunHelperId helperId, object helperArgument)
{
// Necessary type handle is not something that can be in a dictionary (only a constructed type).
// We only use necessary type handles if we can do a constant lookup.
if (helperId == ReadyToRunHelperId.NecessaryTypeHandle)
helperId = ReadyToRunHelperId.TypeHandle;
if (runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ
|| runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_CLASSPARAM)
{
return _compilation.NodeFactory.ReadyToRunHelperFromTypeLookup(helperId, helperArgument, MethodBeingCompiled.OwningType);
}
Debug.Assert(runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_METHODPARAM);
return _compilation.NodeFactory.ReadyToRunHelperFromDictionaryLookup(helperId, helperArgument, MethodBeingCompiled);
}
private byte* getHelperName(CorInfoHelpFunc helpFunc)
{
return (byte*)GetPin(StringToUTF8(helpFunc.ToString()));
@ -2689,7 +2672,8 @@ namespace Internal.JitInterface
// Calling a string constructor doesn't call the actual constructor.
pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(
#if READYTORUN
_compilation.NodeFactory.StringAllocator(targetMethod, _signatureContext)
_compilation.NodeFactory.StringAllocator(targetMethod,
new ModuleToken(_tokenContext, pResolvedToken.token), _signatureContext)
#else
_compilation.NodeFactory.StringAllocator(targetMethod)
@ -2706,7 +2690,8 @@ namespace Internal.JitInterface
Debug.Assert(!forceUseRuntimeLookup);
pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(
#if READYTORUN
_compilation.NodeFactory.MethodEntrypoint(targetMethod, constrainedType, method, _signatureContext)
_compilation.NodeFactory.MethodEntrypoint(targetMethod, constrainedType, method,
new ModuleToken(_tokenContext, pResolvedToken.token), _signatureContext)
#else
_compilation.NodeFactory.MethodEntrypoint(targetMethod)
#endif
@ -2719,7 +2704,8 @@ namespace Internal.JitInterface
if (targetMethod.RequiresInstMethodDescArg())
{
#if READYTORUN
instParam = _compilation.SymbolNodeFactory.MethodGenericDictionary(concreteMethod, _signatureContext);
instParam = _compilation.SymbolNodeFactory.MethodGenericDictionary(concreteMethod,
new ModuleToken(_tokenContext, pResolvedToken.token), _signatureContext);
#else
instParam = _compilation.NodeFactory.MethodGenericDictionary(concreteMethod);
#endif
@ -2741,7 +2727,8 @@ namespace Internal.JitInterface
pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(
#if READYTORUN
_compilation.NodeFactory.MethodEntrypoint(targetMethod, constrainedType, method, _signatureContext)
_compilation.NodeFactory.MethodEntrypoint(targetMethod, constrainedType, method,
new ModuleToken(_tokenContext, pResolvedToken.token), _signatureContext)
#else
_compilation.NodeFactory.MethodEntrypoint(targetMethod)
#endif
@ -2794,7 +2781,8 @@ namespace Internal.JitInterface
pResult->codePointerOrStubLookup.constLookup.accessType = InfoAccessType.IAT_PVALUE;
pResult->codePointerOrStubLookup.constLookup.addr = (void*)ObjectToHandle(
#if READYTORUN
_compilation.SymbolNodeFactory.InterfaceDispatchCell(targetMethod, _signatureContext, isUnboxingStub: false
_compilation.SymbolNodeFactory.InterfaceDispatchCell(targetMethod,
new ModuleToken(_tokenContext, (mdToken)pResolvedToken.token), _signatureContext, isUnboxingStub: false
#else
_compilation.NodeFactory.InterfaceDispatchCell(targetMethod
#endif // READYTORUN
@ -2853,7 +2841,13 @@ namespace Internal.JitInterface
pResult->codePointerOrStubLookup.constLookup =
CreateConstLookupToSymbol(
_compilation.NodeFactory.ReadyToRunHelper(helperId, slotDefiningMethod));
_compilation.NodeFactory.ReadyToRunHelper(helperId,
#if READYTORUN
new MethodWithToken(slotDefiningMethod, new ModuleToken(_tokenContext, pResolvedToken.token))
#else
slotDefiningMethod
#endif
));
}
// The current CoreRT ReadyToRun helpers do not handle null thisptr - ask the JIT to emit explicit null checks

Просмотреть файл

@ -472,6 +472,161 @@ internal class Program
return intResult == ExpectedIntResult && stringResult == ExpectedStringResult;
}
class GenericLookup<T>
{
public static bool CheckStaticTypeArg(string typeArgName)
{
return CompareArgName(typeof(T).ToString(), typeArgName);
}
public bool CheckInstanceTypeArg(string typeArgName)
{
return CompareArgName(typeof(T).ToString(), typeArgName);
}
public static bool CheckStaticTypeArg<U>(string tName, string uName)
{
return CompareArgName(typeof(T).ToString(), tName) && CompareArgName(typeof(U).ToString(), uName);
}
public bool CheckInstanceTypeArg<U>(string tName, string uName)
{
return CompareArgName(typeof(T).ToString(), tName) && CompareArgName(typeof(U).ToString(), uName);
}
private static bool CompareArgName(string actual, string expected)
{
if (actual == expected)
{
Console.WriteLine("Arg type match: {0}", actual);
return true;
}
else
{
Console.WriteLine("Arg type mismatch: actual = {0}, expected = {1}", actual, expected);
return false;
}
}
}
struct GenericStruct<T>
{
public T FieldOfT;
public GenericStruct(T fieldOfT)
{
FieldOfT = fieldOfT;
}
}
class GenericClass<T>
{
public T FieldOfT;
public GenericClass(T fieldOfT)
{
FieldOfT = fieldOfT;
}
}
private static bool ThisObjGenericLookupTest()
{
Console.WriteLine("ThisObjGenericLookup:");
bool result = true;
result &= (new GenericLookup<object>()).CheckInstanceTypeArg("System.Object");
result &= (new GenericLookup<string>()).CheckInstanceTypeArg("System.String");
result &= (new GenericLookup<int>()).CheckInstanceTypeArg("System.Int32");
result &= (new GenericLookup<GenericStruct<object>>()).CheckInstanceTypeArg("Program+GenericStruct`1[System.Object]");
result &= (new GenericLookup<GenericStruct<string>>()).CheckInstanceTypeArg("Program+GenericStruct`1[System.String]");
result &= (new GenericLookup<GenericStruct<int>>()).CheckInstanceTypeArg("Program+GenericStruct`1[System.Int32]");
result &= (new GenericLookup<GenericClass<object>>()).CheckInstanceTypeArg("Program+GenericClass`1[System.Object]");
result &= (new GenericLookup<GenericClass<string>>()).CheckInstanceTypeArg("Program+GenericClass`1[System.String]");
result &= (new GenericLookup<GenericClass<int>>()).CheckInstanceTypeArg("Program+GenericClass`1[System.Int32]");
return result;
}
private static bool ClassParamGenericLookupTest()
{
Console.WriteLine("ClassParamGenericLookup:");
bool result = true;
result &= GenericLookup<object>.CheckStaticTypeArg("System.Object");
result &= GenericLookup<string>.CheckStaticTypeArg("System.String");
result &= GenericLookup<int>.CheckStaticTypeArg("System.Int32");
result &= GenericLookup<GenericStruct<object>>.CheckStaticTypeArg("Program+GenericStruct`1[System.Object]");
result &= GenericLookup<GenericStruct<string>>.CheckStaticTypeArg("Program+GenericStruct`1[System.String]");
result &= GenericLookup<GenericStruct<int>>.CheckStaticTypeArg("Program+GenericStruct`1[System.Int32]");
result &= GenericLookup<GenericClass<object>>.CheckStaticTypeArg("Program+GenericClass`1[System.Object]");
result &= GenericLookup<GenericClass<string>>.CheckStaticTypeArg("Program+GenericClass`1[System.String]");
result &= GenericLookup<GenericClass<int>>.CheckStaticTypeArg("Program+GenericClass`1[System.Int32]");
return result;
}
private static bool MethodParamGenericLookupTest()
{
Console.WriteLine("MethodParamGenericLookup:");
bool result = true;
result &= GenericLookup<object>.CheckStaticTypeArg<int>("System.Object", "System.Int32");
result &= GenericLookup<string>.CheckStaticTypeArg<object>("System.String", "System.Object");
result &= GenericLookup<int>.CheckStaticTypeArg<string>("System.Int32", "System.String");
result &= GenericLookup<GenericStruct<object>>.CheckStaticTypeArg<GenericStruct<int>>(
"Program+GenericStruct`1[System.Object]", "Program+GenericStruct`1[System.Int32]");
result &= GenericLookup<GenericStruct<string>>.CheckStaticTypeArg<GenericStruct<object>>(
"Program+GenericStruct`1[System.String]", "Program+GenericStruct`1[System.Object]");
result &= GenericLookup<GenericStruct<int>>.CheckStaticTypeArg<GenericStruct<string>>(
"Program+GenericStruct`1[System.Int32]", "Program+GenericStruct`1[System.String]");
result &= GenericLookup<GenericClass<object>>.CheckStaticTypeArg<GenericClass<int>>(
"Program+GenericClass`1[System.Object]", "Program+GenericClass`1[System.Int32]");
result &= GenericLookup<GenericClass<string>>.CheckStaticTypeArg<GenericClass<object>>(
"Program+GenericClass`1[System.String]", "Program+GenericClass`1[System.Object]");
result &= GenericLookup<GenericClass<int>>.CheckStaticTypeArg<GenericClass<string>>(
"Program+GenericClass`1[System.Int32]", "Program+GenericClass`1[System.String]");
result &= GenericLookup<GenericClass<object>>.CheckStaticTypeArg<GenericStruct<int>>(
"Program+GenericClass`1[System.Object]", "Program+GenericStruct`1[System.Int32]");
result &= GenericLookup<GenericClass<string>>.CheckStaticTypeArg<GenericStruct<object>>(
"Program+GenericClass`1[System.String]", "Program+GenericStruct`1[System.Object]");
result &= GenericLookup<GenericClass<int>>.CheckStaticTypeArg<GenericStruct<string>>(
"Program+GenericClass`1[System.Int32]", "Program+GenericStruct`1[System.String]");
result &= GenericLookup<GenericStruct<object>>.CheckStaticTypeArg<GenericClass<int>>(
"Program+GenericStruct`1[System.Object]", "Program+GenericClass`1[System.Int32]");
result &= GenericLookup<GenericStruct<string>>.CheckStaticTypeArg<GenericClass<object>>(
"Program+GenericStruct`1[System.String]", "Program+GenericClass`1[System.Object]");
result &= GenericLookup<GenericStruct<int>>.CheckStaticTypeArg<GenericClass<string>>(
"Program+GenericStruct`1[System.Int32]", "Program+GenericClass`1[System.String]");
result &= (new GenericLookup<object>()).CheckInstanceTypeArg<GenericStruct<int>>(
"System.Object", "Program+GenericStruct`1[System.Int32]");
result &= (new GenericLookup<string>()).CheckInstanceTypeArg<GenericStruct<object>>(
"System.String", "Program+GenericStruct`1[System.Object]");
result &= (new GenericLookup<int>()).CheckInstanceTypeArg<GenericStruct<string>>(
"System.Int32", "Program+GenericStruct`1[System.String]");
result &= (new GenericLookup<GenericStruct<object>>()).CheckInstanceTypeArg<int>(
"Program+GenericStruct`1[System.Object]", "System.Int32");
result &= (new GenericLookup<GenericStruct<string>>()).CheckInstanceTypeArg<object>(
"Program+GenericStruct`1[System.String]", "System.Object");
result &= (new GenericLookup<GenericStruct<int>>()).CheckInstanceTypeArg<string>(
"Program+GenericStruct`1[System.Int32]", "System.String");
result &= (new GenericLookup<object>()).CheckInstanceTypeArg<GenericClass<int>>(
"System.Object", "Program+GenericClass`1[System.Int32]");
result &= (new GenericLookup<string>()).CheckInstanceTypeArg<GenericClass<object>>(
"System.String", "Program+GenericClass`1[System.Object]");
result &= (new GenericLookup<int>()).CheckInstanceTypeArg<GenericClass<string>>(
"System.Int32", "Program+GenericClass`1[System.String]");
result &= (new GenericLookup<GenericClass<object>>()).CheckInstanceTypeArg<int>(
"Program+GenericClass`1[System.Object]", "System.Int32");
result &= (new GenericLookup<GenericClass<string>>()).CheckInstanceTypeArg<object>(
"Program+GenericClass`1[System.String]", "System.Object");
result &= (new GenericLookup<GenericClass<int>>()).CheckInstanceTypeArg<string>(
"Program+GenericClass`1[System.Int32]", "System.String");
return result;
}
public static int Main(string[] args)
{
if (args.Length > 0)
@ -513,6 +668,9 @@ internal class Program
RunTest("TryCatch", TryCatch());
RunTest("FileStreamNullRefTryCatch", FileStreamNullRefTryCatch());
RunTest("InstanceMethodTest", InstanceMethodTest());
RunTest("ThisObjGenericLookupTest", ThisObjGenericLookupTest());
RunTest("ClassParamGenericLookupTest", ClassParamGenericLookupTest());
RunTest("MethodParamGenericLookupTest", MethodParamGenericLookupTest());
Console.WriteLine($@"{_passedTests.Count} tests pass:");
foreach (string testName in _passedTests)