// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics; using Internal.JitInterface; using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Internal.ReadyToRunConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { public class GenericLookupSignature : Signature { private readonly CORINFO_RUNTIME_LOOKUP_KIND _runtimeLookupKind; private readonly ReadyToRunFixupKind _fixupKind; private readonly TypeDesc _typeArgument; private readonly MethodWithToken _methodArgument; private readonly FieldWithToken _fieldArgument; private readonly GenericContext _methodContext; public GenericLookupSignature( CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind, ReadyToRunFixupKind fixupKind, TypeDesc typeArgument, MethodWithToken methodArgument, FieldWithToken fieldArgument, GenericContext methodContext) { Debug.Assert(typeArgument != null || methodArgument != null || fieldArgument != null); _runtimeLookupKind = runtimeLookupKind; _fixupKind = fixupKind; _typeArgument = typeArgument; _methodArgument = methodArgument; _fieldArgument = fieldArgument; _methodContext = methodContext; } public override int ClassCode => 258608008; public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { if (relocsOnly) { return new ObjectData(Array.Empty<byte>(), null, 1, null); } // Determine the need for module override IEcmaModule targetModule; if (_methodArgument != null) { targetModule = _methodArgument.Token.Module; } else if (_typeArgument != null) { targetModule = factory.SignatureContext.GetTargetModule(_typeArgument); } else if (_fieldArgument != null) { targetModule = _fieldArgument.Token.Module; } else { throw new NotImplementedException(); } ReadyToRunFixupKind fixupToEmit; TypeDesc contextTypeToEmit = null; switch (_runtimeLookupKind) { case CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_CLASSPARAM: fixupToEmit = ReadyToRunFixupKind.TypeDictionaryLookup; break; case CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_METHODPARAM: fixupToEmit = ReadyToRunFixupKind.MethodDictionaryLookup; break; case CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ: fixupToEmit = ReadyToRunFixupKind.ThisObjDictionaryLookup; contextTypeToEmit = _methodContext.ContextType; break; default: throw new NotImplementedException(); } ObjectDataSignatureBuilder dataBuilder = new ObjectDataSignatureBuilder(factory, relocsOnly); dataBuilder.AddSymbol(this); SignatureContext innerContext = dataBuilder.EmitFixup(factory, fixupToEmit, targetModule, factory.SignatureContext); if (contextTypeToEmit != null) { dataBuilder.EmitTypeSignature(contextTypeToEmit, innerContext); } dataBuilder.EmitByte((byte)_fixupKind); if (_methodArgument != null) { Debug.Assert(_methodArgument.Unboxing == false); dataBuilder.EmitMethodSignature( _methodArgument, enforceDefEncoding: false, enforceOwningType: false, context: innerContext, isInstantiatingStub: true); } else if (_typeArgument != null) { dataBuilder.EmitTypeSignature(_typeArgument, innerContext); } else if (_fieldArgument != null) { dataBuilder.EmitFieldSignature(_fieldArgument, innerContext); } else { throw new NotImplementedException(); } return dataBuilder.ToObjectData(); } protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) { DependencyList dependencies = null; if (_fixupKind == ReadyToRunFixupKind.TypeHandle) { TypeFixupSignature.AddDependenciesForAsyncStateMachineBox(ref dependencies, factory, _typeArgument); } return dependencies; } public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); sb.Append("GenericLookupSignature("u8); sb.Append(_runtimeLookupKind.ToString()); sb.Append(" / "u8); sb.Append(_fixupKind.ToString()); sb.Append(": "u8); if (_methodArgument != null) { sb.Append(nameMangler.GetMangledTypeName(_methodArgument.OwningType)); sb.Append("::"u8); sb.Append(nameMangler.GetMangledMethodName(_methodArgument.Method)); if (_methodArgument.ConstrainedType != null) { sb.Append("@"u8); sb.Append(nameMangler.GetMangledTypeName(_methodArgument.ConstrainedType)); } if (!_methodArgument.Token.IsNull) { sb.Append(" ["u8); sb.Append(_methodArgument.Token.MetadataReader.GetString(_methodArgument.Token.MetadataReader.GetAssemblyDefinition().Name)); sb.Append(":"u8); sb.Append(((uint)_methodArgument.Token.Token).ToString("X8")); sb.Append("]"u8); } } if (_typeArgument != null) { sb.Append(nameMangler.GetMangledTypeName(_typeArgument)); } if (_fieldArgument != null) { _fieldArgument.AppendMangledName(nameMangler, sb); } sb.Append(" ("u8); _methodContext.AppendMangledName(nameMangler, sb); sb.Append(")"u8); } public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { GenericLookupSignature otherNode = (GenericLookupSignature)other; int result = ((int)_runtimeLookupKind).CompareTo((int)otherNode._runtimeLookupKind); if (result != 0) return result; result = ((int)_fixupKind).CompareTo((int)otherNode._fixupKind); if (result != 0) return result; if (_typeArgument != null || otherNode._typeArgument != null) { if (_typeArgument == null) return -1; if (otherNode._typeArgument == null) return 1; result = comparer.Compare(_typeArgument, otherNode._typeArgument); if (result != 0) return result; } if (_fieldArgument != null || otherNode._fieldArgument != null) { if (_fieldArgument == null) return -1; if (otherNode._fieldArgument == null) return 1; result = _fieldArgument.CompareTo(otherNode._fieldArgument, comparer); if (result != 0) return result; } if (_methodArgument != null || otherNode._methodArgument != null) { if (_methodArgument == null) return -1; if (otherNode._methodArgument == null) return 1; result = _methodArgument.CompareTo(otherNode._methodArgument, comparer); if (result != 0) return result; } var contextAsMethod = _methodContext.Context as MethodDesc; var otherContextAsMethod = otherNode._methodContext.Context as MethodDesc; if (contextAsMethod != null || otherContextAsMethod != null) { if (contextAsMethod == null) return -1; if (otherContextAsMethod == null) return 1; return comparer.Compare(contextAsMethod, otherContextAsMethod); } else { return comparer.Compare(_methodContext.ContextType, otherNode._methodContext.ContextType); } } } } |