diff options
author | Jan Kotas <jkotas@microsoft.com> | 2017-06-11 04:29:59 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-11 04:29:59 +0300 |
commit | e3be4f12df5eb685733f19978b442168b8e8d1f1 (patch) | |
tree | 3e807d7f164266e33770ee8f33146977f0d79125 | |
parent | 13f87340d9089cb4a1d3828a4e67c846491526d3 (diff) | |
parent | 208de3dd1aa5f0de33c44bc024dc5122eb455208 (diff) |
Merge pull request #3860 from dotnet/master
Merge master to nmirror
90 files changed, 2660 insertions, 770 deletions
diff --git a/src/Common/src/Internal/Runtime/MetadataBlob.cs b/src/Common/src/Internal/Runtime/MetadataBlob.cs index 2a3af789a..42fedd14e 100644 --- a/src/Common/src/Internal/Runtime/MetadataBlob.cs +++ b/src/Common/src/Internal/Runtime/MetadataBlob.cs @@ -21,7 +21,7 @@ namespace Internal.Runtime EmbeddedMetadata = 13, DefaultConstructorMap = 14, UnboxingAndInstantiatingStubMap = 15, - InvokeInstantiations = 16, // unused + StructMarshallingStubMap = 16, DelegateMarshallingStubMap = 17, GenericVirtualMethodTable = 18, InterfaceGenericVirtualMethodTable = 19, diff --git a/src/ILCompiler.Compiler/src/Compiler/INonEmittableType.cs b/src/Common/src/TypeSystem/CodeGen/INonEmittableType.cs index 942fc93dd..24b1d2eee 100644 --- a/src/ILCompiler.Compiler/src/Compiler/INonEmittableType.cs +++ b/src/Common/src/TypeSystem/CodeGen/INonEmittableType.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace ILCompiler +namespace Internal.TypeSystem { /// <summary> /// Used to mark TypeDesc types that are not part of the core type system diff --git a/src/Common/src/TypeSystem/CodeGen/NativeStructType.CodeGen.cs b/src/Common/src/TypeSystem/CodeGen/NativeStructType.CodeGen.cs new file mode 100644 index 000000000..8e2549913 --- /dev/null +++ b/src/Common/src/TypeSystem/CodeGen/NativeStructType.CodeGen.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Internal.TypeSystem.Interop +{ + // Implements INonEmittableType + partial class NativeStructType : INonEmittableType + { + } +} diff --git a/src/Common/src/TypeSystem/IL/HelperExtensions.cs b/src/Common/src/TypeSystem/IL/HelperExtensions.cs index 694430c8c..44ec59e00 100644 --- a/src/Common/src/TypeSystem/IL/HelperExtensions.cs +++ b/src/Common/src/TypeSystem/IL/HelperExtensions.cs @@ -77,6 +77,21 @@ namespace Internal.IL } /// <summary> + /// Retrieves a nested type on <paramref name="type"/> that is well known to the compiler. + /// Throws an exception if the nested type doesn't exist. + /// </summary> + public static MetadataType GetKnownNestedType(this MetadataType type, string name) + { + MetadataType nestedType = type.GetNestedType(name); + if (nestedType == null) + { + throw new InvalidOperationException(String.Format("Expected type '{0}' not found on type '{1}'", name, type)); + } + + return nestedType; + } + + /// <summary> /// Retrieves a namespace type in <paramref name= "module" /> that is well known to the compiler. /// Throws an exception if the type doesn't exist. /// </summary> diff --git a/src/Common/src/TypeSystem/IL/ILProvider.cs b/src/Common/src/TypeSystem/IL/ILProvider.cs index c1bcf486d..49930c921 100644 --- a/src/Common/src/TypeSystem/IL/ILProvider.cs +++ b/src/Common/src/TypeSystem/IL/ILProvider.cs @@ -90,11 +90,14 @@ namespace Internal.IL if (owningType == null) return null; + string methodName = method.Name; + switch (owningType.Name) { case "RuntimeHelpers": { - if (owningType.Namespace == "System.Runtime.CompilerServices" && method.Name == "IsReferenceOrContainsReferences") + if ((methodName == "IsReferenceOrContainsReferences" || methodName == "IsReference") + && owningType.Namespace == "System.Runtime.CompilerServices") { TypeDesc elementType = method.Instantiation[0]; @@ -102,8 +105,11 @@ namespace Internal.IL if (elementType.IsCanonicalSubtype(CanonicalFormKind.Universal)) return null; - bool result = elementType.IsGCPointer || - (elementType.IsDefType ? ((DefType)elementType).ContainsGCPointers : false); + 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, diff --git a/src/Common/src/TypeSystem/IL/Stubs/DelegateMarshallingMethodThunk.cs b/src/Common/src/TypeSystem/IL/Stubs/DelegateMarshallingMethodThunk.cs index 34a89d3aa..d23a8bcf0 100644 --- a/src/Common/src/TypeSystem/IL/Stubs/DelegateMarshallingMethodThunk.cs +++ b/src/Common/src/TypeSystem/IL/Stubs/DelegateMarshallingMethodThunk.cs @@ -93,6 +93,22 @@ namespace Internal.IL.Stubs } } + private TypeDesc GetNativeMethodParameterType(TypeDesc managedType, MarshalAsDescriptor marshalAs, InteropStateManager interopStateManager, bool isReturn, bool isAnsi) + { + TypeDesc nativeType; + try + { + nativeType = MarshalHelpers.GetNativeMethodParameterType(managedType, marshalAs, interopStateManager, isReturn, isAnsi); + } + catch (NotSupportedException) + { + // if marshalling is not supported for this type the generated stubs will emit appropriate + // error message. We just set native type to be same as managedtype + nativeType = managedType; + } + return nativeType; + } + public override MethodSignature Signature { get @@ -123,7 +139,12 @@ namespace Internal.IL.Stubs marshalAs = parameterMetadataArray[parameterIndex++].MarshalAsDescriptor; } - TypeDesc nativeReturnType = MarshalHelpers.GetNativeMethodParameterType(delegateSignature.ReturnType, null, _interopStateManager, true, isAnsi); + TypeDesc nativeReturnType = GetNativeMethodParameterType(delegateSignature.ReturnType, + marshalAs, + _interopStateManager, + isReturn:true, + isAnsi:isAnsi); + for (int i = 0; i < delegateSignature.Length; i++) { int sequence = i + 1; @@ -142,7 +163,11 @@ namespace Internal.IL.Stubs var managedType = isByRefType ? delegateSignature[i].GetParameterType() : delegateSignature[i]; - var nativeType = MarshalHelpers.GetNativeMethodParameterType(managedType, marshalAs, _interopStateManager, false, isAnsi); + var nativeType = GetNativeMethodParameterType(managedType, + marshalAs, + _interopStateManager, + isReturn:false, + isAnsi:isAnsi); nativeParameterTypes[i] = isByRefType ? nativeType.MakePointerType() : nativeType; } diff --git a/src/Common/src/TypeSystem/Interop/IL/NativeStructType.cs b/src/Common/src/TypeSystem/Interop/IL/NativeStructType.cs index c23c43555..313a5e998 100644 --- a/src/Common/src/TypeSystem/Interop/IL/NativeStructType.cs +++ b/src/Common/src/TypeSystem/Interop/IL/NativeStructType.cs @@ -127,7 +127,23 @@ namespace Internal.TypeSystem.Interop private NativeStructField[] _fields; private InteropStateManager _interopStateManager; + private bool _hasInvalidLayout; + public bool HasInvalidLayout + { + get + { + return _hasInvalidLayout; + } + } + + public FieldDesc[] Fields + { + get + { + return _fields; + } + } public NativeStructType(ModuleDesc owningModule, MetadataType managedStructType, InteropStateManager interopStateManager) { @@ -138,6 +154,7 @@ namespace Internal.TypeSystem.Interop Module = owningModule; ManagedStructType = managedStructType; _interopStateManager = interopStateManager; + _hasInvalidLayout = false; CalculateFields(); } @@ -179,6 +196,7 @@ namespace Internal.TypeSystem.Interop // if marshalling is not supported for this type the generated stubs will emit appropriate // error message. We just set native type to be same as managedtype nativeType = managedType; + _hasInvalidLayout = true; } _fields[index++] = new NativeStructField(nativeType, this, field); diff --git a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs index f476ef2e5..a9770431a 100644 --- a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs +++ b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs @@ -262,7 +262,7 @@ namespace ILCompiler { Debug.Assert(method.IsVirtual); - if (!_factory.CompilationModuleGroup.ShouldProduceFullVTable(method.OwningType)) + if (!_factory.VTable(method.OwningType).HasFixedSlots) _graph.AddRoot(_factory.VirtualMethodUse(method), reason); if (method.IsAbstract) diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs index ae890f6cf..3d1378efe 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs @@ -31,7 +31,6 @@ namespace ILCompiler.DependencyAnalysis public override bool StaticDependenciesAreComputed => true; public override bool IsShareable => IsTypeNodeShareable(_type); - public override bool HasConditionalStaticDependencies => false; protected override bool EmitVirtualSlotsAndInterfaces => true; public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => false; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CodeBasedDependencyAlgorithm.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CodeBasedDependencyAlgorithm.cs index 48fcdea9e..052e70dcb 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CodeBasedDependencyAlgorithm.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CodeBasedDependencyAlgorithm.cs @@ -102,48 +102,7 @@ namespace ILCompiler.DependencyAnalysis // On Project N, the compiler doesn't generate the interop code on the fly if (method.Context.Target.Abi != TargetAbi.ProjectN) { - if (method.IsPInvoke) - { - if (dependencies == null) - dependencies = new DependencyList(); - - MethodSignature methodSig = method.Signature; - AddPInvokeParameterDependencies(ref dependencies, factory, methodSig.ReturnType); - - for (int i = 0; i < methodSig.Length; i++) - { - AddPInvokeParameterDependencies(ref dependencies, factory, methodSig[i]); - } - } - } - } - - private static void AddPInvokeParameterDependencies(ref DependencyList dependencies, NodeFactory factory, TypeDesc parameter) - { - if (parameter.IsDelegate) - { - dependencies.Add(factory.NecessaryTypeSymbol(parameter), "Delegate Marshalling Stub"); - - dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetOpenStaticDelegateMarshallingStub(parameter)), "Delegate Marshalling Stub"); - dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetClosedDelegateMarshallingStub(parameter)), "Delegate Marshalling Stub"); - dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetForwardDelegateCreationStub(parameter)), "Delegate Marshalling Stub"); - } - else if (Internal.TypeSystem.Interop.MarshalHelpers.IsStructMarshallingRequired(parameter)) - { - var stub = (Internal.IL.Stubs.StructMarshallingThunk)factory.InteropStubManager.GetStructMarshallingManagedToNativeStub(parameter); - dependencies.Add(factory.ConstructedTypeSymbol(factory.InteropStubManager.GetStructMarshallingType(parameter)), "Struct Marshalling Type"); - dependencies.Add(factory.MethodEntrypoint(stub), "Struct Marshalling stub"); - dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetStructMarshallingNativeToManagedStub(parameter)), "Struct Marshalling stub"); - dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetStructMarshallingCleanupStub(parameter)), "Struct Marshalling stub"); - - foreach (var inlineArrayCandidate in stub.GetInlineArrayCandidates()) - { - dependencies.Add(factory.ConstructedTypeSymbol(factory.InteropStubManager.GetInlineArrayType(inlineArrayCandidate)), "Struct Marshalling Type"); - foreach (var method in inlineArrayCandidate.ElementType.GetMethods()) - { - dependencies.Add(factory.MethodEntrypoint(method), "inline array marshalling stub"); - } - } + factory.InteropStubManager.AddDependeciesDueToPInvoke(ref dependencies, factory, method); } } } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs index c308ff526..e7889f2aa 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs @@ -2,12 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Diagnostics; using Internal.Runtime; -using Internal.Text; using Internal.TypeSystem; using Internal.IL; @@ -53,79 +51,6 @@ namespace ILCompiler.DependencyAnalysis dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map"); } - if (_type.RuntimeInterfaces.Length > 0 && !factory.CompilationModuleGroup.ShouldProduceFullVTable(_type)) - { - foreach (var implementedInterface in _type.RuntimeInterfaces) - { - // If the type implements ICastable, the methods are implicitly necessary - if (implementedInterface == factory.ICastableInterface) - { - MethodDesc isInstDecl = implementedInterface.GetKnownMethod("IsInstanceOfInterface", null); - MethodDesc getImplTypeDecl = implementedInterface.GetKnownMethod("GetImplType", null); - - MethodDesc isInstMethodImpl = _type.ResolveInterfaceMethodTarget(isInstDecl); - MethodDesc getImplTypeMethodImpl = _type.ResolveInterfaceMethodTarget(getImplTypeDecl); - - if (isInstMethodImpl != null) - dependencyList.Add(factory.VirtualMethodUse(isInstMethodImpl), "ICastable IsInst"); - if (getImplTypeMethodImpl != null) - dependencyList.Add(factory.VirtualMethodUse(getImplTypeMethodImpl), "ICastable GetImplType"); - } - - // If any of the implemented interfaces have variance, calls against compatible interface methods - // could result in interface methods of this type being used (e.g. IEnumberable<object>.GetEnumerator() - // can dispatch to an implementation of IEnumerable<string>.GetEnumerator()). - // For now, we will not try to optimize this and we will pretend all interface methods are necessary. - bool allInterfaceMethodsAreImplicitlyUsed = false; - if (implementedInterface.HasVariance) - { - TypeDesc interfaceDefinition = implementedInterface.GetTypeDefinition(); - for (int i = 0; i < interfaceDefinition.Instantiation.Length; i++) - { - if (((GenericParameterDesc)interfaceDefinition.Instantiation[i]).Variance != 0 && - !implementedInterface.Instantiation[i].IsValueType) - { - allInterfaceMethodsAreImplicitlyUsed = true; - break; - } - } - } - if (!allInterfaceMethodsAreImplicitlyUsed && - (_type.IsArray || _type.GetTypeDefinition() == factory.ArrayOfTEnumeratorType) && - implementedInterface.HasInstantiation) - { - // NOTE: we need to also do this for generic interfaces on arrays because they have a weird casting rule - // that doesn't require the implemented interface to be variant to consider it castable. - // For value types, we only need this when the array is castable by size (int[] and ICollection<uint>), - // or it's a reference type (Derived[] and ICollection<Base>). - TypeDesc elementType = _type.IsArray ? ((ArrayType)_type).ElementType : _type.Instantiation[0]; - allInterfaceMethodsAreImplicitlyUsed = - CastingHelper.IsArrayElementTypeCastableBySize(elementType) || - (elementType.IsDefType && !elementType.IsValueType); - } - - if (allInterfaceMethodsAreImplicitlyUsed) - { - foreach (var interfaceMethod in implementedInterface.GetAllMethods()) - { - if (interfaceMethod.Signature.IsStatic) - continue; - - // Generic virtual methods are tracked by an orthogonal mechanism. - if (interfaceMethod.HasInstantiation) - continue; - - MethodDesc implMethod = closestDefType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod); - if (implMethod != null) - { - dependencyList.Add(factory.VirtualMethodUse(interfaceMethod), "Variant interface method"); - dependencyList.Add(factory.VirtualMethodUse(implMethod), "Variant interface method"); - } - } - } - } - } - if (_type.IsArray) { // Array EEType depends on System.Array's virtuals. Array EETypes don't point to @@ -168,80 +93,9 @@ namespace ILCompiler.DependencyAnalysis // Ask the metadata manager if we have any dependencies due to reflectability. factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencyList, factory, _type); - return dependencyList; - } - - public override bool HasConditionalStaticDependencies - { - get - { - // Since the vtable is dependency driven, generate conditional static dependencies for - // all possible vtable entries - foreach (var method in _type.GetClosestDefType().GetAllMethods()) - { - if (method.IsVirtual) - return true; - } - - // If the type implements at least one interface, calls against that interface could result in this type's - // implementation being used. - if (_type.RuntimeInterfaces.Length > 0) - return true; + factory.InteropStubManager.AddInterestingInteropConstructedTypeDependencies(ref dependencyList, factory, _type); - return false; - } - } - - public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) - { - DefType defType = _type.GetClosestDefType(); - - // If we're producing a full vtable, none of the dependencies are conditional. - if (!factory.CompilationModuleGroup.ShouldProduceFullVTable(defType)) - { - foreach (MethodDesc decl in defType.EnumAllVirtualSlots()) - { - // Generic virtual methods are tracked by an orthogonal mechanism. - if (decl.HasInstantiation) - continue; - - MethodDesc impl = defType.FindVirtualFunctionTargetMethodOnObjectType(decl); - if (impl.OwningType == defType && !impl.IsAbstract) - { - MethodDesc canonImpl = impl.GetCanonMethodTarget(CanonicalFormKind.Specific); - yield return new CombinedDependencyListEntry(factory.MethodEntrypoint(canonImpl, _type.IsValueType), factory.VirtualMethodUse(decl), "Virtual method"); - } - } - - Debug.Assert( - _type == defType || - ((System.Collections.IStructuralEquatable)defType.RuntimeInterfaces).Equals(_type.RuntimeInterfaces, - EqualityComparer<DefType>.Default)); - - // Add conditional dependencies for interface methods the type implements. For example, if the type T implements - // interface IFoo which has a method M1, add a dependency on T.M1 dependent on IFoo.M1 being called, since it's - // possible for any IFoo object to actually be an instance of T. - foreach (DefType interfaceType in defType.RuntimeInterfaces) - { - Debug.Assert(interfaceType.IsInterface); - - foreach (MethodDesc interfaceMethod in interfaceType.GetAllMethods()) - { - if (interfaceMethod.Signature.IsStatic) - continue; - - // Generic virtual methods are tracked by an orthogonal mechanism. - if (interfaceMethod.HasInstantiation) - continue; - - MethodDesc implMethod = defType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod); - if (implMethod != null) - { - yield return new CombinedDependencyListEntry(factory.VirtualMethodUse(implMethod), factory.VirtualMethodUse(interfaceMethod), "Interface method"); - } - } - } - } + return dependencyList; } protected override ISymbolNode GetBaseTypeNode(NodeFactory factory) diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs index bab3051cb..979868dd2 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs @@ -146,11 +146,167 @@ namespace ILCompiler.DependencyAnalysis public override bool IsShareable => IsTypeNodeShareable(_type); + public sealed override bool HasConditionalStaticDependencies + { + get + { + if (!EmitVirtualSlotsAndInterfaces) + return false; + + // Since the vtable is dependency driven, generate conditional static dependencies for + // all possible vtable entries + foreach (var method in _type.GetClosestDefType().GetAllMethods()) + { + if (method.IsVirtual) + return true; + } + + // If the type implements at least one interface, calls against that interface could result in this type's + // implementation being used. + if (_type.RuntimeInterfaces.Length > 0) + return true; + + return false; + } + } + + public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) + { + Debug.Assert(EmitVirtualSlotsAndInterfaces); + + DefType defType = _type.GetClosestDefType(); + + // If we're producing a full vtable, none of the dependencies are conditional. + if (!factory.VTable(defType).HasFixedSlots) + { + foreach (MethodDesc decl in defType.EnumAllVirtualSlots()) + { + // Generic virtual methods are tracked by an orthogonal mechanism. + if (decl.HasInstantiation) + continue; + + MethodDesc impl = defType.FindVirtualFunctionTargetMethodOnObjectType(decl); + if (impl.OwningType == defType && !impl.IsAbstract) + { + MethodDesc canonImpl = impl.GetCanonMethodTarget(CanonicalFormKind.Specific); + yield return new CombinedDependencyListEntry(factory.MethodEntrypoint(canonImpl, _type.IsValueType), factory.VirtualMethodUse(decl), "Virtual method"); + } + } + + Debug.Assert( + _type == defType || + ((System.Collections.IStructuralEquatable)defType.RuntimeInterfaces).Equals(_type.RuntimeInterfaces, + EqualityComparer<DefType>.Default)); + + // Add conditional dependencies for interface methods the type implements. For example, if the type T implements + // interface IFoo which has a method M1, add a dependency on T.M1 dependent on IFoo.M1 being called, since it's + // possible for any IFoo object to actually be an instance of T. + foreach (DefType interfaceType in defType.RuntimeInterfaces) + { + Debug.Assert(interfaceType.IsInterface); + + foreach (MethodDesc interfaceMethod in interfaceType.GetAllMethods()) + { + if (interfaceMethod.Signature.IsStatic) + continue; + + // Generic virtual methods are tracked by an orthogonal mechanism. + if (interfaceMethod.HasInstantiation) + continue; + + MethodDesc implMethod = defType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod); + if (implMethod != null) + { + yield return new CombinedDependencyListEntry(factory.VirtualMethodUse(implMethod), factory.VirtualMethodUse(interfaceMethod), "Interface method"); + } + } + } + } + } + public static bool IsTypeNodeShareable(TypeDesc type) { return type.IsParameterizedType || type.IsFunctionPointer || type is InstantiatedType; } + private void AddVirtualMethodUseDependencies(DependencyList dependencyList, NodeFactory factory) + { + if (_type.RuntimeInterfaces.Length > 0 && !factory.VTable(_type).HasFixedSlots) + { + DefType closestDefType = _type.GetClosestDefType(); + + foreach (var implementedInterface in _type.RuntimeInterfaces) + { + // If the type implements ICastable, the methods are implicitly necessary + if (implementedInterface == factory.ICastableInterface) + { + MethodDesc isInstDecl = implementedInterface.GetKnownMethod("IsInstanceOfInterface", null); + MethodDesc getImplTypeDecl = implementedInterface.GetKnownMethod("GetImplType", null); + + MethodDesc isInstMethodImpl = _type.ResolveInterfaceMethodTarget(isInstDecl); + MethodDesc getImplTypeMethodImpl = _type.ResolveInterfaceMethodTarget(getImplTypeDecl); + + if (isInstMethodImpl != null) + dependencyList.Add(factory.VirtualMethodUse(isInstMethodImpl), "ICastable IsInst"); + if (getImplTypeMethodImpl != null) + dependencyList.Add(factory.VirtualMethodUse(getImplTypeMethodImpl), "ICastable GetImplType"); + } + + // If any of the implemented interfaces have variance, calls against compatible interface methods + // could result in interface methods of this type being used (e.g. IEnumberable<object>.GetEnumerator() + // can dispatch to an implementation of IEnumerable<string>.GetEnumerator()). + // For now, we will not try to optimize this and we will pretend all interface methods are necessary. + bool allInterfaceMethodsAreImplicitlyUsed = false; + if (implementedInterface.HasVariance) + { + TypeDesc interfaceDefinition = implementedInterface.GetTypeDefinition(); + for (int i = 0; i < interfaceDefinition.Instantiation.Length; i++) + { + if (((GenericParameterDesc)interfaceDefinition.Instantiation[i]).Variance != 0 && + !implementedInterface.Instantiation[i].IsValueType) + { + allInterfaceMethodsAreImplicitlyUsed = true; + break; + } + } + } + if (!allInterfaceMethodsAreImplicitlyUsed && + (_type.IsArray || _type.GetTypeDefinition() == factory.ArrayOfTEnumeratorType) && + implementedInterface.HasInstantiation) + { + // NOTE: we need to also do this for generic interfaces on arrays because they have a weird casting rule + // that doesn't require the implemented interface to be variant to consider it castable. + // For value types, we only need this when the array is castable by size (int[] and ICollection<uint>), + // or it's a reference type (Derived[] and ICollection<Base>). + TypeDesc elementType = _type.IsArray ? ((ArrayType)_type).ElementType : _type.Instantiation[0]; + allInterfaceMethodsAreImplicitlyUsed = + CastingHelper.IsArrayElementTypeCastableBySize(elementType) || + (elementType.IsDefType && !elementType.IsValueType); + } + + if (allInterfaceMethodsAreImplicitlyUsed) + { + foreach (var interfaceMethod in implementedInterface.GetAllMethods()) + { + if (interfaceMethod.Signature.IsStatic) + continue; + + // Generic virtual methods are tracked by an orthogonal mechanism. + if (interfaceMethod.HasInstantiation) + continue; + + MethodDesc implMethod = closestDefType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod); + if (implMethod != null) + { + dependencyList.Add(factory.VirtualMethodUse(interfaceMethod), "Variant interface method"); + dependencyList.Add(factory.VirtualMethodUse(implMethod), "Variant interface method"); + } + } + } + } + } + } + protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) { DependencyList dependencies = new DependencyList(); @@ -164,6 +320,11 @@ namespace ILCompiler.DependencyAnalysis StaticsInfoHashtableNode.AddStaticsInfoDependencies(ref dependencies, factory, _type); ReflectionFieldMapNode.AddReflectionFieldMapEntryDependencies(ref dependencies, factory, _type); + if (EmitVirtualSlotsAndInterfaces) + { + AddVirtualMethodUseDependencies(dependencies, factory); + } + return dependencies; } @@ -450,7 +611,7 @@ namespace ILCompiler.DependencyAnalysis // It's only okay to touch the actual list of slots if we're in the final emission phase // or the vtable is not built lazily. - if (relocsOnly && !factory.CompilationModuleGroup.ShouldProduceFullVTable(declType)) + if (relocsOnly && !factory.VTable(declType).HasFixedSlots) return; // Actual vtable slots follow diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericDictionaryNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericDictionaryNode.cs index c54b870e7..70d6147c5 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericDictionaryNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericDictionaryNode.cs @@ -203,6 +203,9 @@ namespace ILCompiler.DependencyAnalysis { DependencyList dependencies = new DependencyList(); GenericMethodsHashtableNode.GetGenericMethodsHashtableDependenciesForMethod(ref dependencies, factory, _owningMethod); + + factory.InteropStubManager.AddMarshalAPIsGenericDependencies(ref dependencies, factory, _owningMethod); + return dependencies; } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericLookupResult.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericLookupResult.cs index fc63d1a43..05d2bb9e7 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericLookupResult.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericLookupResult.cs @@ -362,7 +362,7 @@ namespace ILCompiler.DependencyAnalysis MethodDesc canonMethod = _method.GetCanonMethodTarget(CanonicalFormKind.Universal); // If we're producing a full vtable for the type, we don't need to report virtual method use. - if (factory.CompilationModuleGroup.ShouldProduceFullVTable(canonMethod.OwningType)) + if (factory.VTable(canonMethod.OwningType).HasFixedSlots) return Array.Empty<DependencyNodeCore<NodeFactory>>(); return new DependencyNodeCore<NodeFactory>[] { @@ -1203,8 +1203,7 @@ namespace ILCompiler.DependencyAnalysis { // If there isn't a default constructor, use the fallback one. MetadataType missingCtorType = factory.TypeSystemContext.SystemModule.GetKnownType("System", "Activator"); - missingCtorType = missingCtorType.GetNestedType("ClassWithMissingConstructor"); - Debug.Assert(missingCtorType != null); + missingCtorType = missingCtorType.GetKnownNestedType("ClassWithMissingConstructor"); defaultCtor = missingCtorType.GetParameterlessConstructor(); } else diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs index a4425efee..3ec7d5fd2 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs @@ -1331,7 +1331,7 @@ namespace ILCompiler.DependencyAnalysis break; case VTableEntriesToProcess.AllOnTypesThatShouldProduceFullVTables: - if (factory.CompilationModuleGroup.ShouldProduceFullVTable(declType)) + if (factory.VTable(declType).HasFixedSlots) { vtableEntriesToProcess = factory.VTable(declType).Slots; } @@ -1342,7 +1342,7 @@ namespace ILCompiler.DependencyAnalysis break; case VTableEntriesToProcess.AllOnTypesThatProducePartialVTables: - if (factory.CompilationModuleGroup.ShouldProduceFullVTable(declType)) + if (factory.VTable(declType).HasFixedSlots) { vtableEntriesToProcess = Array.Empty<MethodDesc>(); } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs index 37bea13c0..1f1b76c3c 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs @@ -327,9 +327,9 @@ namespace ILCompiler.DependencyAnalysis _virtMethods = new NodeCache<MethodDesc, VirtualMethodUseNode>((MethodDesc method) => { - // We don't need to track virtual method uses for types that are producing full vtables. + // We don't need to track virtual method uses for types that have a vtable with a known layout. // It's a waste of CPU time and memory. - Debug.Assert(!CompilationModuleGroup.ShouldProduceFullVTable(method.OwningType)); + Debug.Assert(!VTable(method.OwningType).HasFixedSlots); return new VirtualMethodUseNode(method); }); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs index afeb432e2..0c2a49ead 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs @@ -921,7 +921,8 @@ namespace ILCompiler.DependencyAnalysis // Build symbol definition map. objectWriter.BuildSymbolDefinitionMap(node, nodeContents.DefinedSymbols); - if (!factory.Target.IsWindows) + // The DWARF CFI unwind is implemented for AMD64 only. + if (!factory.Target.IsWindows && (factory.Target.Architecture == TargetArchitecture.X64)) objectWriter.BuildCFIMap(factory, node); // Build debug location map diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs index a3a3fb44d..f5f788ee1 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs @@ -55,6 +55,8 @@ namespace ILCompiler.DependencyAnalysis return factory.GenericLookup.MethodEntry((MethodDesc)target); case ReadyToRunHelperId.DelegateCtor: return ((DelegateCreationInfo)target).GetLookupKind(factory); + case ReadyToRunHelperId.DefaultConstructor: + return factory.GenericLookup.DefaultCtorLookupResult((TypeDesc)target); default: throw new NotImplementedException(); } @@ -111,7 +113,7 @@ namespace ILCompiler.DependencyAnalysis if (createInfo.NeedsVirtualMethodUseTracking) { MethodDesc instantiatedTargetMethod = createInfo.TargetMethod.GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(typeInstantiation, methodInstantiation); - if (!factory.CompilationModuleGroup.ShouldProduceFullVTable(instantiatedTargetMethod.OwningType)) + if (!factory.VTable(instantiatedTargetMethod.OwningType).HasFixedSlots) { result.Add( new DependencyListEntry( @@ -131,7 +133,7 @@ namespace ILCompiler.DependencyAnalysis case ReadyToRunHelperId.ResolveVirtualFunction: { MethodDesc instantiatedTarget = ((MethodDesc)_target).GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(typeInstantiation, methodInstantiation); - if (!factory.CompilationModuleGroup.ShouldProduceFullVTable(instantiatedTarget.OwningType)) + if (!factory.VTable(instantiatedTarget.OwningType).HasFixedSlots) { result.Add( new DependencyListEntry( diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs index c4dc1fac9..1ab4a73f4 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs @@ -30,7 +30,8 @@ namespace ILCompiler.DependencyAnalysis MethodHandle, FieldHandle, MethodDictionary, - MethodEntry + MethodEntry, + DefaultConstructor, } public partial class ReadyToRunHelperNode : AssemblyStubNode @@ -149,7 +150,7 @@ namespace ILCompiler.DependencyAnalysis dependencyList.Add(factory.ReflectableMethod(targetMethod), "Abstract reflectable method"); } - if (!factory.CompilationModuleGroup.ShouldProduceFullVTable(targetMethod.OwningType)) + if (!factory.VTable(targetMethod.OwningType).HasFixedSlots) { dependencyList.Add(factory.VirtualMethodUse((MethodDesc)_target), "ReadyToRun Virtual Method Call"); @@ -173,7 +174,7 @@ namespace ILCompiler.DependencyAnalysis dependencyList.Add(factory.ReflectableMethod(targetMethod), "Abstract reflectable method"); } - if (!factory.CompilationModuleGroup.ShouldProduceFullVTable(info.TargetMethod.OwningType)) + if (!factory.VTable(info.TargetMethod.OwningType).HasFixedSlots) { dependencyList.Add(factory.VirtualMethodUse(info.TargetMethod), "ReadyToRun Delegate to virtual method"); } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionVirtualInvokeMapNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionVirtualInvokeMapNode.cs index 3eae212d7..c55e4018e 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionVirtualInvokeMapNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionVirtualInvokeMapNode.cs @@ -112,7 +112,7 @@ namespace ILCompiler.DependencyAnalysis if (!method.HasInstantiation) { MethodDesc slotDefiningMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method); - if (!factory.CompilationModuleGroup.ShouldProduceFullVTable(slotDefiningMethod.OwningType)) + if (!factory.VTable(slotDefiningMethod.OwningType).HasFixedSlots) { dependencies.Add(factory.VirtualMethodUse(slotDefiningMethod), "Reflection virtual invoke method"); } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StructMarshallingStubMapNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StructMarshallingStubMapNode.cs new file mode 100644 index 000000000..5f49f9a1d --- /dev/null +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StructMarshallingStubMapNode.cs @@ -0,0 +1,107 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +using Internal.NativeFormat; +using Internal.Text; + +namespace ILCompiler.DependencyAnalysis +{ + /// <summary> + /// Represents a hash table of struct marshalling stub types generated into the image. + /// </summary> + internal sealed class StructMarshallingStubMapNode : ObjectNode, ISymbolDefinitionNode + { + private ObjectAndOffsetSymbolNode _endSymbol; + private ExternalReferencesTableNode _externalReferences; + + public StructMarshallingStubMapNode(ExternalReferencesTableNode externalReferences) + { + _endSymbol = new ObjectAndOffsetSymbolNode(this, 0, "__struct_marshalling_stub_map_End", true); + _externalReferences = externalReferences; + } + + public ISymbolDefinitionNode EndSymbol => _endSymbol; + + public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + sb.Append(nameMangler.CompilationUnitPrefix).Append("__struct_marshalling_stub_map"); + } + public int Offset => 0; + public override bool IsShareable => false; + + public override ObjectNodeSection Section => _externalReferences.Section; + + public override bool StaticDependenciesAreComputed => true; + + protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); + + public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) + { + // This node does not trigger generation of other nodes. + if (relocsOnly) + return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this }); + + var writer = new NativeWriter(); + var typeMapHashTable = new VertexHashtable(); + + Section hashTableSection = writer.NewSection(); + hashTableSection.Place(typeMapHashTable); + + foreach (var structEntry in factory.InteropStubManager.GetStructMarshallingTypes()) + { + // the order of data written is as follows: + // 0. managed struct type + // 1. struct marshalling thunk + // 2. struct unmarshalling thunk + // 3. struct cleanup thunk + // 4. size + // 5. NumFields<< 1 | HasInvalidLayout + // 6 for each field + // a. name + // b. offset + + var structType = structEntry.StructType; + var nativeType = structEntry.NativeStructType; + Vertex thunks= writer.GetTuple( + writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(structEntry.MarshallingThunk))), + writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(structEntry.UnmarshallingThunk))), + writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(structEntry.CleanupThunk)))); + + uint size = (uint)nativeType.InstanceByteCount.AsInt; + uint mask = (uint)(nativeType.Fields.Length << 1) | (uint)(nativeType.HasInvalidLayout ? 1 : 0); + + Vertex data = writer.GetTuple( + thunks, + writer.GetUnsignedConstant(size), + writer.GetUnsignedConstant(mask) + ); + + for (int i = 0; i < nativeType.Fields.Length; i++) + { + data = writer.GetTuple( + data, + writer.GetStringConstant(nativeType.Fields[i].Name), + writer.GetUnsignedConstant((uint)nativeType.Fields[i].Offset.AsInt) + ); + } + + Vertex vertex = writer.GetTuple( + writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.NecessaryTypeSymbol(structType))), + data + ); + + int hashCode = structType.GetHashCode(); + typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); + } + + byte[] hashTableBytes = writer.Save(); + + _endSymbol.SetSymbolOffset(hashTableBytes.Length); + + return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol }); + } + } +} diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunGenericHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunGenericHelperNode.cs index 93241ff8d..c49d5eb8f 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunGenericHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunGenericHelperNode.cs @@ -210,6 +210,7 @@ namespace ILCompiler.DependencyAnalysis case ReadyToRunHelperId.VirtualCall: case ReadyToRunHelperId.ResolveVirtualFunction: case ReadyToRunHelperId.MethodEntry: + case ReadyToRunHelperId.DefaultConstructor: { EmitDictionaryLookup(factory, ref encoder, contextRegister, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); encoder.EmitRET(); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs index bdb4d5cfd..f01fbf406 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs @@ -29,6 +29,14 @@ namespace ILCompiler.DependencyAnalysis get; } + /// <summary> + /// Gets a value indicating whether the slots are assigned at the beginning of the compilation. + /// </summary> + public abstract bool HasFixedSlots + { + get; + } + protected override string GetName(NodeFactory factory) => $"__vtable_{factory.NameMangler.GetMangledTypeName(_type).ToString()}"; public override bool StaticDependenciesAreComputed => true; @@ -97,6 +105,14 @@ namespace ILCompiler.DependencyAnalysis } } + public override bool HasFixedSlots + { + get + { + return true; + } + } + public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory) { if (_type.HasBaseType) @@ -153,6 +169,14 @@ namespace ILCompiler.DependencyAnalysis } } + public override bool HasFixedSlots + { + get + { + return false; + } + } + public void AddEntry(NodeFactory factory, MethodDesc virtualMethod) { // GVMs are not emitted in the type's vtable. diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VirtualMethodUseNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VirtualMethodUseNode.cs index 66075291e..dfd0b0e86 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VirtualMethodUseNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VirtualMethodUseNode.cs @@ -79,7 +79,7 @@ namespace ILCompiler.DependencyAnalysis DefType universalCanonicalOwningType = (DefType)_decl.OwningType.ConvertToCanonForm(CanonicalFormKind.Universal); Debug.Assert(universalCanonicalOwningType.IsCanonicalSubtype(CanonicalFormKind.Universal)); - if (!factory.CompilationModuleGroup.ShouldProduceFullVTable(universalCanonicalOwningType)) + if (!factory.VTable(universalCanonicalOwningType).HasFixedSlots) { // This code ensures that in cases where we don't structurally force all universal canonical instantiations // to have full vtables, that we ensure that all vtables are equivalently shaped between universal and non-universal types diff --git a/src/ILCompiler.Compiler/src/Compiler/InteropStubManager.cs b/src/ILCompiler.Compiler/src/Compiler/InteropStubManager.cs index 0c5850b1c..411adea69 100644 --- a/src/ILCompiler.Compiler/src/Compiler/InteropStubManager.cs +++ b/src/ILCompiler.Compiler/src/Compiler/InteropStubManager.cs @@ -8,9 +8,10 @@ using System.Collections.Generic; using Internal.IL.Stubs; using Internal.TypeSystem; using Internal.TypeSystem.Interop; - +using ILCompiler.DependencyAnalysis; using Debug = System.Diagnostics.Debug; +using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList; namespace ILCompiler { @@ -22,7 +23,9 @@ namespace ILCompiler private readonly CompilationModuleGroup _compilationModuleGroup; private readonly CompilerTypeSystemContext _typeSystemContext; internal HashSet<TypeDesc> _delegateMarshalingTypes = new HashSet<TypeDesc>(); - private HashSet<NativeStructType> _structMarshallingTypes = new HashSet<NativeStructType>(); + private HashSet<TypeDesc> _structMarshallingTypes = new HashSet<TypeDesc>(); + private ModuleDesc _interopModule; + private const string _interopModuleName = "System.Private.Interop"; public InteropStateManager InteropStateManager { @@ -34,6 +37,9 @@ namespace ILCompiler _compilationModuleGroup = compilationModuleGroup; _typeSystemContext = typeSystemContext; InteropStateManager = interopStateManager; + + // Note: interopModule might be null if we're building with a class library that doesn't support rich interop + _interopModule = typeSystemContext.GetModuleForSimpleName(_interopModuleName, false); } internal MethodDesc GetOpenStaticDelegateMarshallingStub(TypeDesc delegateType) @@ -62,18 +68,12 @@ namespace ILCompiler return stub; } - internal TypeDesc GetStructMarshallingType(TypeDesc structType) - { - NativeStructType nativeType = InteropStateManager.GetStructMarshallingNativeType(structType); - Debug.Assert(nativeType != null); - _structMarshallingTypes.Add(nativeType); - return nativeType; - } - internal MethodDesc GetStructMarshallingManagedToNativeStub(TypeDesc structType) { MethodDesc stub = InteropStateManager.GetStructMarshallingManagedToNativeThunk(structType); Debug.Assert(stub != null); + + _structMarshallingTypes.Add(structType); return stub; } @@ -81,6 +81,8 @@ namespace ILCompiler { MethodDesc stub = InteropStateManager.GetStructMarshallingNativeToManagedThunk(structType); Debug.Assert(stub != null); + + _structMarshallingTypes.Add(structType); return stub; } @@ -88,6 +90,8 @@ namespace ILCompiler { MethodDesc stub = InteropStateManager.GetStructMarshallingCleanupThunk(structType); Debug.Assert(stub != null); + + _structMarshallingTypes.Add(structType); return stub; } @@ -101,32 +105,148 @@ namespace ILCompiler internal struct DelegateMarshallingThunks { public TypeDesc DelegateType; - public DelegateMarshallingMethodThunk OpenStaticDelegateMarshallingThunk; - public DelegateMarshallingMethodThunk ClosedDelegateMarshallingThunk; - public ForwardDelegateCreationThunk DelegateCreationThunk; + public MethodDesc OpenStaticDelegateMarshallingThunk; + public MethodDesc ClosedDelegateMarshallingThunk; + public MethodDesc DelegateCreationThunk; } internal IEnumerable<DelegateMarshallingThunks> GetDelegateMarshallingThunks() { foreach (var delegateType in _delegateMarshalingTypes) { - var openStub = InteropStateManager.GetOpenStaticDelegateMarshallingThunk(delegateType); - var closedStub = InteropStateManager.GetClosedDelegateMarshallingThunk(delegateType); - var delegateCreationStub = InteropStateManager.GetForwardDelegateCreationThunk(delegateType); yield return new DelegateMarshallingThunks() { DelegateType = delegateType, - OpenStaticDelegateMarshallingThunk = openStub, - ClosedDelegateMarshallingThunk = closedStub, - DelegateCreationThunk = delegateCreationStub + OpenStaticDelegateMarshallingThunk = InteropStateManager.GetOpenStaticDelegateMarshallingThunk(delegateType), + ClosedDelegateMarshallingThunk = InteropStateManager.GetClosedDelegateMarshallingThunk(delegateType), + DelegateCreationThunk = InteropStateManager.GetForwardDelegateCreationThunk(delegateType) + }; + } + } + + internal struct StructMarshallingThunks + { + public TypeDesc StructType; + public NativeStructType NativeStructType; + public MethodDesc MarshallingThunk; + public MethodDesc UnmarshallingThunk; + public MethodDesc CleanupThunk; + } + + internal IEnumerable<StructMarshallingThunks> GetStructMarshallingTypes() + { + foreach (var structType in _structMarshallingTypes) + { + yield return + new StructMarshallingThunks() + { + StructType = structType, + NativeStructType = InteropStateManager.GetStructMarshallingNativeType(structType), + MarshallingThunk = InteropStateManager.GetStructMarshallingManagedToNativeThunk(structType), + UnmarshallingThunk = InteropStateManager.GetStructMarshallingNativeToManagedThunk(structType), + CleanupThunk = InteropStateManager.GetStructMarshallingCleanupThunk(structType) }; } } - internal HashSet<NativeStructType> GetStructMarshallingTypes() + public void AddDependeciesDueToPInvoke(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) { - return _structMarshallingTypes; + if (method.IsPInvoke) + { + dependencies = dependencies ?? new DependencyList(); + + MethodSignature methodSig = method.Signature; + AddDependenciesDueToPInvokeDelegate(ref dependencies, factory, methodSig.ReturnType); + + for (int i = 0; i < methodSig.Length; i++) + { + AddDependenciesDueToPInvokeDelegate(ref dependencies, factory, methodSig[i]); + } + } + + if (method.HasInstantiation) + { + dependencies = dependencies ?? new DependencyList(); + AddMarshalAPIsGenericDependencies(ref dependencies, factory, method); + } + } + + public void AddInterestingInteropConstructedTypeDependencies(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) + { + if (type.IsDelegate) + { + var delegateType = (MetadataType)type; + if (delegateType.HasCustomAttribute("System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute")) + { + AddDependenciesDueToPInvokeDelegate(ref dependencies, factory, delegateType); + } + } + } + + /// <summary> + /// For Marshal generic APIs(eg. Marshal.StructureToPtr<T>, GetFunctionPointerForDelegate) we add + /// the generic parameter as dependencies so that we can generate runtime data for them + /// </summary> + public void AddMarshalAPIsGenericDependencies(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) + { + Debug.Assert(method.HasInstantiation); + + TypeDesc owningType = method.OwningType; + MetadataType metadataType = owningType as MetadataType; + if (metadataType != null && metadataType.Module == _interopModule) + { + if (metadataType.Name == "Marshal" && metadataType.Namespace == "System.Runtime.InteropServices") + { + string methodName = method.Name; + if (methodName == "GetFunctionPointerForDelegate" || + methodName == "GetDelegateForFunctionPointer" || + methodName == "PtrToStructure" || + methodName == "StructureToPtr" || + methodName == "SizeOf" || + methodName == "OffsetOf") + { + foreach (TypeDesc type in method.Instantiation) + { + AddDependenciesDueToPInvokeDelegate(ref dependencies, factory, type); + AddDependenciesDueToPInvokeStruct(ref dependencies, factory, type); + } + } + } + } + } + + public void AddDependenciesDueToPInvokeDelegate(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) + { + if (type.IsDelegate) + { + dependencies.Add(factory.NecessaryTypeSymbol(type), "Delegate Marshalling Stub"); + + dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetOpenStaticDelegateMarshallingStub(type)), "Delegate Marshalling Stub"); + dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetClosedDelegateMarshallingStub(type)), "Delegate Marshalling Stub"); + dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetForwardDelegateCreationStub(type)), "Delegate Marshalling Stub"); + } + } + + public void AddDependenciesDueToPInvokeStruct(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) + { + if (MarshalHelpers.IsStructMarshallingRequired(type)) + { + dependencies.Add(factory.NecessaryTypeSymbol(type), "Struct Marshalling Stub"); + + var stub = (Internal.IL.Stubs.StructMarshallingThunk)factory.InteropStubManager.GetStructMarshallingManagedToNativeStub(type); + dependencies.Add(factory.MethodEntrypoint(stub), "Struct Marshalling stub"); + dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetStructMarshallingNativeToManagedStub(type)), "Struct Marshalling stub"); + dependencies.Add(factory.MethodEntrypoint(factory.InteropStubManager.GetStructMarshallingCleanupStub(type)), "Struct Marshalling stub"); + + foreach (var inlineArrayCandidate in stub.GetInlineArrayCandidates()) + { + foreach (var method in inlineArrayCandidate.ElementType.GetMethods()) + { + dependencies.Add(factory.MethodEntrypoint(method), "inline array marshalling stub"); + } + } + } } } } diff --git a/src/ILCompiler.Compiler/src/Compiler/JitHelper.cs b/src/ILCompiler.Compiler/src/Compiler/JitHelper.cs index 59b675487..6f73bea93 100644 --- a/src/ILCompiler.Compiler/src/Compiler/JitHelper.cs +++ b/src/ILCompiler.Compiler/src/Compiler/JitHelper.cs @@ -45,6 +45,12 @@ namespace ILCompiler case ReadyToRunHelper.ThrowDivZero: methodDesc = context.GetHelperEntryPoint("ThrowHelpers", "ThrowDivideByZeroException"); break; + case ReadyToRunHelper.ThrowArgumentOutOfRange: + methodDesc = context.GetHelperEntryPoint("ThrowHelpers", "ThrowArgumentOutOfRangeException"); + break; + case ReadyToRunHelper.ThrowArgument: + methodDesc = context.GetHelperEntryPoint("ThrowHelpers", "ThrowArgumentException"); + break; case ReadyToRunHelper.DebugBreak: mangledName = "RhDebugBreak"; diff --git a/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs b/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs index 23bce180d..725352626 100644 --- a/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs +++ b/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs @@ -100,6 +100,9 @@ namespace ILCompiler var delegateMapNode = new DelegateMarshallingStubMapNode(commonFixupsTableNode); header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.DelegateMarshallingStubMap), delegateMapNode, delegateMapNode, delegateMapNode.EndSymbol); + var structMapNode = new StructMarshallingStubMapNode(commonFixupsTableNode); + header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.StructMarshallingStubMap), structMapNode, structMapNode, structMapNode.EndSymbol); + var arrayMapNode = new ArrayMapNode(commonFixupsTableNode); header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.ArrayMap), arrayMapNode, arrayMapNode, arrayMapNode.EndSymbol); diff --git a/src/ILCompiler.Compiler/src/Compiler/ReadyToRun.cs b/src/ILCompiler.Compiler/src/Compiler/ReadyToRun.cs index 462255ace..98314078d 100644 --- a/src/ILCompiler.Compiler/src/Compiler/ReadyToRun.cs +++ b/src/ILCompiler.Compiler/src/Compiler/ReadyToRun.cs @@ -22,6 +22,8 @@ namespace ILCompiler FailFast = 0x24, ThrowNullRef = 0x25, ThrowDivZero = 0x26, + ThrowArgumentOutOfRange = 0x27, + ThrowArgument = 0x28, DebugBreak = 0x2F, diff --git a/src/ILCompiler.Compiler/src/IL/ILImporter.Scanner.cs b/src/ILCompiler.Compiler/src/IL/ILImporter.Scanner.cs index 4011819b1..eeaebf363 100644 --- a/src/ILCompiler.Compiler/src/IL/ILImporter.Scanner.cs +++ b/src/ILCompiler.Compiler/src/IL/ILImporter.Scanner.cs @@ -102,6 +102,27 @@ namespace Internal.IL public DependencyList Import() { + if (_canonMethod.Signature.IsStatic) + { + TypeDesc owningType = _canonMethod.OwningType; + if (!_isFallbackBodyCompilation && _factory.TypeSystemContext.HasLazyStaticConstructor(owningType)) + { + // For beforefieldinit, we can wait for field access. + if (!((MetadataType)owningType).IsBeforeFieldInit) + { + MethodDesc method = _methodIL.OwningMethod; + if (method.OwningType.IsRuntimeDeterminedSubtype) + { + _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.GetNonGCStaticBase, method.OwningType), "Owning type cctor"); + } + else + { + _dependencies.Add(_factory.ReadyToRunHelper(ReadyToRunHelperId.GetNonGCStaticBase, method.OwningType), "Owning type cctor"); + } + } + } + } + FindBasicBlocks(); ImportBasicBlocks(); @@ -261,12 +282,8 @@ namespace Internal.IL { // String .ctor handled specially below } - else + else if (owningType.IsGCPointer) { - // Nullable needs to be unwrapped. - if (owningType.IsNullable) - owningType = owningType.Instantiation[0]; - if (owningType.IsRuntimeDeterminedSubtype) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.TypeHandle, owningType), reason); @@ -337,6 +354,27 @@ namespace Internal.IL if (_previousInstructionOffset >= 0 && _ilBytes[_previousInstructionOffset] == (byte)ILOpcode.ldtoken) return; } + + if (IsActivatorDefaultConstructorOf(method)) + { + if (runtimeDeterminedMethod.IsRuntimeDeterminedExactMethod) + { + _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.DefaultConstructor, runtimeDeterminedMethod.Instantiation[0]), reason); + } + else + { + MethodDesc ctor = method.Instantiation[0].GetDefaultConstructor(); + if (ctor == null) + { + MetadataType activatorType = _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "Activator"); + MetadataType classWithMissingCtor = activatorType.GetKnownNestedType("ClassWithMissingConstructor"); + ctor = classWithMissingCtor.GetParameterlessConstructor(); + } + _dependencies.Add(_factory.CanonicalEntrypoint(ctor), reason); + } + + return; + } } TypeDesc exactType = method.OwningType; @@ -466,6 +504,31 @@ namespace Internal.IL { if (targetMethod.IsSharedByGenericInstantiations && !resolvedConstraint && !referencingArrayAddressMethod) { + ISymbolNode instParam = null; + + if (targetMethod.RequiresInstMethodDescArg()) + { + instParam = GetGenericLookupHelper(ReadyToRunHelperId.MethodDictionary, runtimeDeterminedMethod); + } + else if (targetMethod.RequiresInstMethodTableArg()) + { + bool hasHiddenParameter = true; + + if (targetMethod.IsIntrinsic) + { + if (_factory.TypeSystemContext.IsSpecialUnboxingThunkTargetMethod(targetMethod)) + hasHiddenParameter = false; + } + + if (hasHiddenParameter) + instParam = GetGenericLookupHelper(ReadyToRunHelperId.TypeHandle, runtimeDeterminedMethod.OwningType); + } + + if (instParam != null) + { + _dependencies.Add(instParam, reason); + } + _dependencies.Add(_factory.RuntimeDeterminedMethod(runtimeDeterminedMethod), reason); } else @@ -639,6 +702,23 @@ namespace Internal.IL if (obj is TypeDesc) { var type = (TypeDesc)obj; + + // First check if this is a ldtoken Type / GetValueInternal sequence. + BasicBlock nextBasicBlock = _basicBlocks[_currentOffset]; + if (nextBasicBlock == null) + { + if ((ILOpcode)_ilBytes[_currentOffset] == ILOpcode.call) + { + int methodToken = ReadILTokenAt(_currentOffset + 1); + var method = (MethodDesc)_methodIL.GetObject(methodToken); + if (IsRuntimeTypeHandleGetValueInternal(method)) + { + // Codegen expands this and doesn't do the normal ldtoken. + return; + } + } + } + if (type.IsRuntimeDeterminedSubtype) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.TypeHandle, type), "ldtoken"); @@ -769,6 +849,7 @@ namespace Internal.IL private void ImportLoadString(int token) { // If we care, this can include allocating the frozen string node. + _dependencies.Add(_factory.SerializedStringObject(""), "ldstr"); } private void ImportBox(int token) @@ -841,6 +922,21 @@ namespace Internal.IL _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.RngChkFail), "ldelema"); } + private void ImportBinaryOperation(ILOpcode opcode) + { + switch (opcode) + { + case ILOpcode.add_ovf: + case ILOpcode.add_ovf_un: + case ILOpcode.mul_ovf: + case ILOpcode.mul_ovf_un: + case ILOpcode.sub_ovf: + case ILOpcode.sub_ovf_un: + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Overflow), "_ovf"); + break; + } + } + private void ImportFallthrough(BasicBlock next) { MarkBasicBlock(next); @@ -882,6 +978,20 @@ namespace Internal.IL return false; } + private bool IsActivatorDefaultConstructorOf(MethodDesc method) + { + if (method.IsIntrinsic && method.Name == "DefaultConstructorOf" && method.Instantiation.Length == 1) + { + MetadataType owningType = method.OwningType as MetadataType; + if (owningType != null) + { + return owningType.Name == "Activator" && owningType.Namespace == "System"; + } + } + + return false; + } + private TypeDesc GetWellKnownType(WellKnownType wellKnownType) { return _compilation.TypeSystemContext.GetWellKnownType(wellKnownType); @@ -903,7 +1013,6 @@ namespace Internal.IL private void ImportLoadIndirect(TypeDesc type) { } private void ImportStoreIndirect(int token) { } private void ImportStoreIndirect(TypeDesc type) { } - private void ImportBinaryOperation(ILOpcode opcode) { } private void ImportShiftOperation(ILOpcode opcode) { } private void ImportCompareOperation(ILOpcode opcode) { } private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool unsigned) { } diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj index b189dd9e5..475866398 100644 --- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj +++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj @@ -136,7 +136,6 @@ <Compile Include="Compiler\ILScanner.cs" /> <Compile Include="Compiler\ILScannerBuilder.cs" /> <Compile Include="Compiler\ILStreamReader.cs" /> - <Compile Include="Compiler\INonEmittableType.cs" /> <Compile Include="Compiler\LibraryInitializers.cs" /> <Compile Include="Compiler\ICompilationRootProvider.cs" /> <Compile Include="Compiler\Compilation.cs" /> @@ -151,6 +150,7 @@ <Compile Include="Compiler\DependencyAnalysis\CallingConventionConverterKey.cs" /> <Compile Include="Compiler\DependencyAnalysis\CodeBasedDependencyAlgorithm.cs" /> <Compile Include="Compiler\DependencyAnalysis\DelegateMarshallingStubMapNode.cs" /> + <Compile Include="Compiler\DependencyAnalysis\StructMarshallingStubMapNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\GenericVirtualMethodTableNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\InterfaceGenericVirtualMethodTableNode.cs" /> <Compile Include="Compiler\DependencyAnalysis\IObjectDumper.cs" /> diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs index ac3016c38..cac63cb1e 100644 --- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs +++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs @@ -968,7 +968,7 @@ namespace Internal.IL else callViaSlot = true; - if (!_nodeFactory.CompilationModuleGroup.ShouldProduceFullVTable(method.OwningType)) + if (!_nodeFactory.VTable(method.OwningType).HasFixedSlots) _dependencies.Add(_nodeFactory.VirtualMethodUse(method)); } } diff --git a/src/ILCompiler.TypeSystem/src/ILCompiler.TypeSystem.csproj b/src/ILCompiler.TypeSystem/src/ILCompiler.TypeSystem.csproj index ce35bbb78..f47db6bf7 100644 --- a/src/ILCompiler.TypeSystem/src/ILCompiler.TypeSystem.csproj +++ b/src/ILCompiler.TypeSystem/src/ILCompiler.TypeSystem.csproj @@ -506,6 +506,12 @@ <Compile Include="..\..\Common\src\TypeSystem\Common\LocalVariableDefinition.cs"> <Link>TypeSystem\Common\LocalVariableDefinition.cs</Link> </Compile> + <Compile Include="..\..\Common\src\TypeSystem\CodeGen\INonEmittableType.cs"> + <Link>TypeSystem\CodeGen\INonEmittableType.cs</Link> + </Compile> + <Compile Include="..\..\Common\src\TypeSystem\CodeGen\NativeStructType.CodeGen.cs"> + <Link>TypeSystem\CodeGen\NativeStructType.CodeGen.cs</Link> + </Compile> <Compile Include="..\..\Common\src\TypeSystem\RuntimeDetermined\ArrayType.RuntimeDetermined.cs"> <Link>TypeSystem\RuntimeDetermined\ArrayType.RuntimeDetermined.cs</Link> </Compile> diff --git a/src/ILVerify/src/ILImporter.StackValue.cs b/src/ILVerify/src/ILImporter.StackValue.cs index 4c1afe5f5..d4fb4d835 100644 --- a/src/ILVerify/src/ILImporter.StackValue.cs +++ b/src/ILVerify/src/ILImporter.StackValue.cs @@ -39,6 +39,11 @@ namespace Internal.IL get { return (Flags & StackValueFlags.ReadOnly) == StackValueFlags.ReadOnly; } } + public bool IsNullReference + { + get { return Kind == StackValueKind.ObjRef && Type == null; } + } + public StackValue DereferenceByRef() { Debug.Assert(Kind == StackValueKind.ByRef && Type != null, "Cannot dereference"); diff --git a/src/ILVerify/src/ILImporter.Verify.cs b/src/ILVerify/src/ILImporter.Verify.cs index bafd47369..806980e8f 100644 --- a/src/ILVerify/src/ILImporter.Verify.cs +++ b/src/ILVerify/src/ILImporter.Verify.cs @@ -123,7 +123,7 @@ namespace Internal.IL _typeSystemContext = method.Context; if (!_methodSignature.IsStatic) - _thisType = method.OwningType; + _thisType = method.OwningType.InstantiateAsOpen(); _methodIL = methodIL; @@ -235,6 +235,20 @@ namespace Internal.IL AbortMethodVerification(); } + // Check whether the condition is true. If not, terminate the verification of current method. + void FatalCheck(bool cond, VerifierError error, StackValue found) + { + if (!Check(cond, error, found)) + AbortMethodVerification(); + } + + // Check whether the condition is true. If not, terminate the verification of current method. + void FatalCheck(bool cond, VerifierError error, StackValue found, StackValue expected) + { + if (!Check(cond, error, found, expected)) + AbortMethodVerification(); + } + // If not, report verification error and continue verification. void VerificationError(VerifierError error) { @@ -978,18 +992,19 @@ namespace Internal.IL if (entryStack != null) { - // TODO: Better error messages - if (entryStack.Length != _stackTop) - throw new InvalidProgramException(); + FatalCheck(entryStack.Length == _stackTop, VerifierError.PathStackDepth); for (int i = 0; i < entryStack.Length; i++) { // TODO: Do we need to allow conversions? - if (entryStack[i].Kind != _stack[i].Kind) - throw new InvalidProgramException(); - + FatalCheck(entryStack[i].Kind == _stack[i].Kind, VerifierError.PathStackUnexpected, entryStack[i], _stack[i]); + if (entryStack[i].Type != _stack[i].Type) - throw new InvalidProgramException(); + { + // if we have two object references and one of them has a null type, then this is no error (see test Branching.NullConditional_Valid) + if (_stack[i].Kind == StackValueKind.ObjRef && entryStack[i].Type != null && _stack[i].Type != null) + FatalCheck(false, VerifierError.PathStackUnexpected, entryStack[i], _stack[i]); + } } } else @@ -1264,7 +1279,9 @@ namespace Internal.IL Check(!address.IsReadOnly, VerifierError.ReadOnlyIllegalWrite); CheckIsByRef(address); - CheckIsAssignable(type, address.Type); + if (!value.IsNullReference) + CheckIsAssignable(type, address.Type); + CheckIsAssignable(value, StackValue.CreateFromType(type)); } diff --git a/src/ILVerify/src/ILVerify.csproj b/src/ILVerify/src/ILVerify.csproj index 3f3a92178..14624907b 100644 --- a/src/ILVerify/src/ILVerify.csproj +++ b/src/ILVerify/src/ILVerify.csproj @@ -13,6 +13,7 @@ <Compile Include="Program.cs" /> <Compile Include="ILImporter.Verify.cs" /> <Compile Include="ILImporter.StackValue.cs" /> + <Compile Include="SimpleArrayOfTRuntimeInterfacesAlgorithm.cs" /> <Compile Include="SimpleTypeSystemContext.cs" /> <Compile Include="VerifierError.cs" /> </ItemGroup> diff --git a/src/ILVerify/src/Resources/Strings.resx b/src/ILVerify/src/Resources/Strings.resx index c40c9df99..c14d1a18f 100644 --- a/src/ILVerify/src/Resources/Strings.resx +++ b/src/ILVerify/src/Resources/Strings.resx @@ -174,6 +174,12 @@ <data name="InitLocals" xml:space="preserve"> <value>initlocals must be set for verifiable methods with one or more local variables.</value> </data> + <data name="PathStackDepth" xml:space="preserve"> + <value>Stack depth differs depending on path.</value> + </data> + <data name="PathStackUnexpected" xml:space="preserve"> + <value>Non-compatible types on stack depending on path.</value> + </data> <data name="ReadOnly" xml:space="preserve"> <value>Missing ldelema or call following readonly prefix.</value> </data> diff --git a/src/ILVerify/src/SimpleArrayOfTRuntimeInterfacesAlgorithm.cs b/src/ILVerify/src/SimpleArrayOfTRuntimeInterfacesAlgorithm.cs new file mode 100644 index 000000000..5e62168f0 --- /dev/null +++ b/src/ILVerify/src/SimpleArrayOfTRuntimeInterfacesAlgorithm.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using Internal.IL; +using Internal.TypeSystem; + +namespace ILVerify +{ + internal class SimpleArrayOfTRuntimeInterfacesAlgorithm : RuntimeInterfacesAlgorithm + { + private DefType[] _arrayRuntimeInterfaces; + private MetadataType[] _genericRuntimeInterfaces; + private ModuleDesc _systemModule; + + private static readonly string[] s_genericRuntimeInterfacesNames = + { + "IEnumerable`1", + "ICollection`1", + "IList`1", + "IReadOnlyList`1", + "IReadOnlyCollection`1", + }; + + public SimpleArrayOfTRuntimeInterfacesAlgorithm(ModuleDesc systemModule) + { + _systemModule = systemModule; + + // initialize interfaces + _arrayRuntimeInterfaces = _systemModule.GetType("System", "Array")?.RuntimeInterfaces + ?? Array.Empty<DefType>(); + + _genericRuntimeInterfaces = new MetadataType[s_genericRuntimeInterfacesNames.Length]; + int count = 0; + for (int i = 0; i < s_genericRuntimeInterfacesNames.Length; ++i) + { + MetadataType runtimeInterface =_systemModule.GetType("System.Collections.Generic", s_genericRuntimeInterfacesNames[i], false); + if (runtimeInterface != null) + _genericRuntimeInterfaces[count++] = runtimeInterface; + }; + Array.Resize(ref _genericRuntimeInterfaces, count); + } + + public override DefType[] ComputeRuntimeInterfaces(TypeDesc type) + { + ArrayType arrayType = (ArrayType)type; + TypeDesc elementType = arrayType.ElementType; + Debug.Assert(arrayType.IsSzArray); + + // first copy runtime interfaces from System.Array + var result = new DefType[_arrayRuntimeInterfaces.Length + _genericRuntimeInterfaces.Length]; + Array.Copy(_arrayRuntimeInterfaces, result, _arrayRuntimeInterfaces.Length); + + // then copy instantiated generic interfaces + int offset = _arrayRuntimeInterfaces.Length; + for (int i = 0; i < _genericRuntimeInterfaces.Length; ++i) + result[i + offset] = _genericRuntimeInterfaces[i].MakeInstantiatedType(elementType); + + return result; + } + } +} diff --git a/src/ILVerify/src/SimpleTypeSystemContext.cs b/src/ILVerify/src/SimpleTypeSystemContext.cs index 791530220..123e2e0d2 100644 --- a/src/ILVerify/src/SimpleTypeSystemContext.cs +++ b/src/ILVerify/src/SimpleTypeSystemContext.cs @@ -4,7 +4,6 @@ using System; using System.IO; -using System.Diagnostics; using System.Collections.Generic; using System.Reflection; using System.Reflection.Metadata; @@ -20,6 +19,9 @@ namespace ILVerify { class SimpleTypeSystemContext : MetadataTypeSystemContext { + private RuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm; + private MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm(); + Dictionary<string, EcmaModule> _modules = new Dictionary<string, EcmaModule>(StringComparer.OrdinalIgnoreCase); class ModuleData @@ -114,5 +116,19 @@ namespace ILVerify { return _moduleData[module].Path; } + + protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type) + { + if (_arrayOfTRuntimeInterfacesAlgorithm == null) + { + _arrayOfTRuntimeInterfacesAlgorithm = new SimpleArrayOfTRuntimeInterfacesAlgorithm(SystemModule); + } + return _arrayOfTRuntimeInterfacesAlgorithm; + } + + protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) + { + return _metadataRuntimeInterfacesAlgorithm; + } } } diff --git a/src/ILVerify/src/VerifierError.cs b/src/ILVerify/src/VerifierError.cs index 7f276889e..014448588 100644 --- a/src/ILVerify/src/VerifierError.cs +++ b/src/ILVerify/src/VerifierError.cs @@ -76,8 +76,8 @@ namespace ILVerify //E_BAD_JMP_TARGET "jmp / exception into the middle of an instruction." //E_PATH_LOC "Non-compatible types depending on path." //E_PATH_THIS "Init state for this differs depending on path." - //E_PATH_STACK "Non-compatible types on stack depending on path." - //E_PATH_STACK_DEPTH "Stack depth differs depending on path." + PathStackUnexpected, //"Non-compatible types on stack depending on path." + PathStackDepth, //"Stack depth differs depending on path." //E_THIS "Instance variable (this) missing." //E_THIS_UNINIT_EXCEP "Uninitialized this on entering a try block." //E_THIS_UNINIT_STORE "Store into this when it is uninitialized." diff --git a/src/ILVerify/tests/ILTests/BranchingTests.il b/src/ILVerify/tests/ILTests/BranchingTests.il new file mode 100644 index 000000000..57554cafe --- /dev/null +++ b/src/ILVerify/tests/ILTests/BranchingTests.il @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Runtime +{ +} + +.assembly Branching +{ +} + +.class public auto ansi beforefieldinit BranchingTestsType + extends [System.Runtime]System.Object +{ + .method static public hidebysig void Branching.NullConditional_Valid() cil managed + { + //object o = null; + //Type t = o != null ? o.GetType() : null; + //Type.GetTypeCode(t); + + .maxstack 1 + .locals init ( + [0] object o + ) + + IL_0000: ldnull + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: brtrue.s IL_0008 + + IL_0005: ldnull + IL_0006: br.s IL_000E + + IL_0008: ldloc.0 + IL_0009: callvirt instance class [System.Runtime]System.Type [System.Runtime]System.Object::GetType() + + IL_000E: call valuetype [System.Runtime]System.TypeCode [System.Runtime]System.Type::GetTypeCode(class [System.Runtime]System.Type) + IL_0013: pop + IL_0014: ret + } + + .method static public hidebysig void Branching.NullConditional_Invalid_StackUnexpected.PathStackUnexpected() cil managed + { + //object o = null; + //Type t = o != null ? o.GetType() : o; + //Type.GetTypeCode(t); + + .maxstack 1 + .locals init ( + [0] object o + ) + + IL_0000: ldnull + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: brtrue.s IL_0008 + + IL_0005: ldloc.0 + IL_0006: br.s IL_000E + + IL_0008: ldloc.0 + IL_0009: callvirt instance class [System.Runtime]System.Type [System.Runtime]System.Object::GetType() + + IL_000E: call valuetype [System.Runtime]System.TypeCode [System.Runtime]System.Type::GetTypeCode(class [System.Runtime]System.Type) + IL_0013: pop + IL_0014: ret + } +} diff --git a/src/ILVerify/tests/ILTests/CastingTests.il b/src/ILVerify/tests/ILTests/CastingTests.il new file mode 100644 index 000000000..b5b9c0a6d --- /dev/null +++ b/src/ILVerify/tests/ILTests/CastingTests.il @@ -0,0 +1,211 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Runtime +{ +} + +.assembly Casting +{ +} + +// Provides tests for casting arrays +.class public auto ansi beforefieldinit ArrayCastingTestsType + extends [System.Runtime]System.Object +{ + // Array<T> tests + .method static public hidebysig void Casting.ArrayOfTToEnumerableOfT_Valid(int32[] test) cil managed + { + .locals init ( + class [System.Runtime]System.Collections.Generic.IEnumerable`1<int32> V_0 + ) + ldarg.0 + stloc.0 + ret + } + + .method static public hidebysig void Casting.ArrayOfTToEnumerable_Valid(int32[] test) cil managed + { + .locals init ( + class [System.Runtime]System.Collections.IEnumerable V_0 + ) + ldarg.0 + stloc.0 + ret + } + + .method static public hidebysig void Casting.ArrayOfTToICollectionOfT_Valid(int32[] test) cil managed + { + .locals init ( + class [System.Runtime]System.Collections.Generic.ICollection`1<int32> V_0 + ) + ldarg.0 + stloc.0 + ret + } + + .method static public hidebysig void Casting.ArrayOfTToICollection_Valid(int32[] test) cil managed + { + .locals init ( + class [System.Runtime]System.Collections.ICollection V_0 + ) + ldarg.0 + stloc.0 + ret + } + + .method static public hidebysig void Casting.ArrayOfTToIListOfT_Valid(int32[] test) cil managed + { + .locals init ( + class [System.Runtime]System.Collections.Generic.IList`1<int32> V_0 + ) + ldarg.0 + stloc.0 + ret + } + + .method static public hidebysig void Casting.ArrayOfTToIList_Valid(int32[] test) cil managed + { + .locals init ( + class [System.Runtime]System.Collections.IList V_0 + ) + ldarg.0 + stloc.0 + ret + } + + .method static public hidebysig void Casting.ArrayOfTToIReadOnlyCollectionOfT_Valid(int32[] test) cil managed + { + .locals init ( + class [System.Runtime]System.Collections.Generic.IReadOnlyCollection`1<int32> V_0 + ) + ldarg.0 + stloc.0 + ret + } + + .method static public hidebysig void Casting.ArrayOfTToIReadOnlyListOfT_Valid(int32[] test) cil managed + { + .locals init ( + class [System.Runtime]System.Collections.Generic.IReadOnlyList`1<int32> V_0 + ) + ldarg.0 + stloc.0 + ret + } + + .method static public hidebysig void Casting.ArrayOfTToArray_Valid(int32[] test) cil managed + { + .locals init ( + class [System.Runtime]System.Array V_0 + ) + ldarg.0 + stloc.0 + ret + } +} + +.class public sequential ansi beforefieldinit GenericOtherFieldsType`1<T> + extends [System.Runtime]System.ValueType +{ + .field public !T GenericField; + .field int32 IntField; +} + +// Provides casting logic tests for stfld, ldfld, call, callvirt +.class public auto ansi beforefieldinit GenericCastingTestsType`1<T> + extends [System.Runtime]System.Object +{ + .field private int32 ThisIntField + .method public hidebysig instance void Casting.StorePlainFieldInThisGenericType_Valid(int32 v) cil managed + { + ldarg.0 + ldarg.1 + stfld int32 class GenericCastingTestsType`1<!T>::ThisIntField + ret + } + + .method public hidebysig instance void Casting.StorePlainFieldInOtherGenericType_Valid(int32 v) cil managed + { + .locals init ( + class GenericOtherFieldsType`1<!T> V_0 + ) + + ldloc.0 + ldarg.1 + stfld !0 class GenericOtherFieldsType`1<!T>::IntField + ret + } + + .field private !T ThisGenericField + .method public hidebysig instance void Casting.StoreGenericFieldInThisGenericType_Valid(!T v) cil managed + { + ldarg.0 + ldarg.1 + stfld !0 class GenericCastingTestsType`1<!T>::ThisGenericField + ret + } + + .method public hidebysig instance void Casting.StoreGenericFieldInOtherGenericType_Valid(!T v) cil managed + { + .locals init ( + class GenericOtherFieldsType`1<!T> V_0 + ) + ldloc.0 + ldarg.1 + stfld !0 class GenericOtherFieldsType`1<!T>::GenericField + ret + } + + .method public hidebysig instance void Casting.CallPlainFunctionFromThisGenericType_Valid(int32 v) cil managed + { + ldarg.0 + ldarg.1 + callvirt instance void class GenericCastingTestsType`1<!T>::Casting.StorePlainFieldInThisGenericType_Valid(int32) + ret + } + + .method public hidebysig instance void Casting.CallGenericFunctionFromThisGenericType_Valid(!T v) cil managed + { + ldarg.0 + ldarg.1 + callvirt instance void class GenericCastingTestsType`1<!T>::Casting.CallGenericFunctionFromOtherGenericType_Valid(!0) + ret + } + + .method public hidebysig instance void Casting.CallGenericFunctionFromOtherGenericType_Valid(!T v) cil managed + { + .locals init ( + class [System.Runtime]System.Func`1<!T> V_0 + ) + + ldarg.0 + ldloc.0 + callvirt instance !0 class [System.Runtime]System.Func`1<!T>::Invoke() + ret + } + + .method public hidebysig instance void Casting.AssignThisToSameTypeWithOtherGenericArgs_Invalid_StackUnexpected() cil managed + { + .locals init ( + class GenericCastingTestsType`1<int32> V_0 + ) + + ldarg.0 + stloc.0 + ret + } + + .method public hidebysig static void Casting.AssignToSameTypeWithOtherGenericArgs_Invalid_StackUnexpected() cil managed + { + .locals init ( + class GenericCastingTestsType`1<int32> V_0, + class GenericCastingTestsType`1<string> V_1 + ) + + ldloc.0 + stloc.1 + ret + } +} diff --git a/src/ILVerify/tests/ILTests/LoadStoreIndirectTest.il b/src/ILVerify/tests/ILTests/LoadStoreIndirectTest.il index 4a9da1ad8..7450a3499 100644 --- a/src/ILVerify/tests/ILTests/LoadStoreIndirectTest.il +++ b/src/ILVerify/tests/ILTests/LoadStoreIndirectTest.il @@ -71,6 +71,17 @@ ret } + .method static public hidebysig void StoreIndirect.AssignNullToRefString_Valid(string&) cil managed + { + // ref string x; + // x = null; + + ldarg.0 + ldnull + stind.ref + ret + } + .method static public hidebysig void StoreObject.ValidTypeToken_Valid() cil managed { .locals init (object V_0) diff --git a/src/JitInterface/src/CorInfoBase.cs b/src/JitInterface/src/CorInfoBase.cs index 4ad9e7938..5e356a488 100644 --- a/src/JitInterface/src/CorInfoBase.cs +++ b/src/JitInterface/src/CorInfoBase.cs @@ -38,6 +38,8 @@ namespace Internal.JitInterface [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] delegate CORINFO_METHOD_STRUCT_* __resolveVirtualMethod(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* virtualMethod, CORINFO_CLASS_STRUCT_* implementingClass, CORINFO_CONTEXT_STRUCT* ownerType); [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] + delegate void __expandRawHandleIntrinsic(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_GENERICHANDLE_RESULT pResult); + [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] delegate CorInfoIntrinsics __getIntrinsicID(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, [MarshalAs(UnmanagedType.U1)] ref bool pMustExpand); [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.I1)]delegate bool __isInSIMDModule(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* classHnd); @@ -50,8 +52,6 @@ namespace Internal.JitInterface [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isCompatibleDelegate(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* objCls, CORINFO_CLASS_STRUCT_* methodParentCls, CORINFO_METHOD_STRUCT_* method, CORINFO_CLASS_STRUCT_* delegateCls, [MarshalAs(UnmanagedType.Bool)] ref bool pfIsOpenDelegate); [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] - [return: MarshalAs(UnmanagedType.Bool)]delegate bool __isDelegateCreationAllowed(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* delegateHnd, CORINFO_METHOD_STRUCT_* calleeHnd); - [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] delegate CorInfoInstantiationVerification __isInstantiationOfVerifiedGeneric(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method); [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] delegate void __initConstraintsForVerification(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, [MarshalAs(UnmanagedType.Bool)] ref bool pfHasCircularClassConstraints, [MarshalAs(UnmanagedType.Bool)] ref bool pfHasCircularMethodConstraint); @@ -238,8 +238,6 @@ namespace Internal.JitInterface [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] delegate int* __getAddrOfCaptureThreadGlobal(IntPtr _this, IntPtr* ppException, ref void* ppIndirection); [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] - delegate void* __getAddrModuleDomainID(IntPtr _this, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module); - [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] delegate void* __getHelperFtn(IntPtr _this, IntPtr* ppException, CorInfoHelpFunc ftnNum, ref void* ppIndirection); [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] delegate void __getFunctionEntryPoint(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags); @@ -520,6 +518,19 @@ namespace Internal.JitInterface } } + static void _expandRawHandleIntrinsic(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + var _this = GetThis(thisHandle); + try + { + _this.expandRawHandleIntrinsic(ref pResolvedToken, ref pResult); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + static CorInfoIntrinsics _getIntrinsicID(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, [MarshalAs(UnmanagedType.U1)] ref bool pMustExpand) { var _this = GetThis(thisHandle); @@ -604,20 +615,6 @@ namespace Internal.JitInterface } } - [return: MarshalAs(UnmanagedType.Bool)]static bool _isDelegateCreationAllowed(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* delegateHnd, CORINFO_METHOD_STRUCT_* calleeHnd) - { - var _this = GetThis(thisHandle); - try - { - return _this.isDelegateCreationAllowed(delegateHnd, calleeHnd); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(bool); - } - } - static CorInfoInstantiationVerification _isInstantiationOfVerifiedGeneric(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) { var _this = GetThis(thisHandle); @@ -1900,20 +1897,6 @@ namespace Internal.JitInterface } } - static void* _getAddrModuleDomainID(IntPtr thisHandle, IntPtr* ppException, CORINFO_MODULE_STRUCT_* module) - { - var _this = GetThis(thisHandle); - try - { - return _this.getAddrModuleDomainID(module); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default(void*); - } - } - static void* _getHelperFtn(IntPtr thisHandle, IntPtr* ppException, CorInfoHelpFunc ftnNum, ref void* ppIndirection) { var _this = GetThis(thisHandle); @@ -2626,8 +2609,8 @@ namespace Internal.JitInterface static IntPtr GetUnmanagedCallbacks(out Object keepAlive) { - IntPtr * callbacks = (IntPtr *)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 166); - Object[] delegates = new Object[166]; + IntPtr * callbacks = (IntPtr *)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 165); + Object[] delegates = new Object[165]; var d0 = new __getMethodAttribs(_getMethodAttribs); callbacks[0] = Marshal.GetFunctionPointerForDelegate(d0); @@ -2668,25 +2651,25 @@ namespace Internal.JitInterface var d12 = new __resolveVirtualMethod(_resolveVirtualMethod); callbacks[12] = Marshal.GetFunctionPointerForDelegate(d12); delegates[12] = d12; - var d13 = new __getIntrinsicID(_getIntrinsicID); + var d13 = new __expandRawHandleIntrinsic(_expandRawHandleIntrinsic); callbacks[13] = Marshal.GetFunctionPointerForDelegate(d13); delegates[13] = d13; - var d14 = new __isInSIMDModule(_isInSIMDModule); + var d14 = new __getIntrinsicID(_getIntrinsicID); callbacks[14] = Marshal.GetFunctionPointerForDelegate(d14); delegates[14] = d14; - var d15 = new __getUnmanagedCallConv(_getUnmanagedCallConv); + var d15 = new __isInSIMDModule(_isInSIMDModule); callbacks[15] = Marshal.GetFunctionPointerForDelegate(d15); delegates[15] = d15; - var d16 = new __pInvokeMarshalingRequired(_pInvokeMarshalingRequired); + var d16 = new __getUnmanagedCallConv(_getUnmanagedCallConv); callbacks[16] = Marshal.GetFunctionPointerForDelegate(d16); delegates[16] = d16; - var d17 = new __satisfiesMethodConstraints(_satisfiesMethodConstraints); + var d17 = new __pInvokeMarshalingRequired(_pInvokeMarshalingRequired); callbacks[17] = Marshal.GetFunctionPointerForDelegate(d17); delegates[17] = d17; - var d18 = new __isCompatibleDelegate(_isCompatibleDelegate); + var d18 = new __satisfiesMethodConstraints(_satisfiesMethodConstraints); callbacks[18] = Marshal.GetFunctionPointerForDelegate(d18); delegates[18] = d18; - var d19 = new __isDelegateCreationAllowed(_isDelegateCreationAllowed); + var d19 = new __isCompatibleDelegate(_isCompatibleDelegate); callbacks[19] = Marshal.GetFunctionPointerForDelegate(d19); delegates[19] = d19; var d20 = new __isInstantiationOfVerifiedGeneric(_isInstantiationOfVerifiedGeneric); @@ -2968,165 +2951,162 @@ namespace Internal.JitInterface var d112 = new __getAddrOfCaptureThreadGlobal(_getAddrOfCaptureThreadGlobal); callbacks[112] = Marshal.GetFunctionPointerForDelegate(d112); delegates[112] = d112; - var d113 = new __getAddrModuleDomainID(_getAddrModuleDomainID); + var d113 = new __getHelperFtn(_getHelperFtn); callbacks[113] = Marshal.GetFunctionPointerForDelegate(d113); delegates[113] = d113; - var d114 = new __getHelperFtn(_getHelperFtn); + var d114 = new __getFunctionEntryPoint(_getFunctionEntryPoint); callbacks[114] = Marshal.GetFunctionPointerForDelegate(d114); delegates[114] = d114; - var d115 = new __getFunctionEntryPoint(_getFunctionEntryPoint); + var d115 = new __getFunctionFixedEntryPoint(_getFunctionFixedEntryPoint); callbacks[115] = Marshal.GetFunctionPointerForDelegate(d115); delegates[115] = d115; - var d116 = new __getFunctionFixedEntryPoint(_getFunctionFixedEntryPoint); + var d116 = new __getMethodSync(_getMethodSync); callbacks[116] = Marshal.GetFunctionPointerForDelegate(d116); delegates[116] = d116; - var d117 = new __getMethodSync(_getMethodSync); + var d117 = new __getLazyStringLiteralHelper(_getLazyStringLiteralHelper); callbacks[117] = Marshal.GetFunctionPointerForDelegate(d117); delegates[117] = d117; - var d118 = new __getLazyStringLiteralHelper(_getLazyStringLiteralHelper); + var d118 = new __embedModuleHandle(_embedModuleHandle); callbacks[118] = Marshal.GetFunctionPointerForDelegate(d118); delegates[118] = d118; - var d119 = new __embedModuleHandle(_embedModuleHandle); + var d119 = new __embedClassHandle(_embedClassHandle); callbacks[119] = Marshal.GetFunctionPointerForDelegate(d119); delegates[119] = d119; - var d120 = new __embedClassHandle(_embedClassHandle); + var d120 = new __embedMethodHandle(_embedMethodHandle); callbacks[120] = Marshal.GetFunctionPointerForDelegate(d120); delegates[120] = d120; - var d121 = new __embedMethodHandle(_embedMethodHandle); + var d121 = new __embedFieldHandle(_embedFieldHandle); callbacks[121] = Marshal.GetFunctionPointerForDelegate(d121); delegates[121] = d121; - var d122 = new __embedFieldHandle(_embedFieldHandle); + var d122 = new __embedGenericHandle(_embedGenericHandle); callbacks[122] = Marshal.GetFunctionPointerForDelegate(d122); delegates[122] = d122; - var d123 = new __embedGenericHandle(_embedGenericHandle); + var d123 = new __getLocationOfThisType(_getLocationOfThisType); callbacks[123] = Marshal.GetFunctionPointerForDelegate(d123); delegates[123] = d123; - var d124 = new __getLocationOfThisType(_getLocationOfThisType); + var d124 = new __getPInvokeUnmanagedTarget(_getPInvokeUnmanagedTarget); callbacks[124] = Marshal.GetFunctionPointerForDelegate(d124); delegates[124] = d124; - var d125 = new __getPInvokeUnmanagedTarget(_getPInvokeUnmanagedTarget); + var d125 = new __getAddressOfPInvokeFixup(_getAddressOfPInvokeFixup); callbacks[125] = Marshal.GetFunctionPointerForDelegate(d125); delegates[125] = d125; - var d126 = new __getAddressOfPInvokeFixup(_getAddressOfPInvokeFixup); + var d126 = new __getAddressOfPInvokeTarget(_getAddressOfPInvokeTarget); callbacks[126] = Marshal.GetFunctionPointerForDelegate(d126); delegates[126] = d126; - var d127 = new __getAddressOfPInvokeTarget(_getAddressOfPInvokeTarget); + var d127 = new __GetCookieForPInvokeCalliSig(_GetCookieForPInvokeCalliSig); callbacks[127] = Marshal.GetFunctionPointerForDelegate(d127); delegates[127] = d127; - var d128 = new __GetCookieForPInvokeCalliSig(_GetCookieForPInvokeCalliSig); + var d128 = new __canGetCookieForPInvokeCalliSig(_canGetCookieForPInvokeCalliSig); callbacks[128] = Marshal.GetFunctionPointerForDelegate(d128); delegates[128] = d128; - var d129 = new __canGetCookieForPInvokeCalliSig(_canGetCookieForPInvokeCalliSig); + var d129 = new __getJustMyCodeHandle(_getJustMyCodeHandle); callbacks[129] = Marshal.GetFunctionPointerForDelegate(d129); delegates[129] = d129; - var d130 = new __getJustMyCodeHandle(_getJustMyCodeHandle); + var d130 = new __GetProfilingHandle(_GetProfilingHandle); callbacks[130] = Marshal.GetFunctionPointerForDelegate(d130); delegates[130] = d130; - var d131 = new __GetProfilingHandle(_GetProfilingHandle); + var d131 = new __getCallInfo(_getCallInfo); callbacks[131] = Marshal.GetFunctionPointerForDelegate(d131); delegates[131] = d131; - var d132 = new __getCallInfo(_getCallInfo); + var d132 = new __canAccessFamily(_canAccessFamily); callbacks[132] = Marshal.GetFunctionPointerForDelegate(d132); delegates[132] = d132; - var d133 = new __canAccessFamily(_canAccessFamily); + var d133 = new __isRIDClassDomainID(_isRIDClassDomainID); callbacks[133] = Marshal.GetFunctionPointerForDelegate(d133); delegates[133] = d133; - var d134 = new __isRIDClassDomainID(_isRIDClassDomainID); + var d134 = new __getClassDomainID(_getClassDomainID); callbacks[134] = Marshal.GetFunctionPointerForDelegate(d134); delegates[134] = d134; - var d135 = new __getClassDomainID(_getClassDomainID); + var d135 = new __getFieldAddress(_getFieldAddress); callbacks[135] = Marshal.GetFunctionPointerForDelegate(d135); delegates[135] = d135; - var d136 = new __getFieldAddress(_getFieldAddress); + var d136 = new __getVarArgsHandle(_getVarArgsHandle); callbacks[136] = Marshal.GetFunctionPointerForDelegate(d136); delegates[136] = d136; - var d137 = new __getVarArgsHandle(_getVarArgsHandle); + var d137 = new __canGetVarArgsHandle(_canGetVarArgsHandle); callbacks[137] = Marshal.GetFunctionPointerForDelegate(d137); delegates[137] = d137; - var d138 = new __canGetVarArgsHandle(_canGetVarArgsHandle); + var d138 = new __constructStringLiteral(_constructStringLiteral); callbacks[138] = Marshal.GetFunctionPointerForDelegate(d138); delegates[138] = d138; - var d139 = new __constructStringLiteral(_constructStringLiteral); + var d139 = new __emptyStringLiteral(_emptyStringLiteral); callbacks[139] = Marshal.GetFunctionPointerForDelegate(d139); delegates[139] = d139; - var d140 = new __emptyStringLiteral(_emptyStringLiteral); + var d140 = new __getFieldThreadLocalStoreID(_getFieldThreadLocalStoreID); callbacks[140] = Marshal.GetFunctionPointerForDelegate(d140); delegates[140] = d140; - var d141 = new __getFieldThreadLocalStoreID(_getFieldThreadLocalStoreID); + var d141 = new __setOverride(_setOverride); callbacks[141] = Marshal.GetFunctionPointerForDelegate(d141); delegates[141] = d141; - var d142 = new __setOverride(_setOverride); + var d142 = new __addActiveDependency(_addActiveDependency); callbacks[142] = Marshal.GetFunctionPointerForDelegate(d142); delegates[142] = d142; - var d143 = new __addActiveDependency(_addActiveDependency); + var d143 = new __GetDelegateCtor(_GetDelegateCtor); callbacks[143] = Marshal.GetFunctionPointerForDelegate(d143); delegates[143] = d143; - var d144 = new __GetDelegateCtor(_GetDelegateCtor); + var d144 = new __MethodCompileComplete(_MethodCompileComplete); callbacks[144] = Marshal.GetFunctionPointerForDelegate(d144); delegates[144] = d144; - var d145 = new __MethodCompileComplete(_MethodCompileComplete); + var d145 = new __getTailCallCopyArgsThunk(_getTailCallCopyArgsThunk); callbacks[145] = Marshal.GetFunctionPointerForDelegate(d145); delegates[145] = d145; - var d146 = new __getTailCallCopyArgsThunk(_getTailCallCopyArgsThunk); + var d146 = new __getMemoryManager(_getMemoryManager); callbacks[146] = Marshal.GetFunctionPointerForDelegate(d146); delegates[146] = d146; - var d147 = new __getMemoryManager(_getMemoryManager); + var d147 = new __allocMem(_allocMem); callbacks[147] = Marshal.GetFunctionPointerForDelegate(d147); delegates[147] = d147; - var d148 = new __allocMem(_allocMem); + var d148 = new __reserveUnwindInfo(_reserveUnwindInfo); callbacks[148] = Marshal.GetFunctionPointerForDelegate(d148); delegates[148] = d148; - var d149 = new __reserveUnwindInfo(_reserveUnwindInfo); + var d149 = new __allocUnwindInfo(_allocUnwindInfo); callbacks[149] = Marshal.GetFunctionPointerForDelegate(d149); delegates[149] = d149; - var d150 = new __allocUnwindInfo(_allocUnwindInfo); + var d150 = new __allocGCInfo(_allocGCInfo); callbacks[150] = Marshal.GetFunctionPointerForDelegate(d150); delegates[150] = d150; - var d151 = new __allocGCInfo(_allocGCInfo); + var d151 = new __yieldExecution(_yieldExecution); callbacks[151] = Marshal.GetFunctionPointerForDelegate(d151); delegates[151] = d151; - var d152 = new __yieldExecution(_yieldExecution); + var d152 = new __setEHcount(_setEHcount); callbacks[152] = Marshal.GetFunctionPointerForDelegate(d152); delegates[152] = d152; - var d153 = new __setEHcount(_setEHcount); + var d153 = new __setEHinfo(_setEHinfo); callbacks[153] = Marshal.GetFunctionPointerForDelegate(d153); delegates[153] = d153; - var d154 = new __setEHinfo(_setEHinfo); + var d154 = new __logMsg(_logMsg); callbacks[154] = Marshal.GetFunctionPointerForDelegate(d154); delegates[154] = d154; - var d155 = new __logMsg(_logMsg); + var d155 = new __doAssert(_doAssert); callbacks[155] = Marshal.GetFunctionPointerForDelegate(d155); delegates[155] = d155; - var d156 = new __doAssert(_doAssert); + var d156 = new __reportFatalError(_reportFatalError); callbacks[156] = Marshal.GetFunctionPointerForDelegate(d156); delegates[156] = d156; - var d157 = new __reportFatalError(_reportFatalError); + var d157 = new __allocBBProfileBuffer(_allocBBProfileBuffer); callbacks[157] = Marshal.GetFunctionPointerForDelegate(d157); delegates[157] = d157; - var d158 = new __allocBBProfileBuffer(_allocBBProfileBuffer); + var d158 = new __getBBProfileData(_getBBProfileData); callbacks[158] = Marshal.GetFunctionPointerForDelegate(d158); delegates[158] = d158; - var d159 = new __getBBProfileData(_getBBProfileData); + var d159 = new __recordCallSite(_recordCallSite); callbacks[159] = Marshal.GetFunctionPointerForDelegate(d159); delegates[159] = d159; - var d160 = new __recordCallSite(_recordCallSite); + var d160 = new __recordRelocation(_recordRelocation); callbacks[160] = Marshal.GetFunctionPointerForDelegate(d160); delegates[160] = d160; - var d161 = new __recordRelocation(_recordRelocation); + var d161 = new __getRelocTypeHint(_getRelocTypeHint); callbacks[161] = Marshal.GetFunctionPointerForDelegate(d161); delegates[161] = d161; - var d162 = new __getRelocTypeHint(_getRelocTypeHint); + var d162 = new __getModuleNativeEntryPointRange(_getModuleNativeEntryPointRange); callbacks[162] = Marshal.GetFunctionPointerForDelegate(d162); delegates[162] = d162; - var d163 = new __getModuleNativeEntryPointRange(_getModuleNativeEntryPointRange); + var d163 = new __getExpectedTargetArchitecture(_getExpectedTargetArchitecture); callbacks[163] = Marshal.GetFunctionPointerForDelegate(d163); delegates[163] = d163; - var d164 = new __getExpectedTargetArchitecture(_getExpectedTargetArchitecture); + var d164 = new __getJitFlags(_getJitFlags); callbacks[164] = Marshal.GetFunctionPointerForDelegate(d164); delegates[164] = d164; - var d165 = new __getJitFlags(_getJitFlags); - callbacks[165] = Marshal.GetFunctionPointerForDelegate(d165); - delegates[165] = d165; keepAlive = delegates; return (IntPtr)callbacks; diff --git a/src/JitInterface/src/CorInfoImpl.Intrinsics.cs b/src/JitInterface/src/CorInfoImpl.Intrinsics.cs index 10b345d41..de56a69f3 100644 --- a/src/JitInterface/src/CorInfoImpl.Intrinsics.cs +++ b/src/JitInterface/src/CorInfoImpl.Intrinsics.cs @@ -124,11 +124,13 @@ namespace Internal.JitInterface // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetManagedThreadId, "get_ManagedThreadId", "System", "Thread"); // not in .NET Core table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_ByReference_Ctor, ".ctor", "System", "ByReference`1"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_ByReference_Value, "get_Value", "System", "ByReference`1"); - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Span_GetItem, "get_Item", "System", "Span`1"); // not handled - table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_ReadOnlySpan_GetItem, "get_Item", "System", "ReadOnlySpan`1"); // not handled + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Span_GetItem, "get_Item", "System", "Span`1"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_ReadOnlySpan_GetItem, "get_Item", "System", "ReadOnlySpan`1"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetRawHandle, "EETypePtrOf", "System", "EETypePtr"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetRawHandle, "DefaultConstructorOf", "System", "Activator"); // If this assert fails, make sure to add the new intrinsics to the table above and update the expected count below. - Debug.Assert((int)CorInfoIntrinsics.CORINFO_INTRINSIC_Count == 49); + Debug.Assert((int)CorInfoIntrinsics.CORINFO_INTRINSIC_Count == 50); return table; } @@ -203,6 +205,10 @@ namespace Internal.JitInterface pMustExpand = true; break; + case CorInfoIntrinsics.CORINFO_INTRINSIC_GetRawHandle: + pMustExpand = method.Name == "DefaultConstructorOf"; + break; + default: break; } diff --git a/src/JitInterface/src/CorInfoImpl.cs b/src/JitInterface/src/CorInfoImpl.cs index 9e4508b19..9e8c802bf 100644 --- a/src/JitInterface/src/CorInfoImpl.cs +++ b/src/JitInterface/src/CorInfoImpl.cs @@ -797,6 +797,67 @@ namespace Internal.JitInterface private CORINFO_METHOD_STRUCT_* resolveVirtualMethod(CORINFO_METHOD_STRUCT_* virtualMethod, CORINFO_CLASS_STRUCT_* implementingClass, CORINFO_CONTEXT_STRUCT* ownerType) { throw new NotImplementedException("resolveVirtualMethod"); } + private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + // Resolved token as a potentially RuntimeDetermined object. + MethodDesc method = (MethodDesc)GetRuntimeDeterminedObjectForToken(ref pResolvedToken); + + if (method.IsRuntimeDeterminedExactMethod) + { + pResult.lookup.lookupKind.needsRuntimeLookup = true; + pResult.lookup.runtimeLookup.signature = null; + pResult.lookup.runtimeLookup.indirections = CORINFO.USEHELPER; + + MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext); + + // Do not bother computing the runtime lookup if we are inlining. The JIT is going + // to abort the inlining attempt anyway. + if (contextMethod == MethodBeingCompiled) + { + switch (method.Name) + { + case "EETypePtrOf": + pResult.lookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.TypeHandle; + pResult.lookup.lookupKind.runtimeLookupArgs = ObjectToHandle(method.Instantiation[0]); + break; + case "DefaultConstructorOf": + pResult.lookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.DefaultConstructor; + pResult.lookup.lookupKind.runtimeLookupArgs = ObjectToHandle(method.Instantiation[0]); + break; + default: + Debug.Assert(false); + break; + } + + pResult.lookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod); + } + } + else + { + pResult.lookup.lookupKind.needsRuntimeLookup = false; + + switch (method.Name) + { + case "EETypePtrOf": + pResult.lookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(method.Instantiation[0])); + break; + case "DefaultConstructorOf": + MethodDesc ctor = method.Instantiation[0].GetDefaultConstructor(); + if (ctor == null) + { + MetadataType activatorType = _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "Activator"); + MetadataType classWithMissingCtor = activatorType.GetKnownNestedType("ClassWithMissingConstructor"); + ctor = classWithMissingCtor.GetParameterlessConstructor(); + } + pResult.lookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.CanonicalEntrypoint(ctor)); + break; + default: + Debug.Assert(false); + break; + } + } + } + private SimdHelper _simdHelper; private bool isInSIMDModule(CORINFO_CLASS_STRUCT_* classHnd) { @@ -856,12 +917,6 @@ namespace Internal.JitInterface { throw new NotImplementedException("satisfiesMethodConstraints"); } private bool isCompatibleDelegate(CORINFO_CLASS_STRUCT_* objCls, CORINFO_CLASS_STRUCT_* methodParentCls, CORINFO_METHOD_STRUCT_* method, CORINFO_CLASS_STRUCT_* delegateCls, ref bool pfIsOpenDelegate) { throw new NotImplementedException("isCompatibleDelegate"); } - - private bool isDelegateCreationAllowed(CORINFO_CLASS_STRUCT_* delegateHnd, CORINFO_METHOD_STRUCT_* calleeHnd) - { - return true; - } - private CorInfoInstantiationVerification isInstantiationOfVerifiedGeneric(CORINFO_METHOD_STRUCT_* method) { throw new NotImplementedException("isInstantiationOfVerifiedGeneric"); } private void initConstraintsForVerification(CORINFO_METHOD_STRUCT_* method, ref bool pfHasCircularClassConstraints, ref bool pfHasCircularMethodConstraint) @@ -927,8 +982,14 @@ namespace Internal.JitInterface return result; } } + else + { + object result = methodIL.GetObject((int)pResolvedToken.token); + if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Newarr) + return ((TypeDesc)result).MakeArrayType(); - return null; + return result; + } } private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) @@ -964,7 +1025,12 @@ namespace Internal.JitInterface { TypeDesc type = (TypeDesc)result; if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Newarr) + { + if (type.IsVoid) + throw new TypeSystemException.InvalidProgramException(ExceptionStringID.InvalidProgramSpecific, methodIL.OwningMethod); + type = type.MakeArrayType(); + } pResolvedToken.hClass = ObjectToHandle(type); } @@ -1352,23 +1418,6 @@ namespace Internal.JitInterface return type.IsNullable ? CorInfoHelpFunc.CORINFO_HELP_UNBOX_NULLABLE : CorInfoHelpFunc.CORINFO_HELP_UNBOX; } - private object GetTargetForFixup(object resolvedToken, ReadyToRunHelperId helperId) - { - switch (helperId) - { - case ReadyToRunHelperId.TypeHandle: - if (resolvedToken is TypeDesc) - return resolvedToken; - else if (resolvedToken is MethodDesc) - return ((MethodDesc)resolvedToken).OwningType; - else - return ((FieldDesc)resolvedToken).OwningType; - - default: - return resolvedToken; - } - } - private ISymbolNode GetGenericLookupHelper(CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind, ReadyToRunHelperId helperId, object helperArgument) { if (runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ @@ -1459,11 +1508,7 @@ namespace Internal.JitInterface Debug.Assert(pGenericLookupKind.needsRuntimeLookup); ReadyToRunHelperId helperId = (ReadyToRunHelperId)pGenericLookupKind.runtimeLookupFlags; - object helperArg; - if (helperId != ReadyToRunHelperId.DelegateCtor) - helperArg = GetTargetForFixup(GetRuntimeDeterminedObjectForToken(ref pResolvedToken), helperId); - else - helperArg = HandleToObject((IntPtr)pGenericLookupKind.runtimeLookupArgs); + object helperArg = HandleToObject((IntPtr)pGenericLookupKind.runtimeLookupArgs); ISymbolNode helper = GetGenericLookupHelper(pGenericLookupKind.runtimeLookupKind, helperId, helperArg); pLookup = CreateConstLookupToSymbol(helper); } @@ -2286,8 +2331,6 @@ namespace Internal.JitInterface { throw new NotImplementedException("getInlinedCallFrameVptr"); } private int* getAddrOfCaptureThreadGlobal(ref void* ppIndirection) { throw new NotImplementedException("getAddrOfCaptureThreadGlobal"); } - private void* getAddrModuleDomainID(CORINFO_MODULE_STRUCT_* module) - { throw new NotImplementedException("getAddrModuleDomainID"); } private Dictionary<CorInfoHelpFunc, ISymbolNode> _helperCache = new Dictionary<CorInfoHelpFunc, ISymbolNode>(); private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) @@ -2304,6 +2347,8 @@ namespace Internal.JitInterface case CorInfoHelpFunc.CORINFO_HELP_FAIL_FAST: id = ReadyToRunHelper.FailFast; break; case CorInfoHelpFunc.CORINFO_HELP_THROWNULLREF: id = ReadyToRunHelper.ThrowNullRef; break; case CorInfoHelpFunc.CORINFO_HELP_THROWDIVZERO: id = ReadyToRunHelper.ThrowDivZero; break; + case CorInfoHelpFunc.CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION: id = ReadyToRunHelper.ThrowArgumentOutOfRange; break; + case CorInfoHelpFunc.CORINFO_HELP_THROW_ARGUMENTEXCEPTION: id = ReadyToRunHelper.ThrowArgument; break; case CorInfoHelpFunc.CORINFO_HELP_ASSIGN_REF: id = ReadyToRunHelper.WriteBarrier; break; case CorInfoHelpFunc.CORINFO_HELP_CHECKED_ASSIGN_REF: id = ReadyToRunHelper.CheckedWriteBarrier; break; @@ -2512,6 +2557,8 @@ namespace Internal.JitInterface pResult.lookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.MethodDictionary; else throw new NotImplementedException(); + + pResult.lookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken)); } } else if (!fEmbedParent && pResolvedToken.hField != null) @@ -2533,6 +2580,7 @@ namespace Internal.JitInterface { Debug.Assert(pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Ldtoken); pResult.lookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.FieldHandle; + pResult.lookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken)); } } else @@ -2558,6 +2606,23 @@ namespace Internal.JitInterface else { pResult.lookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.TypeHandle; + + object obj = GetRuntimeDeterminedObjectForToken(ref pResolvedToken); + TypeDesc type = obj as TypeDesc; + if (type == null) + { + if (obj is MethodDesc) + { + type = ((MethodDesc)obj).OwningType; + } + else + { + Debug.Assert(obj is FieldDesc); + type = ((FieldDesc)obj).OwningType; + } + } + + pResult.lookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(type); } } @@ -2807,6 +2872,7 @@ namespace Internal.JitInterface { pResult.codePointerOrStubLookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod); pResult.codePointerOrStubLookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.MethodEntry; + pResult.codePointerOrStubLookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken)); } } else @@ -2939,6 +3005,7 @@ namespace Internal.JitInterface { pResult.codePointerOrStubLookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod); pResult.codePointerOrStubLookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.MethodHandle; + pResult.codePointerOrStubLookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken)); } } @@ -2979,6 +3046,7 @@ namespace Internal.JitInterface { pResult.codePointerOrStubLookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod); pResult.codePointerOrStubLookup.lookupKind.runtimeLookupFlags = (ushort)helperId; + pResult.codePointerOrStubLookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken)); } } else diff --git a/src/JitInterface/src/CorInfoTypes.cs b/src/JitInterface/src/CorInfoTypes.cs index ed8c6eec4..53bb1f721 100644 --- a/src/JitInterface/src/CorInfoTypes.cs +++ b/src/JitInterface/src/CorInfoTypes.cs @@ -280,6 +280,9 @@ namespace Internal.JitInterface public IntPtr offset1; public IntPtr offset2; public IntPtr offset3; + + public byte _indirectFirstOffset; + public bool indirectFirstOffset { get { return _indirectFirstOffset != 0; } set { _indirectFirstOffset = value ? (byte)1 : (byte)0; } } } // Result of calling embedGenericHandle @@ -473,6 +476,7 @@ namespace Internal.JitInterface CORINFO_INTRINSIC_ByReference_Value, CORINFO_INTRINSIC_Span_GetItem, CORINFO_INTRINSIC_ReadOnlySpan_GetItem, + CORINFO_INTRINSIC_GetRawHandle, CORINFO_INTRINSIC_Count, CORINFO_INTRINSIC_Illegal = -1, // Not a true intrinsic, diff --git a/src/JitInterface/src/ThunkGenerator/ThunkInput.txt b/src/JitInterface/src/ThunkGenerator/ThunkInput.txt index 9e34ade7e..25aaa420d 100644 --- a/src/JitInterface/src/ThunkGenerator/ThunkInput.txt +++ b/src/JitInterface/src/ThunkGenerator/ThunkInput.txt @@ -171,13 +171,13 @@ FUNCTIONS CORINFO_MODULE_HANDLE getMethodModule( CORINFO_METHOD_HANDLE method ); void getMethodVTableOffset( CORINFO_METHOD_HANDLE method, unsigned* offsetOfIndirection, unsigned* offsetAfterIndirection ); CORINFO_METHOD_HANDLE resolveVirtualMethod( CORINFO_METHOD_HANDLE virtualMethod, CORINFO_CLASS_HANDLE implementingClass, CORINFO_CONTEXT_HANDLE ownerType); + void expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_GENERICHANDLE_RESULT * pResult); CorInfoIntrinsics getIntrinsicID( CORINFO_METHOD_HANDLE method , bool * pMustExpand); bool isInSIMDModule( CORINFO_CLASS_HANDLE classHnd ); CorInfoUnmanagedCallConv getUnmanagedCallConv( CORINFO_METHOD_HANDLE method ); BOOL pInvokeMarshalingRequired( CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig ); BOOL satisfiesMethodConstraints( CORINFO_CLASS_HANDLE parent, CORINFO_METHOD_HANDLE method ); BOOL isCompatibleDelegate( CORINFO_CLASS_HANDLE objCls, CORINFO_CLASS_HANDLE methodParentCls, CORINFO_METHOD_HANDLE method, CORINFO_CLASS_HANDLE delegateCls, BOOL *pfIsOpenDelegate ); - BOOL isDelegateCreationAllowed( CORINFO_CLASS_HANDLE delegateHnd, CORINFO_METHOD_HANDLE calleeHnd ); CorInfoInstantiationVerification isInstantiationOfVerifiedGeneric( CORINFO_METHOD_HANDLE method ); void initConstraintsForVerification( CORINFO_METHOD_HANDLE method, BOOL *pfHasCircularClassConstraints, BOOL *pfHasCircularMethodConstraint ); CorInfoCanSkipVerificationResult canSkipMethodVerification( CORINFO_METHOD_HANDLE ftnHandle ); @@ -271,7 +271,6 @@ FUNCTIONS DWORD getThreadTLSIndex(void **ppIndirection); const void * getInlinedCallFrameVptr(void **ppIndirection); LONG * getAddrOfCaptureThreadGlobal(void **ppIndirection); - SIZE_T* getAddrModuleDomainID(CORINFO_MODULE_HANDLE module); void* getHelperFtn (CorInfoHelpFunc ftnNum, void **ppIndirection); void getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftn, CORINFO_CONST_LOOKUP * pResult, CORINFO_ACCESS_FLAGS accessFlags); void getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, CORINFO_CONST_LOOKUP * pResult); diff --git a/src/JitInterface/src/ThunkGenerator/corinfo.h b/src/JitInterface/src/ThunkGenerator/corinfo.h index 2495de251..e27283c8b 100644 --- a/src/JitInterface/src/ThunkGenerator/corinfo.h +++ b/src/JitInterface/src/ThunkGenerator/corinfo.h @@ -213,11 +213,11 @@ TODO: Talk about initializing strutures before use #define SELECTANY extern __declspec(selectany) #endif -SELECTANY const GUID JITEEVersionIdentifier = { /* f00b3f49-ddd2-49be-ba43-6e49ffa66959 */ - 0xf00b3f49, - 0xddd2, - 0x49be, - { 0xba, 0x43, 0x6e, 0x49, 0xff, 0xa6, 0x69, 0x59 } +SELECTANY const GUID JITEEVersionIdentifier = { /* e5708e9e-dd18-4287-8745-5d10ff2697cf */ + 0xe5708e9e, + 0xdd18, + 0x4287, + { 0x87, 0x45, 0x5d, 0x10, 0xff, 0x26, 0x97, 0xcf } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -960,6 +960,7 @@ enum CorInfoIntrinsics CORINFO_INTRINSIC_ByReference_Value, CORINFO_INTRINSIC_Span_GetItem, CORINFO_INTRINSIC_ReadOnlySpan_GetItem, + CORINFO_INTRINSIC_GetRawHandle, CORINFO_INTRINSIC_Count, CORINFO_INTRINSIC_Illegal = -1, // Not a true intrinsic, @@ -1323,6 +1324,13 @@ struct CORINFO_RUNTIME_LOOKUP bool testForFixup; SIZE_T offsets[CORINFO_MAXINDIRECTIONS]; + + // If set, first offset is indirect. + // 0 means that value stored at first offset (offsets[0]) from pointer is next pointer, to which the next offset + // (offsets[1]) is added and so on. + // 1 means that value stored at first offset (offsets[0]) from pointer is offset1, and the next pointer is + // stored at pointer+offsets[0]+offset1. + bool indirectFirstOffset; } ; // Result of calling embedGenericHandle @@ -1513,7 +1521,8 @@ enum CORINFO_CALL_KIND CORINFO_VIRTUALCALL_VTABLE }; - +// Indicates that the CORINFO_VIRTUALCALL_VTABLE lookup needn't do a chunk indirection +#define CORINFO_VIRTUALCALL_NO_CHUNK 0xFFFFFFFF enum CORINFO_THIS_TRANSFORM { @@ -2067,6 +2076,15 @@ public: CORINFO_CONTEXT_HANDLE ownerType = NULL /* IN */ ) = 0; + // Given resolved token that corresponds to an intrinsic classified as + // a CORINFO_INTRINSIC_GetRawHandle intrinsic, fetch the handle associated + // with the token. If this is not possible at compile-time (because the current method's + // code is shared and the token contains generic parameters) then indicate + // how the handle should be looked up at runtime. + virtual void expandRawHandleIntrinsic( + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_GENERICHANDLE_RESULT * pResult) = 0; + // If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set, // getIntrinsicID() returns the intrinsic ID. // *pMustExpand tells whether or not JIT must expand the intrinsic. @@ -2111,13 +2129,6 @@ public: BOOL *pfIsOpenDelegate /* is the delegate open */ ) = 0; - // Determines whether the delegate creation obeys security transparency rules - virtual BOOL isDelegateCreationAllowed ( - CORINFO_CLASS_HANDLE delegateHnd, - CORINFO_METHOD_HANDLE calleeHnd - ) = 0; - - // Indicates if the method is an instance of the generic // method that passes (or has passed) verification virtual CorInfoInstantiationVerification isInstantiationOfVerifiedGeneric ( @@ -2838,8 +2849,6 @@ public: void **ppIndirection = NULL ) = 0; - virtual SIZE_T* getAddrModuleDomainID(CORINFO_MODULE_HANDLE module) = 0; - // return the native entry point to an EE helper (see CorInfoHelpFunc) virtual void* getHelperFtn ( CorInfoHelpFunc ftnNum, diff --git a/src/Native/Runtime/arm/CallDescrWorker.S b/src/Native/Runtime/arm/CallDescrWorker.S index de818954b..77017f4f8 100644 --- a/src/Native/Runtime/arm/CallDescrWorker.S +++ b/src/Native/Runtime/arm/CallDescrWorker.S @@ -4,4 +4,29 @@ #include <unixasmmacros.inc> +.syntax unified +.thumb + // TODO: Implement Arm support + +NESTED_ENTRY RhCallDescrWorker, _TEXT, NoHandler +LOCAL_LABEL(ReturnFromCallDescrThunk): + + // UNIXTODO: Implement this function + // int 3 +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif +NESTED_END RhCallDescrWorker, _TEXT + +//.text +//.align 8 +//C_FUNC(PointerToReturnFromCallDescrThunk): +//.quad LOCAL_LABEL(ReturnFromCallDescrThunk) +//.global C_FUNC(PointerToReturnFromCallDescrThunk) + +LEAF_ENTRY PointerToReturnFromCallDescrThunk, _TEXT +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif +LEAF_END PointerToReturnFromCallDescrThunk, _TEXT diff --git a/src/Native/Runtime/arm/ExceptionHandling.S b/src/Native/Runtime/arm/ExceptionHandling.S index de818954b..e5eaf6372 100644 --- a/src/Native/Runtime/arm/ExceptionHandling.S +++ b/src/Native/Runtime/arm/ExceptionHandling.S @@ -4,4 +4,143 @@ #include <unixasmmacros.inc> +.syntax unified +.thumb + // TODO: Implement Arm support + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// RhpThrowHwEx +// +// INPUT: RDI: exception code of fault +// RSI: faulting RIP +// +// OUTPUT: +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +NESTED_ENTRY RhpThrowHwEx, _TEXT, NoHandler + +ALTERNATE_ENTRY RhpThrowHwEx2 + +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif + +NESTED_END RhpThrowHwEx + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// RhpThrowEx +// +// INPUT: RDI: exception object +// +// OUTPUT: +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +NESTED_ENTRY RhpThrowEx, _TEXT, NoHandler + +ALTERNATE_ENTRY RhpThrowEx2 + +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif + +NESTED_END RhpThrowEx, _TEXT + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// void FASTCALL RhpRethrow() +// +// SUMMARY: Similar to RhpThrowEx, except that it passes along the currently active ExInfo +// +// INPUT: +// +// OUTPUT: +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +NESTED_ENTRY RhpRethrow, _TEXT, NoHandler + +ALTERNATE_ENTRY RhpRethrow2 + +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif + +NESTED_END RhpRethrow, _TEXT + +// +// Prologue of all funclet calling helpers (RhpCallXXXXFunclet) +// + +// +// Epilogue of all funclet calling helpers (RhpCallXXXXFunclet) +// + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// void* FASTCALL RhpCallCatchFunclet(RtuObjectRef exceptionObj, void* pHandlerIP, REGDISPLAY* pRegDisplay, +// ExInfo* pExInfo) +// +// INPUT: RDI: exception object +// RSI: handler funclet address +// RDX: REGDISPLAY* +// RCX: ExInfo* +// +// OUTPUT: +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +NESTED_ENTRY RhpCallCatchFunclet, _TEXT, NoHandler + +ALTERNATE_ENTRY RhpCallCatchFunclet2 + + +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif + +NESTED_END RhpCallCatchFunclet, _TEXT + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// void FASTCALL RhpCallFinallyFunclet(void* pHandlerIP, REGDISPLAY* pRegDisplay) +// +// INPUT: RDI: handler funclet address +// RSI: REGDISPLAY* +// +// OUTPUT: +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +NESTED_ENTRY RhpCallFinallyFunclet, _TEXT, NoHandler + +ALTERNATE_ENTRY RhpCallFinallyFunclet2 + +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif + +NESTED_END RhpCallFinallyFunclet, _TEXT + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// void* FASTCALL RhpCallFilterFunclet(RtuObjectRef exceptionObj, void* pFilterIP, REGDISPLAY* pRegDisplay) +// +// INPUT: RDI: exception object +// RSI: filter funclet address +// RDX: REGDISPLAY* +// +// OUTPUT: +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +NESTED_ENTRY RhpCallFilterFunclet, _TEXT, NoHandler + +ALTERNATE_ENTRY RhpCallFilterFunclet2 + +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif + +NESTED_END RhpCallFilterFunclet, _TEXT diff --git a/src/Native/Runtime/arm/StubDispatch.S b/src/Native/Runtime/arm/StubDispatch.S index de818954b..7c79a11b8 100644 --- a/src/Native/Runtime/arm/StubDispatch.S +++ b/src/Native/Runtime/arm/StubDispatch.S @@ -4,4 +4,79 @@ #include <unixasmmacros.inc> +.syntax unified +.thumb + // TODO: Implement Arm support + +LEAF_ENTRY RhpCastableObjectDispatch_CommonStub, _TEXT + // UNIXTODO: Implement this function + //int 3 +LEAF_END RhpCastableObjectDispatch_CommonStub, _TEXT + +LEAF_ENTRY RhpTailCallTLSDispatchCell, _TEXT + // UNIXTODO: Implement this function + // int 3 +LEAF_END RhpTailCallTLSDispatchCell, _TEXT + +LEAF_ENTRY RhpCastableObjectDispatchHelper_TailCalled, _TEXT + // UNIXTODO: Implement this function + // int 3 +LEAF_END RhpCastableObjectDispatchHelper_TailCalled, _TEXT + +LEAF_ENTRY RhpCastableObjectDispatchHelper, _TEXT + // UNIXTODO: Implement this function + // int 3 +LEAF_END RhpCastableObjectDispatchHelper, _TEXT + + +// Stub dispatch routine for dispatch to a vtable slot +LEAF_ENTRY RhpVTableOffsetDispatch, _TEXT + // UNIXTODO: Implement this function + // int 3 +LEAF_END RhpVTableOffsetDispatch, _TEXT + +// Initial dispatch on an interface when we don't have a cache yet. +LEAF_ENTRY RhpInitialInterfaceDispatch, _TEXT +ALTERNATE_ENTRY RhpInitialDynamicInterfaceDispatch + + // Just tail call to the cache miss helper. + // jmp C_FUNC(RhpInterfaceDispatchSlow) + +LEAF_END RhpInitialInterfaceDispatch, _TEXT + +// Cache miss case, call the runtime to resolve the target and update the cache. +// Use universal transition helper to allow an exception to flow out of resolution +LEAF_ENTRY RhpInterfaceDispatchSlow, _TEXT + // jmp C_FUNC(RhpUniversalTransition_DebugStepTailCall) + +LEAF_END RhpInterfaceDispatchSlow, _TEXT + + +LEAF_ENTRY RhpInterfaceDispatch1, _TEXT + +LEAF_END RhpInterfaceDispatch1, _TEXT + +LEAF_ENTRY RhpInterfaceDispatch2, _TEXT + +LEAF_END RhpInterfaceDispatch2, _TEXT + +LEAF_ENTRY RhpInterfaceDispatch4, _TEXT + +LEAF_END RhpInterfaceDispatch4, _TEXT + +LEAF_ENTRY RhpInterfaceDispatch8, _TEXT + +LEAF_END RhpInterfaceDispatch8, _TEXT + +LEAF_ENTRY RhpInterfaceDispatch16, _TEXT + +LEAF_END RhpInterfaceDispatch16, _TEXT + +LEAF_ENTRY RhpInterfaceDispatch32, _TEXT + +LEAF_END RhpInterfaceDispatch32, _TEXT + +LEAF_ENTRY RhpInterfaceDispatch64, _TEXT + +LEAF_END RhpInterfaceDispatch64, _TEXT diff --git a/src/Native/Runtime/arm/UniversalTransition.S b/src/Native/Runtime/arm/UniversalTransition.S index de818954b..feaace2eb 100644 --- a/src/Native/Runtime/arm/UniversalTransition.S +++ b/src/Native/Runtime/arm/UniversalTransition.S @@ -4,4 +4,84 @@ #include <unixasmmacros.inc> +.syntax unified +.thumb + // TODO: Implement Arm support + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// RhpUniversalTransition +// +// At input to this function, r0-3, d0-7 and the stack may contain any number of arguments. +// +// In addition, there are 2 extra arguments passed in the RED ZONE (8 byte negative space +// off of sp). +// sp-4 will contain the managed function that is to be called by this transition function +// sp-8 will contain the pointer sized extra argument to the managed function +// +// When invoking the callee: +// +// r0 shall contain a pointer to the TransitionBlock +// r1 shall contain the value that was in sp-8 at entry to this function +// +// Frame layout is: +// +// {StackPassedArgs} ChildSP+078 CallerSP+000 +// {IntArgRegs (r0-r3) (0x10 bytes)} ChildSP+068 CallerSP-010 +// {ReturnBlock (0x20 bytes)} ChildSP+048 CallerSP-030 +// -- The base address of the Return block is the TransitionBlock pointer, the floating point args are +// in the neg space of the TransitionBlock pointer. Note that the callee has knowledge of the exact +// layout of all pieces of the frame that lie at or above the pushed floating point registers. +// {FpArgRegs (d0-d7) (0x40 bytes)} ChildSP+008 CallerSP-070 +// {PushedLR} ChildSP+004 CallerSP-074 +// {PushedR11} ChildSP+000 CallerSP-078 +// +// NOTE: If the frame layout ever changes, the C++ UniversalTransitionStackFrame structure +// must be updated as well. +// +// NOTE: The callee receives a pointer to the base of the ReturnBlock, and the callee has +// knowledge of the exact layout of all pieces of the frame that lie at or above the pushed +// FpArgRegs. +// +// NOTE: The stack walker guarantees that conservative GC reporting will be applied to +// everything between the base of the ReturnBlock and the top of the StackPassedArgs. +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +NESTED_ENTRY RhpUniversalTransition, _TEXT, NoHandler + +LOCAL_LABEL(ReturnFromUniversalTransition): + +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif + +NESTED_END RhpUniversalTransition + +NESTED_ENTRY PointerToReturnFromUniversalTransition, _TEXT, NoHandler + +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif + +NESTED_END PointerToReturnFromUniversalTransition + + +NESTED_ENTRY RhpUniversalTransition_DebugStepTailCall, _TEXT, NoHandler + +LOCAL_LABEL(ReturnFromUniversalTransition_DebugStepTailCall): + +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif + +NESTED_END RhpUniversalTransition_DebugStepTailCall + +NESTED_ENTRY PointerToReturnFromUniversalTransition_DebugStepTailCall, _TEXT, NoHandler + +#ifdef _DEBUG + bl C_FUNC(NYI_Assert) +#endif + +NESTED_END PointerToReturnFromUniversalTransition_DebugStepTailCall diff --git a/src/Native/Runtime/arm/WriteBarriers.S b/src/Native/Runtime/arm/WriteBarriers.S index 316770987..c34af7e09 100644 --- a/src/Native/Runtime/arm/WriteBarriers.S +++ b/src/Native/Runtime/arm/WriteBarriers.S @@ -5,12 +5,27 @@ // TODO: Implement Unix write barriers #include <unixasmmacros.inc> +.syntax unified +.thumb + LEAF_ENTRY RhpAssignRef, _TEXT +ALTERNATE_ENTRY RhpAssignRefAVLocation str r1, [r0] bx lr LEAF_END RhpAssignRef, _TEXT +// Define a helper with a name of the form RhpCheckedAssignRefEAX etc. (along with suitable calling standard +// decoration). The location to be updated is always in RDI. The object reference that will be assigned into +// that location is in one of the other general registers determined by the value of REFREG. + +// WARNING: Code in EHHelpers.cpp makes assumptions about write barrier code, in particular: +// - Function "InWriteBarrierHelper" assumes an AV due to passed in null pointer will happen on the first instruction +// - Function "UnwindWriteBarrierToCaller" assumes the stack contains just the pushed return address LEAF_ENTRY RhpCheckedAssignRef, _TEXT + +// ALTERNATE_ENTRY RhpCheckedAssignRef +ALTERNATE_ENTRY RhpCheckedAssignRefAVLocation + str r1, [r0] bx lr LEAF_END RhpCheckedAssignRef, _TEXT @@ -32,3 +47,22 @@ LEAF_ENTRY RhpByRefAssignRef, _TEXT str r3, [r0], #4 bx lr LEAF_END RhpByRefAssignRef, _TEXT + + +// WARNING: Code in EHHelpers.cpp makes assumptions about write barrier code, in particular: +// - Function "InWriteBarrierHelper" assumes an AV due to passed in null pointer will happen at RhpCheckedLockCmpXchgAVLocation +// - Function "UnwindWriteBarrierToCaller" assumes the stack contains just the pushed return address +LEAF_ENTRY RhpCheckedLockCmpXchg, _TEXT +ALTERNATE_ENTRY RhpCheckedLockCmpXchgAVLocation +LEAF_END RhpCheckedLockCmpXchg, _TEXT + + +// WARNING: Code in EHHelpers.cpp makes assumptions about write barrier code, in particular: +// - Function "InWriteBarrierHelper" assumes an AV due to passed in null pointer will happen at RhpCheckedXchgAVLocation +// - Function "UnwindWriteBarrierToCaller" assumes the stack contains just the pushed return address +LEAF_ENTRY RhpCheckedXchg, _TEXT + +// Setup rax with the new object for the exchange, that way it will automatically hold the correct result +// afterwards and we can leave rdx unaltered ready for the GC write barrier below. +ALTERNATE_ENTRY RhpCheckedXchgAVLocation +LEAF_END RhpCheckedXchg, _TEXT diff --git a/src/Native/Runtime/rhassert.cpp b/src/Native/Runtime/rhassert.cpp index 4928befa0..04fa1ac97 100644 --- a/src/Native/Runtime/rhassert.cpp +++ b/src/Native/Runtime/rhassert.cpp @@ -95,8 +95,10 @@ void Assert(const char * expr, const char * file, UInt32 line_num, const char * #endif //!DACCESS_COMPILE } -void NYI_Assert() +extern "C" void NYI_Assert() { +#if !defined(DACCESS_COMPILE) ASSERT_UNCONDITIONALLY("NYI"); +#endif } #endif // _DEBUG diff --git a/src/Native/Runtime/rhassert.h b/src/Native/Runtime/rhassert.h index 5808941e8..9863822fc 100644 --- a/src/Native/Runtime/rhassert.h +++ b/src/Native/Runtime/rhassert.h @@ -26,8 +26,6 @@ void Assert(const char * expr, const char * file, unsigned int line_num, const char * message); -void NYI_Assert(); - #else #define ASSERT(expr) @@ -38,7 +36,13 @@ void NYI_Assert(); #define ASSERT_UNCONDITIONALLY(message) -#endif +#endif + +#if defined(_DEBUG) + +void NYI_ASSERT(); + +#endif #define PORTABILITY_ASSERT(message) \ ASSERT_UNCONDITIONALLY(message); \ diff --git a/src/Native/jitinterface/jitinterface.h b/src/Native/jitinterface/jitinterface.h index d6a58a82f..c655eb1e5 100644 --- a/src/Native/jitinterface/jitinterface.h +++ b/src/Native/jitinterface/jitinterface.h @@ -23,13 +23,13 @@ struct JitInterfaceCallbacks void* (__stdcall * getMethodModule)(void * thisHandle, CorInfoException** ppException, void* method); void (__stdcall * getMethodVTableOffset)(void * thisHandle, CorInfoException** ppException, void* method, unsigned* offsetOfIndirection, unsigned* offsetAfterIndirection); void* (__stdcall * resolveVirtualMethod)(void * thisHandle, CorInfoException** ppException, void* virtualMethod, void* implementingClass, void* ownerType); + void (__stdcall * expandRawHandleIntrinsic)(void * thisHandle, CorInfoException** ppException, void* pResolvedToken, void* pResult); int (__stdcall * getIntrinsicID)(void * thisHandle, CorInfoException** ppException, void* method, bool* pMustExpand); bool (__stdcall * isInSIMDModule)(void * thisHandle, CorInfoException** ppException, void* classHnd); int (__stdcall * getUnmanagedCallConv)(void * thisHandle, CorInfoException** ppException, void* method); int (__stdcall * pInvokeMarshalingRequired)(void * thisHandle, CorInfoException** ppException, void* method, void* callSiteSig); int (__stdcall * satisfiesMethodConstraints)(void * thisHandle, CorInfoException** ppException, void* parent, void* method); int (__stdcall * isCompatibleDelegate)(void * thisHandle, CorInfoException** ppException, void* objCls, void* methodParentCls, void* method, void* delegateCls, int* pfIsOpenDelegate); - int (__stdcall * isDelegateCreationAllowed)(void * thisHandle, CorInfoException** ppException, void* delegateHnd, void* calleeHnd); int (__stdcall * isInstantiationOfVerifiedGeneric)(void * thisHandle, CorInfoException** ppException, void* method); void (__stdcall * initConstraintsForVerification)(void * thisHandle, CorInfoException** ppException, void* method, int* pfHasCircularClassConstraints, int* pfHasCircularMethodConstraint); int (__stdcall * canSkipMethodVerification)(void * thisHandle, CorInfoException** ppException, void* ftnHandle); @@ -123,7 +123,6 @@ struct JitInterfaceCallbacks unsigned int (__stdcall * getThreadTLSIndex)(void * thisHandle, CorInfoException** ppException, void** ppIndirection); const void* (__stdcall * getInlinedCallFrameVptr)(void * thisHandle, CorInfoException** ppException, void** ppIndirection); long* (__stdcall * getAddrOfCaptureThreadGlobal)(void * thisHandle, CorInfoException** ppException, void** ppIndirection); - size_t* (__stdcall * getAddrModuleDomainID)(void * thisHandle, CorInfoException** ppException, void* module); void* (__stdcall * getHelperFtn)(void * thisHandle, CorInfoException** ppException, int ftnNum, void** ppIndirection); void (__stdcall * getFunctionEntryPoint)(void * thisHandle, CorInfoException** ppException, void* ftn, void* pResult, int accessFlags); void (__stdcall * getFunctionFixedEntryPoint)(void * thisHandle, CorInfoException** ppException, void* ftn, void* pResult); @@ -301,6 +300,14 @@ public: return _ret; } + virtual void expandRawHandleIntrinsic(void* pResolvedToken, void* pResult) + { + CorInfoException* pException = nullptr; + _callbacks->expandRawHandleIntrinsic(_thisHandle, &pException, pResolvedToken, pResult); + if (pException != nullptr) + throw pException; + } + virtual int getIntrinsicID(void* method, bool* pMustExpand) { CorInfoException* pException = nullptr; @@ -355,15 +362,6 @@ public: return _ret; } - virtual int isDelegateCreationAllowed(void* delegateHnd, void* calleeHnd) - { - CorInfoException* pException = nullptr; - int _ret = _callbacks->isDelegateCreationAllowed(_thisHandle, &pException, delegateHnd, calleeHnd); - if (pException != nullptr) - throw pException; - return _ret; - } - virtual int isInstantiationOfVerifiedGeneric(void* method) { CorInfoException* pException = nullptr; @@ -1158,15 +1156,6 @@ public: return _ret; } - virtual size_t* getAddrModuleDomainID(void* module) - { - CorInfoException* pException = nullptr; - size_t* _ret = _callbacks->getAddrModuleDomainID(_thisHandle, &pException, module); - if (pException != nullptr) - throw pException; - return _ret; - } - virtual void* getHelperFtn(int ftnNum, void** ppIndirection) { CorInfoException* pException = nullptr; diff --git a/src/Native/jitinterface/jitwrapper.cpp b/src/Native/jitinterface/jitwrapper.cpp index 8a3af11f8..88699badb 100644 --- a/src/Native/jitinterface/jitwrapper.cpp +++ b/src/Native/jitinterface/jitwrapper.cpp @@ -27,11 +27,11 @@ private: unsigned __int64 corJitFlags; }; -static const GUID JITEEVersionIdentifier = { /* f00b3f49-ddd2-49be-ba43-6e49ffa66959 */ - 0xf00b3f49, - 0xddd2, - 0x49be, - { 0xba, 0x43, 0x6e, 0x49, 0xff, 0xa6, 0x69, 0x59 } +static const GUID JITEEVersionIdentifier = { /* e5708e9e-dd18-4287-8745-5d10ff2697cf */ + 0xe5708e9e, + 0xdd18, + 0x4287, + { 0x87, 0x45, 0x5d, 0x10, 0xff, 0x26, 0x97, 0xcf } }; class Jit diff --git a/src/System.Private.CoreLib/shared/System/Char.cs b/src/System.Private.CoreLib/shared/System/Char.cs index 3fad7a482..72441763e 100644 --- a/src/System.Private.CoreLib/shared/System/Char.cs +++ b/src/System.Private.CoreLib/shared/System/Char.cs @@ -21,6 +21,7 @@ namespace System { [Serializable] [StructLayout(LayoutKind.Sequential)] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct Char : IComparable, IComparable<Char>, IEquatable<Char>, IConvertible { // diff --git a/src/System.Private.CoreLib/shared/System/Collections/DictionaryEntry.cs b/src/System.Private.CoreLib/shared/System/Collections/DictionaryEntry.cs index 290306d00..3c1c0befa 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/DictionaryEntry.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/DictionaryEntry.cs @@ -9,10 +9,11 @@ namespace System.Collections // A DictionaryEntry holds a key and a value from a dictionary. // It is returned by IDictionaryEnumerator::GetEntry(). [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct DictionaryEntry { - private Object _key; - private Object _value; + private Object _key; // Do not rename (binary serialization) + private Object _value; // Do not rename (binary serialization) // Constructs a new DictionaryEnumerator by setting the Key // and Value fields appropriately. diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/KeyValuePair.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/KeyValuePair.cs index fc51af25f..aeafecd95 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/KeyValuePair.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/KeyValuePair.cs @@ -46,10 +46,11 @@ namespace System.Collections.Generic // It is used by the IEnumerable<T> implementation for both IDictionary<TKey, TValue> // and IReadOnlyDictionary<TKey, TValue>. [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct KeyValuePair<TKey, TValue> { - private TKey key; // DO NOT change the field name, it's required for compatibility with desktop .NET as it appears in serialization payload. - private TValue value; // DO NOT change the field name, it's required for compatibility with desktop .NET as it appears in serialization payload. + private TKey key; // Do not rename (binary serialization) + private TValue value; // Do not rename (binary serialization) public KeyValuePair(TKey key, TValue value) { diff --git a/src/System.Private.CoreLib/shared/System/DateTime.cs b/src/System.Private.CoreLib/shared/System/DateTime.cs index ddb72da77..4fd9727fc 100644 --- a/src/System.Private.CoreLib/shared/System/DateTime.cs +++ b/src/System.Private.CoreLib/shared/System/DateTime.cs @@ -54,6 +54,7 @@ namespace System // [StructLayout(LayoutKind.Auto)] [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public partial struct DateTime : IComparable, IFormattable, IConvertible, IComparable<DateTime>, IEquatable<DateTime>, ISerializable { // Number of 100ns ticks per time unit @@ -125,8 +126,8 @@ namespace System private const UInt64 KindLocalAmbiguousDst = 0xC000000000000000; private const Int32 KindShift = 62; - private const String TicksField = "ticks"; - private const String DateDataField = "_dateData"; + private const String TicksField = "ticks"; // Do not rename (binary serialization) + private const String DateDataField = "dateData"; // Do not rename (binary serialization) // The data is stored as an unsigned 64-bit integeter // Bits 01-62: The value of 100-nanosecond ticks where 0 represents 1/1/0001 12:00am, up until the value diff --git a/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs b/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs index d5ccbd919..ab35bdb0f 100644 --- a/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs +++ b/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs @@ -30,6 +30,7 @@ namespace System [StructLayout(LayoutKind.Auto)] [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct DateTimeOffset : IComparable, IFormattable, IComparable<DateTimeOffset>, IEquatable<DateTimeOffset>, ISerializable, IDeserializationCallback { // Constants @@ -573,8 +574,8 @@ namespace System throw new ArgumentNullException(nameof(info)); } - info.AddValue("DateTime", _dateTime); - info.AddValue("OffsetMinutes", _offsetMinutes); + info.AddValue("DateTime", _dateTime); // Do not rename (binary serialization) + info.AddValue("OffsetMinutes", _offsetMinutes); // Do not rename (binary serialization) } @@ -585,8 +586,8 @@ namespace System throw new ArgumentNullException(nameof(info)); } - _dateTime = (DateTime)info.GetValue("DateTime", typeof(DateTime)); - _offsetMinutes = (Int16)info.GetValue("OffsetMinutes", typeof(Int16)); + _dateTime = (DateTime)info.GetValue("DateTime", typeof(DateTime)); // Do not rename (binary serialization) + _offsetMinutes = (Int16)info.GetValue("OffsetMinutes", typeof(Int16)); // Do not rename (binary serialization) } // Returns the hash code for this DateTimeOffset. diff --git a/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs b/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs index 94c04d706..46e9a833e 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs @@ -5,6 +5,7 @@ namespace System.Globalization { [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public sealed class SortVersion : IEquatable<SortVersion> { private int m_NlsVersion; // Do not rename (binary serialization) diff --git a/src/System.Private.CoreLib/shared/System/StringComparer.cs b/src/System.Private.CoreLib/shared/System/StringComparer.cs index b327e770d..4b6193c18 100644 --- a/src/System.Private.CoreLib/shared/System/StringComparer.cs +++ b/src/System.Private.CoreLib/shared/System/StringComparer.cs @@ -10,6 +10,7 @@ using System.Diagnostics.Contracts; namespace System { [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public abstract class StringComparer : IComparer, IEqualityComparer, IComparer<string>, IEqualityComparer<string> { private static readonly CultureAwareComparer s_invariantCulture = new CultureAwareComparer(CultureInfo.InvariantCulture, false); @@ -170,30 +171,33 @@ namespace System } [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] internal sealed class CultureAwareComparer : StringComparer { - private readonly CompareInfo _compareInfo; - private readonly CompareOptions _options; + private readonly CompareInfo _compareInfo; // Do not rename (binary serialization) + private readonly bool _ignoreCase; // Do not rename (binary serialization) internal CultureAwareComparer(CultureInfo culture, bool ignoreCase) { _compareInfo = culture.CompareInfo; - _options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None; + _ignoreCase = ignoreCase; } + private CompareOptions Options => _ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None; + public override int Compare(string x, string y) { if (object.ReferenceEquals(x, y)) return 0; if (x == null) return -1; if (y == null) return 1; - return _compareInfo.Compare(x, y, _options); + return _compareInfo.Compare(x, y, Options); } public override bool Equals(string x, string y) { if (object.ReferenceEquals(x, y)) return true; if (x == null || y == null) return false; - return _compareInfo.Compare(x, y, _options) == 0; + return _compareInfo.Compare(x, y, Options) == 0; } public override int GetHashCode(string obj) @@ -202,7 +206,7 @@ namespace System { throw new ArgumentNullException(nameof(obj)); } - return _compareInfo.GetHashCodeOfString(obj, _options); + return _compareInfo.GetHashCodeOfString(obj, Options); } // Equals method for the comparer itself. @@ -211,18 +215,19 @@ namespace System CultureAwareComparer comparer = obj as CultureAwareComparer; return comparer != null && - _options == comparer._options && + _ignoreCase == comparer._ignoreCase && _compareInfo.Equals(comparer._compareInfo); } public override int GetHashCode() { int hashCode = _compareInfo.GetHashCode(); - return _options == CompareOptions.None ? hashCode : ~hashCode; + return _ignoreCase ? ~hashCode : hashCode; } } [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] internal sealed class OrdinalComparer : StringComparer { public override int Compare(string x, string y) => string.CompareOrdinal(x, y); @@ -248,6 +253,7 @@ namespace System } [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] internal sealed class OrdinalIgnoreCaseComparer : StringComparer { public override int Compare(string x, string y) => string.Compare(x, y, StringComparison.OrdinalIgnoreCase); diff --git a/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs index 3a06114bf..1167016cc 100644 --- a/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs +++ b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs @@ -35,6 +35,7 @@ namespace System.Text // Console.WriteLine(sb2); // [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public sealed partial class StringBuilder : ISerializable { // A StringBuilder is internally represented as a linked list of blocks each of which holds @@ -58,10 +59,11 @@ namespace System.Text // // internal const int DefaultCapacity = 16; - private const String CapacityField = "Capacity"; - private const String MaxCapacityField = "m_MaxCapacity"; - private const String StringValueField = "m_StringValue"; - private const String ThreadIDField = "m_currentThread"; + private const String CapacityField = "Capacity"; // Do not rename (binary serialization) + private const String MaxCapacityField = "m_MaxCapacity"; // Do not rename (binary serialization) + private const String StringValueField = "m_StringValue"; // Do not rename (binary serialization) + private const String ThreadIDField = "m_currentThread"; // Do not rename (binary serialization) + // We want to keep chunk arrays out of large object heap (< 85K bytes ~ 40K chars) to be sure. // Making the maximum chunk size big means less allocation code called, but also more waste // in unused characters and slower inserts / replaces (since you do need to slide characters over diff --git a/src/System.Private.CoreLib/shared/System/ValueTuple.cs b/src/System.Private.CoreLib/shared/System/ValueTuple.cs index e0cd02e91..3464f2781 100644 --- a/src/System.Private.CoreLib/shared/System/ValueTuple.cs +++ b/src/System.Private.CoreLib/shared/System/ValueTuple.cs @@ -29,6 +29,7 @@ namespace System /// - their members (such as Item1, Item2, etc) are fields rather than properties. /// </summary> [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct ValueTuple : IEquatable<ValueTuple>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple>, IValueTupleInternal, ITuple { @@ -298,6 +299,7 @@ namespace System /// <summary>Represents a 1-tuple, or singleton, as a value type.</summary> /// <typeparam name="T1">The type of the tuple's only component.</typeparam> [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct ValueTuple<T1> : IEquatable<ValueTuple<T1>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1>>, IValueTupleInternal, ITuple { @@ -464,6 +466,7 @@ namespace System /// <typeparam name="T2">The type of the tuple's second component.</typeparam> [Serializable] [StructLayout(LayoutKind.Auto)] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct ValueTuple<T1, T2> : IEquatable<ValueTuple<T1, T2>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2>>, IValueTupleInternal, ITuple { @@ -674,6 +677,7 @@ namespace System /// <typeparam name="T3">The type of the tuple's third component.</typeparam> [Serializable] [StructLayout(LayoutKind.Auto)] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct ValueTuple<T1, T2, T3> : IEquatable<ValueTuple<T1, T2, T3>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3>>, IValueTupleInternal, ITuple { @@ -882,6 +886,7 @@ namespace System /// <typeparam name="T4">The type of the tuple's fourth component.</typeparam> [Serializable] [StructLayout(LayoutKind.Auto)] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct ValueTuple<T1, T2, T3, T4> : IEquatable<ValueTuple<T1, T2, T3, T4>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3, T4>>, IValueTupleInternal, ITuple { @@ -1109,6 +1114,7 @@ namespace System /// <typeparam name="T5">The type of the tuple's fifth component.</typeparam> [Serializable] [StructLayout(LayoutKind.Auto)] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct ValueTuple<T1, T2, T3, T4, T5> : IEquatable<ValueTuple<T1, T2, T3, T4, T5>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3, T4, T5>>, IValueTupleInternal, ITuple { @@ -1355,6 +1361,7 @@ namespace System /// <typeparam name="T6">The type of the tuple's sixth component.</typeparam> [Serializable] [StructLayout(LayoutKind.Auto)] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct ValueTuple<T1, T2, T3, T4, T5, T6> : IEquatable<ValueTuple<T1, T2, T3, T4, T5, T6>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3, T4, T5, T6>>, IValueTupleInternal, ITuple { @@ -1620,6 +1627,7 @@ namespace System /// <typeparam name="T7">The type of the tuple's seventh component.</typeparam> [Serializable] [StructLayout(LayoutKind.Auto)] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7> : IEquatable<ValueTuple<T1, T2, T3, T4, T5, T6, T7>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3, T4, T5, T6, T7>>, IValueTupleInternal, ITuple { @@ -1904,6 +1912,7 @@ namespace System /// <typeparam name="TRest">The type of the tuple's eighth component.</typeparam> [Serializable] [StructLayout(LayoutKind.Auto)] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public struct ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> : IEquatable<ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>>, IValueTupleInternal, ITuple where TRest : struct diff --git a/src/System.Private.CoreLib/shared/System/Version.cs b/src/System.Private.CoreLib/shared/System/Version.cs index 54b2052dd..a2140ab13 100644 --- a/src/System.Private.CoreLib/shared/System/Version.cs +++ b/src/System.Private.CoreLib/shared/System/Version.cs @@ -16,14 +16,15 @@ namespace System // specified component. [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public sealed class Version : ICloneable, IComparable , IComparable<Version>, IEquatable<Version> { // AssemblyName depends on the order staying the same - private readonly int _Major; - private readonly int _Minor; - private readonly int _Build = -1; - private readonly int _Revision = -1; + private readonly int _Major; // Do not rename (binary serialization) + private readonly int _Minor; // Do not rename (binary serialization) + private readonly int _Build = -1; // Do not rename (binary serialization) + private readonly int _Revision = -1; // Do not rename (binary serialization) public Version(int major, int minor, int build, int revision) { diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/InteropCallbacks.cs b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/InteropCallbacks.cs index 4dd2c4369..7424ebcc5 100644 --- a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/InteropCallbacks.cs +++ b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/InteropCallbacks.cs @@ -12,5 +12,15 @@ namespace Internal.Runtime.Augments public abstract class InteropCallbacks { public abstract bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData delegateData); + + public abstract bool TryGetStructUnmarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr unmarshalStub); + + public abstract bool TryGetStructMarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr marshalStub); + + public abstract bool TryGetDestroyStructureStub(RuntimeTypeHandle structureTypeHandle, out IntPtr destroyStructureStub, out bool hasInvalidLayout); + + public abstract bool TryGetStructFieldOffset(RuntimeTypeHandle structureTypeHandle, string fieldName, out bool structExists, out uint offset); + + public abstract bool TryGetStructUnsafeStructSize(RuntimeTypeHandle structureTypeHandle, out int size); } } diff --git a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj index f028cf293..1a1706b1e 100644 --- a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> <PropertyGroup> @@ -647,6 +647,9 @@ <Compile Include="System\Globalization\FormatProvider.FormatAndParse.Unix.cs" /> <Compile Include="System\Environment.Unix.cs" /> <Compile Include="System\Runtime\InteropServices\PInvokeMarshal.Unix.cs" /> + <Compile Include="System\Threading\ClrThreadPool.cs" /> + <Compile Include="System\Threading\ClrThreadPool.HillClimbing.cs" /> + <Compile Include="System\Threading\ClrThreadPool.HillClimbing.Complex.cs" /> <Compile Include="System\Threading\EventWaitHandle.Unix.cs" /> <Compile Include="System\Threading\LowLevelLock.Unix.cs" /> <Compile Include="System\Threading\LowLevelMonitor.Unix.cs" /> @@ -851,4 +854,4 @@ </ItemGroup> <Import Project="..\shared\System.Private.CoreLib.Shared.projitems" Label="Shared" /> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> -</Project> +</Project>
\ No newline at end of file diff --git a/src/System.Private.CoreLib/src/System/Activator.cs b/src/System.Private.CoreLib/src/System/Activator.cs index e77006e0a..8ecfa24b8 100644 --- a/src/System.Private.CoreLib/src/System/Activator.cs +++ b/src/System.Private.CoreLib/src/System/Activator.cs @@ -35,12 +35,15 @@ namespace System EETypePtr eetype = EETypePtr.EETypePtrOf<T>(); - // ProjectN:936613 - Early exit for variable sized types (strings, arrays, etc.) as we cannot call - // CreateInstanceIntrinsic on them since the intrinsic will attempt to allocate an instance of these types - // and that is verboten (it results in silent heap corruption!). - if (eetype.ComponentSize != 0) + if (!RuntimeHelpers.IsReference<T>()) + { + // Early out for valuetypes since we don't support default constructors anyway. + // This lets codegens that expand IsReference<T> optimize away the rest of this code. + } + else if (eetype.ComponentSize != 0) { // ComponentSize > 0 indicates an array-like type (e.g. string, array, etc). + // Allocating this using the normal allocator would result in silent heap corruption. missingDefaultConstructor = true; } else if (eetype.IsInterface) @@ -54,8 +57,19 @@ namespace System try { +#if PROJECTN t = CreateInstanceIntrinsic<T>(); - System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); + DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); +#else + t = (T)(RuntimeImports.RhNewObject(eetype)); + + // Run the default constructor. If the default constructor was missing, codegen + // will expand DefaultConstructorOf to ClassWithMissingConstructor::.ctor + // and we detect that later. + IntPtr defaultConstructor = DefaultConstructorOf<T>(); + RawCalliHelper.Call(defaultConstructor, t); + DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); +#endif } catch (Exception e) { @@ -81,27 +95,14 @@ namespace System } [Intrinsic] - [DebuggerGuidedStepThrough] - private static T CreateInstanceIntrinsic<T>() - { - // Fallback implementation for codegens that don't support this intrinsic. - // This uses the type loader and doesn't have the kind of guarantees about it always working - // as the intrinsic expansion has. Also, it's slower. - - EETypePtr eetype = EETypePtr.EETypePtrOf<T>(); + private extern static T CreateInstanceIntrinsic<T>(); - // The default(T) check can be evaluated statically and will result in the body of this method - // becoming empty for valuetype Ts. We still need a dynamic IsNullable check to cover Nullables though. - // This will obviously need work once we start supporting default valuetype constructors. - if (default(T) == null && !eetype.IsNullable) - { - object o = null; - TypeLoaderExports.ActivatorCreateInstanceAny(ref o, eetype.RawValue); - System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); - return (T)o; - } - - return default(T); + [Intrinsic] + private static IntPtr DefaultConstructorOf<T>() + { + // Codegens must expand this intrinsic. + // We could implement a fallback with the type loader if we wanted to, but it will be slow and unreliable. + throw new NotSupportedException(); } [ThreadStatic] diff --git a/src/System.Private.CoreLib/src/System/Buffer.cs b/src/System.Private.CoreLib/src/System/Buffer.cs index 0bdad3203..a7f2860f4 100644 --- a/src/System.Private.CoreLib/src/System/Buffer.cs +++ b/src/System.Private.CoreLib/src/System/Buffer.cs @@ -21,15 +21,8 @@ using nuint = System.UInt32; namespace System { - [EagerStaticClassConstruction] public static class Buffer { - /// <summary> - /// This field is used to quickly check whether an array that is given to the BlockCopy - /// method is a byte array and the code can take optimized path. - /// </summary> - private static readonly EETypePtr s_byteArrayEEType = EETypePtr.EETypePtrOf<byte[]>(); - public static unsafe void BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count) @@ -43,8 +36,8 @@ namespace System throw new ArgumentNullException(nameof(dst)); // Use optimized path for byte arrays since this is the main scenario for Buffer::BlockCopy - EETypePtr byteArrayEEType = s_byteArrayEEType; - if (src.EETypePtr.FastEquals(byteArrayEEType)) + // We only need an unreliable comparison since the slow path can handle the byte[] case too. + if (src.EETypePtr.FastEqualsUnreliable(EETypePtr.EETypePtrOf<byte[]>())) { uSrcLen = (nuint)src.Length; } @@ -58,7 +51,9 @@ namespace System if (src != dst) { - if (dst.EETypePtr.FastEquals(byteArrayEEType)) + // Use optimized path for byte arrays since this is the main scenario for Buffer::BlockCopy + // We only need an unreliable comparison since the slow path can handle the byte[] case too. + if (dst.EETypePtr.FastEqualsUnreliable(EETypePtr.EETypePtrOf<byte[]>())) { uDstLen = (nuint)dst.Length; } diff --git a/src/System.Private.CoreLib/src/System/EETypePtr.cs b/src/System.Private.CoreLib/src/System/EETypePtr.cs index 39215d209..fa5abb6b0 100644 --- a/src/System.Private.CoreLib/src/System/EETypePtr.cs +++ b/src/System.Private.CoreLib/src/System/EETypePtr.cs @@ -90,6 +90,19 @@ namespace System return RuntimeImports.AreTypesEquivalent(this, other); } + // + // An even faster version of FastEquals that only checks if two EEType pointers are identical. + // Note: this method might return false for cases where FastEquals would return true. + // Only use if you know what you're doing. + // + internal bool FastEqualsUnreliable(EETypePtr other) + { + Debug.Assert(!this.IsNull); + Debug.Assert(!other.IsNull); + + return this.RawValue == other.RawValue; + } + // Caution: You cannot safely compare RawValue's as RH does NOT unify EETypes. Use the == or Equals() methods exposed by EETypePtr itself. internal IntPtr RawValue { diff --git a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index b77a41343..2c1c1dfda 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -219,6 +219,13 @@ namespace System.Runtime.CompilerServices return !pEEType.IsValueType || pEEType.HasPointers; } + [Intrinsic] + public static bool IsReference<T>() + { + var pEEType = EETypePtr.EETypePtrOf<T>(); + return !pEEType.IsValueType; + } + // Constrained Execution Regions APIs are NOP's because we do not support CERs in .NET Core at all. public static void ProbeForSufficientStack() { } public static void PrepareConstrainedRegions() { } diff --git a/src/System.Private.CoreLib/src/System/Threading/ClrThreadPool.HillClimbing.Complex.cs b/src/System.Private.CoreLib/src/System/Threading/ClrThreadPool.HillClimbing.Complex.cs new file mode 100644 index 000000000..7be30ed65 --- /dev/null +++ b/src/System.Private.CoreLib/src/System/Threading/ClrThreadPool.HillClimbing.Complex.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + +namespace System.Threading +{ + internal static partial class ClrThreadPool + { + + private partial class HillClimbing + { + private struct Complex + { + public Complex(double real, double imaginary) + { + Real = real; + Imaginary = imaginary; + } + + public double Imaginary { get; } + public double Real { get; } + + public static Complex operator*(double scalar, Complex complex) => new Complex(scalar * complex.Real, scalar * complex.Imaginary); + + public static Complex operator*(Complex complex, double scalar) => scalar * complex; + + public static Complex operator/(Complex complex, double scalar) => new Complex(complex.Real / scalar, complex.Imaginary / scalar); + + public static Complex operator-(Complex lhs, Complex rhs) => new Complex(lhs.Real - rhs.Real, lhs.Imaginary - rhs.Imaginary); + + public static Complex operator/(Complex lhs, Complex rhs) + { + double denom = rhs.Real * rhs.Real + rhs.Imaginary * rhs.Imaginary; + return new Complex((lhs.Real * rhs.Real + lhs.Imaginary * rhs.Imaginary) / denom, (-lhs.Real * rhs.Imaginary + lhs.Imaginary * rhs.Real) / denom); + } + + public double Abs() => Math.Sqrt(Real * Real + Imaginary * Imaginary); + } + } + } +} diff --git a/src/System.Private.CoreLib/src/System/Threading/ClrThreadPool.HillClimbing.cs b/src/System.Private.CoreLib/src/System/Threading/ClrThreadPool.HillClimbing.cs new file mode 100644 index 000000000..909a2fd72 --- /dev/null +++ b/src/System.Private.CoreLib/src/System/Threading/ClrThreadPool.HillClimbing.cs @@ -0,0 +1,388 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace System.Threading +{ + internal static partial class ClrThreadPool + { + // The Hill Climbing algorithm is described at http://mattwarren.org/2017/04/13/The-CLR-Thread-Pool-Thread-Injection-Algorithm/ + private partial class HillClimbing + { + // Config values pulled from CoreCLR + // TODO: Move to runtime configuration variables. + public static HillClimbing ThreadPoolHillClimber { get; } = new HillClimbing(4, 20, 100 / 100.0, 8, 15 / 100.0, 300 / 100.0, 4, 20, 10, 200, 1 / 100.0, 200 / 100.0, 15 / 100.0); + + public enum StateOrTransition + { + Warmup, + Initializing, + RandomMove, + ClimbingMove, + ChangePoint, + Stabilizing, + Starvation, + ThreadTimedOut, + } + + private readonly int _wavePeriod; + private readonly int _samplesToMeasure; + private readonly double _targetThroughputRatio; + private readonly double _targetSignalToNoiseRatio; + private readonly double _maxChangePerSecond; + private readonly double _maxChangePerSample; + private readonly int _maxThreadWaveMagnitude; + private readonly int _sampleIntervalLow; + private readonly double _threadMagnitudeMultiplier; + private readonly int _sampleIntervalHigh; + private readonly double _throughputErrorSmoothingFactor; + private readonly double _gainExponent; + private readonly double _maxSampleError; + + private double _currentControlSetting; + private int _totalSamples; + private int _lastThreadCount; + private double _averageThroughputNoise; + private double _secondsElapsedSinceLastChange; + private double _completionsSinceLastChange; + private int _accumulatedCompletionCount; + private double _accumulatedSampleDurationSeconds; + private double[] _samples; + private double[] _threadCounts; + private int _currentSampleInterval; + + private Random _randomIntervalGenerator = new Random(); + + public HillClimbing(int wavePeriod, int maxWaveMagnitude, double waveMagnitudeMultiplier, int waveHistorySize, double targetThroughputRatio, + double targetSignalToNoiseRatio, double maxChangePerSecond, double maxChangePerSample, int sampleIntervalLow, int sampleIntervalHigh, + double errorSmoothingFactor, double gainExponent, double maxSampleError) + { + _wavePeriod = wavePeriod; + _maxThreadWaveMagnitude = maxWaveMagnitude; + _threadMagnitudeMultiplier = waveMagnitudeMultiplier; + _samplesToMeasure = wavePeriod * waveHistorySize; + _targetThroughputRatio = targetThroughputRatio; + _targetSignalToNoiseRatio = targetSignalToNoiseRatio; + _maxChangePerSecond = maxChangePerSecond; + _maxChangePerSample = maxChangePerSample; + _sampleIntervalLow = sampleIntervalLow; + _sampleIntervalHigh = sampleIntervalHigh; + _throughputErrorSmoothingFactor = errorSmoothingFactor; + _gainExponent = gainExponent; + _maxSampleError = maxSampleError; + + _samples = new double[_samplesToMeasure]; + _threadCounts = new double[_samplesToMeasure]; + + _currentSampleInterval = _randomIntervalGenerator.Next(_sampleIntervalLow, _sampleIntervalHigh + 1); + } + + public (int newThreadCount, int newSampleInterval) Update(int currentThreadCount, double sampleDurationSeconds, int numCompletions) + { + + // + // If someone changed the thread count without telling us, update our records accordingly. + // + if (currentThreadCount != _lastThreadCount) + ForceChange(currentThreadCount, StateOrTransition.Initializing); + + // + // Update the cumulative stats for this thread count + // + _secondsElapsedSinceLastChange += sampleDurationSeconds; + _completionsSinceLastChange += numCompletions; + + // + // Add in any data we've already collected about this sample + // + sampleDurationSeconds += _accumulatedSampleDurationSeconds; + numCompletions += _accumulatedCompletionCount; + + // + // We need to make sure we're collecting reasonably accurate data. Since we're just counting the end + // of each work item, we are goinng to be missing some data about what really happened during the + // sample interval. The count produced by each thread includes an initial work item that may have + // started well before the start of the interval, and each thread may have been running some new + // work item for some time before the end of the interval, which did not yet get counted. So + // our count is going to be off by +/- threadCount workitems. + // + // The exception is that the thread that reported to us last time definitely wasn't running any work + // at that time, and the thread that's reporting now definitely isn't running a work item now. So + // we really only need to consider threadCount-1 threads. + // + // Thus the percent error in our count is +/- (threadCount-1)/numCompletions. + // + // We cannot rely on the frequency-domain analysis we'll be doing later to filter out this error, because + // of the way it accumulates over time. If this sample is off by, say, 33% in the negative direction, + // then the next one likely will be too. The one after that will include the sum of the completions + // we missed in the previous samples, and so will be 33% positive. So every three samples we'll have + // two "low" samples and one "high" sample. This will appear as periodic variation right in the frequency + // range we're targeting, which will not be filtered by the frequency-domain translation. + // + if (_totalSamples > 0 && ((currentThreadCount - 1.0) / numCompletions) >= _maxSampleError) + { + // not accurate enough yet. Let's accumulate the data so far, and tell the ThreadPool + // to collect a little more. + _accumulatedSampleDurationSeconds = sampleDurationSeconds; + _accumulatedCompletionCount = numCompletions; + return (currentThreadCount, 10); + } + + // + // We've got enouugh data for our sample; reset our accumulators for next time. + // + _accumulatedSampleDurationSeconds = 0; + _accumulatedCompletionCount = 0; + + // + // Add the current thread count and throughput sample to our history + // + double throughput = numCompletions / sampleDurationSeconds; + // TODO: Event: Worker Thread Adjustment Sample + + int sampleIndex = _totalSamples % _samplesToMeasure; + _samples[sampleIndex] = throughput; + _threadCounts[sampleIndex] = currentThreadCount; + _totalSamples++; + + // + // Set up defaults for our metrics + // + Complex threadWaveComponent = default(Complex); + Complex throughputWaveComponent = default(Complex); + double throughputErrorEstimate = 0; + Complex ratio = default(Complex); + double confidence = 0; + + StateOrTransition state = StateOrTransition.Warmup; + + // + // How many samples will we use? It must be at least the three wave periods we're looking for, and it must also be a whole + // multiple of the primary wave's period; otherwise the frequency we're looking for will fall between two frequency bands + // in the Fourier analysis, and we won't be able to measure it accurately. + // + int sampleCount = Math.Min(_totalSamples - 1, _samplesToMeasure) / _wavePeriod * _wavePeriod; + + if (sampleCount > _wavePeriod) + { + // + // Average the throughput and thread count samples, so we can scale the wave magnitudes later. + // + double sampleSum = 0; + double threadSum = 0; + for (int i = 0; i < sampleCount; i++) + { + sampleSum += _samples[(_totalSamples - sampleCount + i) % _samplesToMeasure]; + threadSum += _threadCounts[(_totalSamples - sampleCount + i) % _samplesToMeasure]; + } + double averageThroughput = sampleSum / sampleCount; + double averageThreadCount = threadSum / sampleCount; + + if (averageThroughput > 0 && averageThreadCount > 0) + { + // + // Calculate the periods of the adjacent frequency bands we'll be using to measure noise levels. + // We want the two adjacent Fourier frequency bands. + // + double adjacentPeriod1 = sampleCount / (((double)sampleCount / _wavePeriod) + 1); + double adjacentPeriod2 = sampleCount / (((double)sampleCount / _wavePeriod) - 1); + + // + // Get the the three different frequency components of the throughput (scaled by average + // throughput). Our "error" estimate (the amount of noise that might be present in the + // frequency band we're really interested in) is the average of the adjacent bands. + // + throughputWaveComponent = GetWaveComponent(_samples, sampleCount, _wavePeriod) / averageThroughput; + throughputErrorEstimate = (GetWaveComponent(_samples, sampleCount, adjacentPeriod1) / averageThroughput).Abs(); + if (adjacentPeriod2 <= sampleCount) + { + throughputErrorEstimate = Math.Max(throughputErrorEstimate, (GetWaveComponent(_samples, sampleCount, adjacentPeriod2) / averageThroughput).Abs()); + } + + // + // Do the same for the thread counts, so we have something to compare to. We don't measure thread count + // noise, because there is none; these are exact measurements. + // + threadWaveComponent = GetWaveComponent(_threadCounts, sampleCount, _wavePeriod) / averageThreadCount; + + // + // Update our moving average of the throughput noise. We'll use this later as feedback to + // determine the new size of the thread wave. + // + if (_averageThroughputNoise == 0) + _averageThroughputNoise = throughputErrorEstimate; + else + _averageThroughputNoise = (_throughputErrorSmoothingFactor * throughputErrorEstimate) + ((1.0 - _throughputErrorSmoothingFactor) * _averageThroughputNoise); + + if (threadWaveComponent.Abs() > 0) + { + // + // Adjust the throughput wave so it's centered around the target wave, and then calculate the adjusted throughput/thread ratio. + // + ratio = (throughputWaveComponent - (_targetThroughputRatio * threadWaveComponent)) / threadWaveComponent; + state = StateOrTransition.ClimbingMove; + } + else + { + ratio = new Complex(0, 0); + state = StateOrTransition.Stabilizing; + } + + // + // Calculate how confident we are in the ratio. More noise == less confident. This has + // the effect of slowing down movements that might be affected by random noise. + // + double noiseForConfidence = Math.Max(_averageThroughputNoise, throughputErrorEstimate); + if (noiseForConfidence > 0) + confidence = (threadWaveComponent.Abs() / noiseForConfidence) / _targetSignalToNoiseRatio; + else + confidence = 1.0; //there is no noise! + + } + } + + // + // We use just the real part of the complex ratio we just calculated. If the throughput signal + // is exactly in phase with the thread signal, this will be the same as taking the magnitude of + // the complex move and moving that far up. If they're 180 degrees out of phase, we'll move + // backward (because this indicates that our changes are having the opposite of the intended effect). + // If they're 90 degrees out of phase, we won't move at all, because we can't tell wether we're + // having a negative or positive effect on throughput. + // + double move = Math.Min(1.0, Math.Max(-1.0, ratio.Real)); + + // + // Apply our confidence multiplier. + // + move *= Math.Min(1.0, Math.Max(0.0, confidence)); + + // + // Now apply non-linear gain, such that values around zero are attenuated, while higher values + // are enhanced. This allows us to move quickly if we're far away from the target, but more slowly + // if we're getting close, giving us rapid ramp-up without wild oscillations around the target. + // + double gain = _maxChangePerSecond * sampleDurationSeconds; + move = Math.Pow(Math.Abs(move), _gainExponent) * (move >= 0.0 ? 1 : -1) * gain; + move = Math.Min(move, _maxChangePerSample); + + // + // If the result was positive, and CPU is > 95%, refuse the move. + // + if (move > 0.0 && s_cpuUtilization > CpuUtilizationHigh) + move = 0.0; + + // + // Apply the move to our control setting + // + _currentControlSetting += move; + + // + // Calculate the new thread wave magnitude, which is based on the moving average we've been keeping of + // the throughput error. This average starts at zero, so we'll start with a nice safe little wave at first. + // + int newThreadWaveMagnitude = (int)(0.5 + (_currentControlSetting * _averageThroughputNoise * _targetSignalToNoiseRatio * _threadMagnitudeMultiplier * 2.0)); + newThreadWaveMagnitude = Math.Min(newThreadWaveMagnitude, _maxThreadWaveMagnitude); + newThreadWaveMagnitude = Math.Max(newThreadWaveMagnitude, 1); + + // + // Make sure our control setting is within the ThreadPool's limits + // + int maxThreads = s_maxThreads; + int minThreads = s_minThreads; + + _currentControlSetting = Math.Min(maxThreads - newThreadWaveMagnitude, _currentControlSetting); + _currentControlSetting = Math.Max(minThreads, _currentControlSetting); + + // + // Calculate the new thread count (control setting + square wave) + // + int newThreadCount = (int)(_currentControlSetting + newThreadWaveMagnitude * ((_totalSamples / (_wavePeriod / 2)) % 2)); + + // + // Make sure the new thread count doesn't exceed the ThreadPool's limits + // + newThreadCount = Math.Min(maxThreads, newThreadCount); + newThreadCount = Math.Max(minThreads, newThreadCount); + + // + // Record these numbers for posterity + // + + // TODO: Event: Worker Thread Adjustment stats + + + // + // If all of this caused an actual change in thread count, log that as well. + // + if (newThreadCount != currentThreadCount) + ChangeThreadCount(newThreadCount, state); + + // + // Return the new thread count and sample interval. This is randomized to prevent correlations with other periodic + // changes in throughput. Among other things, this prevents us from getting confused by Hill Climbing instances + // running in other processes. + // + // If we're at minThreads, and we seem to be hurting performance by going higher, we can't go any lower to fix this. So + // we'll simply stay at minThreads much longer, and only occasionally try a higher value. + // + int newSampleInterval; + if (ratio.Real < 0.0 && newThreadCount == minThreads) + newSampleInterval = (int)(0.5 + _currentSampleInterval * (10.0 * Math.Max(-ratio.Real, 1.0))); + else + newSampleInterval = _currentSampleInterval; + + return (newThreadCount, newSampleInterval); + } + + private void ChangeThreadCount(int newThreadCount, StateOrTransition state) + { + _lastThreadCount = newThreadCount; + _currentSampleInterval = _randomIntervalGenerator.Next(_sampleIntervalLow, _sampleIntervalHigh + 1); + double throughput = _secondsElapsedSinceLastChange > 0 ? _completionsSinceLastChange / _secondsElapsedSinceLastChange : 0; + LogTransition(newThreadCount, throughput, state); + _secondsElapsedSinceLastChange = 0; + _completionsSinceLastChange = 0; + } + + private void LogTransition(int newThreadCount, double throughput, StateOrTransition state) + { + // TODO: Log transitions + } + + public void ForceChange(int newThreadCount, StateOrTransition state) + { + if(_lastThreadCount != newThreadCount) + { + _currentControlSetting += newThreadCount - _lastThreadCount; + ChangeThreadCount(newThreadCount, state); + } + } + + private Complex GetWaveComponent(double[] samples, int numSamples, double period) + { + Debug.Assert(numSamples >= period); // can't measure a wave that doesn't fit + Debug.Assert(period >= 2); // can't measure above the Nyquist frequency + Debug.Assert(numSamples <= samples.Length); // can't measure more samples than we have + + // + // Calculate the sinusoid with the given period. + // We're using the Goertzel algorithm for this. See http://en.wikipedia.org/wiki/Goertzel_algorithm. + // + + double w = 2 * Math.PI / period; + double cos = Math.Cos(w); + double coeff = 2 * cos; + double q0 = 0, q1 = 0, q2 = 0; + for(int i = 0; i < numSamples; ++i) + { + q0 = coeff * q1 - q2 + samples[(_totalSamples - numSamples + i) % _samplesToMeasure]; + q2 = q1; + q1 = q0; + } + return new Complex(q1 - q2 * cos, q2 * Math.Sin(w)) / numSamples; + } + } + } +} diff --git a/src/System.Private.CoreLib/src/System/Threading/ClrThreadPool.cs b/src/System.Private.CoreLib/src/System/Threading/ClrThreadPool.cs new file mode 100644 index 000000000..0e56931ae --- /dev/null +++ b/src/System.Private.CoreLib/src/System/Threading/ClrThreadPool.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Threading +{ + internal static partial class ClrThreadPool + { + private const int CpuUtilizationHigh = 95; + private const int CpuUtilizationLow = 80; + private static int s_cpuUtilization = 85; // TODO: Add calculation for CPU utilization + + private static int s_minThreads; // TODO: Initialize + private static int s_maxThreads; // TODO: Initialize + + // TODO: SetMinThreads and SetMaxThreads need to be synchronized with a lock + // TODO: Compare with CoreCLR implementation and ensure this has the same guarantees. + public static bool SetMinThreads(int threads) + { + if (threads < 0 || threads > s_maxThreads) + { + return false; + } + else + { + s_minThreads = threads; + return true; + } + } + + public static int GetMinThreads() => s_minThreads; + + public static bool SetMaxThreads(int threads) + { + if (threads < s_minThreads || threads == 0) + { + return false; + } + else + { + s_maxThreads = threads; + return true; + } + } + + public static int GetMaxThreads() => s_maxThreads; + } +} diff --git a/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/Callbacks.CoreRT.cs b/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/Callbacks.CoreRT.cs deleted file mode 100644 index 9e30dffc7..000000000 --- a/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/Callbacks.CoreRT.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using Internal.Runtime.Augments; -using Internal.NativeFormat; -using Internal.Runtime.TypeLoader; -using Internal.Reflection.Execution; -using System.Runtime.InteropServices; - -namespace Internal.Runtime.CompilerHelpers -{ - internal class Callbacks : InteropCallbacks - { - public override bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData data) - { - IntPtr openStub, closedStub, delegateCreationStub; - if (!TryGetMarshallersForDelegate(delegateTypeHandle, out openStub, out closedStub, out delegateCreationStub)) - { - data = default(McgPInvokeDelegateData); - return false; - } - - data = new global::System.Runtime.InteropServices.McgPInvokeDelegateData() - { - ReverseOpenStaticDelegateStub = openStub, - ReverseStub = closedStub, - ForwardDelegateCreationStub = delegateCreationStub - }; - return true; - } - - private static unsafe bool TryGetNativeReaderForBlob(NativeFormatModuleInfo module, ReflectionMapBlob blob, out NativeReader reader) - { - byte* pBlob; - uint cbBlob; - - if (module.TryFindBlob((int)blob, out pBlob, out cbBlob)) - { - reader = new NativeReader(pBlob, cbBlob); - return true; - } - - reader = default(NativeReader); - return false; - } - - private unsafe bool TryGetMarshallersForDelegate(RuntimeTypeHandle delegateTypeHandle, out IntPtr openStub, out IntPtr closedStub, out IntPtr delegateCreationStub) - { - int delegateHashcode = delegateTypeHandle.GetHashCode(); - openStub = IntPtr.Zero; - closedStub = IntPtr.Zero; - delegateCreationStub = IntPtr.Zero; - - foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules()) - { - NativeReader delegateMapReader; - if (TryGetNativeReaderForBlob(module, ReflectionMapBlob.DelegateMarshallingStubMap, out delegateMapReader)) - { - NativeParser delegateMapParser = new NativeParser(delegateMapReader, 0); - NativeHashtable delegateHashtable = new NativeHashtable(delegateMapParser); - - ExternalReferencesTable externalReferences = default(ExternalReferencesTable); - externalReferences.InitializeCommonFixupsTable(module); - - var lookup = delegateHashtable.Lookup(delegateHashcode); - NativeParser entryParser; - while (!(entryParser = lookup.GetNext()).IsNull) - { - RuntimeTypeHandle foundDelegateType = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); - if (foundDelegateType.Equals(delegateTypeHandle)) - { - byte* pOpen = (byte*)externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned()); - byte* pClose = (byte*)externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned()); - byte* pDelegateCreation = (byte*)externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned()); - openStub = (IntPtr)pOpen; - closedStub = (IntPtr)pClose; - delegateCreationStub = (IntPtr)pDelegateCreation; - return true; - } - } - } - } - - return false; - } - - } - -} diff --git a/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/LibraryInitializer.cs b/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/LibraryInitializer.cs index 0b85c75cf..95ea711f0 100644 --- a/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/LibraryInitializer.cs +++ b/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/LibraryInitializer.cs @@ -22,7 +22,7 @@ namespace Internal.Runtime.CompilerHelpers __vtable_IUnknown.Initialize(); McgModuleManager.Initialize(); #endif - RuntimeAugments.InitializeInteropLookups(new Callbacks()); + RuntimeAugments.InitializeInteropLookups(RuntimeInteropData.Instance); } } } diff --git a/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.CoreRT.cs b/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.CoreRT.cs new file mode 100644 index 000000000..4de8b4603 --- /dev/null +++ b/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.CoreRT.cs @@ -0,0 +1,203 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Internal.Runtime.Augments; +using Internal.NativeFormat; +using Internal.Runtime.TypeLoader; +using Internal.Reflection.Execution; +using System.Runtime.InteropServices; + +namespace Internal.Runtime.CompilerHelpers +{ + internal partial class RuntimeInteropData + { + public override bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData data) + { + IntPtr openStub, closedStub, delegateCreationStub; + if (!TryGetMarshallersForDelegate(delegateTypeHandle, out openStub, out closedStub, out delegateCreationStub)) + { + data = default(McgPInvokeDelegateData); + return false; + } + + data = new global::System.Runtime.InteropServices.McgPInvokeDelegateData() + { + ReverseOpenStaticDelegateStub = openStub, + ReverseStub = closedStub, + ForwardDelegateCreationStub = delegateCreationStub + }; + return true; + } + #region "Struct Data" + public override bool TryGetStructUnmarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr unmarshalStub) + { + IntPtr marshalStub; + IntPtr destroyStub; + bool hasInvalidLayout; + int size; + return TryGetMarshallersForStruct(structureTypeHandle, out marshalStub, out unmarshalStub, out destroyStub, out hasInvalidLayout, out size); + } + + public override bool TryGetStructMarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr marshalStub) + { + IntPtr unmarshalStub; + IntPtr destroyStub; + bool hasInvalidLayout; + int size; + return TryGetMarshallersForStruct(structureTypeHandle, out marshalStub, out unmarshalStub, out destroyStub, out hasInvalidLayout, out size); + } + + public override bool TryGetDestroyStructureStub(RuntimeTypeHandle structureTypeHandle, out IntPtr destroyStub, out bool hasInvalidLayout) + { + IntPtr marshalStub; + IntPtr unmarshalStub; + int size; + return TryGetMarshallersForStruct(structureTypeHandle, out marshalStub, out unmarshalStub, out destroyStub, out hasInvalidLayout, out size); + } + + public override bool TryGetStructUnsafeStructSize(RuntimeTypeHandle structureTypeHandle, out int size) + { + IntPtr marshalStub; + IntPtr unmarshalStub; + IntPtr destroyStub; + bool hasInvalidLayout; + return TryGetMarshallersForStruct(structureTypeHandle, out marshalStub, out unmarshalStub, out destroyStub, out hasInvalidLayout, out size); + } + + public override bool TryGetStructFieldOffset(RuntimeTypeHandle structureTypeHandle, string fieldName, out bool structExists, out uint offset) + { + ExternalReferencesTable externalReferences; + NativeParser entryParser; + structExists = false; + if (TryGetStructData(structureTypeHandle, out externalReferences, out entryParser)) + { + structExists = true; + // skip the first 4 IntPtrs(3 stubs and size) + entryParser.SkipInteger(); + entryParser.SkipInteger(); + entryParser.SkipInteger(); + entryParser.SkipInteger(); + + uint mask = entryParser.GetUnsigned(); + uint fieldCount = mask >> 1; + for (uint index = 0; index < fieldCount; index++) + { + string name = entryParser.GetString(); + offset = entryParser.GetUnsigned(); + if (name == fieldName) + { + return true; + } + } + } + offset = 0; + return false; + } + #endregion + + private static unsafe bool TryGetNativeReaderForBlob(NativeFormatModuleInfo module, ReflectionMapBlob blob, out NativeReader reader) + { + byte* pBlob; + uint cbBlob; + + if (module.TryFindBlob((int)blob, out pBlob, out cbBlob)) + { + reader = new NativeReader(pBlob, cbBlob); + return true; + } + + reader = default(NativeReader); + return false; + } + + private unsafe bool TryGetMarshallersForDelegate(RuntimeTypeHandle delegateTypeHandle, out IntPtr openStub, out IntPtr closedStub, out IntPtr delegateCreationStub) + { + int delegateHashcode = delegateTypeHandle.GetHashCode(); + openStub = IntPtr.Zero; + closedStub = IntPtr.Zero; + delegateCreationStub = IntPtr.Zero; + + foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules()) + { + NativeReader delegateMapReader; + if (TryGetNativeReaderForBlob(module, ReflectionMapBlob.DelegateMarshallingStubMap, out delegateMapReader)) + { + NativeParser delegateMapParser = new NativeParser(delegateMapReader, 0); + NativeHashtable delegateHashtable = new NativeHashtable(delegateMapParser); + + ExternalReferencesTable externalReferences = default(ExternalReferencesTable); + externalReferences.InitializeCommonFixupsTable(module); + + var lookup = delegateHashtable.Lookup(delegateHashcode); + NativeParser entryParser; + while (!(entryParser = lookup.GetNext()).IsNull) + { + RuntimeTypeHandle foundDelegateType = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); + if (foundDelegateType.Equals(delegateTypeHandle)) + { + openStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned()); + closedStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned()); + delegateCreationStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned()); + return true; + } + } + } + } + return false; + } + + private unsafe bool TryGetStructData(RuntimeTypeHandle structTypeHandle, out ExternalReferencesTable externalReferences, out NativeParser entryParser) + { + int structHashcode = structTypeHandle.GetHashCode(); + externalReferences = default(ExternalReferencesTable); + entryParser = default(NativeParser); + foreach (NativeFormatModuleInfo module in ModuleList.EnumerateModules()) + { + NativeReader structMapReader; + if (TryGetNativeReaderForBlob(module, ReflectionMapBlob.StructMarshallingStubMap, out structMapReader)) + { + NativeParser structMapParser = new NativeParser(structMapReader, 0); + NativeHashtable structHashtable = new NativeHashtable(structMapParser); + + externalReferences.InitializeCommonFixupsTable(module); + + var lookup = structHashtable.Lookup(structHashcode); + while (!(entryParser = lookup.GetNext()).IsNull) + { + RuntimeTypeHandle foundStructType = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); + if (foundStructType.Equals(structTypeHandle)) + { + return true; + } + } + } + } + return false; + } + + private unsafe bool TryGetMarshallersForStruct(RuntimeTypeHandle structTypeHandle, out IntPtr marshalStub, out IntPtr unmarshalStub, out IntPtr destroyStub, out bool hasInvalidLayout, out int size) + { + marshalStub = IntPtr.Zero; + unmarshalStub = IntPtr.Zero; + destroyStub = IntPtr.Zero; + hasInvalidLayout = true; + size = 0; + + ExternalReferencesTable externalReferences; + NativeParser entryParser; + if (TryGetStructData(structTypeHandle, out externalReferences, out entryParser)) + { + marshalStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned()); + unmarshalStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned()); + destroyStub = externalReferences.GetIntPtrFromIndex(entryParser.GetUnsigned()); + size = (int)entryParser.GetUnsigned(); + uint mask = entryParser.GetUnsigned(); + hasInvalidLayout = (mask & 0x1) == 1; + return true; + } + return false; + } + } +} diff --git a/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.ProjectN.cs b/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.ProjectN.cs new file mode 100644 index 000000000..84678d1b9 --- /dev/null +++ b/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.ProjectN.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + +using System; +using Internal.Runtime.Augments; +using Internal.NativeFormat; +using Internal.Runtime.TypeLoader; +using Internal.Reflection.Execution; +using System.Runtime.InteropServices; + +namespace Internal.Runtime.CompilerHelpers +{ + internal partial class RuntimeInteropData : InteropCallbacks + { + public override bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData data) + { + return McgModuleManager.GetPInvokeDelegateData(delegateTypeHandle, out data); + } + + #region "Struct Data" + public override bool TryGetStructUnmarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr unmarshalStub) + { + return McgModuleManager.TryGetStructUnmarshalStub(structureTypeHandle, out unmarshalStub); + } + + public override bool TryGetStructMarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr marshalStub) + { + return McgModuleManager.TryGetStructMarshalStub(structureTypeHandle, out marshalStub); + } + + public override bool TryGetDestroyStructureStub(RuntimeTypeHandle structureTypeHandle, out IntPtr destroyStructureStub, out bool hasInvalidLayout) + { + return McgModuleManager.TryGetDestroyStructureStub(structureTypeHandle, out destroyStructureStub, out hasInvalidLayout); + } + + public override bool TryGetStructFieldOffset(RuntimeTypeHandle structureTypeHandle, string fieldName, out bool structExists, out uint offset) + { + return McgModuleManager.TryGetStructFieldOffset(structureTypeHandle, fieldName, out structExists, out offset); + } + + public override bool TryGetStructUnsafeStructSize(RuntimeTypeHandle structureTypeHandle, out int size) + { + RuntimeTypeHandle unsafeStructType; + size = 0; + if (McgModuleManager.TryGetStructUnsafeStructType(structureTypeHandle, out unsafeStructType)) + { + size = unsafeStructType.GetValueTypeSize(); + return true; + } + return false; + } + #endregion + } +} diff --git a/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/Callbacks.ProjectN.cs b/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.cs index 9705cba33..4daf4ad66 100644 --- a/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/Callbacks.ProjectN.cs +++ b/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.cs @@ -12,11 +12,19 @@ using System.Runtime.InteropServices; namespace Internal.Runtime.CompilerHelpers { - internal class Callbacks : InteropCallbacks + internal partial class RuntimeInteropData : InteropCallbacks { - public override bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData data) + private static RuntimeInteropData s_interopData; + public static RuntimeInteropData Instance { - return McgModuleManager.GetPInvokeDelegateData(delegateTypeHandle, out data); + get + { + if (s_interopData == null) + { + s_interopData = new RuntimeInteropData(); + } + return s_interopData; + } } } } diff --git a/src/System.Private.Interop/src/System.Private.Interop.csproj b/src/System.Private.Interop/src/System.Private.Interop.csproj index aa08ccddc..ec92627fa 100644 --- a/src/System.Private.Interop/src/System.Private.Interop.csproj +++ b/src/System.Private.Interop/src/System.Private.Interop.csproj @@ -139,8 +139,9 @@ <Compile Include="System\Runtime\InteropServices\WindowsRuntime\EventRegistrationToken.cs" /> <Compile Include="Internal\Runtime\CompilerHelpers\LibraryInitializer.cs" /> <Compile Include="Interop\Interop.Memory.cs" /> - <Compile Condition="'$(IsProjectNLibrary)' == 'true'" Include="Internal\Runtime\CompilerHelpers\Callbacks.ProjectN.cs"/> - <Compile Condition="'$(IsProjectNLibrary)' != 'true'" Include="Internal\Runtime\CompilerHelpers\Callbacks.CoreRT.cs"/> + <Compile Include="Internal\Runtime\CompilerHelpers\RuntimeInteropData.cs"/> + <Compile Condition="'$(IsProjectNLibrary)' == 'true'" Include="Internal\Runtime\CompilerHelpers\RuntimeInteropData.ProjectN.cs"/> + <Compile Condition="'$(IsProjectNLibrary)' != 'true'" Include="Internal\Runtime\CompilerHelpers\RuntimeInteropData.CoreRT.cs"/> </ItemGroup> <ItemGroup Condition="'$(IsProjectNLibrary)' != 'true'"> <Compile Include="..\..\Common\src\Internal\Runtime\MetadataBlob.cs"> diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs index 6f1489bac..71fbdead9 100644 --- a/src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs +++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs @@ -20,6 +20,7 @@ using System.Security; using System.Text; using System.Threading; using System.Runtime.InteropServices.ComTypes; +using Internal.Runtime.CompilerHelpers; namespace System.Runtime.InteropServices { @@ -177,10 +178,10 @@ namespace System.Runtime.InteropServices { RuntimeTypeHandle typeHandle = t.TypeHandle; - RuntimeTypeHandle unsafeStructType; - if (McgModuleManager.TryGetStructUnsafeStructType(typeHandle, out unsafeStructType)) + int size; + if (RuntimeInteropData.Instance.TryGetStructUnsafeStructSize(typeHandle, out size)) { - return unsafeStructType.GetValueTypeSize(); + return size; } if (!typeHandle.IsBlittable() && !typeHandle.IsValueType()) @@ -216,7 +217,7 @@ namespace System.Runtime.InteropServices { bool structExists; uint offset; - if (McgModuleManager.TryGetStructFieldOffset(t.TypeHandle, fieldName, out structExists, out offset)) + if (RuntimeInteropData.Instance.TryGetStructFieldOffset(t.TypeHandle, fieldName, out structExists, out offset)) { return new IntPtr(offset); } @@ -1096,7 +1097,7 @@ namespace System.Runtime.InteropServices } IntPtr unmarshalStub; - if (McgModuleManager.TryGetStructUnmarshalStub(structureTypeHandle, out unmarshalStub)) + if (RuntimeInteropData.Instance.TryGetStructUnmarshalStub(structureTypeHandle, out unmarshalStub)) { InteropExtensions.PinObjectAndCall(structure, unboxedStructPtr => @@ -1191,7 +1192,7 @@ namespace System.Runtime.InteropServices bool isBlittable = false; // whether Mcg treat this struct as blittable struct IntPtr marshalStub; - if (McgModuleManager.TryGetStructMarshalStub(structureTypeHandle, out marshalStub)) + if (RuntimeInteropData.Instance.TryGetStructMarshalStub(structureTypeHandle, out marshalStub)) { if (marshalStub != IntPtr.Zero) { @@ -1279,7 +1280,7 @@ namespace System.Runtime.InteropServices IntPtr destroyStructureStub; bool hasInvalidLayout; - if (McgModuleManager.TryGetDestroyStructureStub(structureTypeHandle, out destroyStructureStub, out hasInvalidLayout)) + if (RuntimeInteropData.Instance.TryGetDestroyStructureStub(structureTypeHandle, out destroyStructureStub, out hasInvalidLayout)) { if (hasInvalidLayout) throw new ArgumentException(SR.Argument_MustHaveLayoutOrBeBlittable, structureTypeHandle.GetDisplayName()); diff --git a/src/packaging/project.json b/src/packaging/objectwriter/project.json index b6098fb4b..beda765c3 100644 --- a/src/packaging/project.json +++ b/src/packaging/objectwriter/project.json @@ -1,6 +1,5 @@ { "dependencies": { - "Microsoft.NETCore.Jit": "2.1.0-preview1-25324-01", "Microsoft.DotNet.ObjectWriter": "1.0.18-prerelease-00002" }, "frameworks": { diff --git a/src/packaging/packages.targets b/src/packaging/packages.targets index 5ed71cd97..3695f21a9 100644 --- a/src/packaging/packages.targets +++ b/src/packaging/packages.targets @@ -26,8 +26,10 @@ <CoreFxNuPkgRid Condition="'$(OSGroup)'=='OSX'">osx-x64</CoreFxNuPkgRid> <CoreFxNuPkgRid Condition="'$(CoreFxNuPkgRid)'==''">$(NuPkgRid)</CoreFxNuPkgRid> - <JitPackageVersion>2.1.0-preview1-25324-01</JitPackageVersion> - <JitNuPkgRid Condition="'$(OSGroup)'=='OSX'">osx.10.12-x64</JitNuPkgRid> + <JitPackageVersion>2.1.0-preview1-25406-04</JitPackageVersion> + <JitNuPkgRid Condition="'$(OSGroup)'=='Windows_NT'">win-x64</JitNuPkgRid> + <JitNuPkgRid Condition="'$(OSGroup)'=='OSX'">osx-x64</JitNuPkgRid> + <JitNuPkgRid Condition="'$(OSGroup)'=='Linux'">linux-x64</JitNuPkgRid> <JitNuPkgRid Condition="'$(JitNuPkgRid)'==''">$(NuPkgRid)</JitNuPkgRid> <MicrosoftNetCoreNativePackageVersion>2.0.0-beta-25021-03</MicrosoftNetCoreNativePackageVersion> @@ -144,6 +146,7 @@ <ILCompilerAnyFrameworkFiles Include="System.IO.FileSystem.Primitives" /> <ILCompilerAnyFrameworkFiles Include="System.Linq" /> <ILCompilerAnyFrameworkFiles Include="System.Net.Primitives" /> + <ILCompilerAnyFrameworkFiles Include="System.Numerics.Vectors" /> <ILCompilerAnyFrameworkFiles Include="System.ObjectModel" /> <ILCompilerAnyFrameworkFiles Include="System.Private.Uri" /> <ILCompilerAnyFrameworkFiles Include="System.Reflection" /> diff --git a/src/packaging/ryujit/project.json b/src/packaging/ryujit/project.json new file mode 100644 index 000000000..fc003705f --- /dev/null +++ b/src/packaging/ryujit/project.json @@ -0,0 +1,13 @@ +{ + "dependencies": { + "Microsoft.NETCore.Jit": "2.1.0-preview1-25406-04" + }, + "frameworks": { + "netcoreapp2.0": { } + }, + "runtimes": { + "win-x64": { }, + "osx-x64": { }, + "linux-x64": { } + } +} diff --git a/tests/CoreCLR.issues.targets b/tests/CoreCLR.issues.targets index dbfc551f5..3cd0938fc 100644 --- a/tests/CoreCLR.issues.targets +++ b/tests/CoreCLR.issues.targets @@ -10,6 +10,7 @@ <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\NaN\intrinsic_cs_do\intrinsic_cs_do.*" /> <ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\intrinsic\pow\pow1\pow1.*" /> <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\NaN\intrinsic_cs_r\intrinsic_cs_r.*" /> + <ExcludeList Include="$(XunitTestBinBase)\GC\Scenarios\Samples\gc\gc.*" /> <!-- Infinite generic expansion --> <!-- https://github.com/dotnet/corert/issues/363 --> @@ -36,155 +37,10 @@ <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\VT\callconv\_il_dbgvtret\_il_dbgvtret.*" /> <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\VT\callconv\_il_relvtret\_il_relvtret.*" /> - <!-- CreateInstance<T> --> - <!-- https://github.com/dotnet/corert/issues/368 --> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\CheckedCtor\Generic_Test_CSharp_Base_6\Generic_Test_CSharp_Base_6.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\CheckedCtor\Generic_Test_CSharp_Peer_6\Generic_Test_CSharp_Peer_6.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\class1_cs_d\class1_cs_d.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\class1_cs_do\class1_cs_do.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\class1_cs_r\class1_cs_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\class1_cs_ro\class1_cs_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\class2_cs_d\class2_cs_d.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\class2_cs_do\class2_cs_do.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\class2_cs_r\class2_cs_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\class2_cs_ro\class2_cs_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\vt4_cs_d\vt4_cs_d.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\vt4_cs_do\vt4_cs_do.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\vt4_cs_r\vt4_cs_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Generics\ConstrainedCall\vt4_cs_ro\vt4_cs_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\generics\regressions\341477\Test\Test.*" /> - <ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\regressions\dev10_568786\4_Misc\SealedTypes\SealedTypes.*" /> - <!-- System.Reflection.Emit.Lightweight --> <!-- https://github.com/dotnet/corert/issues/370 --> <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\dynamic_methods\bug_445388\bug_445388.*" /> - <!-- SIMD --> - <!-- https://github.com/dotnet/corert/issues/370 --> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\AbsGeneric\AbsGeneric.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\AbsSqrt\AbsSqrt.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\AddingSequence\AddingSequence.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\BitwiseOperations\BitwiseOperations.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\BoxUnbox\BoxUnbox.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\BugWithAVX\BugWithAVX.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\CircleInConvex\CircleInConvex.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\CreateGeneric\CreateGeneric.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\CtorFromArray\CtorFromArray.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Ctors\Ctors.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\DivSignedUnsignedTest\DivSignedUnsignedTest.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Dup\Dup.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Haar-likeFeaturesGeneric\Haar-likeFeaturesGeneric.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Ldfld\Ldfld.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\LdfldGeneric\LdfldGeneric.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Ldind\Ldind.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\MinMax\MinMax.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Mul\Mul.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\SqrtGeneric\SqrtGeneric.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\StoreElement\StoreElement.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Sums\Sums.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Vector3\Vector3.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Vector4\Vector4.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\AbsGeneric_r\AbsGeneric_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\AbsGeneric_ro\AbsGeneric_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\AbsSqrt_r\AbsSqrt_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\AbsSqrt_ro\AbsSqrt_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\AddingSequence_r\AddingSequence_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\AddingSequence_ro\AddingSequence_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\BitwiseOperations_r\BitwiseOperations_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\BitwiseOperations_ro\BitwiseOperations_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\BoxUnbox_r\BoxUnbox_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\BoxUnbox_ro\BoxUnbox_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\BugWithAVX_r\BugWithAVX_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\BugWithAVX_ro\BugWithAVX_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\CircleInConvex_r\CircleInConvex_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\CircleInConvex_ro\CircleInConvex_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\CreateGeneric_r\CreateGeneric_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\CreateGeneric_ro\CreateGeneric_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\CtorFromArray_r\CtorFromArray_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\CtorFromArray_ro\CtorFromArray_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Ctors_r\Ctors_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Ctors_ro\Ctors_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\DivSignedUnsignedTest_r\DivSignedUnsignedTest_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\DivSignedUnsignedTest_ro\DivSignedUnsignedTest_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Dup_r\Dup_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Dup_ro\Dup_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Haar-likeFeaturesGeneric_r\Haar-likeFeaturesGeneric_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Haar-likeFeaturesGeneric_ro\Haar-likeFeaturesGeneric_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\LdfldGeneric_r\LdfldGeneric_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\LdfldGeneric_ro\LdfldGeneric_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Ldfld_r\Ldfld_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Ldfld_ro\Ldfld_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Ldind_r\Ldind_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Ldind_ro\Ldind_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\MinMax_r\MinMax_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\MinMax_ro\MinMax_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Mul_r\Mul_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Mul_ro\Mul_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\SqrtGeneric_r\SqrtGeneric_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\SqrtGeneric_ro\SqrtGeneric_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\StoreElement_r\StoreElement_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\StoreElement_ro\StoreElement_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Sums_r\Sums_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Sums_ro\Sums_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Vector3_r\Vector3_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Vector3_ro\Vector3_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Vector4_r\Vector4_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Vector4_ro\Vector4_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorAbs_r\VectorAbs_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorAbs_ro\VectorAbs_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorAdd_r\VectorAdd_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorAdd_ro\VectorAdd_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorArgs_r\VectorArgs_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorArgs_ro\VectorArgs_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorArrayInit_r\VectorArrayInit_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorArrayInit_ro\VectorArrayInit_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorArray_r\VectorArray_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorArray_ro\VectorArray_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorCopyToArray_r\VectorCopyToArray_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorCopyToArray_ro\VectorCopyToArray_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorDiv_r\VectorDiv_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorDiv_ro\VectorDiv_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorDot_r\VectorDot_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorDot_ro\VectorDot_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorExp_r\VectorExp_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorExp_ro\VectorExp_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorGet_r\VectorGet_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorGet_ro\VectorGet_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorHWAccel2_r\VectorHWAccel2_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorHWAccel2_ro\VectorHWAccel2_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorHWAccel_r\VectorHWAccel_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorHWAccel_ro\VectorHWAccel_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorInitN_r\VectorInitN_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorInitN_ro\VectorInitN_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorInit_r\VectorInit_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorInit_ro\VectorInit_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorIntEquals_r\VectorIntEquals_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorIntEquals_ro\VectorIntEquals_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorMatrix_r\VectorMatrix_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorMatrix_ro\VectorMatrix_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorMax_r\VectorMax_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorMax_ro\VectorMax_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorMin_r\VectorMin_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorMin_ro\VectorMin_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorMul_r\VectorMul_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorMul_ro\VectorMul_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorRelOp_r\VectorRelOp_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorRelOp_ro\VectorRelOp_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorReturn_r\VectorReturn_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorReturn_ro\VectorReturn_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorSet_r\VectorSet_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorSet_ro\VectorSet_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorSqrt_r\VectorSqrt_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorSqrt_ro\VectorSqrt_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorSub_r\VectorSub_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorSub_ro\VectorSub_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorUnused_r\VectorUnused_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\VectorUnused_ro\VectorUnused_ro.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\JitBlue\GitHub_6318\GitHub_6318\GitHub_6318.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\JitBlue\GitHub_7906\GitHub_7906\GitHub_7906.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Vector3Interop_r\Vector3Interop_r.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Vector3Interop_ro\Vector3Interop_ro.*" /> - <!-- Test has expectations about CoreRun and running on CoreCLR --> <ExcludeList Include="$(XunitTestBinBase)\Loader\NativeLibs\FromNativePaths\FromNativePaths.*" /> @@ -298,10 +154,6 @@ <!-- Reflection enabling a virtual method methodimpl'd by other virtual method --> <ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\methodoverriding\regressions\576621\VSW576621\VSW576621.*" /> - <!-- DynamicInvoke stub for a method with 8192 parameters --> - <!-- https://github.com/dotnet/corert/issues/2349 --> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\CLR-x86-JIT\V1.2-Beta1\b191926\b191926\b191926.*" /> - <!-- Bogus MethodImpls --> <!-- https://github.com/dotnet/corert/issues/2350 --> <ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\MethodImpl\self_override3\self_override3.*" /> @@ -439,6 +291,8 @@ <ExcludeList Include="$(XunitTestBinBase)\GC\Scenarios\Dynamo\dynamo\dynamo.*" /> <ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\CLR-x86-JIT\V1-M09\b16294\b16294\b16294.*" /> <ExcludeList Include="$(XunitTestBinBase)\Regressions\common\AboveStackLimit\AboveStackLimit.*" /> + <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Vector3Interop_r\Vector3Interop_r.*" /> + <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\Vector3Interop_ro\Vector3Interop_ro.*" /> <!-- System.Diagnostics.Process --> <ExcludeList Include="$(XunitTestBinBase)\GC\API\GC\Collect_Default_1\Collect_Default_1.*" /> @@ -568,6 +422,7 @@ <ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\TSAmbiguities\CollapsedMethods\InterfaceImplementation\HelloWorld\HelloWorld.*" /> <ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\TSAmbiguities\CollapsedMethods\Override\HelloWorld\HelloWorld.*" /> <ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\regressions\dev10_568786\4_Misc\Variance2\Variance2.*" /> + <ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\regressions\dev10_568786\4_Misc\SealedTypes\SealedTypes.*" /> <!-- Marshal.GetExceptionForHR not setting HResult --> <!-- https://github.com/dotnet/corert/issues/2256 --> @@ -599,10 +454,6 @@ <!-- https://github.com/dotnet/corert/issues/2272 --> <ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\coverage\oldtests\callipinvoke\callipinvoke.*" /> - <!-- Newarr void --> - <!-- https://github.com/dotnet/corert/issues/2280 --> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\CLR-x86-JIT\V2.0-Beta2\b353858\b353858\b353858.*" /> - <!-- Bad check for Explicit/Sequential layout --> <!-- https://github.com/dotnet/corert/issues/2281 --> <ExcludeList Include="$(XunitTestBinBase)\Loader\classloader\generics\Layout\General\Base01d_seq_ser\Base01d_seq_ser.*" /> @@ -723,17 +574,6 @@ <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\Arrays\misc\_speed_dbgarrres\_speed_dbgarrres.*" /> <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\Arrays\misc\_relarrres\_relarrres.*" /> - <!-- Tests that fail after RyuJIT update --> - <!-- https://github.com/dotnet/corert/issues/2782 --> - <ExcludeList Include="$(XunitTestBinBase)\GC\Scenarios\DoublinkList\doublinkstay\doublinkstay.*" /> - <ExcludeList Include="$(XunitTestBinBase)\GC\Scenarios\DoublinkList\doublinkgen\doublinkgen.*" /> - <ExcludeList Include="$(XunitTestBinBase)\GC\Scenarios\FinalNStruct\nstructresur\nstructresur.*" /> - <ExcludeList Include="$(XunitTestBinBase)\GC\Scenarios\NDPin\ndpinfinal\ndpinfinal.*" /> - <ExcludeList Include="$(XunitTestBinBase)\JIT\Directed\pinning\object-pin\object-pin\object-pin.*" /> - - <!-- More failing GC tests --> - <ExcludeList Include="$(XunitTestBinBase)\GC\Scenarios\Samples\gc\gc.*" /> - <!-- Variant interface method resolution --> <!-- https://github.com/dotnet/corert/issues/2358 --> <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\inlining\dev10_bug719093\variancesmall\variancesmall.*" /> @@ -809,6 +649,8 @@ <ExcludeList Include="$(XunitTestBinBase)\JIT\Methodical\fp\apps\bouncingball_cs_d\bouncingball_cs_d.*" /> <ExcludeList Include="$(XunitTestBinBase)\JIT\opt\perf\doublealign\Locals\Locals.*" /> <ExcludeList Include="$(XunitTestBinBase)\JIT\Regression\CLR-x86-JIT\V1.2-M02\b00719\b00719\b00719.*" /> + <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\BitwiseOperations_r\BitwiseOperations_r.*" /> + <ExcludeList Include="$(XunitTestBinBase)\JIT\SIMD\BitwiseOperations_ro\BitwiseOperations_ro.*" /> <!-- Crossgen tests, not runtime tests --> <ExcludeList Include="$(XunitTestBinBase)\readytorun\genericsload\callgenericctor\callgenericctor.*" /> diff --git a/tests/runtest.sh b/tests/runtest.sh index 94942284d..b315747d5 100755 --- a/tests/runtest.sh +++ b/tests/runtest.sh @@ -267,10 +267,10 @@ if [ ${CoreRT_CrossBuild} != 0 ]; then source $ROOTFS_DIR/etc/os-release fi if [ "$ID" = "tizen" ]; then - CoreRT_CrossCXXFlags="${CoreRT_CrossCXXFlags} -isystem ${CoreRT_CrossRootFS}/usr/lib/gcc/armv7l-tizen-linux-gnueabi/4.9.2/include/c++ ` - `-isystem ${CoreRT_CrossRootFS}//usr/lib/gcc/armv7l-tizen-linux-gnueabi/4.9.2/include/c++/armv7l-tizen-linux-gnueabi ` + TIZEN_TOOLCHAIN="armv7l-tizen-linux-gnueabi/6.2.1" + CoreRT_CrossCXXFlags="${CoreRT_CrossCXXFlags} -isystem ${CoreRT_CrossRootFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}/include/c++ ` + `-isystem ${CoreRT_CrossRootFS}//usr/lib/gcc/${TIZEN_TOOLCHAIN}/include/c++/armv7l-tizen-linux-gnueabi ` `-isystem ${CoreRT_CrossRootFS}/armel/usr/include" - TIZEN_TOOLCHAIN="armv7l-tizen-linux-gnueabi/4.9.2" CoreRT_CrossLinkerFlags="${CoreRT_CrossLinkerFlags} -B${CoreRT_CrossRootFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN} ` `-L${CoreRT_CrossRootFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}" else diff --git a/tests/src/Simple/Generics/Generics.cs b/tests/src/Simple/Generics/Generics.cs index f0b05e60f..213400efe 100644 --- a/tests/src/Simple/Generics/Generics.cs +++ b/tests/src/Simple/Generics/Generics.cs @@ -30,6 +30,7 @@ class Program TestGvmDelegates.Run(); TestGvmDependencies.Run(); TestFieldAccess.Run(); + TestNativeLayoutGeneration.Run(); return 100; } @@ -1964,4 +1965,53 @@ class Program throw new Exception(s_NumErrors + " errors!"); } } + + // Regression test for https://github.com/dotnet/corert/issues/3659 + class TestNativeLayoutGeneration + { +#pragma warning disable 649 // s_ref was never assigned + private static object s_ref; +#pragma warning restore 649 + + class Used + { + [MethodImpl(MethodImplOptions.NoInlining)] + public virtual string DoStuff() + { + return "Used"; + } + } + + class Unused<T> : Used + { + [MethodImpl(MethodImplOptions.NoInlining)] + public override string DoStuff() + { + return "Unused " + typeof(T).ToString(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public void Blagh() + { + } + } + + public static void Run() + { + new Used().DoStuff(); + + try + { + // Call an instance method on something we never allocated, but overrides a used virtual. + // This asserted the compiler when trying to build a template for Unused<__Canon>. + ((Unused<object>)s_ref).Blagh(); + } + catch (NullReferenceException) + { + return; + } + + throw new Exception(); + } + } } diff --git a/tests/src/Simple/PInvoke/PInvoke.cs b/tests/src/Simple/PInvoke/PInvoke.cs index fef465840..e4fe3c783 100644 --- a/tests/src/Simple/PInvoke/PInvoke.cs +++ b/tests/src/Simple/PInvoke/PInvoke.cs @@ -519,9 +519,20 @@ namespace PInvokeTests public ExplicitStruct f2; } + + [StructLayout(LayoutKind.Explicit)] + public struct TestStruct2 + { + [FieldOffset(0)] + public int f1; + + [FieldOffset(8)] + public bool f2; + } private static void TestStruct() { +#if !CODEGEN_CPP Console.WriteLine("Testing Structs"); SequentialStruct ss = new SequentialStruct(); ss.f0 = 100; @@ -581,7 +592,24 @@ namespace PInvokeTests InlineUnicodeStruct ius = new InlineUnicodeStruct(); ius.inlineString = "Hello World"; -#if !CODEGEN_CPP + + TestStruct2 ts = new TestStruct2() { f1 = 100, f2 = true }; + int size = Marshal.SizeOf<TestStruct2>(ts); + IntPtr memory = Marshal.AllocHGlobal(size); + try + { + Marshal.StructureToPtr<TestStruct2>(ts, memory, false); + TestStruct2 ts2 = Marshal.PtrToStructure<TestStruct2>(memory); + ThrowIfNotEquals(true, ts2.f1 == 100 && ts2.f2 == true, "Struct marshalling Marshal API failed"); + + IntPtr offset = Marshal.OffsetOf<TestStruct2>("f2"); + ThrowIfNotEquals(new IntPtr(8), offset, "Struct marshalling OffsetOf failed."); + } + finally + { + Marshal.FreeHGlobal(memory); + } + ThrowIfNotEquals(true, InlineArrayTest(ref ias, ref ius), "inline array marshalling failed"); bool pass = true; for (short i = 0; i < 128; i++) |