diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs index 5c2650c52616f..c9863573cf654 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelegateCtorSignature.cs @@ -14,12 +14,12 @@ public class DelegateCtorSignature : Signature private readonly IMethodNode _targetMethod; - private readonly ModuleToken _methodToken; + private readonly MethodWithToken _methodToken; public DelegateCtorSignature( TypeDesc delegateType, IMethodNode targetMethod, - ModuleToken methodToken) + MethodWithToken methodToken) { _delegateType = delegateType; _targetMethod = targetMethod; @@ -40,10 +40,10 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) if (!relocsOnly) { - SignatureContext innerContext = builder.EmitFixup(factory, ReadyToRunFixupKind.DelegateCtor, _methodToken.Module, factory.SignatureContext); + SignatureContext innerContext = builder.EmitFixup(factory, ReadyToRunFixupKind.DelegateCtor, _methodToken.Token.Module, factory.SignatureContext); builder.EmitMethodSignature( - new MethodWithToken(_targetMethod.Method, _methodToken, constrainedType: null, unboxing: false), + _methodToken, enforceDefEncoding: false, enforceOwningType: false, innerContext, @@ -88,7 +88,7 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer if (result != 0) return result; - return _methodToken.CompareTo(otherNode._methodToken); + return _methodToken.CompareTo(otherNode._methodToken, comparer); } } } diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs index 01098a7be573e..62b5f5ce8c18e 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/FieldFixupSignature.cs @@ -68,7 +68,8 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); - sb.Append($@"TypeFixupSignature({_fixupKind.ToString()}): {_fieldDesc.ToString()}"); + sb.Append($@"FieldFixupSignature({_fixupKind.ToString()}): "); + sb.Append(nameMangler.GetMangledFieldName(_fieldDesc)); } public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs index e337c0ea71200..03ccc73b7343b 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs @@ -61,7 +61,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) ArraySignatureBuilder signatureBuilder = new ArraySignatureBuilder(); signatureBuilder.EmitMethodSignature( - new MethodWithToken(method.Method, moduleToken, constrainedType: null, unboxing: false), + new MethodWithToken(method.Method, moduleToken, constrainedType: null, unboxing: false, context: null), enforceDefEncoding: true, enforceOwningType: _factory.CompilationModuleGroup.EnforceOwningType(moduleToken.Module), factory.SignatureContext, diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs index 58ea379d920b4..eaeddd907ea5a 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodFixupSignature.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using Internal.JitInterface; using Internal.Text; @@ -32,6 +35,8 @@ public MethodFixupSignature( // Ensure types in signature are loadable and resolvable, otherwise we'll fail later while emitting the signature CompilerTypeSystemContext compilerContext = (CompilerTypeSystemContext)method.Method.Context; compilerContext.EnsureLoadableMethod(method.Method); + compilerContext.EnsureLoadableType(_method.OwningType); + if (method.ConstrainedType != null) compilerContext.EnsureLoadableType(method.ConstrainedType); } @@ -68,8 +73,11 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) } else if (_method.Token.TokenType == CorTokenType.mdtMemberRef) { - fixupKind = ReadyToRunFixupKind.MethodEntry_RefToken; - optimized = true; + if (!_method.OwningTypeNotDerivedFromToken) + { + fixupKind = ReadyToRunFixupKind.MethodEntry_RefToken; + optimized = true; + } } } } @@ -80,13 +88,13 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { if (method.Token.TokenType == CorTokenType.mdtMethodSpec) { - method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method, throwIfNotFound: false), method.ConstrainedType, unboxing: _method.Unboxing); + method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method, throwIfNotFound: false), method.ConstrainedType, unboxing: _method.Unboxing, null); } else if (!optimized && (method.Token.TokenType == CorTokenType.mdtMemberRef)) { if (method.Method.OwningType.GetTypeDefinition() is EcmaType) { - method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method, throwIfNotFound: false), method.ConstrainedType, unboxing: _method.Unboxing); + method = new MethodWithToken(method.Method, factory.SignatureContext.GetModuleTokenForMethod(method.Method, throwIfNotFound: false), method.ConstrainedType, unboxing: _method.Unboxing, null); } } } diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs index fd80e7e74a582..a91aecaa25e41 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureBuilder.cs @@ -412,62 +412,12 @@ public void EmitMethodSignature( { flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_Constrained; } - if (enforceOwningType) + if (enforceOwningType || method.OwningTypeNotDerivedFromToken) { flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; } - if ((method.Method.HasInstantiation || method.Method.OwningType.HasInstantiation) && !method.Method.IsGenericMethodDefinition) - { - EmitMethodSpecificationSignature(method, flags, enforceDefEncoding, context); - } - else - { - switch (method.Token.TokenType) - { - case CorTokenType.mdtMethodDef: - { - EmitUInt(flags); - if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) - { - EmitTypeSignature(method.Method.OwningType, context); - } - EmitMethodDefToken(method.Token); - } - break; - - case CorTokenType.mdtMemberRef: - { - flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MemberRefToken; - - // Owner type is needed for type specs to instantiating stubs or generics with signature variables still present - if (!method.Method.OwningType.IsDefType && - ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_InstantiatingStub) != 0 || method.Method.OwningType.ContainsSignatureVariables())) - { - flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; - } - else if (method.Method.IsArrayMethod()) - { - var memberRefMethod = method.Token.Module.GetMethod(MetadataTokens.EntityHandle((int)method.Token.Token)); - if (memberRefMethod.OwningType != method.Method.OwningType) - { - flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; - } - } - - EmitUInt(flags); - if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) - { - EmitTypeSignature(method.Method.OwningType, context); - } - EmitMethodRefToken(method.Token); - } - break; - - default: - throw new NotImplementedException(); - } - } + EmitMethodSpecificationSignature(method, flags, enforceDefEncoding, context); if (method.ConstrainedType != null) { @@ -491,7 +441,7 @@ private void EmitMethodSpecificationSignature(MethodWithToken method, uint flags, bool enforceDefEncoding, SignatureContext context) { ModuleToken methodToken = method.Token; - if (method.Method.HasInstantiation) + if (method.Method.HasInstantiation && !method.Method.IsGenericMethodDefinition) { flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation; if (!method.Token.IsNull) @@ -504,23 +454,7 @@ private void EmitMethodSpecificationSignature(MethodWithToken method, } } - if (methodToken.IsNull && !enforceDefEncoding) - { - methodToken = context.GetModuleTokenForMethod(method.Method, throwIfNotFound: false); - } - if (methodToken.IsNull) - { - flags |= (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType; - methodToken = context.GetModuleTokenForMethod(method.Method); - } - - if (method.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; - } + Debug.Assert(!methodToken.IsNull); switch (methodToken.TokenType) { @@ -538,7 +472,8 @@ private void EmitMethodSpecificationSignature(MethodWithToken method, EmitUInt(flags); if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) { - EmitTypeSignature(method.Method.OwningType, context); + // The type here should be the type referred to by the memberref (if this is one, not the type where the method was eventually found! + EmitTypeSignature(method.OwningType, context); } EmitTokenRid(methodToken.Token); if ((flags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_MethodInstantiation) != 0) diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index 9f9ebf9366280..cf1e452041c34 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -396,7 +396,7 @@ public IEnumerable EnumerateCompiledMethods(EcmaModule moduleT EcmaModule module = ((EcmaMethod)method.GetTypicalMethodDefinition()).Module; ModuleToken moduleToken = Resolver.GetModuleTokenForMethod(method, throwIfNotFound: true); - IMethodNode methodNodeDebug = MethodEntrypoint(new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false), false, false); + IMethodNode methodNodeDebug = MethodEntrypoint(new MethodWithToken(method, moduleToken, constrainedType: null, unboxing: false, context: null), false, false); MethodWithGCInfo methodCodeNodeDebug = methodNodeDebug as MethodWithGCInfo; if (methodCodeNodeDebug == null && methodNodeDebug is DelayLoadMethodImport DelayLoadMethodImport) { diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs index 1178d4372c33a..539d4404ebcaf 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs @@ -124,7 +124,7 @@ private void CreateNodeCaches() _codegenNodeFactory, _codegenNodeFactory.HelperImports, ReadyToRunHelper.DelayLoad_Helper_ObjObj, - new DelegateCtorSignature(ctorKey.Type, targetMethodNode, ctorKey.Method.Token)); + new DelegateCtorSignature(ctorKey.Type, targetMethodNode, ctorKey.Method)); }); _checkTypeLayoutCache = new NodeCache(key => diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 3ca5d127aefb1..67a9f9eefa7f8 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -40,14 +40,139 @@ public class MethodWithToken public readonly ModuleToken Token; public readonly TypeDesc ConstrainedType; public readonly bool Unboxing; + public readonly bool OwningTypeNotDerivedFromToken; + public readonly TypeDesc OwningType; - public MethodWithToken(MethodDesc method, ModuleToken token, TypeDesc constrainedType, bool unboxing) + + public MethodWithToken(MethodDesc method, ModuleToken token, TypeDesc constrainedType, bool unboxing, object context) { Debug.Assert(!method.IsUnboxingThunk()); Method = method; Token = token; ConstrainedType = constrainedType; Unboxing = unboxing; + OwningType = GetMethodTokenOwningType(this, constrainedType, context, out OwningTypeNotDerivedFromToken); + } + + private static TypeDesc GetMethodTokenOwningType(MethodWithToken methodToken, TypeDesc constrainedType, object context, out bool owningTypeNotDerivedFromToken) + { + ModuleToken moduleToken = methodToken.Token; + owningTypeNotDerivedFromToken = false; + + // Strip off method spec details. The owning type is only associated with a MethodDef or a MemberRef + if (moduleToken.TokenType == CorTokenType.mdtMethodSpec) + { + var methodSpecification = moduleToken.MetadataReader.GetMethodSpecification((MethodSpecificationHandle)moduleToken.Handle); + moduleToken = new ModuleToken(moduleToken.Module, methodSpecification.Method); + } + + if (moduleToken.TokenType == CorTokenType.mdtMethodDef) + { + var methodDefinition = moduleToken.MetadataReader.GetMethodDefinition((MethodDefinitionHandle)moduleToken.Handle); + return HandleContext(moduleToken.Module, methodDefinition.GetDeclaringType(), methodToken.Method.OwningType, constrainedType, context, ref owningTypeNotDerivedFromToken); + } + + // At this point moduleToken must point at a MemberRef. + Debug.Assert(moduleToken.TokenType == CorTokenType.mdtMemberRef); + var memberRef = moduleToken.MetadataReader.GetMemberReference((MemberReferenceHandle)moduleToken.Handle); + switch (memberRef.Parent.Kind) + { + case HandleKind.TypeDefinition: + case HandleKind.TypeReference: + case HandleKind.TypeSpecification: + { + return HandleContext(moduleToken.Module, memberRef.Parent, methodToken.Method.OwningType, constrainedType, context, ref owningTypeNotDerivedFromToken); + } + + default: + return methodToken.Method.OwningType; + } + + TypeDesc HandleContext(EcmaModule module, EntityHandle handle, TypeDesc methodTargetOwner, TypeDesc constrainedType, object context, ref bool owningTypeNotDerivedFromToken) + { + var tokenOnlyOwningType = module.GetType(handle); + TypeDesc actualOwningType; + + if (context == null) + { + actualOwningType = methodTargetOwner; + } + else + { + Instantiation typeInstantiation; + Instantiation methodInstantiation = new Instantiation(); + + if (context is MethodDesc methodContext) + { + typeInstantiation = methodContext.OwningType.Instantiation; + methodInstantiation = methodContext.Instantiation; + } + else + { + TypeDesc typeContext = (TypeDesc)context; + typeInstantiation = typeContext.Instantiation; + } + + var instantiatedOwningType = tokenOnlyOwningType.InstantiateSignature(typeInstantiation, methodInstantiation); + var canonicalizedOwningType = instantiatedOwningType.ConvertToCanonForm(CanonicalFormKind.Specific); + if ((instantiatedOwningType == canonicalizedOwningType) || (constrainedType != null)) + { + actualOwningType = instantiatedOwningType; + } + else + { + actualOwningType = ComputeActualOwningType(methodTargetOwner, instantiatedOwningType, canonicalizedOwningType); + + // Implement via a helper function, so that managing the loop escape behavior is easier to read + TypeDesc ComputeActualOwningType(TypeDesc methodTargetOwner, TypeDesc instantiatedOwningType, TypeDesc canonicalizedOwningType) + { + // Pick between Canonical and Exact OwningTypes. + // + // If the canonicalizedOwningType is the OwningType (or parent type) of the associated method + // Then return canonicalizedOwningType + // Else If the Exact Owning type is the OwningType (or parent type) of the associated method + // Then return actualOwningType + // Else If the canonicallized owningType (or canonicalized parent type) of the associated method + // Return the canonicalizedOwningType + // Else + // Fail, unexpected behavior + var currentType = canonicalizedOwningType; + while (currentType != null) + { + if (currentType == methodTargetOwner) + return canonicalizedOwningType; + currentType = currentType.BaseType; + } + + currentType = instantiatedOwningType; + while (currentType != null) + { + if (currentType == methodTargetOwner) + return instantiatedOwningType; + currentType = currentType.BaseType; + } + + currentType = canonicalizedOwningType; + while (currentType != null) + { + currentType = currentType.ConvertToCanonForm(CanonicalFormKind.Specific); + if (currentType == methodTargetOwner) + return canonicalizedOwningType; + currentType = currentType.BaseType; + } + + Debug.Assert(false); + throw new Exception(); + } + } + } + + if (actualOwningType != tokenOnlyOwningType) + { + owningTypeNotDerivedFromToken = true; + } + return actualOwningType; + } } public override bool Equals(object obj) @@ -63,7 +188,15 @@ public override int GetHashCode() public bool Equals(MethodWithToken methodWithToken) { - return Method == methodWithToken.Method && Token.Equals(methodWithToken.Token) && ConstrainedType == methodWithToken.ConstrainedType && Unboxing == methodWithToken.Unboxing; + bool equals = Method == methodWithToken.Method && Token.Equals(methodWithToken.Token) && ConstrainedType == methodWithToken.ConstrainedType && + Unboxing == methodWithToken.Unboxing; + if (equals) + { + Debug.Assert(OwningTypeNotDerivedFromToken == methodWithToken.OwningTypeNotDerivedFromToken); + Debug.Assert(OwningType == methodWithToken.OwningType); + } + + return equals; } public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) @@ -103,7 +236,23 @@ public int CompareTo(MethodWithToken other, TypeSystemComparer comparer) if (result != 0) return result; - return Unboxing.CompareTo(other.Unboxing); + result = Unboxing.CompareTo(other.Unboxing); + if (result != 0) + return result; + + // The OwningType/OwningTypeNotDerivedFromToken shoud be equivalent if the above conditions are equal. + Debug.Assert(OwningTypeNotDerivedFromToken == other.OwningTypeNotDerivedFromToken); + Debug.Assert(OwningType == other.OwningType); + + if (OwningTypeNotDerivedFromToken != other.OwningTypeNotDerivedFromToken) + { + if (OwningTypeNotDerivedFromToken) + return 1; + else + return -1; + } + + return comparer.Compare(OwningType, other.OwningType); } } @@ -326,7 +475,9 @@ private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref object helperArg = GetRuntimeDeterminedObjectForToken(ref pResolvedToken); if (helperArg is MethodDesc methodDesc) { - helperArg = new MethodWithToken(methodDesc, HandleToModuleToken(ref pResolvedToken), constrainedType, unboxing: false); + var methodIL = (MethodIL)HandleToObject((IntPtr)pResolvedToken.tokenScope); + MethodDesc sharedMethod = methodIL.OwningMethod.GetSharedRuntimeFormMethodTarget(); + helperArg = new MethodWithToken(methodDesc, HandleToModuleToken(ref pResolvedToken), constrainedType, unboxing: false, context: sharedMethod); } GenericContext methodContext = new GenericContext(entityFromContext(pResolvedToken.tokenContext)); @@ -356,7 +507,7 @@ private void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetM TypeDesc delegateTypeDesc = HandleToObject(delegateType); MethodDesc targetMethodDesc = HandleToObject(pTargetMethod.hMethod); Debug.Assert(!targetMethodDesc.IsUnboxingThunk()); - MethodWithToken targetMethod = new MethodWithToken(targetMethodDesc, HandleToModuleToken(ref pTargetMethod), constrainedType: null, unboxing: false); + MethodWithToken targetMethod = new MethodWithToken(targetMethodDesc, HandleToModuleToken(ref pTargetMethod), constrainedType: null, unboxing: false, context: entityFromContext(pTargetMethod.tokenContext)); pLookup.lookupKind.needsRuntimeLookup = false; pLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.DelegateCtor(delegateTypeDesc, targetMethod)); @@ -680,7 +831,13 @@ private bool canTailCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUC return false; } - private ModuleToken HandleToModuleToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken, MethodDesc methodDesc) + private MethodWithToken ComputeMethodWithToken(MethodDesc method, ref CORINFO_RESOLVED_TOKEN pResolvedToken, TypeDesc constrainedType, bool unboxing) + { + ModuleToken token = HandleToModuleToken(ref pResolvedToken, method, out object context, ref constrainedType); + return new MethodWithToken(method, token, constrainedType: constrainedType, unboxing: unboxing, context: context); + } + + private ModuleToken HandleToModuleToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken, MethodDesc methodDesc, out object context, ref TypeDesc constrainedType) { if (methodDesc != null && (_compilation.NodeFactory.CompilationModuleGroup.VersionsWithMethodBody(methodDesc) || methodDesc.IsPInvoke)) { @@ -688,12 +845,20 @@ private ModuleToken HandleToModuleToken(ref CORINFO_RESOLVED_TOKEN pResolvedToke methodDesc?.GetTypicalMethodDefinition() is EcmaMethod ecmaMethod) { mdToken token = (mdToken)MetadataTokens.GetToken(ecmaMethod.Handle); + + // This is used for de-virtualization of non-generic virtual methods, and should be treated + // as a the methodDesc parameter defining the exact OwningType, not doing resolution through the token. + context = null; + constrainedType = null; + return new ModuleToken(ecmaMethod.Module, token); } } + context = entityFromContext(pResolvedToken.tokenContext); return HandleToModuleToken(ref pResolvedToken); } + private ModuleToken HandleToModuleToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) { mdToken token = pResolvedToken.token; @@ -1613,7 +1778,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol( _compilation.SymbolNodeFactory.InterfaceDispatchCell( - new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType: null, unboxing: false), + ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: null, unboxing: false), MethodBeingCompiled)); // If the abi of the method isn't stable, this will cause a usage of the RequiresRuntimeJitSymbol, which will trigger a RequiresRuntimeJitException @@ -1652,7 +1817,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO // READYTORUN: FUTURE: Direct calls if possible pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol( _compilation.NodeFactory.MethodEntrypoint( - new MethodWithToken(nonUnboxingMethod, HandleToModuleToken(ref pResolvedToken, nonUnboxingMethod), constrainedType, unboxing: isUnboxingStub), + ComputeMethodWithToken(nonUnboxingMethod, ref pResolvedToken, constrainedType, unboxing: isUnboxingStub), isInstantiatingStub: useInstantiatingStub, isPrecodeImportRequired: (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0)); @@ -1675,7 +1840,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO bool atypicalCallsite = (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_ATYPICAL_CALLSITE) != 0; pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol( _compilation.NodeFactory.DynamicHelperCell( - new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType: null, unboxing: false), + ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: null, unboxing: false), useInstantiatingStub)); Debug.Assert(!pResult->sig.hasTypeArg()); @@ -1702,7 +1867,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO { pResult->instParamLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper( ReadyToRunHelperId.MethodDictionary, - new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType, unboxing: false))); + ComputeMethodWithToken(targetMethod, ref pResolvedToken, constrainedType: constrainedType, unboxing: false))); } else { @@ -1941,7 +2106,7 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool symbolNode = _compilation.SymbolNodeFactory.CreateReadyToRunHelper( ReadyToRunHelperId.MethodHandle, - new MethodWithToken(md, HandleToModuleToken(ref pResolvedToken), constrainedType: null, unboxing: unboxingStub)); + ComputeMethodWithToken(md, ref pResolvedToken, constrainedType: null, unboxing: unboxingStub)); } break; @@ -2179,7 +2344,7 @@ private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORIN methodDesc = rawPInvoke.Target; EcmaMethod ecmaMethod = (EcmaMethod)methodDesc; ModuleToken moduleToken = new ModuleToken(ecmaMethod.Module, ecmaMethod.Handle); - MethodWithToken methodWithToken = new MethodWithToken(ecmaMethod, moduleToken, constrainedType: null, unboxing: false); + MethodWithToken methodWithToken = new MethodWithToken(ecmaMethod, moduleToken, constrainedType: null, unboxing: false, context: null); if (ecmaMethod.IsSuppressGCTransition()) { diff --git a/src/tests/build.cmd b/src/tests/build.cmd index ea6d47d076f8a..499e069000d8e 100644 --- a/src/tests/build.cmd +++ b/src/tests/build.cmd @@ -637,7 +637,7 @@ set __CrossgenCmd="%__RepoRootDir%\dotnet.cmd" "%CORE_ROOT%\R2RTest\R2RTest.dll" if defined __CompositeBuildMode ( set __CrossgenCmd=%__CrossgenCmd% --composite ) else ( - set __CrossgenCmd=%__CrossgenCmd% --large-bubble + set __CrossgenCmd=%__CrossgenCmd% --large-bubble --crossgen2-parallelism 1 ) set __CrossgenDir=%__BinDir% @@ -659,7 +659,7 @@ if defined __DoCrossgen ( if /i "%__BuildArch%" == "x86" ( set __CrossgenDir=!__CrossgenDir!\x64 ) - set __CrossgenCmd=%__CrossgenCmd% --verify-type-and-field-layout --crossgen2-parallelism 1 --crossgen2-path "!__CrossgenDir!\crossgen2\crossgen2.dll" + set __CrossgenCmd=%__CrossgenCmd% --verify-type-and-field-layout --crossgen2-path "!__CrossgenDir!\crossgen2\crossgen2.dll" ) echo Running %__CrossgenCmd% diff --git a/src/tests/build.sh b/src/tests/build.sh index 9b35b7def652f..cfd6aad741593 100755 --- a/src/tests/build.sh +++ b/src/tests/build.sh @@ -174,6 +174,8 @@ precompile_coreroot_fx() if [[ "$__CompositeBuildMode" != 0 ]]; then crossgenCmd="$crossgenCmd --composite" + else + crossgenCmd="$crossgenCmd --crossgen2-parallelism 1" fi local crossgenDir="$__BinDir" @@ -184,7 +186,7 @@ precompile_coreroot_fx() if [[ "$__DoCrossgen" != 0 ]]; then crossgenCmd="$crossgenCmd --crossgen --nocrossgen2 --crossgen-path \"$crossgenDir/crossgen\"" else - crossgenCmd="$crossgenCmd --verify-type-and-field-layout --crossgen2-parallelism 1 --crossgen2-path \"$crossgenDir/crossgen2/crossgen2.dll\"" + crossgenCmd="$crossgenCmd --verify-type-and-field-layout --crossgen2-path \"$crossgenDir/crossgen2/crossgen2.dll\"" fi echo "Running $crossgenCmd" diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 587bf6b360b1a..5916773076ea1 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -943,226 +943,6 @@ - - - - https://github.com/dotnet/runtime/issues/43466 - - - https://github.com/dotnet/runtime/issues/43466 - - - https://github.com/dotnet/runtime/issues/43466 - - - https://github.com/dotnet/runtime/issues/43466 - - - https://github.com/dotnet/runtime/issues/43466 - - - https://github.com/dotnet/runtime/issues/43466 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - https://github.com/dotnet/runtime/issues/43467 - - - @@ -1773,6 +1553,9 @@ needs triage + + needs triage + needs triage diff --git a/src/tests/readytorun/crossgen2/Program.cs b/src/tests/readytorun/crossgen2/Program.cs index 348b0e122e242..b0c011e5b94a8 100644 --- a/src/tests/readytorun/crossgen2/Program.cs +++ b/src/tests/readytorun/crossgen2/Program.cs @@ -2164,6 +2164,11 @@ public static int Main(string[] args) TextFileName = EmitTextFileForTesting(); + RunTest("CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller", HelperILDllTests.CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller()); + RunTest("CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller", HelperILDllTests.CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller()); + RunTest("CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCreateDelegate", HelperILDllTests.CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCreateDelegate()); + RunTest("CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller", HelperILDllTests.CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller()); + RunTest("CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller", HelperILDllTests.CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller()); RunTest("NewString", NewString()); RunTest("WriteLine", WriteLine()); RunTest("IsInstanceOf", IsInstanceOf()); @@ -2227,7 +2232,6 @@ public static int Main(string[] args) RunTest("TestWithStructureNonBlittableFieldDueToGenerics", TestWithStructureNonBlittableFieldDueToGenerics()); RunTest("TestSingleElementStructABI", TestSingleElementStructABI()); RunTest("TestEnumLayoutAlignments", TestEnumLayoutAlignments()); - File.Delete(TextFileName); Console.WriteLine($@"{_passedTests.Count} tests pass:"); diff --git a/src/tests/readytorun/crossgen2/crossgen2smoke.csproj b/src/tests/readytorun/crossgen2/crossgen2smoke.csproj index eb44c22d788f0..c233cd8dcbd04 100644 --- a/src/tests/readytorun/crossgen2/crossgen2smoke.csproj +++ b/src/tests/readytorun/crossgen2/crossgen2smoke.csproj @@ -1,21 +1,10 @@ - exe - BuildAndRun - true - 0 - true true - - - - - - - + diff --git a/src/tests/readytorun/crossgen2/crossgen2smoke_donotalwaysusecrossgen2.csproj b/src/tests/readytorun/crossgen2/crossgen2smoke_donotalwaysusecrossgen2.csproj new file mode 100644 index 0000000000000..04b56bcc111dc --- /dev/null +++ b/src/tests/readytorun/crossgen2/crossgen2smoke_donotalwaysusecrossgen2.csproj @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/tests/readytorun/crossgen2/helperdll.cs b/src/tests/readytorun/crossgen2/helperdll.cs index 82a4928fabf32..79427e84764d3 100644 --- a/src/tests/readytorun/crossgen2/helperdll.cs +++ b/src/tests/readytorun/crossgen2/helperdll.cs @@ -69,3 +69,29 @@ public int GenericFunction(T genericValue, V genericMethodValue, string toStr return inputIntValue; } } + +public class BaseTypeNonGenericMethodActuallyOnBase +{ + public string Method() + { + return "BaseTypeNonGenericMethodActuallyOnBase::Method"; + } + + public string GenMethod() + { + return "BaseTypeNonGenericMethodActuallyOnBase::GenMethod"; + } +} + +public class BaseTypeGenericMethodActuallyOnBase +{ + public string Method() + { + return "BaseTypeGenericMethodActuallyOnBase::Method"; + } + + public string GenMethod() + { + return "BaseTypeGenericMethodActuallyOnBase::GenMethod"; + } +} diff --git a/src/tests/readytorun/crossgen2/helperildll.il b/src/tests/readytorun/crossgen2/helperildll.il index 752d16c83c151..ed3b7327a6ea0 100644 --- a/src/tests/readytorun/crossgen2/helperildll.il +++ b/src/tests/readytorun/crossgen2/helperildll.il @@ -155,3 +155,128 @@ ret } } + +.class auto ansi public beforefieldinit BaseTypeNonGenericMethodActuallyOnBase_ModuleLocal extends [mscorlib]System.Object +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig instance string Method() cil managed noinlining + { + ldstr "BaseTypeNonGenericMethodActuallyOnBase::Method" + ret + } +} + +.class auto ansi public beforefieldinit DerivedTypeGenericMethodActuallyOnBase_ModuleLocal`1 extends BaseTypeNonGenericMethodActuallyOnBase_ModuleLocal +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void BaseTypeNonGenericMethodActuallyOnBase_ModuleLocal::.ctor() + ret + } +} + +.class auto ansi public beforefieldinit DerivedTypeGenericMethodActuallyOnBase`1 extends [helperdll]BaseTypeNonGenericMethodActuallyOnBase +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [helperdll]BaseTypeNonGenericMethodActuallyOnBase::.ctor() + ret + } +} + +.class auto ansi public beforefieldinit DerivedTypeNonGenericMethodActuallyOnBase`1 extends class [helperdll]BaseTypeGenericMethodActuallyOnBase +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void class [helperdll]BaseTypeGenericMethodActuallyOnBase::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit HelperILDllTests { + + .method static class [mscorlib]System.Func`1 GetDelegateMethodFromGenericType() cil managed noinlining + { + newobj instance void class DerivedTypeGenericMethodActuallyOnBase_ModuleLocal`1::.ctor() + ldftn instance string class DerivedTypeGenericMethodActuallyOnBase_ModuleLocal`1::Method() + newobj instance void class [mscorlib]System.Func`1::.ctor(object, native int) + ret + } + + .method static string CallMethodFromGenericType() cil managed noinlining + { + newobj instance void class DerivedTypeGenericMethodActuallyOnBase`1::.ctor() + callvirt instance string class DerivedTypeGenericMethodActuallyOnBase`1::Method() + ret + } + + .method static string CallGenMethodFromGenericType() cil managed noinlining + { + newobj instance void class DerivedTypeGenericMethodActuallyOnBase`1::.ctor() + callvirt instance string class DerivedTypeGenericMethodActuallyOnBase`1::GenMethod() + ret + } + + .method public hidebysig static bool CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCreateDelegate() cil managed noinlining + { + .maxstack 10 + .locals init (object V_0) + call class [mscorlib]System.Func`1 HelperILDllTests::GetDelegateMethodFromGenericType() + callvirt instance !0 class [mscorlib]System.Func`1::Invoke() + ldstr "BaseTypeNonGenericMethodActuallyOnBase::Method" + call bool [mscorlib]System.String::op_Equality(string,string) + ret + } + + + .method public hidebysig static bool CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller() cil managed noinlining + { + .maxstack 10 + .locals init (object V_0) + call string HelperILDllTests::CallMethodFromGenericType() + ldstr "BaseTypeNonGenericMethodActuallyOnBase::Method" + call bool [mscorlib]System.String::op_Equality(string,string) + ret + } + + .method public hidebysig static bool CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_GenericCaller() cil managed noinlining + { + .maxstack 10 + .locals init (object V_0) + call string HelperILDllTests::CallGenMethodFromGenericType() + ldstr "BaseTypeNonGenericMethodActuallyOnBase::GenMethod" + call bool [mscorlib]System.String::op_Equality(string,string) + ret + } + + .method public hidebysig static bool CallMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller() cil managed noinlining + { + .maxstack 10 + .locals init (object V_0) + newobj instance void class DerivedTypeGenericMethodActuallyOnBase`1::.ctor() + callvirt instance string class DerivedTypeGenericMethodActuallyOnBase`1::Method() + ldstr "BaseTypeNonGenericMethodActuallyOnBase::Method" + call bool [mscorlib]System.String::op_Equality(string,string) + ret + } + + .method public hidebysig static bool CallGenMethodUsingMemberRefToDerivedWhereMethodIsActuallyOnBase_NonGenericCaller() cil managed noinlining + { + .maxstack 10 + .locals init (object V_0) + newobj instance void class DerivedTypeGenericMethodActuallyOnBase`1::.ctor() + callvirt instance string class DerivedTypeGenericMethodActuallyOnBase`1::GenMethod() + ldstr "BaseTypeNonGenericMethodActuallyOnBase::GenMethod" + call bool [mscorlib]System.String::op_Equality(string,string) + ret + } +} diff --git a/src/tests/readytorun/crossgen2/smoketest.targets b/src/tests/readytorun/crossgen2/smoketest.targets new file mode 100644 index 0000000000000..085ef5d2c261c --- /dev/null +++ b/src/tests/readytorun/crossgen2/smoketest.targets @@ -0,0 +1,16 @@ + + + + exe + BuildAndRun + true + 0 + + + + + + + + + \ No newline at end of file