public static MethodIL EmitIL(MethodDesc target) { Debug.Assert(target.Name == "EETypePtrOf"); Debug.Assert(target.Signature.Length == 0 && target.Signature.ReturnType == target.OwningType); Debug.Assert(target.Instantiation.Length == 1); ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); TypeSystemContext context = target.Context; TypeDesc runtimeTypeHandleType = context.GetWellKnownType(WellKnownType.RuntimeTypeHandle); MethodDesc getValueInternalMethod = runtimeTypeHandleType.GetKnownMethod("GetValueInternal", null); MethodDesc eetypePtrCtorMethod = context.SystemModule .GetKnownType("System", "EETypePtr") .GetKnownMethod(".ctor", new MethodSignature(0, 0, context.GetWellKnownType(WellKnownType.Void), new TypeDesc[] { context.GetWellKnownType(WellKnownType.IntPtr) })); // The sequence of these instructions is important. JIT is able to optimize out // the LDTOKEN+GetValueInternal call into "load EEType pointer onto the evaluation stack". codeStream.Emit(ILOpcode.ldtoken, emitter.NewToken(context.GetSignatureVariable(0, true))); codeStream.Emit(ILOpcode.call, emitter.NewToken(getValueInternalMethod)); codeStream.Emit(ILOpcode.newobj, emitter.NewToken(eetypePtrCtorMethod)); codeStream.Emit(ILOpcode.ret); return(emitter.Link()); }
public override MethodIL EmitIL() { if (_owningType.BoxedValue == null) { // If this is the fake unboxing thunk for ByRef-like types, just make a method that throws. return(new ILStubMethodIL(this, new byte[] { (byte)ILOpcode.ldnull, (byte)ILOpcode.throw_ }, Array.Empty <LocalVariableDefinition>(), Array.Empty <object>())); } // Generate the unboxing stub. This loosely corresponds to following C#: // return BoxedValue.InstanceMethod([rest of parameters]) ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); FieldDesc boxedValueField = _owningType.BoxedValue.InstantiateAsOpen(); // unbox to get a pointer to the value type codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldflda, emit.NewToken(boxedValueField)); // Load rest of the arguments for (int i = 0; i < _targetMethod.Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } TypeDesc owner = _targetMethod.OwningType; MethodDesc methodToInstantiate = _targetMethod; if (owner.HasInstantiation) { MetadataType instantiatedOwner = (MetadataType)owner.InstantiateAsOpen(); methodToInstantiate = _targetMethod.Context.GetMethodForInstantiatedType(_targetMethod, (InstantiatedType)instantiatedOwner); } if (methodToInstantiate.HasInstantiation) { TypeSystemContext context = methodToInstantiate.Context; var inst = new TypeDesc[methodToInstantiate.Instantiation.Length]; for (int i = 0; i < inst.Length; i++) { inst[i] = context.GetSignatureVariable(i, true); } methodToInstantiate = context.GetInstantiatedMethod(methodToInstantiate, new Instantiation(inst)); } codeStream.Emit(ILOpcode.call, emit.NewToken(methodToInstantiate)); codeStream.Emit(ILOpcode.ret); return(emit.Link(this)); }
private static MethodIL EmitSizeOf(MethodDesc method) { Debug.Assert(method.Signature.IsStatic && method.Signature.Length == 0); TypeSystemContext context = method.Context; ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.Emit(ILOpcode.sizeof_, emit.NewToken(context.GetSignatureVariable(0, method: true))); codeStream.Emit(ILOpcode.ret); return(emit.Link(method)); }
private static MethodIL EmitCopy(MethodDesc method) { Debug.Assert(method.Signature.IsStatic && method.Signature.Length == 2); TypeSystemContext context = method.Context; ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); ILToken token = emit.NewToken(context.GetSignatureVariable(0, method: true)); codeStream.EmitLdArg(0); codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.ldobj, token); codeStream.Emit(ILOpcode.stobj, token); codeStream.Emit(ILOpcode.ret); return(emit.Link(method)); }
private static MethodIL EmitReadWrite(MethodDesc method, bool write, bool unaligned = false) { Debug.Assert(method.Signature.IsStatic && method.Signature.Length == (write ? 2 : 1)); TypeSystemContext context = method.Context; ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.EmitLdArg(0); if (write) { codeStream.EmitLdArg(1); } if (unaligned) { codeStream.EmitUnaligned(); } codeStream.Emit(write ? ILOpcode.stobj : ILOpcode.ldobj, emit.NewToken(context.GetSignatureVariable(0, method: true))); codeStream.Emit(ILOpcode.ret); return(emit.Link(method)); }
public override MethodIL GetMethodIL(MethodDesc method) { RemoveAction action = GetAction(method); switch (action) { case RemoveAction.Nothing: return(_baseILProvider.GetMethodIL(method)); case RemoveAction.ConvertToStub: if (method.Signature.ReturnType.IsVoid) { return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), null)); } else if (method.Signature.ReturnType.Category == TypeFlags.Boolean) { return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldc_i4_0, (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), null)); } else { goto default; } case RemoveAction.ConvertToTrueStub: return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldc_i4_1, (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), null)); case RemoveAction.ConvertToGetResourceStringStub: return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), null)); case RemoveAction.ConvertToThrow: return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldnull, (byte)ILOpcode.throw_ }, Array.Empty <LocalVariableDefinition>(), null)); case RemoveAction.ConvertToGetKnownObjectComparer: case RemoveAction.ConvertToGetKnownObjectEqualityComparer: { TypeSystemContext context = method.Context; MetadataType comparerType = action == RemoveAction.ConvertToGetKnownObjectComparer ? context.SystemModule.GetType("System.Collections.Generic", "ObjectComparer`1") : context.SystemModule.GetType("System.Collections.Generic", "ObjectEqualityComparer`1"); MethodDesc methodDef = method.GetTypicalMethodDefinition(); ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); FieldDesc defaultField = methodDef.OwningType.InstantiateAsOpen().GetField("s_default"); TypeDesc objectType = context.GetWellKnownType(WellKnownType.Object); MethodDesc compareExchangeObject = context.SystemModule. GetType("System.Threading", "Interlocked"). GetMethod("CompareExchange", new MethodSignature( MethodSignatureFlags.Static, genericParameterCount: 0, returnType: objectType, parameters: new TypeDesc[] { objectType.MakeByRefType(), objectType, objectType })); codeStream.Emit(ILOpcode.ldsflda, emitter.NewToken(defaultField)); codeStream.Emit(ILOpcode.newobj, emitter.NewToken(comparerType.MakeInstantiatedType(context.GetSignatureVariable(0, method: false)).GetDefaultConstructor())); codeStream.Emit(ILOpcode.ldnull); codeStream.Emit(ILOpcode.call, emitter.NewToken(compareExchangeObject)); codeStream.Emit(ILOpcode.pop); codeStream.Emit(ILOpcode.ldsfld, emitter.NewToken(defaultField)); codeStream.Emit(ILOpcode.ret); return(new InstantiatedMethodIL(method, emitter.Link(methodDef))); } default: throw new NotImplementedException(); } }
private TypeDesc ParseTypeImpl(SignatureTypeCode typeCode) { // Switch on the type. switch (typeCode) { case SignatureTypeCode.Void: return(GetWellKnownType(WellKnownType.Void)); case SignatureTypeCode.Boolean: return(GetWellKnownType(WellKnownType.Boolean)); case SignatureTypeCode.SByte: return(GetWellKnownType(WellKnownType.SByte)); case SignatureTypeCode.Byte: return(GetWellKnownType(WellKnownType.Byte)); case SignatureTypeCode.Int16: return(GetWellKnownType(WellKnownType.Int16)); case SignatureTypeCode.UInt16: return(GetWellKnownType(WellKnownType.UInt16)); case SignatureTypeCode.Int32: return(GetWellKnownType(WellKnownType.Int32)); case SignatureTypeCode.UInt32: return(GetWellKnownType(WellKnownType.UInt32)); case SignatureTypeCode.Int64: return(GetWellKnownType(WellKnownType.Int64)); case SignatureTypeCode.UInt64: return(GetWellKnownType(WellKnownType.UInt64)); case SignatureTypeCode.Single: return(GetWellKnownType(WellKnownType.Single)); case SignatureTypeCode.Double: return(GetWellKnownType(WellKnownType.Double)); case SignatureTypeCode.Char: return(GetWellKnownType(WellKnownType.Char)); case SignatureTypeCode.String: return(GetWellKnownType(WellKnownType.String)); case SignatureTypeCode.IntPtr: return(GetWellKnownType(WellKnownType.IntPtr)); case SignatureTypeCode.UIntPtr: return(GetWellKnownType(WellKnownType.UIntPtr)); case SignatureTypeCode.Object: return(GetWellKnownType(WellKnownType.Object)); case SignatureTypeCode.TypeHandle: return(ResolveHandle(_reader.ReadTypeHandle())); case SignatureTypeCode.SZArray: { var elementType = ParseType(); if (elementType == null) { return(null); } return(_tsc.GetArrayType(elementType)); } case SignatureTypeCode.Array: { var elementType = ParseType(); var rank = _reader.ReadCompressedInteger(); if (_embeddedSignatureDataList != null) { var boundsCount = _reader.ReadCompressedInteger(); int [] bounds = boundsCount > 0 ? new int[boundsCount] : Array.Empty <int>(); for (int i = 0; i < boundsCount; i++) { bounds[i] = _reader.ReadCompressedInteger(); } var lowerBoundsCount = _reader.ReadCompressedInteger(); int [] lowerBounds = lowerBoundsCount > 0 ? new int[lowerBoundsCount] : Array.Empty <int>(); bool nonZeroLowerBounds = false; for (int j = 0; j < lowerBoundsCount; j++) { int loBound = _reader.ReadCompressedSignedInteger(); if (loBound != 0) { nonZeroLowerBounds = true; } lowerBounds[j] = loBound; } if (boundsCount != 0 || lowerBoundsCount != rank || nonZeroLowerBounds) { StringBuilder arrayShapeString = new StringBuilder(); arrayShapeString.Append(string.Join(",", bounds)); arrayShapeString.Append('|'); arrayShapeString.Append(string.Join(",", lowerBounds)); _embeddedSignatureDataList.Add(new EmbeddedSignatureData { index = string.Join(".", _indexStack) + "|" + arrayShapeString.ToString(), kind = EmbeddedSignatureDataKind.ArrayShape, type = null }); } } else { var boundsCount = _reader.ReadCompressedInteger(); for (int i = 0; i < boundsCount; i++) { _reader.ReadCompressedInteger(); } var lowerBoundsCount = _reader.ReadCompressedInteger(); for (int j = 0; j < lowerBoundsCount; j++) { _reader.ReadCompressedSignedInteger(); } } if (elementType != null) { return(_tsc.GetArrayType(elementType, rank)); } else { return(null); } } case SignatureTypeCode.ByReference: { TypeDesc byRefedType = ParseType(); if (byRefedType != null) { return(byRefedType.MakeByRefType()); } else { return(null); } } case SignatureTypeCode.Pointer: { TypeDesc pointedAtType = ParseType(); if (pointedAtType != null) { return(_tsc.GetPointerType(pointedAtType)); } else { return(null); } } case SignatureTypeCode.GenericTypeParameter: return(_tsc.GetSignatureVariable(_reader.ReadCompressedInteger(), false)); case SignatureTypeCode.GenericMethodParameter: return(_tsc.GetSignatureVariable(_reader.ReadCompressedInteger(), true)); case SignatureTypeCode.GenericTypeInstance: { TypeDesc typeDef = ParseType(); MetadataType metadataTypeDef = null; if (typeDef != null) { metadataTypeDef = typeDef as MetadataType; if (metadataTypeDef == null) { throw new BadImageFormatException(); } } TypeDesc[] instance = new TypeDesc[_reader.ReadCompressedInteger()]; for (int i = 0; i < instance.Length; i++) { instance[i] = ParseType(); if (instance[i] == null) { metadataTypeDef = null; } } if (metadataTypeDef != null) { return(_tsc.GetInstantiatedType(metadataTypeDef, new Instantiation(instance))); } else { return(null); } } case SignatureTypeCode.TypedReference: return(GetWellKnownType(WellKnownType.TypedReference)); case SignatureTypeCode.FunctionPointer: MethodSignature sig = ParseMethodSignatureInternal(skipEmbeddedSignatureData: true); if (sig != null) { return(_tsc.GetFunctionPointerType(sig)); } else { return(null); } default: throw new BadImageFormatException(); } }
/// <summary> /// Provides method bodies for intrinsics recognized by the compiler that /// are specialized per instantiation. It can return null if the intrinsic /// is not recognized. /// </summary> private MethodIL TryGetPerInstantiationIntrinsicMethodIL(MethodDesc method) { Debug.Assert(method.IsIntrinsic); MetadataType owningType = method.OwningType.GetTypeDefinition() as MetadataType; if (owningType == null) { return(null); } string methodName = method.Name; switch (owningType.Name) { case "Activator": { TypeSystemContext context = owningType.Context; if (methodName == "CreateInstance" && method.Signature.Length == 0 && method.HasInstantiation && method.Instantiation[0] is TypeDesc activatedType && activatedType != context.UniversalCanonType && activatedType.IsValueType && activatedType.GetParameterlessConstructor() == null) { ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); var t = emit.NewLocal(context.GetSignatureVariable(0, method: true)); codeStream.EmitLdLoca(t); codeStream.Emit(ILOpcode.initobj, emit.NewToken(context.GetSignatureVariable(0, method: true))); codeStream.EmitLdLoc(t); codeStream.Emit(ILOpcode.ret); return(new InstantiatedMethodIL(method, emit.Link(method.GetMethodDefinition()))); } } break; case "RuntimeHelpers": { if (owningType.Namespace == "System.Runtime.CompilerServices") { return(RuntimeHelpersIntrinsics.EmitIL(method)); } } break; case "Comparer`1": { if (methodName == "Create" && owningType.Namespace == "System.Collections.Generic") { return(ComparerIntrinsics.EmitComparerCreate(method)); } } break; case "EqualityComparer`1": { if (methodName == "Create" && owningType.Namespace == "System.Collections.Generic") { return(ComparerIntrinsics.EmitEqualityComparerCreate(method)); } } break; case "ComparerHelpers": { if (owningType.Namespace != "Internal.IntrinsicSupport") { return(null); } if (methodName == "EnumOnlyCompare") { //calls CompareTo for underlyingType to avoid boxing TypeDesc elementType = method.Instantiation[0]; if (!elementType.IsEnum) { return(null); } TypeDesc underlyingType = elementType.UnderlyingType; TypeDesc returnType = method.Context.GetWellKnownType(WellKnownType.Int32); MethodDesc underlyingCompareToMethod = underlyingType.GetKnownMethod("CompareTo", new MethodSignature( MethodSignatureFlags.None, genericParameterCount: 0, returnType: returnType, parameters: new TypeDesc[] { underlyingType })); ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); codeStream.EmitLdArga(0); codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.call, emitter.NewToken(underlyingCompareToMethod)); codeStream.Emit(ILOpcode.ret); return(emitter.Link(method)); } } break; case "EqualityComparerHelpers": { if (owningType.Namespace != "Internal.IntrinsicSupport") { return(null); } if (methodName == "EnumOnlyEquals") { // EnumOnlyEquals would basically like to do this: // static bool EnumOnlyEquals<T>(T x, T y) where T: struct => x == y; // This is not legal though. // We don't want to do this: // static bool EnumOnlyEquals<T>(T x, T y) where T: struct => x.Equals(y); // Because it would box y. // So we resort to some per-instantiation magic. TypeDesc elementType = method.Instantiation[0]; if (!elementType.IsEnum) { return(null); } ILOpcode convInstruction; if (((DefType)elementType).InstanceFieldSize.AsInt <= 4) { convInstruction = ILOpcode.conv_i4; } else { Debug.Assert(((DefType)elementType).InstanceFieldSize.AsInt == 8); convInstruction = ILOpcode.conv_i8; } return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)convInstruction, (byte)ILOpcode.ldarg_1, (byte)convInstruction, (byte)ILOpcode.prefix1, unchecked ((byte)ILOpcode.ceq), (byte)ILOpcode.ret, }, Array.Empty <LocalVariableDefinition>(), null)); } else if (methodName == "GetComparerForReferenceTypesOnly") { TypeDesc elementType = method.Instantiation[0]; if (!elementType.IsRuntimeDeterminedSubtype && !elementType.IsCanonicalSubtype(CanonicalFormKind.Any) && !elementType.IsGCPointer) { return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldnull, (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), null)); } } else if (methodName == "StructOnlyEquals") { TypeDesc elementType = method.Instantiation[0]; if (!elementType.IsRuntimeDeterminedSubtype && !elementType.IsCanonicalSubtype(CanonicalFormKind.Any) && !elementType.IsGCPointer) { Debug.Assert(elementType.IsValueType); TypeSystemContext context = elementType.Context; MetadataType helperType = context.SystemModule.GetKnownType("Internal.IntrinsicSupport", "EqualityComparerHelpers"); MethodDesc methodToCall; if (elementType.IsEnum) { methodToCall = helperType.GetKnownMethod("EnumOnlyEquals", null).MakeInstantiatedMethod(elementType); } else if (elementType.IsNullable && ComparerIntrinsics.ImplementsIEquatable(elementType.Instantiation[0])) { methodToCall = helperType.GetKnownMethod("StructOnlyEqualsNullable", null).MakeInstantiatedMethod(elementType.Instantiation[0]); } else if (ComparerIntrinsics.ImplementsIEquatable(elementType)) { methodToCall = helperType.GetKnownMethod("StructOnlyEqualsIEquatable", null).MakeInstantiatedMethod(elementType); } else { methodToCall = helperType.GetKnownMethod("StructOnlyNormalEquals", null).MakeInstantiatedMethod(elementType); } return(new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, (byte)ILOpcode.call, 1, 0, 0, 0, (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), new object[] { methodToCall })); } } } break; } return(null); }
private TypeDesc ParseTypeImpl(SignatureTypeCode typeCode) { // Switch on the type. switch (typeCode) { case SignatureTypeCode.Void: return(GetWellKnownType(WellKnownType.Void)); case SignatureTypeCode.Boolean: return(GetWellKnownType(WellKnownType.Boolean)); case SignatureTypeCode.SByte: return(GetWellKnownType(WellKnownType.SByte)); case SignatureTypeCode.Byte: return(GetWellKnownType(WellKnownType.Byte)); case SignatureTypeCode.Int16: return(GetWellKnownType(WellKnownType.Int16)); case SignatureTypeCode.UInt16: return(GetWellKnownType(WellKnownType.UInt16)); case SignatureTypeCode.Int32: return(GetWellKnownType(WellKnownType.Int32)); case SignatureTypeCode.UInt32: return(GetWellKnownType(WellKnownType.UInt32)); case SignatureTypeCode.Int64: return(GetWellKnownType(WellKnownType.Int64)); case SignatureTypeCode.UInt64: return(GetWellKnownType(WellKnownType.UInt64)); case SignatureTypeCode.Single: return(GetWellKnownType(WellKnownType.Single)); case SignatureTypeCode.Double: return(GetWellKnownType(WellKnownType.Double)); case SignatureTypeCode.Char: return(GetWellKnownType(WellKnownType.Char)); case SignatureTypeCode.String: return(GetWellKnownType(WellKnownType.String)); case SignatureTypeCode.IntPtr: return(GetWellKnownType(WellKnownType.IntPtr)); case SignatureTypeCode.UIntPtr: return(GetWellKnownType(WellKnownType.UIntPtr)); case SignatureTypeCode.Object: return(GetWellKnownType(WellKnownType.Object)); case SignatureTypeCode.TypeHandle: return(ResolveHandle(_reader.ReadTypeHandle())); case SignatureTypeCode.SZArray: { var elementType = ParseType(); if (elementType == null) { return(null); } return(_tsc.GetArrayType(elementType)); } case SignatureTypeCode.Array: { var elementType = ParseType(); var rank = _reader.ReadCompressedInteger(); // TODO: Bounds for multi-dimmensional arrays var boundsCount = _reader.ReadCompressedInteger(); for (int i = 0; i < boundsCount; i++) { _reader.ReadCompressedInteger(); } var lowerBoundsCount = _reader.ReadCompressedInteger(); for (int j = 0; j < lowerBoundsCount; j++) { _reader.ReadCompressedInteger(); } if (elementType != null) { return(_tsc.GetArrayType(elementType, rank)); } else { return(null); } } case SignatureTypeCode.ByReference: { TypeDesc byRefedType = ParseType(); if (byRefedType != null) { return(byRefedType.MakeByRefType()); } else { return(null); } } case SignatureTypeCode.Pointer: { TypeDesc pointedAtType = ParseType(); if (pointedAtType != null) { return(_tsc.GetPointerType(pointedAtType)); } else { return(null); } } case SignatureTypeCode.GenericTypeParameter: return(_tsc.GetSignatureVariable(_reader.ReadCompressedInteger(), false)); case SignatureTypeCode.GenericMethodParameter: return(_tsc.GetSignatureVariable(_reader.ReadCompressedInteger(), true)); case SignatureTypeCode.GenericTypeInstance: { TypeDesc typeDef = ParseType(); MetadataType metadataTypeDef = null; if (typeDef != null) { metadataTypeDef = typeDef as MetadataType; if (metadataTypeDef == null) { throw new BadImageFormatException(); } } TypeDesc[] instance = new TypeDesc[_reader.ReadCompressedInteger()]; for (int i = 0; i < instance.Length; i++) { instance[i] = ParseType(); if (instance[i] == null) { metadataTypeDef = null; } } if (metadataTypeDef != null) { return(_tsc.GetInstantiatedType(metadataTypeDef, new Instantiation(instance))); } else { return(null); } } case SignatureTypeCode.TypedReference: return(GetWellKnownType(WellKnownType.TypedReference)); case SignatureTypeCode.FunctionPointer: MethodSignature sig = ParseMethodSignatureInternal(skipEmbeddedSignatureData: true); if (sig != null) { return(_tsc.GetFunctionPointerType(sig)); } else { return(null); } default: throw new BadImageFormatException(); } }
public override IEnumerable <CombinedDependencyListEntry> SearchDynamicDependencies(List <DependencyNodeCore <NodeFactory> > markedNodes, int firstNode, NodeFactory factory) { List <CombinedDependencyListEntry> dynamicDependencies = new List <CombinedDependencyListEntry>(); TypeDesc methodOwningType = _method.OwningType; bool methodIsShared = _method.IsSharedByGenericInstantiations; TypeSystemContext context = _method.Context; for (int i = firstNode; i < markedNodes.Count; i++) { DependencyNodeCore <NodeFactory> entry = markedNodes[i]; EETypeNode entryAsEETypeNode = entry as EETypeNode; if (entryAsEETypeNode == null) { continue; } TypeDesc potentialOverrideType = entryAsEETypeNode.Type; if (!potentialOverrideType.IsDefType || potentialOverrideType.IsInterface) { continue; } // If method is canonical, don't allow using it with non-canonical types - we can wait until // we see the __Canon instantiation. If there isn't one, the canonical method wouldn't be useful anyway. if (methodIsShared && potentialOverrideType.ConvertToCanonForm(CanonicalFormKind.Specific) != potentialOverrideType) { continue; } // Similarly, if the type is canonical but this method instantiation isn't, don't mix them. if (!methodIsShared && potentialOverrideType.IsCanonicalSubtype(CanonicalFormKind.Any)) { continue; } // If this is an interface gvm, look for types that implement the interface // and other instantantiations that have the same canonical form. // This ensure the various slot numbers remain equivalent across all types where there is an equivalence // relationship in the vtable. if (methodOwningType.IsInterface) { // We go over definitions because a single canonical interface method could actually be implemented // by multiple methods - consider: // // class Foo<T, U> : IFoo<T>, IFoo<U>, IFoo<string> { } // // If we ask what implements IFoo<__Canon>.Method, the answer could be "three methods" // and that's expected. We therefore resolve IFoo<__Canon>.Method for each IFoo<!0>.Method, // IFoo<!1>.Method, and IFoo<string>.Method, adding GVMDependencies for each. TypeDesc potentialOverrideDefinition = potentialOverrideType.GetTypeDefinition(); DefType[] potentialInterfaces = potentialOverrideType.RuntimeInterfaces; DefType[] potentialDefinitionInterfaces = potentialOverrideDefinition.RuntimeInterfaces; for (int interfaceIndex = 0; interfaceIndex < potentialInterfaces.Length; interfaceIndex++) { if (potentialInterfaces[interfaceIndex].ConvertToCanonForm(CanonicalFormKind.Specific) == methodOwningType) { MethodDesc interfaceMethod = _method.GetMethodDefinition(); if (methodOwningType.HasInstantiation) { interfaceMethod = context.GetMethodForInstantiatedType( _method.GetTypicalMethodDefinition(), (InstantiatedType)potentialDefinitionInterfaces[interfaceIndex]); } MethodDesc slotDecl = potentialOverrideDefinition.InstantiateAsOpen().ResolveInterfaceMethodTarget(interfaceMethod); if (slotDecl == null) { // The method might be implemented through a default interface method var result = potentialOverrideDefinition.InstantiateAsOpen().ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethod, out slotDecl); if (result != DefaultInterfaceMethodResolution.DefaultImplementation) { slotDecl = null; } } if (slotDecl != null) { TypeDesc[] openInstantiation = new TypeDesc[_method.Instantiation.Length]; for (int instArg = 0; instArg < openInstantiation.Length; instArg++) { openInstantiation[instArg] = context.GetSignatureVariable(instArg, method: true); } MethodDesc implementingMethodInstantiation = slotDecl.MakeInstantiatedMethod(openInstantiation).InstantiateSignature(potentialOverrideType.Instantiation, _method.Instantiation); dynamicDependencies.Add(new CombinedDependencyListEntry(factory.GVMDependencies(implementingMethodInstantiation.GetCanonMethodTarget(CanonicalFormKind.Specific)), null, "ImplementingMethodInstantiation")); } } } } else { // This is not an interface GVM. Check whether the current type overrides the virtual method. // We might need to change what virtual method we ask about - consider: // // class Base<T> { virtual Method(); } // class Derived : Base<string> { override Method(); } // // We need to resolve Base<__Canon>.Method on Derived, but if we were to ask the virtual // method resolution algorithm, the answer would be "does not override" because Base<__Canon> // is not even in the inheritance hierarchy. // // So we need to modify the question to resolve Base<string>.Method instead and then // canonicalize the result. TypeDesc overrideTypeCur = potentialOverrideType; do { if (overrideTypeCur.ConvertToCanonForm(CanonicalFormKind.Specific) == methodOwningType) { break; } overrideTypeCur = overrideTypeCur.BaseType; }while (overrideTypeCur != null); if (overrideTypeCur == null) { continue; } MethodDesc methodToResolve; if (methodOwningType == overrideTypeCur) { methodToResolve = _method; } else { methodToResolve = context .GetMethodForInstantiatedType(_method.GetTypicalMethodDefinition(), (InstantiatedType)overrideTypeCur) .MakeInstantiatedMethod(_method.Instantiation); } MethodDesc instantiatedTargetMethod = potentialOverrideType.FindVirtualFunctionTargetMethodOnObjectType(methodToResolve) .GetCanonMethodTarget(CanonicalFormKind.Specific); if (instantiatedTargetMethod != _method) { dynamicDependencies.Add(new CombinedDependencyListEntry( factory.GVMDependencies(instantiatedTargetMethod), null, "DerivedMethodInstantiation")); } } } return(dynamicDependencies); }
public TypeDesc GetGenericMethodParameter(object genericContext, int index) => _tsc.GetSignatureVariable(index, method: true);
public static MethodIL EmitIL(MethodDesc method) { Debug.Assert(method.OwningType.IsDelegate); Debug.Assert(method.OwningType.IsTypeDefinition); Debug.Assert(method.IsRuntimeImplemented); if (method.Name == "BeginInvoke" || method.Name == "EndInvoke") { // BeginInvoke and EndInvoke are not supported on .NET Core ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); MethodDesc notSupportedExceptionHelper = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowPlatformNotSupportedException"); codeStream.EmitCallThrowHelper(emit, notSupportedExceptionHelper); return(emit.Link(method)); } if (method.Name == ".ctor") { // We only support delegate creation if the IL follows the delegate creation verifiability requirements // described in ECMA-335 III.4.21 (newobj - create a new object). The codegen is expected to // intrinsically expand the pattern. // If the delegate creation doesn't follow the pattern, we generate code that throws at runtime. // We could potentially implement this (unreliably) through the use of reflection metadata, // but it remains to be proven that this is an actual customer scenario. ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); MethodDesc notSupportedExceptionHelper = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowPlatformNotSupportedException"); codeStream.EmitCallThrowHelper(emit, notSupportedExceptionHelper); return(emit.Link(method)); } if (method.Name == "Invoke") { TypeSystemContext context = method.Context; ILEmitter emit = new ILEmitter(); TypeDesc delegateType = context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType; FieldDesc firstParameterField = delegateType.GetKnownField("m_firstParameter"); FieldDesc functionPointerField = delegateType.GetKnownField("m_functionPointer"); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emit.NewToken(firstParameterField.InstantiateAsOpen())); for (int i = 0; i < method.Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emit.NewToken(functionPointerField.InstantiateAsOpen())); MethodSignature signature = method.Signature; if (method.OwningType.HasInstantiation) { // If the owning type is generic, the signature will contain T's and U's. // We need !0's and !1's. TypeDesc[] typesToReplace = new TypeDesc[method.OwningType.Instantiation.Length]; TypeDesc[] replacementTypes = new TypeDesc[typesToReplace.Length]; for (int i = 0; i < typesToReplace.Length; i++) { typesToReplace[i] = method.OwningType.Instantiation[i]; replacementTypes[i] = context.GetSignatureVariable(i, method: false); } TypeDesc[] parameters = new TypeDesc[method.Signature.Length]; for (int i = 0; i < parameters.Length; i++) { parameters[i] = method.Signature[i].ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes); } TypeDesc returnType = method.Signature.ReturnType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes); signature = new MethodSignature(signature.Flags, signature.GenericParameterCount, returnType, parameters); } codeStream.Emit(ILOpcode.calli, emit.NewToken(signature)); codeStream.Emit(ILOpcode.ret); return(emit.Link(method)); } return(null); }
public static MethodIL EmitIL(MethodDesc method) { Debug.Assert(method.OwningType.IsDelegate); Debug.Assert(method.OwningType.IsTypeDefinition); Debug.Assert(method.IsRuntimeImplemented); if (method.Name == "BeginInvoke" || method.Name == "EndInvoke") { // BeginInvoke and EndInvoke are not supported on .NET Core ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); MethodDesc notSupportedExceptionHelper = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowPlatformNotSupportedException"); codeStream.EmitCallThrowHelper(emit, notSupportedExceptionHelper); return(emit.Link(method)); } if (method.Name == ".ctor") { // TODO: this should be an assert that codegen never asks for this. // This is just a workaround for https://github.com/dotnet/corert/issues/2102 // The code below is making a wild guess that we're creating a closed // instance delegate. Without shared generics, this should only happen // for virtual method (so we're fine there). With shared generics, this can // happen for anything and might be pretty wrong. TypeSystemContext context = method.Context; ILEmitter emit = new ILEmitter(); TypeDesc delegateType = context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType; MethodDesc initializeMethod = delegateType.GetKnownMethod("InitializeClosedInstanceSlow", null); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.EmitLdArg(0); codeStream.EmitLdArg(1); codeStream.EmitLdArg(2); codeStream.Emit(ILOpcode.call, emit.NewToken(initializeMethod)); codeStream.Emit(ILOpcode.ret); return(emit.Link(method)); } if (method.Name == "Invoke") { TypeSystemContext context = method.Context; ILEmitter emit = new ILEmitter(); TypeDesc delegateType = context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType; FieldDesc firstParameterField = delegateType.GetKnownField("m_firstParameter"); FieldDesc functionPointerField = delegateType.GetKnownField("m_functionPointer"); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emit.NewToken(firstParameterField.InstantiateAsOpen())); for (int i = 0; i < method.Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emit.NewToken(functionPointerField.InstantiateAsOpen())); MethodSignature signature = method.Signature; if (method.OwningType.HasInstantiation) { // If the owning type is generic, the signature will contain T's and U's. // We need !0's and !1's. TypeDesc[] typesToReplace = new TypeDesc[method.OwningType.Instantiation.Length]; TypeDesc[] replacementTypes = new TypeDesc[typesToReplace.Length]; for (int i = 0; i < typesToReplace.Length; i++) { typesToReplace[i] = method.OwningType.Instantiation[i]; replacementTypes[i] = context.GetSignatureVariable(i, method: false); } TypeDesc[] parameters = new TypeDesc[method.Signature.Length]; for (int i = 0; i < parameters.Length; i++) { parameters[i] = method.Signature[i].ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes); } TypeDesc returnType = method.Signature.ReturnType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes); signature = new MethodSignature(signature.Flags, signature.GenericParameterCount, returnType, parameters); } codeStream.Emit(ILOpcode.calli, emit.NewToken(signature)); codeStream.Emit(ILOpcode.ret); return(emit.Link(method)); } return(null); }