/// <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); }
/// <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 "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 "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); }
/// <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 "RuntimeHelpers": { if ((methodName == "IsReferenceOrContainsReferences" || methodName == "IsReference") && owningType.Namespace == "System.Runtime.CompilerServices") { TypeDesc elementType = method.Instantiation[0]; // Fallback to non-intrinsic implementation for universal generics if (elementType.IsCanonicalSubtype(CanonicalFormKind.Universal)) { return(null); } bool result = elementType.IsGCPointer; if (methodName == "IsReferenceOrContainsReferences") { result |= (elementType.IsDefType ? ((DefType)elementType).ContainsGCPointers : false); } return(new ILStubMethodIL(method, new byte[] { result ? (byte)ILOpcode.ldc_i4_1 : (byte)ILOpcode.ldc_i4_0, (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), null)); } } 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 "EqualityComparerHelpers": { if (methodName == "EnumOnlyEquals" && owningType.Namespace == "Internal.IntrinsicSupport") { // 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)); } break; } } return(null); }